<commit_before>use ::arch::cpu;
use ::arch::debug;
use ::arch::keyboard::Keyboard;
use ::arch::thread;
use ::phys_mem::{self,PhysicalBitmap};
use ::process::Process;
use ::virt_mem::VirtualTree;
use alloc::heap;
use libc::{self,jmp_buf};
use spin::{Mutex,MutexGuard};
use std::boxed::FnBox;
use std::collections::VecDeque;
use std::mem;
use std::slice::bytes;
use std::slice;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use syscall::ErrNum;

pub fn setjmp() -> Option<jmp_buf> {
    unsafe {
        let mut jmp_buf = mem::uninitialized();
        if libc::setjmp(&mut jmp_buf) == 0 {
            Some(jmp_buf)
        } else {
            None
        }
    }
}

fn drop_write_guard<'a, T>(guard: MutexGuard<'a, T>) {
    mem::drop(guard);
}

fn forget_write_guard<'a, T>(guard: MutexGuard<'a, T>) {
    mem::forget(guard);
}

fn assert_no_lock() {
    assert!(cpu::interrupts_enabled());
}

struct Thread {
    id: usize,
    stack: &'static mut [u8],
    process: Arc<Process>
}

impl Thread {
    pub fn new(process: Arc<Process>, stack: &'static mut [u8]) -> Thread {
        static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT;
        Thread {
            id: NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed),
            stack: stack,
            process: process
        }
    }
}

struct DeferredState<A> {
    result: Option<A>,
    waiters: VecDeque<(jmp_buf, Thread)>
}

struct SchedulerState {
    current: Thread,
    threads: VecDeque<(jmp_buf, Thread)>,
    garbage_stacks: Vec<&'static mut [u8]>
}

#[derive(Clone)]
pub struct Deferred<A> {
    scheduler: Arc<Scheduler>,
    state: Arc<Mutex<DeferredState<A>>>
}

pub struct Scheduler {
    state: Mutex<SchedulerState>
}

impl Scheduler {
    pub fn new(idle_process: Arc<Process>) -> Scheduler {
        let state = SchedulerState {
            current: Thread::new(idle_process, &mut []),
            threads: VecDeque::new(),
            garbage_stacks: Vec::new()
        };

        Scheduler { state: Mutex::new(state) }
    }

    pub fn schedule(&self) {
        assert_no_lock();

        let mut state = lock!(self.state);
        match state.threads.pop_front() {
            Some((new_jmp_buf, new_current)) => {
                let old_current = mem::replace(&mut state.current, new_current);

                match setjmp() {
                    Some(old_jmp_buf) => {
                        state.threads.push_back((old_jmp_buf, old_current));
                        drop_write_guard(state);

                        unsafe {
                            libc::longjmp(&new_jmp_buf, 1);
                        }
                    },

                    None => {
                        forget_write_guard(state);
                    }
                }
            },

            None => { }
        };
    }

    pub fn exit_current(&self) -> ! {
        assert_no_lock();

        let mut state = lock!(self.state);
        let (new_jmp_buf, new_current) =
            match state.threads.pop_front() {
                Some(front) => front,
                None => panic!("exit_current({}): no more threads", state.current.id)
            };

        let old_current = mem::replace(&mut state.current, new_current);
        state.garbage_stacks.push(old_current.stack);
        drop_write_guard(state);

        unsafe {
            libc::longjmp(&new_jmp_buf, 1);
        }
    }

    fn get_deferred<A>(&self, dstate: &Mutex<DeferredState<A>>) -> A {
        loop {
            assert_no_lock();

            let mut dstate = lock!(dstate);
            match mem::replace(&mut dstate.result, None) {
                Some(result) => { return result; },
                None => { }
            }

            let mut state = lock!(self.state);
            let (new_jmp_buf, new_current) =
                match state.threads.pop_front() {
                    Some(front) => front,
                    None => panic!("block({}): no more threads", state.current.id)
                };

            let old_current = mem::replace(&mut state.current, new_current);

            match setjmp() {
                Some(old_jmp_buf) => {
                    dstate.waiters.push_back((old_jmp_buf, old_current));
                    drop_write_guard(state);
                    drop_write_guard(dstate);

                    unsafe {
                        libc::longjmp(&new_jmp_buf, 1);
                    }
                },

                None => {
                    forget_write_guard(state);
                    forget_write_guard(dstate);
                }
            }
        }
    }

    fn try_get_deferred<A>(&self, dstate: &Mutex<DeferredState<A>>) -> Option<A> {
        mem::replace(&mut lock!(dstate).result, None)
    }

    fn resolve_deferred<A>(&self, dstate: &Mutex<DeferredState<A>>, result: A) {
        let mut dstate = lock!(dstate);
        match dstate.result {
            Some(_) => panic!("promise is already resolved"),
            None => { }
        }

        let mut state = lock!(self.state);
        dstate.result = Some(result);

        let mut waiters = mem::replace(&mut dstate.waiters, VecDeque::new());
        state.threads.append(&mut waiters);
    }

    fn spawn_inner(&self, process: Arc<Process>, start: Box<FnBox()>) {
        let stack_len = 4096;
        let stack = unsafe { slice::from_raw_parts_mut(heap::allocate(stack_len, 16), stack_len) };
        let jmp_buf = thread::new_jmp_buf(Box::new(start), stack);
        let thread = Thread::new(process, stack);

        {
            let mut state = lock!(self.state);
            state.threads.push_back((jmp_buf, thread));
        }
    }

    pub fn spawn_user_mode(&self, pc: *const u8, stack: &mut [u8]) {
        let stack_ptr = stack.as_mut_ptr();
        let stack_len = stack.len();

        let start = move || {
            unsafe {
                thread::jmp_user_mode(pc, stack_ptr.offset(stack_len as isize))
            }
            // TODO: free stack
        };

        let process = lock!(self.state).current.process.clone();
        self.spawn_inner(process, Box::new(start))
    }
}

impl Drop for Scheduler {
    fn drop(&mut self) {
        let garbage_stacks = {
            let mut state = lock!(self.state);
            mem::replace(&mut state.garbage_stacks, Vec::new())
        };

        for stack in garbage_stacks {
            unsafe { heap::deallocate(stack.as_mut_ptr(), stack.len(), 16) };
        }
    }
}

pub trait Promise<A> {
    fn get(&self) -> A;
    fn try_get(&self) -> Option<A>;
    // fn then<B>(f: FnOnce(A) -> B) -> Promise<B>;
}

impl<A> Deferred<A> {
    pub fn new(scheduler: Arc<Scheduler>) -> Deferred<A> {
        let dstate = Arc::new(Mutex::new(DeferredState {
            result: None,
            waiters: VecDeque::new()
        }));

        Deferred { scheduler: scheduler, state: dstate }
    }

    pub fn resolve(&self, result: A) {
        self.scheduler.resolve_deferred(&self.state, result)
    }
}

impl<A> Promise<A> for Deferred<A> {
    fn get(&self) -> A {
        self.scheduler.get_deferred(&self.state)
    }

    fn try_get(&self) -> Option<A> {
        self.scheduler.try_get_deferred(&self.state)
    }
}

pub fn spawn_remote<T, A>(scheduler: Arc<Scheduler>, process: Arc<Process>, start: T) -> Deferred<A> where T : FnOnce() -> A + 'static, A : 'static {
    let dstate = Arc::new(Mutex::new(DeferredState {
        result: None,
        waiters: VecDeque::new()
    }));

    let start = {
        let dstate = dstate.clone();
        let scheduler = scheduler.clone();
        move || {
            let result = start();
            scheduler.resolve_deferred(&dstate, result);
            scheduler.exit_current();
        }
    };

    scheduler.spawn_inner(process, Box::new(start));

    Deferred { scheduler: scheduler, state: dstate }
}

pub fn spawn<T, A>(scheduler: Arc<Scheduler>, start: T) -> Deferred<A> where T : FnOnce() -> A + 'static, A : 'static {
    let process = lock!(scheduler.state).current.process.clone();
    spawn_remote(scheduler, process, start)
}

struct TestSyscallHandler {
    scheduler: Arc<Scheduler>,
    dstate: Arc<Mutex<DeferredState<i32>>>,
    keyboard: Keyboard,
    process: Arc<Process>
}

impl ::syscall::Handler for TestSyscallHandler {
    fn write(&self, s: &str) -> Result<(), ErrNum> {
        Ok(debug::puts(s))
    }

    fn exit_thread(&self, code: i32) -> Result<(), ErrNum> {
        self.scheduler.resolve_deferred(&self.dstate, code);
        self.scheduler.exit_current()
    }

    fn read_line(&self, buf: &mut [u8]) -> Result<usize, ErrNum> {
        Ok(self.keyboard.read_line(buf))
    }

    fn alloc_pages(&self, len: usize) -> Result<*mut u8, ErrNum> {
        match self.process.alloc(len, true, true) {
            Ok(slice) => Ok(slice.as_mut_ptr()),
            Err(_) => Err(ErrNum::OutOfMemory)
        }
    }

    fn free_pages(&self, p: *mut u8) -> Result<bool, ErrNum> {
        Ok(self.process.free(p))
    }
}

test! {
    fn can_spawn_exit_thread() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));
        let d = spawn(scheduler, || 123);
        assert_eq!(123, d.get());
    }

    fn can_spawn_exit_two_threads() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));
        let d1 = spawn(scheduler.clone(), || 456);
        let d2 = spawn(scheduler, || 789);
        assert_eq!(456, d1.get());
        assert_eq!(789, d2.get());
    }

    fn can_closure() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));
        let s = String::from("hello");
        let d = spawn(scheduler, move || s + &" world");
        assert_eq!("hello world", d.get());
    }

    fn threads_can_spawn_more_threads() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));

        let thread2_fn = || 1234;

        let thread1_fn = {
            let scheduler = scheduler.clone();
            || {
                let d = spawn(scheduler, thread2_fn);
                d.get() * 2
            }
        };

        let d = spawn(scheduler, thread1_fn);
        assert_eq!(1234 * 2, d.get());
    }

    fn can_run_hello_world() {
        static HELLO: &'static [u8] = include_bytes!("../hello/hello.bin");
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::for_kernel());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));
        let keyboard = Keyboard::new(scheduler.clone());
        p.switch();

        let mut code_slice = p.alloc(HELLO.len(), true, true).unwrap();
        let stack_slice = p.alloc(phys_mem::PAGE_SIZE, true, true).unwrap();
        log!("code_slice = {:p}, stack_slice = {:p}", code_slice.as_ptr(), stack_slice.as_ptr());
        bytes::copy_memory(HELLO, code_slice);
        log!("code_slice = {:?}", &code_slice[0..16]);

        let dstate = Arc::new(Mutex::new(DeferredState {
            result: None,
            waiters: VecDeque::new()
        }));

        let handler = TestSyscallHandler {
            scheduler: scheduler.clone(),
            dstate: dstate.clone(),
            keyboard: keyboard,
            process: p.clone()
        };

        let d = Deferred { scheduler: scheduler.clone(), state: dstate };
        let _x = thread::register_syscall_handler(handler);
        scheduler.spawn_user_mode(code_slice.as_ptr(), stack_slice);

        assert_eq!(0x1234, d.get());
    }
}
<commit_msg>Move spawn and spawn_remote functions<commit_after>use ::arch::cpu;
use ::arch::debug;
use ::arch::keyboard::Keyboard;
use ::arch::thread;
use ::phys_mem::{self,PhysicalBitmap};
use ::process::Process;
use ::virt_mem::VirtualTree;
use alloc::heap;
use libc::{self,jmp_buf};
use spin::{Mutex,MutexGuard};
use std::boxed::FnBox;
use std::collections::VecDeque;
use std::mem;
use std::slice::bytes;
use std::slice;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use syscall::ErrNum;

pub fn setjmp() -> Option<jmp_buf> {
    unsafe {
        let mut jmp_buf = mem::uninitialized();
        if libc::setjmp(&mut jmp_buf) == 0 {
            Some(jmp_buf)
        } else {
            None
        }
    }
}

fn drop_write_guard<'a, T>(guard: MutexGuard<'a, T>) {
    mem::drop(guard);
}

fn forget_write_guard<'a, T>(guard: MutexGuard<'a, T>) {
    mem::forget(guard);
}

fn assert_no_lock() {
    assert!(cpu::interrupts_enabled());
}

struct Thread {
    id: usize,
    stack: &'static mut [u8],
    process: Arc<Process>
}

impl Thread {
    pub fn new(process: Arc<Process>, stack: &'static mut [u8]) -> Thread {
        static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT;
        Thread {
            id: NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed),
            stack: stack,
            process: process
        }
    }
}

struct DeferredState<A> {
    result: Option<A>,
    waiters: VecDeque<(jmp_buf, Thread)>
}

struct SchedulerState {
    current: Thread,
    threads: VecDeque<(jmp_buf, Thread)>,
    garbage_stacks: Vec<&'static mut [u8]>
}

#[derive(Clone)]
pub struct Deferred<A> {
    scheduler: Arc<Scheduler>,
    state: Arc<Mutex<DeferredState<A>>>
}

pub struct Scheduler {
    state: Mutex<SchedulerState>
}

impl Scheduler {
    pub fn new(idle_process: Arc<Process>) -> Scheduler {
        let state = SchedulerState {
            current: Thread::new(idle_process, &mut []),
            threads: VecDeque::new(),
            garbage_stacks: Vec::new()
        };

        Scheduler { state: Mutex::new(state) }
    }

    pub fn schedule(&self) {
        assert_no_lock();

        let mut state = lock!(self.state);
        match state.threads.pop_front() {
            Some((new_jmp_buf, new_current)) => {
                let old_current = mem::replace(&mut state.current, new_current);

                match setjmp() {
                    Some(old_jmp_buf) => {
                        state.threads.push_back((old_jmp_buf, old_current));
                        drop_write_guard(state);

                        unsafe {
                            libc::longjmp(&new_jmp_buf, 1);
                        }
                    },

                    None => {
                        forget_write_guard(state);
                    }
                }
            },

            None => { }
        };
    }

    pub fn exit_current(&self) -> ! {
        assert_no_lock();

        let mut state = lock!(self.state);
        let (new_jmp_buf, new_current) =
            match state.threads.pop_front() {
                Some(front) => front,
                None => panic!("exit_current({}): no more threads", state.current.id)
            };

        let old_current = mem::replace(&mut state.current, new_current);
        state.garbage_stacks.push(old_current.stack);
        drop_write_guard(state);

        unsafe {
            libc::longjmp(&new_jmp_buf, 1);
        }
    }

    fn get_deferred<A>(&self, dstate: &Mutex<DeferredState<A>>) -> A {
        loop {
            assert_no_lock();

            let mut dstate = lock!(dstate);
            match mem::replace(&mut dstate.result, None) {
                Some(result) => { return result; },
                None => { }
            }

            let mut state = lock!(self.state);
            let (new_jmp_buf, new_current) =
                match state.threads.pop_front() {
                    Some(front) => front,
                    None => panic!("block({}): no more threads", state.current.id)
                };

            let old_current = mem::replace(&mut state.current, new_current);

            match setjmp() {
                Some(old_jmp_buf) => {
                    dstate.waiters.push_back((old_jmp_buf, old_current));
                    drop_write_guard(state);
                    drop_write_guard(dstate);

                    unsafe {
                        libc::longjmp(&new_jmp_buf, 1);
                    }
                },

                None => {
                    forget_write_guard(state);
                    forget_write_guard(dstate);
                }
            }
        }
    }

    fn try_get_deferred<A>(&self, dstate: &Mutex<DeferredState<A>>) -> Option<A> {
        mem::replace(&mut lock!(dstate).result, None)
    }

    fn resolve_deferred<A>(&self, dstate: &Mutex<DeferredState<A>>, result: A) {
        let mut dstate = lock!(dstate);
        match dstate.result {
            Some(_) => panic!("promise is already resolved"),
            None => { }
        }

        let mut state = lock!(self.state);
        dstate.result = Some(result);

        let mut waiters = mem::replace(&mut dstate.waiters, VecDeque::new());
        state.threads.append(&mut waiters);
    }

    fn spawn_inner(&self, process: Arc<Process>, start: Box<FnBox()>) {
        let stack_len = 4096;
        let stack = unsafe { slice::from_raw_parts_mut(heap::allocate(stack_len, 16), stack_len) };
        let jmp_buf = thread::new_jmp_buf(Box::new(start), stack);
        let thread = Thread::new(process, stack);

        {
            let mut state = lock!(self.state);
            state.threads.push_back((jmp_buf, thread));
        }
    }

    pub fn spawn_user_mode(&self, pc: *const u8, stack: &mut [u8]) {
        let stack_ptr = stack.as_mut_ptr();
        let stack_len = stack.len();

        let start = move || {
            unsafe {
                thread::jmp_user_mode(pc, stack_ptr.offset(stack_len as isize))
            }
            // TODO: free stack
        };

        let process = lock!(self.state).current.process.clone();
        self.spawn_inner(process, Box::new(start))
    }
}

impl Drop for Scheduler {
    fn drop(&mut self) {
        let garbage_stacks = {
            let mut state = lock!(self.state);
            mem::replace(&mut state.garbage_stacks, Vec::new())
        };

        for stack in garbage_stacks {
            unsafe { heap::deallocate(stack.as_mut_ptr(), stack.len(), 16) };
        }
    }
}

pub trait Promise<A> {
    fn get(&self) -> A;
    fn try_get(&self) -> Option<A>;
    // fn then<B>(f: FnOnce(A) -> B) -> Promise<B>;
}

impl<A> Deferred<A> {
    pub fn new(scheduler: Arc<Scheduler>) -> Deferred<A> {
        let dstate = Arc::new(Mutex::new(DeferredState {
            result: None,
            waiters: VecDeque::new()
        }));

        Deferred { scheduler: scheduler, state: dstate }
    }

    pub fn resolve(&self, result: A) {
        self.scheduler.resolve_deferred(&self.state, result)
    }
}

impl<A> Promise<A> for Deferred<A> {
    fn get(&self) -> A {
        self.scheduler.get_deferred(&self.state)
    }

    fn try_get(&self) -> Option<A> {
        self.scheduler.try_get_deferred(&self.state)
    }
}

pub trait SchedulerExt {
    fn spawn_remote<T, A>(self, process: Arc<Process>, start: T) -> Deferred<A> where T : FnOnce() -> A + 'static, A : 'static;
    fn spawn<T, A>(self, start: T) -> Deferred<A> where T : FnOnce() -> A + 'static, A : 'static;
}

impl SchedulerExt for Arc<Scheduler> {
    fn spawn_remote<T, A>(self, process: Arc<Process>, start: T) -> Deferred<A> where T : FnOnce() -> A + 'static, A : 'static {
        let dstate = Arc::new(Mutex::new(DeferredState {
            result: None,
            waiters: VecDeque::new()
        }));

        let start = {
            let dstate = dstate.clone();
            let scheduler = self.clone();
            move || {
                let result = start();
                scheduler.resolve_deferred(&dstate, result);
                scheduler.exit_current();
            }
        };

        self.spawn_inner(process, Box::new(start));

        Deferred { scheduler: self, state: dstate }
    }

    fn spawn<T, A>(self, start: T) -> Deferred<A> where T : FnOnce() -> A + 'static, A : 'static {
        let process = lock!(self.state).current.process.clone();
        self.spawn_remote(process, start)
    }
}

struct TestSyscallHandler {
    scheduler: Arc<Scheduler>,
    dstate: Arc<Mutex<DeferredState<i32>>>,
    keyboard: Keyboard,
    process: Arc<Process>
}

impl ::syscall::Handler for TestSyscallHandler {
    fn write(&self, s: &str) -> Result<(), ErrNum> {
        Ok(debug::puts(s))
    }

    fn exit_thread(&self, code: i32) -> Result<(), ErrNum> {
        self.scheduler.resolve_deferred(&self.dstate, code);
        self.scheduler.exit_current()
    }

    fn read_line(&self, buf: &mut [u8]) -> Result<usize, ErrNum> {
        Ok(self.keyboard.read_line(buf))
    }

    fn alloc_pages(&self, len: usize) -> Result<*mut u8, ErrNum> {
        match self.process.alloc(len, true, true) {
            Ok(slice) => Ok(slice.as_mut_ptr()),
            Err(_) => Err(ErrNum::OutOfMemory)
        }
    }

    fn free_pages(&self, p: *mut u8) -> Result<bool, ErrNum> {
        Ok(self.process.free(p))
    }
}

test! {
    fn can_spawn_exit_thread() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));
        let d = scheduler.spawn(|| 123);
        assert_eq!(123, d.get());
    }

    fn can_spawn_exit_two_threads() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));
        let d1 = scheduler.clone().spawn(|| 456);
        let d2 = scheduler.spawn(|| 789);
        assert_eq!(456, d1.get());
        assert_eq!(789, d2.get());
    }

    fn can_closure() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));
        let s = String::from("hello");
        let d = scheduler.spawn(move || s + &" world");
        assert_eq!("hello world", d.get());
    }

    fn threads_can_spawn_more_threads() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));

        let thread2_fn = || 1234;

        let thread1_fn = {
            let scheduler = scheduler.clone();
            || {
                let d = scheduler.spawn(thread2_fn);
                d.get() * 2
            }
        };

        let d = scheduler.spawn(thread1_fn);
        assert_eq!(1234 * 2, d.get());
    }

    fn can_run_hello_world() {
        static HELLO: &'static [u8] = include_bytes!("../hello/hello.bin");
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::for_kernel());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p.clone()));
        let keyboard = Keyboard::new(scheduler.clone());
        p.switch();

        let mut code_slice = p.alloc(HELLO.len(), true, true).unwrap();
        let stack_slice = p.alloc(phys_mem::PAGE_SIZE, true, true).unwrap();
        log!("code_slice = {:p}, stack_slice = {:p}", code_slice.as_ptr(), stack_slice.as_ptr());
        bytes::copy_memory(HELLO, code_slice);
        log!("code_slice = {:?}", &code_slice[0..16]);

        let dstate = Arc::new(Mutex::new(DeferredState {
            result: None,
            waiters: VecDeque::new()
        }));

        let handler = TestSyscallHandler {
            scheduler: scheduler.clone(),
            dstate: dstate.clone(),
            keyboard: keyboard,
            process: p.clone()
        };

        let d = Deferred { scheduler: scheduler.clone(), state: dstate };
        let _x = thread::register_syscall_handler(handler);
        scheduler.spawn_user_mode(code_slice.as_ptr(), stack_slice);

        assert_eq!(0x1234, d.get());
    }
}
<|endoftext|>


<commit_before>#[repr(C)]
struct __exit_status {
    __e_termination: ::short_t,
    __e_exit: ::short_t,
}

#[repr(C)]
pub struct utmpx {
    pub ut_type:          ::short_t,
    pub ut_pid:           ::sys::types::pid_t,
    pub ut_line:          [::char_t, ..32u],
    pub ut_id:            [::char_t, ..4u],
    pub ut_user:          [::char_t, ..32u],
    pub ut_host:          [::char_t, ..256u],
    ut_exit:          __exit_status,
    pub ut_session:       i32,
    pub ut_tv:            ::sys::time::timeval,
    pub ut_addr_v6:       [i32, ..4u],
    __glibc_reserved: [::char_t, ..20u],
}

pub static EMPTY:         ::short_t = 0;
pub static BOOT_TIME:     ::short_t = 2;
pub static OLD_TIME:      ::short_t = 4;
pub static NEW_TIME:      ::short_t = 3;
pub static USER_PROCESS:  ::short_t = 7;
pub static INIT_PROCESS:  ::short_t = 5;
pub static LOGIN_PROCESS: ::short_t = 6;
pub static DEAD_PROCESS:  ::short_t = 8;
<commit_msg>utmpx.h<commit_after>#[repr(C)]
struct __exit_status {
    __e_termination: ::short_t,
    __e_exit: ::short_t,
}

#[repr(C)]
pub struct utmpx {
    pub ut_type:          ::short_t,
    pub ut_pid:           ::sys::types::pid_t,
    pub ut_line:          [::char_t, ..32u],
    pub ut_id:            [::char_t, ..4u],
    pub ut_user:          [::char_t, ..32u],
    pub ut_host:          [::char_t, ..256u],
    ut_exit:          __exit_status,
    pub ut_session:       i32,
    pub ut_tv:            ::sys::time::timeval,
    pub ut_addr_v6:       [i32, ..4u],
    __glibc_reserved: [::char_t, ..20u],
}

new!(utmpx)

pub static EMPTY:         ::short_t = 0;
pub static BOOT_TIME:     ::short_t = 2;
pub static OLD_TIME:      ::short_t = 4;
pub static NEW_TIME:      ::short_t = 3;
pub static USER_PROCESS:  ::short_t = 7;
pub static INIT_PROCESS:  ::short_t = 5;
pub static LOGIN_PROCESS: ::short_t = 6;
pub static DEAD_PROCESS:  ::short_t = 8;
<|endoftext|>


<commit_before>
extern crate dsp;

use {Compressor, Detector, EvenGainFunction, PeakCompressor, RmsCompressor};

impl<F, D, EFG> Compressor<F, D, EFG>
    where F: dsp::Frame,
          D: Detector<F>,
          EFG: EvenGainFunction,
{
    /// Compresses the given `output` using an even gain across all channels.
    #[inline]
    pub fn compress_slice(&mut self, frames: &mut [F]) {
        dsp::slice::map_in_place(frames, |f| self.next_frame(f));
    }
}

impl<F, EGF> dsp::Node<F> for PeakCompressor<F, EGF>
    where F: dsp::Frame,
          EGF: EvenGainFunction,
{
    fn audio_requested(&mut self, output: &mut [F], sample_hz: f64) {
        self.update_attack_to_sample_hz(sample_hz);
        self.update_release_to_sample_hz(sample_hz);
        self.compress_slice(output);
    }
}

impl<F, EGF> dsp::Node<F> for RmsCompressor<F, EGF>
    where F: dsp::Frame,
          EGF: EvenGainFunction,
{
    fn audio_requested(&mut self, output: &mut [F], sample_hz: f64) {
        self.update_attack_to_sample_hz(sample_hz);
        self.update_release_to_sample_hz(sample_hz);
        self.update_window_to_sample_hz(sample_hz);
        self.compress_slice(output);
    }
}
<commit_msg>Fix abbreviated generic type names.<commit_after>
extern crate dsp;

use {Compressor, Detector, EvenGainFunction, PeakCompressor, RmsCompressor};

impl<F, D, EGF> Compressor<F, D, EGF>
    where F: dsp::Frame,
          D: Detector<F>,
          EGF: EvenGainFunction,
{
    /// Compresses the given `output` using an even gain across all channels.
    #[inline]
    pub fn compress_slice(&mut self, frames: &mut [F]) {
        dsp::slice::map_in_place(frames, |f| self.next_frame(f));
    }
}

impl<F, EGF> dsp::Node<F> for PeakCompressor<F, EGF>
    where F: dsp::Frame,
          EGF: EvenGainFunction,
{
    fn audio_requested(&mut self, output: &mut [F], sample_hz: f64) {
        self.update_attack_to_sample_hz(sample_hz);
        self.update_release_to_sample_hz(sample_hz);
        self.compress_slice(output);
    }
}

impl<F, EGF> dsp::Node<F> for RmsCompressor<F, EGF>
    where F: dsp::Frame,
          EGF: EvenGainFunction,
{
    fn audio_requested(&mut self, output: &mut [F], sample_hz: f64) {
        self.update_attack_to_sample_hz(sample_hz);
        self.update_release_to_sample_hz(sample_hz);
        self.update_window_to_sample_hz(sample_hz);
        self.compress_slice(output);
    }
}
<|endoftext|>


<commit_before>use wpilib::wpilib_hal::*;

pub fn is_browned_out() -> HalResult<bool> {
    Ok(hal_call!(HAL_GetBrownedOut())? as bool)
}

pub fn is_system_active() -> HalResult<bool> {
    Ok(hal_call!(HAL_GetSystemActive())? as bool)
}

pub fn get_battery_voltage() -> HalResult<f64> {
    hal_call!(HAL_GetVinVoltage())
}
<commit_msg>Fix robot state functions to return correctly<commit_after>use wpilib::wpilib_hal::*;
use wpilib::hal_call::*;

pub fn is_browned_out() -> HalResult<bool> {
    Ok(hal_call!(HAL_GetBrownedOut())? != 0)
}

pub fn is_system_active() -> HalResult<bool> {
    Ok(hal_call!(HAL_GetSystemActive())? != 0)
}

pub fn get_battery_voltage() -> HalResult<f64> {
    hal_call!(HAL_GetVinVoltage())
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::rc::Rc;
use std::cell::RefCell;

use gtk::prelude::*;
use gtk::{DrawingArea, WidgetExt};

use cairo::{Context, Matrix};

pub fn set_up_sounding_area(sounding_area: &DrawingArea, sounding_context: SoundingContextPointer) {

    sounding_area.set_hexpand(true);
    sounding_area.set_vexpand(true);

    sounding_area.connect_draw(move |da, cr| {
        draw_sounding(da, cr, sounding_context.clone())
    });
}

pub type SoundingContextPointer = Rc<RefCell<SoundingContext>>;

pub fn create_sounding_context() -> SoundingContextPointer {
    Rc::new(RefCell::new(SoundingContext {
        zoom_factor: 1.0,
        translate_x: 0.0,
        translate_y: 0.0,
    }))
}

pub struct SoundingContext {
    // Standard x-y coords
    zoom_factor: f32, // Multiply by this after translating
    translate_x: f32, // subtract this from x before converting to screen coords.
    translate_y: f32, // subtract this from y before converting to screen coords.
}

pub type TPCoords = (f32, f32);
pub type XYCoords = (f32, f32);
pub type ScreenCoords = (f64, f64);

impl SoundingContext {
    // Constants for defining a standard x-y coordinate system
    const MAXP: f32 = 1050.0; // mb
    const MINP: f32 = 90.0; // mb
    const MINT: f32 = -46.5; // C - at MAXP
    const MAXT: f32 = 50.5; // C - at MAXP

    // Conversion from temperature (t) and pressure (p) to a standard (x,y) coords
    #[inline]
    pub fn convert_tp_to_xy(coords: TPCoords) -> XYCoords {
        use std::f32;

        let y = (f32::log10(SoundingContext::MAXP) - f32::log10(coords.1)) /
            (f32::log10(SoundingContext::MAXP) - f32::log10(SoundingContext::MINP));
        // let y = f32::log10(-(coords.1 - SoundingContext::MAXP) + 0.00001) /
        //     f32::log10(-(SoundingContext::MINP - SoundingContext::MAXP) + 0.00001);
        let x = (coords.0 - SoundingContext::MINT) /
            (SoundingContext::MAXT - SoundingContext::MINT);
        // do the skew
        let x = x + y;
        (x, y)
    }

    // TODO: implement Conversion from a standard x,y coords to temperature and pressure.
    #[inline]
    pub fn convert_xy_to_tp(coords: XYCoords) -> TPCoords {
        unimplemented!();
    }

    // Conversion from standard x,y coords to screen coords
    #[inline]
    pub fn convert_xy_to_screen(&self, coords: XYCoords) -> ScreenCoords {
        // Screen coords go 0 -> 1 up the y axis and 0 -> aspect_ratio right along the x axis.

        // Apply translation first
        let x = coords.0 - self.translate_x;
        let y = coords.1 - self.translate_y;

        // Apply scaling
        let x = (self.zoom_factor * x) as f64;
        let y = (self.zoom_factor * y) as f64;
        (x, y)
    }

    // TODO: implement Conversion from standard x,y coords to screen coords
    #[inline]
    pub fn convert_screen_to_xy(&self, coords: ScreenCoords) -> XYCoords {
        // Screen coords go 0 -> 1 down the y axis and 0 -> aspect_ratio right along the x axis.

        // Calculate the translation in XYCoords and apply that first

        // Calculate the scaling to get the x-range to fit on screen
        // Calculate the scaling to get the y-range to fit on screen
        // Choose the scaling that is smaller.
        unimplemented!();
    }

    // Conversion from temperature/pressure to screen coordinates.
    #[inline]
    pub fn convert_tp_to_screen(&self, coords: TPCoords) -> ScreenCoords {
        let xy = SoundingContext::convert_tp_to_xy(coords);
        self.convert_xy_to_screen(xy)
    }

    // TODO: implement Conversion from screen coordinates to temperature, pressure.
    #[inline]
    pub fn convert_screen_to_tp(&self, coords: ScreenCoords) -> TPCoords {
        unimplemented!();
    }

    // TODO: implement Adjust the translate & scale values for a zoom.
    #[inline]
    pub fn zoom_to(&mut self, center: ScreenCoords) {
        unimplemented!();
    }

    // TODO: implement Fit to the given x-y max coords.
    #[inline]
    pub fn fit_to(&mut self, lower_left: XYCoords, upper_right: XYCoords) {
        unimplemented!();
    }
}

fn draw_sounding(sounding_area: &DrawingArea, cr: &Context, sc: SoundingContextPointer) -> Inhibit {

    let sc = sc.borrow();

    // Get the dimensions of the DrawingArea
    let alloc = sounding_area.get_allocation();
    let width = alloc.width;
    let height = alloc.height;
    let aspect_ratio = width as f64 / height as f64;

    // Make coordinates x: 0 -> aspect_ratio and y: 0 -> 1.0
    cr.scale(height as f64, height as f64);
    // Set origin at lower right.
    cr.transform(Matrix {
        xx: 1.0,
        yx: 0.0,
        xy: 0.0,
        yy: -1.0,
        x0: 0.0,
        y0: 1.0,
    });

    // Draw black backgound
    cr.rectangle(0.0, 0.0, aspect_ratio, 1.0);
    cr.set_source_rgb(0.0, 0.0, 0.0);
    cr.fill();

    // Draw blue lines below freezing
    let mut end_points: Vec<_> = COLD_ISOTHERMS
        .into_iter()
        .map(|t| {
            ((*t, SoundingContext::MAXP), (*t, SoundingContext::MINP))
        })
        .collect();
    plot_straight_lines(cr, &sc, 1.0, (0.0, 0.0, 1.0, 0.5), &end_points);

    // Draw red lines above freezing
    end_points = WARM_ISOTHERMS
        .into_iter()
        .map(|t| {
            ((*t, SoundingContext::MAXP), (*t, SoundingContext::MINP))
        })
        .collect();
    plot_straight_lines(cr, &sc, 1.0, (1.0, 0.0, 0.0, 0.5), &end_points);

    // Draw pressure lines
    end_points = ISO_BARS
        .into_iter()
        .map(|p| ((-150.0, *p), (60.0, *p)))
        .collect();
    plot_straight_lines(cr, &sc, 1.0, (1.0, 1.0, 1.0, 0.5), &end_points);

    Inhibit(false)
}

#[inline]
fn plot_straight_lines(
    cr: &Context,
    sc: &SoundingContext,
    line_width_pixels: f64,
    rgba: (f64, f64, f64, f64),
    end_points: &[(TPCoords, TPCoords)],
) {
    cr.set_source_rgba(rgba.0, rgba.1, rgba.2, rgba.3);
    cr.set_line_width(cr.device_to_user_distance(line_width_pixels, 0.0).0);
    for &(start, end) in end_points {
        let start = sc.convert_tp_to_screen(start);
        let end = sc.convert_tp_to_screen(end);
        cr.move_to(start.0, start.1);
        cr.line_to(end.0, end.1);
    }
    cr.stroke();
}

const COLD_ISOTHERMS: [f32; 19] = [
    -150.0,
    -140.0,
    -130.0,
    -120.0,
    -110.0,
    -100.0,
    -90.0,
    -80.0,
    -70.0,
    -60.0,
    -50.0,
    -40.0,
    -30.0,
    -25.0,
    -20.0,
    -15.0,
    -10.0,
    -5.0,
    0.0,
];

const WARM_ISOTHERMS: [f32; 12] = [
    5.0,
    10.0,
    15.0,
    20.0,
    25.0,
    30.0,
    35.0,
    40.0,
    45.0,
    50.0,
    55.0,
    60.0,
];

const ISO_BARS: [f32; 9] = [
    1050.0,
    1000.0,
    925.0,
    850.0,
    700.0,
    500.0,
    300.0,
    200.0,
    100.0,
];
<commit_msg>Added isentrops.<commit_after>#![allow(dead_code)]

use std::rc::Rc;
use std::cell::RefCell;

use gtk::prelude::*;
use gtk::{DrawingArea, WidgetExt};

use cairo::{Context, Matrix};

pub fn set_up_sounding_area(sounding_area: &DrawingArea, sounding_context: SoundingContextPointer) {

    sounding_area.set_hexpand(true);
    sounding_area.set_vexpand(true);

    sounding_area.connect_draw(move |da, cr| {
        draw_sounding(da, cr, sounding_context.clone())
    });
}

pub type SoundingContextPointer = Rc<RefCell<SoundingContext>>;

pub fn create_sounding_context() -> SoundingContextPointer {
    Rc::new(RefCell::new(SoundingContext {
        zoom_factor: 1.0,
        translate_x: 0.0,
        translate_y: 0.0,
    }))
}

pub struct SoundingContext {
    // Standard x-y coords
    zoom_factor: f32, // Multiply by this after translating
    translate_x: f32, // subtract this from x before converting to screen coords.
    translate_y: f32, // subtract this from y before converting to screen coords.
}

pub type TPCoords = (f32, f32);
pub type XYCoords = (f32, f32);
pub type ScreenCoords = (f64, f64);

impl SoundingContext {
    // Constants for defining a standard x-y coordinate system
    const MAXP: f32 = 1050.0; // mb
    const MINP: f32 = 90.0; // mb
    const MINT: f32 = -46.5; // C - at MAXP
    const MAXT: f32 = 50.5; // C - at MAXP

    // Conversion from temperature (t) and pressure (p) to a standard (x,y) coords
    #[inline]
    pub fn convert_tp_to_xy(coords: TPCoords) -> XYCoords {
        use std::f32;

        let y = (f32::log10(SoundingContext::MAXP) - f32::log10(coords.1)) /
            (f32::log10(SoundingContext::MAXP) - f32::log10(SoundingContext::MINP));
        // let y = f32::log10(-(coords.1 - SoundingContext::MAXP) + 0.00001) /
        //     f32::log10(-(SoundingContext::MINP - SoundingContext::MAXP) + 0.00001);
        let x = (coords.0 - SoundingContext::MINT) /
            (SoundingContext::MAXT - SoundingContext::MINT);
        // do the skew
        let x = x + y;
        (x, y)
    }

    // TODO: implement Conversion from a standard x,y coords to temperature and pressure.
    #[inline]
    pub fn convert_xy_to_tp(coords: XYCoords) -> TPCoords {
        unimplemented!();
    }

    // Conversion from standard x,y coords to screen coords
    #[inline]
    pub fn convert_xy_to_screen(&self, coords: XYCoords) -> ScreenCoords {
        // Screen coords go 0 -> 1 up the y axis and 0 -> aspect_ratio right along the x axis.

        // Apply translation first
        let x = coords.0 - self.translate_x;
        let y = coords.1 - self.translate_y;

        // Apply scaling
        let x = (self.zoom_factor * x) as f64;
        let y = (self.zoom_factor * y) as f64;
        (x, y)
    }

    // TODO: implement Conversion from standard x,y coords to screen coords
    #[inline]
    pub fn convert_screen_to_xy(&self, coords: ScreenCoords) -> XYCoords {
        // Screen coords go 0 -> 1 down the y axis and 0 -> aspect_ratio right along the x axis.

        // Calculate the translation in XYCoords and apply that first

        // Calculate the scaling to get the x-range to fit on screen
        // Calculate the scaling to get the y-range to fit on screen
        // Choose the scaling that is smaller.
        unimplemented!();
    }

    // Conversion from temperature/pressure to screen coordinates.
    #[inline]
    pub fn convert_tp_to_screen(&self, coords: TPCoords) -> ScreenCoords {
        let xy = SoundingContext::convert_tp_to_xy(coords);
        self.convert_xy_to_screen(xy)
    }

    // TODO: implement Conversion from screen coordinates to temperature, pressure.
    #[inline]
    pub fn convert_screen_to_tp(&self, coords: ScreenCoords) -> TPCoords {
        unimplemented!();
    }

    // TODO: implement Adjust the translate & scale values for a zoom.
    #[inline]
    pub fn zoom_to(&mut self, center: ScreenCoords) {
        unimplemented!();
    }

    // TODO: implement Fit to the given x-y max coords.
    #[inline]
    pub fn fit_to(&mut self, lower_left: XYCoords, upper_right: XYCoords) {
        unimplemented!();
    }
}

fn draw_sounding(sounding_area: &DrawingArea, cr: &Context, sc: SoundingContextPointer) -> Inhibit {

    let sc = sc.borrow();

    // Get the dimensions of the DrawingArea
    let alloc = sounding_area.get_allocation();
    let width = alloc.width;
    let height = alloc.height;
    let aspect_ratio = width as f64 / height as f64;

    // Make coordinates x: 0 -> aspect_ratio and y: 0 -> 1.0
    cr.scale(height as f64, height as f64);
    // Set origin at lower right.
    cr.transform(Matrix {
        xx: 1.0,
        yx: 0.0,
        xy: 0.0,
        yy: -1.0,
        x0: 0.0,
        y0: 1.0,
    });

    // Draw black backgound
    cr.rectangle(0.0, 0.0, aspect_ratio, 1.0);
    cr.set_source_rgb(0.0, 0.0, 0.0);
    cr.fill();

    // Draw isentrops
    for theta in &ISENTROPS {
        plot_curve_from_points(
            cr,
            &sc,
            1.0,
            (0.6, 0.6, 0.0, 0.5),
            generate_isentrop(*theta),
        );
    }

    // Draw blue lines below freezing
    let mut end_points: Vec<_> = COLD_ISOTHERMS
        .into_iter()
        .map(|t| {
            ((*t, SoundingContext::MAXP), (*t, SoundingContext::MINP))
        })
        .collect();
    plot_straight_lines(cr, &sc, 1.0, (0.0, 0.0, 1.0, 0.5), &end_points);

    // Draw red lines above freezing
    end_points = WARM_ISOTHERMS
        .into_iter()
        .map(|t| {
            ((*t, SoundingContext::MAXP), (*t, SoundingContext::MINP))
        })
        .collect();
    plot_straight_lines(cr, &sc, 1.0, (1.0, 0.0, 0.0, 0.5), &end_points);

    // Draw pressure lines
    end_points = ISOBARS
        .into_iter()
        .map(|p| ((-150.0, *p), (60.0, *p)))
        .collect();
    plot_straight_lines(cr, &sc, 1.0, (1.0, 1.0, 1.0, 0.5), &end_points);

    Inhibit(false)
}

#[inline]
fn plot_straight_lines(
    cr: &Context,
    sc: &SoundingContext,
    line_width_pixels: f64,
    rgba: (f64, f64, f64, f64),
    end_points: &[(TPCoords, TPCoords)],
) {
    cr.set_source_rgba(rgba.0, rgba.1, rgba.2, rgba.3);
    cr.set_line_width(cr.device_to_user_distance(line_width_pixels, 0.0).0);
    for &(start, end) in end_points {
        let start = sc.convert_tp_to_screen(start);
        let end = sc.convert_tp_to_screen(end);
        cr.move_to(start.0, start.1);
        cr.line_to(end.0, end.1);
    }
    cr.stroke();
}

fn plot_curve_from_points(
    cr: &Context,
    sc: &SoundingContext,
    line_width_pixels: f64,
    rgba: (f64, f64, f64, f64),
    points: Vec<TPCoords>,
) {
    cr.set_source_rgba(rgba.0, rgba.1, rgba.2, rgba.3);
    cr.set_line_width(cr.device_to_user_distance(line_width_pixels, 0.0).0);

    let mut iter = points.into_iter();
    let start = sc.convert_tp_to_screen(iter.by_ref().next().unwrap());
    cr.move_to(start.0, start.1);
    for end in iter {
        let end = sc.convert_tp_to_screen(end);
        cr.line_to(end.0, end.1);
    }

    cr.stroke();
}

fn generate_isentrop(theta: f32) -> Vec<TPCoords> {
    use std::f32;
    const P0: f32 = 1000.0; // For calcuating theta
    const PS: f32 = SoundingContext::MAXP; // This and the next one are the range to calc for.
    const PF: f32 = 300.0;
    const NUM_PNTS: u32 = 30;

    let mut result = vec![];

    let mut p = SoundingContext::MAXP;
    while p >= 300.0 {
        let t = theta * f32::powf(P0 / p, -0.286) - 273.15;
        result.push((t, p));
        p += (PF - PS) / (NUM_PNTS as f32);
    }

    result
}

const COLD_ISOTHERMS: [f32; 19] = [
    -150.0,
    -140.0,
    -130.0,
    -120.0,
    -110.0,
    -100.0,
    -90.0,
    -80.0,
    -70.0,
    -60.0,
    -50.0,
    -40.0,
    -30.0,
    -25.0,
    -20.0,
    -15.0,
    -10.0,
    -5.0,
    0.0,
];

const WARM_ISOTHERMS: [f32; 12] = [
    5.0,
    10.0,
    15.0,
    20.0,
    25.0,
    30.0,
    35.0,
    40.0,
    45.0,
    50.0,
    55.0,
    60.0,
];

const ISOBARS: [f32; 9] = [
    1050.0,
    1000.0,
    925.0,
    850.0,
    700.0,
    500.0,
    300.0,
    200.0,
    100.0,
];

const ISENTROPS: [f32; 17] = [
    230.0,
    240.0,
    250.0,
    260.0,
    270.0,
    280.0,
    290.0,
    300.0,
    310.0,
    320.0,
    330.0,
    340.0,
    350.0,
    360.0,
    370.0,
    380.0,
    390.0,
];
<|endoftext|>


<commit_before>//! Panic support in the standard library.

#![stable(feature = "core_panic_info", since = "1.41.0")]

use crate::any::Any;
use crate::fmt;

/// A struct providing information about a panic.
///
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
/// function.
///
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
///         println!("panic occurred: {:?}", s);
///     } else {
///         println!("panic occurred");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_info"]
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
    payload: &'a (dyn Any + Send),
    message: Option<&'a fmt::Arguments<'a>>,
    location: &'a Location<'a>,
}

impl<'a> PanicInfo<'a> {
    #[unstable(
        feature = "panic_internals",
        reason = "internal details of the implementation of the `panic!` \
                         and related macros",
        issue = "none"
    )]
    #[doc(hidden)]
    #[inline]
    pub fn internal_constructor(
        message: Option<&'a fmt::Arguments<'a>>,
        location: &'a Location<'a>,
    ) -> Self {
        struct NoPayload;
        PanicInfo { location, message, payload: &NoPayload }
    }

    #[unstable(
        feature = "panic_internals",
        reason = "internal details of the implementation of the `panic!` \
                         and related macros",
        issue = "none"
    )]
    #[doc(hidden)]
    #[inline]
    pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
        self.payload = info;
    }

    /// Returns the payload associated with the panic.
    ///
    /// This will commonly, but not always, be a `&'static str` or [`String`].
    ///
    /// [`String`]: ../../std/string/struct.String.html
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn payload(&self) -> &(dyn Any + Send) {
        self.payload
    }

    /// If the `panic!` macro from the `core` crate (not from `std`)
    /// was used with a formatting string and some additional arguments,
    /// returns that message ready to be used for example with [`fmt::write`]
    ///
    /// [`fmt::write`]: ../fmt/fn.write.html
    #[unstable(feature = "panic_info_message", issue = "66745")]
    pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
        self.message
    }

    /// Returns information about the location from which the panic originated,
    /// if available.
    ///
    /// This method will currently always return [`Some`], but this may change
    /// in future versions.
    ///
    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}' at line {}", location.file(),
    ///             location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn location(&self) -> Option<&Location<'_>> {
        // NOTE: If this is changed to sometimes return None,
        // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
        Some(&self.location)
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for PanicInfo<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("panicked at ")?;
        if let Some(message) = self.message {
            write!(formatter, "'{}', ", message)?
        } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
            write!(formatter, "'{}', ", payload)?
        }
        // NOTE: we cannot use downcast_ref::<String>() here
        // since String is not available in libcore!
        // The payload is a String when `std::panic!` is called with multiple arguments,
        // but in that case the message is also available.

        self.location.fmt(formatter)
    }
}

/// A struct containing information about the location of a panic.
///
/// This structure is created by the [`location`] method of [`PanicInfo`].
///
/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(location) = panic_info.location() {
///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
///     } else {
///         println!("panic occurred but can't get location information...");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_location"]
#[derive(Debug)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
    file: &'a str,
    line: u32,
    col: u32,
}

impl<'a> Location<'a> {
    /// Returns the source location of the caller of this function. If that function's caller is
    /// annotated then its call location will be returned, and so on up the stack to the first call
    /// within a non-tracked function body.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(track_caller)]
    /// use core::panic::Location;
    ///
    /// /// Returns the [`Location`] at which it is called.
    /// #[track_caller]
    /// fn get_caller_location() -> &'static Location<'static> {
    ///     Location::caller()
    /// }
    ///
    /// /// Returns a [`Location`] from within this function's definition.
    /// fn get_just_one_location() -> &'static Location<'static> {
    ///     get_caller_location()
    /// }
    ///
    /// let fixed_location = get_just_one_location();
    /// assert_eq!(fixed_location.file(), file!());
    /// assert_eq!(fixed_location.line(), 15);
    /// assert_eq!(fixed_location.column(), 5);
    ///
    /// // running the same untracked function in a different location gives us the same result
    /// let second_fixed_location = get_just_one_location();
    /// assert_eq!(fixed_location.file(), second_fixed_location.file());
    /// assert_eq!(fixed_location.line(), second_fixed_location.line());
    /// assert_eq!(fixed_location.column(), second_fixed_location.column());
    ///
    /// let this_location = get_caller_location();
    /// assert_eq!(this_location.file(), file!());
    /// assert_eq!(this_location.line(), 29);
    /// assert_eq!(this_location.column(), 21);
    ///
    /// // running the tracked function in a different location produces a different value
    /// let another_location = get_caller_location();
    /// assert_eq!(this_location.file(), another_location.file());
    /// assert_ne!(this_location.line(), another_location.line());
    /// assert_ne!(this_location.column(), another_location.column());
    /// ```
    #[unstable(
        feature = "track_caller",
        reason = "uses #[track_caller] which is not yet stable",
        issue = "47809"
    )]
    #[track_caller]
    pub const fn caller() -> &'static Location<'static> {
        crate::intrinsics::caller_location()
    }
}

impl<'a> Location<'a> {
    #![unstable(
        feature = "panic_internals",
        reason = "internal details of the implementation of the `panic!` \
                          and related macros",
        issue = "none"
    )]
    #[doc(hidden)]
    pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
        Location { file, line, col }
    }

    /// Returns the name of the source file from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}'", location.file());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn file(&self) -> &str {
        self.file
    }

    /// Returns the line number from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at line {}", location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// Returns the column from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at column {}", location.column());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_col", since = "1.25.0")]
    pub fn column(&self) -> u32 {
        self.col
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for Location<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
    }
}

/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
/// and other panic runtimes. Not intended to be stabilized any time soon, do
/// not use.
#[unstable(feature = "std_internals", issue = "none")]
#[doc(hidden)]
pub unsafe trait BoxMeUp {
    /// Take full ownership of the contents.
    /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
    ///
    /// After this method got called, only some dummy default value is left in `self`.
    /// Calling this method twice, or calling `get` after calling this method, is an error.
    ///
    /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
    /// gets a borrowed `dyn BoxMeUp`.
    fn take_box(&mut self) -> *mut (dyn Any + Send);

    /// Just borrow the contents.
    fn get(&mut self) -> &(dyn Any + Send);
}
<commit_msg>Rollup merge of #71480 - GuillaumeGomez:panic-info-example, r=Dylan-DPC<commit_after>//! Panic support in the standard library.

#![stable(feature = "core_panic_info", since = "1.41.0")]

use crate::any::Any;
use crate::fmt;

/// A struct providing information about a panic.
///
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
/// function.
///
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
///         println!("panic occurred: {:?}", s);
///     } else {
///         println!("panic occurred");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_info"]
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
    payload: &'a (dyn Any + Send),
    message: Option<&'a fmt::Arguments<'a>>,
    location: &'a Location<'a>,
}

impl<'a> PanicInfo<'a> {
    #[unstable(
        feature = "panic_internals",
        reason = "internal details of the implementation of the `panic!` \
                         and related macros",
        issue = "none"
    )]
    #[doc(hidden)]
    #[inline]
    pub fn internal_constructor(
        message: Option<&'a fmt::Arguments<'a>>,
        location: &'a Location<'a>,
    ) -> Self {
        struct NoPayload;
        PanicInfo { location, message, payload: &NoPayload }
    }

    #[unstable(
        feature = "panic_internals",
        reason = "internal details of the implementation of the `panic!` \
                         and related macros",
        issue = "none"
    )]
    #[doc(hidden)]
    #[inline]
    pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
        self.payload = info;
    }

    /// Returns the payload associated with the panic.
    ///
    /// This will commonly, but not always, be a `&'static str` or [`String`].
    ///
    /// [`String`]: ../../std/string/struct.String.html
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
    ///         println!("panic occurred: {:?}", s);
    ///     } else {
    ///         println!("panic occurred");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn payload(&self) -> &(dyn Any + Send) {
        self.payload
    }

    /// If the `panic!` macro from the `core` crate (not from `std`)
    /// was used with a formatting string and some additional arguments,
    /// returns that message ready to be used for example with [`fmt::write`]
    ///
    /// [`fmt::write`]: ../fmt/fn.write.html
    #[unstable(feature = "panic_info_message", issue = "66745")]
    pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
        self.message
    }

    /// Returns information about the location from which the panic originated,
    /// if available.
    ///
    /// This method will currently always return [`Some`], but this may change
    /// in future versions.
    ///
    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}' at line {}",
    ///             location.file(),
    ///             location.line(),
    ///         );
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn location(&self) -> Option<&Location<'_>> {
        // NOTE: If this is changed to sometimes return None,
        // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
        Some(&self.location)
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for PanicInfo<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("panicked at ")?;
        if let Some(message) = self.message {
            write!(formatter, "'{}', ", message)?
        } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
            write!(formatter, "'{}', ", payload)?
        }
        // NOTE: we cannot use downcast_ref::<String>() here
        // since String is not available in libcore!
        // The payload is a String when `std::panic!` is called with multiple arguments,
        // but in that case the message is also available.

        self.location.fmt(formatter)
    }
}

/// A struct containing information about the location of a panic.
///
/// This structure is created by the [`location`] method of [`PanicInfo`].
///
/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(location) = panic_info.location() {
///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
///     } else {
///         println!("panic occurred but can't get location information...");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_location"]
#[derive(Debug)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
    file: &'a str,
    line: u32,
    col: u32,
}

impl<'a> Location<'a> {
    /// Returns the source location of the caller of this function. If that function's caller is
    /// annotated then its call location will be returned, and so on up the stack to the first call
    /// within a non-tracked function body.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(track_caller)]
    /// use core::panic::Location;
    ///
    /// /// Returns the [`Location`] at which it is called.
    /// #[track_caller]
    /// fn get_caller_location() -> &'static Location<'static> {
    ///     Location::caller()
    /// }
    ///
    /// /// Returns a [`Location`] from within this function's definition.
    /// fn get_just_one_location() -> &'static Location<'static> {
    ///     get_caller_location()
    /// }
    ///
    /// let fixed_location = get_just_one_location();
    /// assert_eq!(fixed_location.file(), file!());
    /// assert_eq!(fixed_location.line(), 15);
    /// assert_eq!(fixed_location.column(), 5);
    ///
    /// // running the same untracked function in a different location gives us the same result
    /// let second_fixed_location = get_just_one_location();
    /// assert_eq!(fixed_location.file(), second_fixed_location.file());
    /// assert_eq!(fixed_location.line(), second_fixed_location.line());
    /// assert_eq!(fixed_location.column(), second_fixed_location.column());
    ///
    /// let this_location = get_caller_location();
    /// assert_eq!(this_location.file(), file!());
    /// assert_eq!(this_location.line(), 29);
    /// assert_eq!(this_location.column(), 21);
    ///
    /// // running the tracked function in a different location produces a different value
    /// let another_location = get_caller_location();
    /// assert_eq!(this_location.file(), another_location.file());
    /// assert_ne!(this_location.line(), another_location.line());
    /// assert_ne!(this_location.column(), another_location.column());
    /// ```
    #[unstable(
        feature = "track_caller",
        reason = "uses #[track_caller] which is not yet stable",
        issue = "47809"
    )]
    #[track_caller]
    pub const fn caller() -> &'static Location<'static> {
        crate::intrinsics::caller_location()
    }
}

impl<'a> Location<'a> {
    #![unstable(
        feature = "panic_internals",
        reason = "internal details of the implementation of the `panic!` \
                          and related macros",
        issue = "none"
    )]
    #[doc(hidden)]
    pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
        Location { file, line, col }
    }

    /// Returns the name of the source file from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}'", location.file());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn file(&self) -> &str {
        self.file
    }

    /// Returns the line number from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at line {}", location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// Returns the column from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at column {}", location.column());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_col", since = "1.25.0")]
    pub fn column(&self) -> u32 {
        self.col
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for Location<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
    }
}

/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
/// and other panic runtimes. Not intended to be stabilized any time soon, do
/// not use.
#[unstable(feature = "std_internals", issue = "none")]
#[doc(hidden)]
pub unsafe trait BoxMeUp {
    /// Take full ownership of the contents.
    /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
    ///
    /// After this method got called, only some dummy default value is left in `self`.
    /// Calling this method twice, or calling `get` after calling this method, is an error.
    ///
    /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
    /// gets a borrowed `dyn BoxMeUp`.
    fn take_box(&mut self) -> *mut (dyn Any + Send);

    /// Just borrow the contents.
    fn get(&mut self) -> &(dyn Any + Send);
}
<|endoftext|>


<commit_before>//! Asynchronous values.

use core::cell::Cell;
use core::marker::Unpin;
use core::pin::Pin;
use core::option::Option;
use core::ptr::NonNull;
use core::task::{Context, Poll};
use core::ops::{Drop, Generator, GeneratorState};

#[doc(inline)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub use core::future::*;

/// Wrap a generator in a future.
///
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
    GenFuture(x)
}

/// A wrapper around generators used to implement `Future` for `async`/`await` code.
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")]
struct GenFuture<T: Generator<Yield = ()>>(T);

// We rely on the fact that async/await futures are immovable in order to create
// self-referential borrows in the underlying generator.
impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
    type Output = T::Return;
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
        let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
        set_task_context(cx, || match gen.resume() {
            GeneratorState::Yielded(()) => Poll::Pending,
            GeneratorState::Complete(x) => Poll::Ready(x),
        })
    }
}

thread_local! {
    static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
}

struct SetOnDrop(Option<NonNull<Context<'static>>>);

impl Drop for SetOnDrop {
    fn drop(&mut self) {
        TLS_CX.with(|tls_cx| {
            tls_cx.set(self.0.take());
        });
    }
}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// Sets the thread-local task context used by async/await futures.
pub fn set_task_context<F, R>(cx: &mut Context<'_>, f: F) -> R
where
    F: FnOnce() -> R
{
    // transmute the context's lifetime to 'static so we can store it.
    let cx = unsafe {
        core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx)
    };
    let old_cx = TLS_CX.with(|tls_cx| {
        tls_cx.replace(Some(NonNull::from(cx)))
    });
    let _reset = SetOnDrop(old_cx);
    f()
}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// Retrieves the thread-local task context used by async/await futures.
///
/// This function acquires exclusive access to the task context.
///
/// Panics if no context has been set or if the context has already been
/// retrieved by a surrounding call to get_task_context.
pub fn get_task_context<F, R>(f: F) -> R
where
    F: FnOnce(&mut Context<'_>) -> R
{
    let cx_ptr = TLS_CX.with(|tls_cx| {
        // Clear the entry so that nested `get_task_waker` calls
        // will fail or set their own value.
        tls_cx.replace(None)
    });
    let _reset = SetOnDrop(cx_ptr);

    let mut cx_ptr = cx_ptr.expect(
        "TLS Context not set. This is a rustc bug. \
        Please file an issue on https://github.com/rust-lang/rust.");

    // Safety: we've ensured exclusive access to the context by
    // removing the pointer from TLS, only to be replaced once
    // we're done with it.
    //
    // The pointer that was inserted came from an `&mut Context<'_>`,
    // so it is safe to treat as mutable.
    unsafe { f(cx_ptr.as_mut()) }
}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// Polls a future in the current thread-local task waker.
pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
where
    F: Future
{
    get_task_context(|cx| F::poll(f, cx))
}
<commit_msg>Rollup merge of #66398 - sfackler:no-async-nesting, r=Centril<commit_after>//! Asynchronous values.

use core::cell::Cell;
use core::marker::Unpin;
use core::pin::Pin;
use core::option::Option;
use core::ptr::NonNull;
use core::task::{Context, Poll};
use core::ops::{Drop, Generator, GeneratorState};

#[doc(inline)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub use core::future::*;

/// Wrap a generator in a future.
///
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
    GenFuture(x)
}

/// A wrapper around generators used to implement `Future` for `async`/`await` code.
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")]
struct GenFuture<T: Generator<Yield = ()>>(T);

// We rely on the fact that async/await futures are immovable in order to create
// self-referential borrows in the underlying generator.
impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
    type Output = T::Return;
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
        let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
        let _guard = unsafe { set_task_context(cx) };
        match gen.resume() {
            GeneratorState::Yielded(()) => Poll::Pending,
            GeneratorState::Complete(x) => Poll::Ready(x),
        }
    }
}

thread_local! {
    static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
}

struct SetOnDrop(Option<NonNull<Context<'static>>>);

impl Drop for SetOnDrop {
    fn drop(&mut self) {
        TLS_CX.with(|tls_cx| {
            tls_cx.set(self.0.take());
        });
    }
}

// Safety: the returned guard must drop before `cx` is dropped and before
// any previous guard is dropped.
unsafe fn set_task_context(cx: &mut Context<'_>) -> SetOnDrop {
    // transmute the context's lifetime to 'static so we can store it.
    let cx = core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx);
    let old_cx = TLS_CX.with(|tls_cx| {
        tls_cx.replace(Some(NonNull::from(cx)))
    });
    SetOnDrop(old_cx)
}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// Polls a future in the current thread-local task waker.
pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
where
    F: Future
{
    let cx_ptr = TLS_CX.with(|tls_cx| {
        // Clear the entry so that nested `get_task_waker` calls
        // will fail or set their own value.
        tls_cx.replace(None)
    });
    let _reset = SetOnDrop(cx_ptr);

    let mut cx_ptr = cx_ptr.expect(
        "TLS Context not set. This is a rustc bug. \
        Please file an issue on https://github.com/rust-lang/rust.");

    // Safety: we've ensured exclusive access to the context by
    // removing the pointer from TLS, only to be replaced once
    // we're done with it.
    //
    // The pointer that was inserted came from an `&mut Context<'_>`,
    // so it is safe to treat as mutable.
    unsafe { F::poll(f, cx_ptr.as_mut()) }
}
<|endoftext|>


<commit_before>extern crate llvm_sys;

use std::ptr;
use self::llvm_sys::core::*;
use self::llvm_sys::*;
use llvm::codegen::{Context, c_str_ptr};

// Generate LLVM IR for functions built into the language
pub unsafe fn generate_builtins(context: &mut Context) {
    generate_types(context);
    generate_print(context);

    // Generate a `main` function for the script to be housed
    let int32 = LLVMInt32TypeInContext(context.get_context());
    let fn_type = LLVMFunctionType(int32, ptr::null_mut(), 0, 0);
    let main = LLVMAddFunction(context.get_module(), c_str_ptr("main"), fn_type);
    let bb = LLVMAppendBasicBlockInContext(context.get_context(), main, c_str_ptr("entry"));

    // Goes to the end of the block
    LLVMPositionBuilderAtEnd(context.get_builder(), bb);

    // Adds a return statement
    LLVMBuildRet(context.get_builder(), LLVMConstInt(int32, 1, 1));

    // Reposition to the start of the block
    LLVMPositionBuilder(context.get_builder(), bb, LLVMGetFirstInstruction(bb));
}

unsafe fn generate_print(context: &mut Context) {
    // Types
    let void = LLVMVoidTypeInContext(context.get_context());
    let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                  LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];
    let int32_type = LLVMInt32TypeInContext(context.get_context());
    let string_type = LLVMStructTypeInContext(context.get_context(), string_type_fields.as_ptr() as *mut _, 2, 0);

    let args = vec![string_type];

    // 2nd arg is param types (*mut LLVMTypeRef) and 3rd is param count. 4 is variable # of args t/f?
    let fn_type = LLVMFunctionType(void, args.as_ptr() as *mut _, 1, 0);
    let print_fn = LLVMAddFunction(context.get_module(), c_str_ptr("print"), fn_type);

    // Name the param
    let param = LLVMGetFirstParam(print_fn);
    LLVMSetValueName(param, c_str_ptr("str"));

    // Create basic blocks to generate code in
    let start_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("start"));
    let loop_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("loop"));
    let end_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("end"));

    // Start
    LLVMPositionBuilderAtEnd(context.get_builder(), start_block);

    let zero = LLVMConstInt(int32_type, 0, 0);
    let op = LLVMIntPredicate::LLVMIntEQ;
    let offset_ptr = LLVMBuildAlloca(context.get_builder(), int32_type, c_str_ptr("offsetptr"));
    LLVMBuildStore(context.get_builder(), zero, offset_ptr);
    let len = LLVMBuildExtractValue(context.get_builder(), param, 0, c_str_ptr("len"));
    let str_ptr = LLVMBuildExtractValue(context.get_builder(), param, 1, c_str_ptr("strptr"));
    let cmp = LLVMBuildICmp(context.get_builder(), op, len, zero, c_str_ptr("cmp"));

    // Branch to end if string len is 0
    LLVMBuildCondBr(context.get_builder(), cmp, end_block, loop_block);

    // Loop
    LLVMPositionBuilderAtEnd(context.get_builder(), loop_block);

    let offset_val = LLVMBuildLoad(context.get_builder(), offset_ptr, c_str_ptr("offsetsval"));
    let ptr_iter = LLVMBuildAdd(context.get_builder(), str_ptr, offset_val, c_str_ptr("iter"));
    let mut putchar_fn = LLVMGetNamedFunction(context.get_module(), c_str_ptr("putchar"));
    if putchar_fn.is_null() {
        let fn_type2 = LLVMFunctionType(int32_type, vec![int32_type].as_ptr() as *mut _, 1, 0);
        putchar_fn = LLVMAddFunction(context.get_module(), c_str_ptr("putchar"), fn_type2);
    }

    // Print char at ptr_iter here
    LLVMBuildCall(context.get_builder(), putchar_fn, vec![ptr_iter].as_ptr() as *mut _, 1, c_str_ptr(""));

    // TODO: Increment offset_val? (move its init out of the loop?)

    // TODO: If equal to len, branch to end else branch to loop

    LLVMBuildBr(context.get_builder(), end_block);

    // End
    LLVMPositionBuilderAtEnd(context.get_builder(), end_block);
    LLVMBuildRetVoid(context.get_builder());
}

unsafe fn generate_types(context: &mut Context) {
    // Define a string structure that looks like:
    // string {
    //     len: i32,
    //     array: i8*
    // }

    let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                  LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];

//    let struct_type = LLVMStructType(string_type_fields.as_ptr() as *mut _, 2, 0);
//    let const_str_var = LLVMAddGlobal(context.get_module(), struct_type, c_str_ptr("struct.String"));

    let string_struct_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), c_str_ptr("string"));
    LLVMStructSetBody(string_struct_type, string_type_fields.as_ptr() as *mut _, 2, 0);
//    let string_struct = LLVMStructType(struct_type, 2, 0);
}
<commit_msg>Finished writing general flow of print IR.<commit_after>extern crate llvm_sys;

use std::ptr;
use self::llvm_sys::core::*;
use self::llvm_sys::*;
use llvm::codegen::{Context, c_str_ptr};

// Generate LLVM IR for functions built into the language
pub unsafe fn generate_builtins(context: &mut Context) {
    generate_types(context);
    generate_print(context);

    // Generate a `main` function for the script to be housed
    let int32 = LLVMInt32TypeInContext(context.get_context());
    let fn_type = LLVMFunctionType(int32, ptr::null_mut(), 0, 0);
    let main = LLVMAddFunction(context.get_module(), c_str_ptr("main"), fn_type);
    let bb = LLVMAppendBasicBlockInContext(context.get_context(), main, c_str_ptr("entry"));

    // Goes to the end of the block
    LLVMPositionBuilderAtEnd(context.get_builder(), bb);

    // Adds a return statement
    LLVMBuildRet(context.get_builder(), LLVMConstInt(int32, 1, 1));

    // Reposition to the start of the block
    LLVMPositionBuilder(context.get_builder(), bb, LLVMGetFirstInstruction(bb));
}

unsafe fn generate_print(context: &mut Context) {
    // Types
    let void = LLVMVoidTypeInContext(context.get_context());
    let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                  LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];
    let int32_type = LLVMInt32TypeInContext(context.get_context());
    let string_type = LLVMStructTypeInContext(context.get_context(), string_type_fields.as_ptr() as *mut _, 2, 0);

    let args = vec![string_type];

    // 2nd arg is param types (*mut LLVMTypeRef) and 3rd is param count. 4 is variable # of args t/f?
    let fn_type = LLVMFunctionType(void, args.as_ptr() as *mut _, 1, 0);
    let print_fn = LLVMAddFunction(context.get_module(), c_str_ptr("print"), fn_type);

    // Name the param
    let param = LLVMGetFirstParam(print_fn);
    LLVMSetValueName(param, c_str_ptr("str"));

    // Create basic blocks to generate code in
    let start_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("start"));
    let loop_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("loop"));
    let end_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("end"));

    // Start
    LLVMPositionBuilderAtEnd(context.get_builder(), start_block);

    let i32_zero = LLVMConstInt(int32_type, 0, 0);
    let op = LLVMIntPredicate::LLVMIntEQ;
    let offset_ptr = LLVMBuildAlloca(context.get_builder(), int32_type, c_str_ptr("offsetptr"));
    LLVMBuildStore(context.get_builder(), i32_zero, offset_ptr);
    let len = LLVMBuildExtractValue(context.get_builder(), param, 0, c_str_ptr("len"));
    let str_ptr = LLVMBuildExtractValue(context.get_builder(), param, 1, c_str_ptr("strptr"));
    let cmp = LLVMBuildICmp(context.get_builder(), op, len, i32_zero, c_str_ptr("cmp"));

    // Branch to end if string len is 0
    LLVMBuildCondBr(context.get_builder(), cmp, end_block, loop_block);

    // Loop
    LLVMPositionBuilderAtEnd(context.get_builder(), loop_block);

    let offset = LLVMBuildLoad(context.get_builder(), offset_ptr, c_str_ptr("offset"));
    let ptr_iter = LLVMBuildAdd(context.get_builder(), str_ptr, offset, c_str_ptr("iter"));
    let mut putchar_fn = LLVMGetNamedFunction(context.get_module(), c_str_ptr("putchar"));
    if putchar_fn.is_null() {
        let fn_type2 = LLVMFunctionType(int32_type, vec![int32_type].as_ptr() as *mut _, 1, 0);
        putchar_fn = LLVMAddFunction(context.get_module(), c_str_ptr("putchar"), fn_type2);
    }

    // Print char at ptr_iter here
    LLVMBuildCall(context.get_builder(), putchar_fn, vec![ptr_iter].as_ptr() as *mut _, 1, c_str_ptr(""));

    // Increment the offset
    let i32_one = LLVMConstInt(int32_type, 1, 0);
    let inc = LLVMBuildAdd(context.get_builder(), offset, i32_one, c_str_ptr("inc"));
    LLVMBuildStore(context.get_builder(), inc, offset_ptr);

    // Branch if offset equals len, else keep looping
    let op = LLVMIntPredicate::LLVMIntEQ;
    let cmp2 = LLVMBuildICmp(context.get_builder(), op, inc, len, c_str_ptr("cmp"));
    LLVMBuildCondBr(context.get_builder(), cmp2, end_block, loop_block);

    // End
    LLVMPositionBuilderAtEnd(context.get_builder(), end_block);
    LLVMBuildRetVoid(context.get_builder());
}

unsafe fn generate_types(context: &mut Context) {
    // Define a string structure that looks like:
    // string {
    //     len: i32,
    //     array: i8*
    // }

    let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                  LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];

//    let struct_type = LLVMStructType(string_type_fields.as_ptr() as *mut _, 2, 0);
//    let const_str_var = LLVMAddGlobal(context.get_module(), struct_type, c_str_ptr("struct.String"));

    let string_struct_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), c_str_ptr("string"));
    LLVMStructSetBody(string_struct_type, string_type_fields.as_ptr() as *mut _, 2, 0);
//    let string_struct = LLVMStructType(struct_type, 2, 0);
}
<|endoftext|>


<commit_before>generate_error_imports!();
use std::convert::From;

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct CustomErrorData {}

generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
    ConfigurationError      => "Store Configuration Error",
    FileError               => "File Error",
    IoError                 => "IO Error",
    IdLocked                => "ID locked",
    IdNotFound              => "ID not found",
    OutOfMemory             => "Out of Memory",
    FileNotFound            => "File corresponding to ID not found",
    FileNotCreated          => "File corresponding to ID could not be created",
    StorePathExists         => "Store path exists",
    StorePathCreate         => "Store path create",
    LockError               => "Error locking datastructure",
    LockPoisoned            => "The internal Store Lock has been poisoned",
    EntryAlreadyBorrowed    => "Entry is already borrowed",
    EntryAlreadyExists      => "Entry already exists",
    MalformedEntry          => "Entry has invalid formatting, missing header",
    HeaderPathSyntaxError   => "Syntax error in accessor string",
    HeaderPathTypeFailure   => "Header has wrong type for path",
    HeaderKeyNotFound       => "Header Key not found",
    HeaderTypeFailure       => "Header type is wrong",
    HookRegisterError       => "Hook register error",
    AspectNameNotFoundError => "Aspect name not found",
    HookExecutionError      => "Hook execution error",
    PreHookExecuteError     => "Pre-Hook execution error",
    PostHookExecuteError    => "Post-Hook execution error",
    StorePathLacksVersion   => "The supplied store path has no version part",
    GlobError               => "glob() error",
    EncodingError           => "Encoding error",
    StorePathError          => "Store Path error",
    EntryRenameError        => "Entry rename error",

    CreateCallError            => "Error when calling create()",
    RetrieveCallError          => "Error when calling retrieve()",
    GetCallError               => "Error when calling get()",
    GetAllVersionsCallError    => "Error when calling get_all_versions()",
    RetrieveForModuleCallError => "Error when calling retrieve_for_module()",
    UpdateCallError            => "Error when calling update()",
    RetrieveCopyCallError      => "Error when calling retrieve_copy()",
    DeleteCallError            => "Error when calling delete()",
    MoveCallError              => "Error when calling move()",
    MoveByIdCallError          => "Error when calling move_by_id()"
);

generate_custom_error_types!(ParserError, ParserErrorKind, CustomErrorData,
    TOMLParserErrors    => "Several TOML-Parser-Errors",
    MissingMainSection  => "Missing main section",
    MissingVersionInfo  => "Missing version information in main section",
    NonTableInBaseTable => "A non-table was found in the base table",
    HeaderInconsistency => "The header is inconsistent"
);

impl From<ParserError> for StoreError {
    fn from(ps: ParserError) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::MalformedEntry,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

impl From<::std::io::Error> for StoreError {
    fn from(ps: ::std::io::Error) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::IoError,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

<commit_msg>call helper generator macros in error module<commit_after>generate_error_imports!();
use std::convert::From;

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct CustomErrorData {}

generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
    ConfigurationError      => "Store Configuration Error",
    FileError               => "File Error",
    IoError                 => "IO Error",
    IdLocked                => "ID locked",
    IdNotFound              => "ID not found",
    OutOfMemory             => "Out of Memory",
    FileNotFound            => "File corresponding to ID not found",
    FileNotCreated          => "File corresponding to ID could not be created",
    StorePathExists         => "Store path exists",
    StorePathCreate         => "Store path create",
    LockError               => "Error locking datastructure",
    LockPoisoned            => "The internal Store Lock has been poisoned",
    EntryAlreadyBorrowed    => "Entry is already borrowed",
    EntryAlreadyExists      => "Entry already exists",
    MalformedEntry          => "Entry has invalid formatting, missing header",
    HeaderPathSyntaxError   => "Syntax error in accessor string",
    HeaderPathTypeFailure   => "Header has wrong type for path",
    HeaderKeyNotFound       => "Header Key not found",
    HeaderTypeFailure       => "Header type is wrong",
    HookRegisterError       => "Hook register error",
    AspectNameNotFoundError => "Aspect name not found",
    HookExecutionError      => "Hook execution error",
    PreHookExecuteError     => "Pre-Hook execution error",
    PostHookExecuteError    => "Post-Hook execution error",
    StorePathLacksVersion   => "The supplied store path has no version part",
    GlobError               => "glob() error",
    EncodingError           => "Encoding error",
    StorePathError          => "Store Path error",
    EntryRenameError        => "Entry rename error",

    CreateCallError            => "Error when calling create()",
    RetrieveCallError          => "Error when calling retrieve()",
    GetCallError               => "Error when calling get()",
    GetAllVersionsCallError    => "Error when calling get_all_versions()",
    RetrieveForModuleCallError => "Error when calling retrieve_for_module()",
    UpdateCallError            => "Error when calling update()",
    RetrieveCopyCallError      => "Error when calling retrieve_copy()",
    DeleteCallError            => "Error when calling delete()",
    MoveCallError              => "Error when calling move()",
    MoveByIdCallError          => "Error when calling move_by_id()"
);

generate_result_helper!(StoreError, StoreErrorKind);
generate_option_helper!(StoreError, StoreErrorKind);

generate_custom_error_types!(ParserError, ParserErrorKind, CustomErrorData,
    TOMLParserErrors    => "Several TOML-Parser-Errors",
    MissingMainSection  => "Missing main section",
    MissingVersionInfo  => "Missing version information in main section",
    NonTableInBaseTable => "A non-table was found in the base table",
    HeaderInconsistency => "The header is inconsistent"
);

impl From<ParserError> for StoreError {
    fn from(ps: ParserError) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::MalformedEntry,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

impl From<::std::io::Error> for StoreError {
    fn from(ps: ::std::io::Error) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::IoError,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

<|endoftext|>