<commit_before>//! Global descriptor table

use core::convert::TryInto;
use core::mem;

use x86::segmentation::load_cs;
use x86::bits32::task::TaskStateSegment;
use x86::Ring;
use x86::dtables::{self, DescriptorTablePointer};
use x86::segmentation::{self, Descriptor as SegmentDescriptor, SegmentSelector};
use x86::task;

use super::cpuid::cpuid;

pub const GDT_NULL: usize = 0;
pub const GDT_KERNEL_CODE: usize = 1;
pub const GDT_KERNEL_DATA: usize = 2;
pub const GDT_KERNEL_KPCR: usize = 3;
pub const GDT_USER_CODE: usize = 4;
pub const GDT_USER_DATA: usize = 5;
pub const GDT_USER_FS: usize = 6;
pub const GDT_USER_GS: usize = 7;
pub const GDT_TSS: usize = 8;
pub const GDT_CPU_ID_CONTAINER: usize = 9;

pub const GDT_A_PRESENT: u8 = 1 << 7;
pub const GDT_A_RING_0: u8 = 0 << 5;
pub const GDT_A_RING_1: u8 = 1 << 5;
pub const GDT_A_RING_2: u8 = 2 << 5;
pub const GDT_A_RING_3: u8 = 3 << 5;
pub const GDT_A_SYSTEM: u8 = 1 << 4;
pub const GDT_A_EXECUTABLE: u8 = 1 << 3;
pub const GDT_A_CONFORMING: u8 = 1 << 2;
pub const GDT_A_PRIVILEGE: u8 = 1 << 1;
pub const GDT_A_DIRTY: u8 = 1;

pub const GDT_A_TSS_AVAIL: u8 = 0x9;
pub const GDT_A_TSS_BUSY: u8 = 0xB;

pub const GDT_F_PAGE_SIZE: u8 = 1 << 7;
pub const GDT_F_PROTECTED_MODE: u8 = 1 << 6;
pub const GDT_F_LONG_MODE: u8 = 1 << 5;

static mut INIT_GDT: [GdtEntry; 4] = [
    // Null
    GdtEntry::new(0, 0, 0, 0),
    // Kernel code
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // Kernel data
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // Kernel TLS
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
];

#[thread_local]
pub static mut GDT: [GdtEntry; 10] = [
    // Null
    GdtEntry::new(0, 0, 0, 0),
    // Kernel code
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // Kernel data
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // Kernel TLS
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // User (32-bit) code
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // User data
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // User FS (for TLS)
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // User GS (for TLS)
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
    // TSS
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_TSS_AVAIL, 0),
    // Unused entry which stores the CPU ID. This is necessary for paranoid interrupts as they have
    // no other way of determining it.
    GdtEntry::new(0, 0, 0, 0),
];

#[repr(C, align(16))]
pub struct ProcessorControlRegion {
    pub tcb_end: usize,
    pub user_rsp_tmp: usize,
    pub tss: TssWrapper,
}

// NOTE: Despite not using #[repr(packed)], we do know that while there may be some padding
// inserted before and after the TSS, the main TSS structure will remain intact.
#[repr(C, align(16))]
pub struct TssWrapper(pub TaskStateSegment);

#[thread_local]
pub static mut KPCR: ProcessorControlRegion = ProcessorControlRegion {
    tcb_end: 0,
    user_rsp_tmp: 0,
    tss: TssWrapper(TaskStateSegment::new()),
};

#[cfg(feature = "pti")]
pub unsafe fn set_tss_stack(stack: usize) {
    use super::pti::{PTI_CPU_STACK, PTI_CONTEXT_STACK};
    KPCR.tss.0.ss0 = (GDT_KERNEL_DATA << 3) as u16;
    KPCR.tss.0.esp0 = (PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len()) as u32;
    PTI_CONTEXT_STACK = stack;
}

#[cfg(not(feature = "pti"))]
pub unsafe fn set_tss_stack(stack: usize) {
    KPCR.tss.0.ss0 = (GDT_KERNEL_DATA << 3) as u16;
    KPCR.tss.0.esp0 = stack as u32;
}

// Initialize GDT
pub unsafe fn init() {
    {
        // Setup the initial GDT with TLS, so we can setup the TLS GDT (a little confusing)
        // This means that each CPU will have its own GDT, but we only need to define it once as a thread local

        let limit = (INIT_GDT.len() * mem::size_of::<GdtEntry>() - 1)
            .try_into()
            .expect("initial GDT way too large");
        let base = INIT_GDT.as_ptr() as *const SegmentDescriptor;

        let init_gdtr: DescriptorTablePointer<SegmentDescriptor> = DescriptorTablePointer {
            limit,
            base,
        };

        // Load the initial GDT, before we have access to thread locals
        dtables::lgdt(&init_gdtr);
    }

    // Load the segment descriptors
    load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16, Ring::Ring0));
    segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_KPCR as u16, Ring::Ring0));
    segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
}

/// Initialize GDT with TLS
pub unsafe fn init_paging(cpu_id: u32, tcb_offset: usize, stack_offset: usize) {
    //TODO: will this work with multicore?
    {
        INIT_GDT[GDT_KERNEL_KPCR].set_offset(tcb_offset as u32);
        segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_KPCR as u16, Ring::Ring0));
    }

    // Now that we have access to thread locals, begin by getting a pointer to the Processor
    // Control Region.
    let kpcr = &mut KPCR;

    // Then, setup the AP's individual GDT
    let limit = (GDT.len() * mem::size_of::<GdtEntry>() - 1)
        .try_into()
        .expect("main GDT way too large");
    let base = GDT.as_ptr() as *const SegmentDescriptor;

    let gdtr: DescriptorTablePointer<SegmentDescriptor> = DescriptorTablePointer {
        limit,
        base,
    };

    // Once we have fetched the real KPCR address, set the TLS segment to the TCB pointer there.
    kpcr.tcb_end = (tcb_offset as *const usize).read();

    GDT[GDT_KERNEL_KPCR].set_offset(tcb_offset as u32);

    {
        // We can now access our TSS, via the KPCR, which is a thread local
        let tss = &kpcr.tss.0 as *const _ as usize as u32;

        GDT[GDT_TSS].set_offset(tss);
        GDT[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
    }

    // And finally, populate the last GDT entry with the current CPU ID, to allow paranoid
    // interrupt handlers to safely use TLS.
    (&mut GDT[GDT_CPU_ID_CONTAINER] as *mut GdtEntry).cast::<u32>().write(cpu_id);

    // Set the stack pointer to use when coming back from userspace.
    set_tss_stack(stack_offset);

    // Load the new GDT, which is correctly located in thread local storage.
    dtables::lgdt(&gdtr);

    // Reload the segment descriptors
    load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16, Ring::Ring0));
    segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_KPCR as u16, Ring::Ring0));
    segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));

    // Load the task register
    task::load_tr(SegmentSelector::new(GDT_TSS as u16, Ring::Ring0));
}

#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct GdtEntry {
    pub limitl: u16,
    pub offsetl: u16,
    pub offsetm: u8,
    pub access: u8,
    pub flags_limith: u8,
    pub offseth: u8
}

impl GdtEntry {
    pub const fn new(offset: u32, limit: u32, access: u8, flags: u8) -> Self {
        GdtEntry {
            limitl: limit as u16,
            offsetl: offset as u16,
            offsetm: (offset >> 16) as u8,
            access,
            flags_limith: flags & 0xF0 | ((limit >> 16) as u8) & 0x0F,
            offseth: (offset >> 24) as u8
        }
    }

    pub fn offset(&self) -> u32 {
        (self.offsetl as u32) |
        ((self.offsetm as u32) << 16) |
        ((self.offseth as u32) << 24)
    }

    pub fn set_offset(&mut self, offset: u32) {
        self.offsetl = offset as u16;
        self.offsetm = (offset >> 16) as u8;
        self.offseth = (offset >> 24) as u8;
    }

    pub fn set_limit(&mut self, limit: u32) {
        self.limitl = limit as u16;
        self.flags_limith = self.flags_limith & 0xF0 | ((limit >> 16) as u8) & 0x0F;
    }
}
<commit_msg>Set limits for x86 GDT entries<commit_after>//! Global descriptor table

use core::convert::TryInto;
use core::mem;

use x86::segmentation::load_cs;
use x86::bits32::task::TaskStateSegment;
use x86::Ring;
use x86::dtables::{self, DescriptorTablePointer};
use x86::segmentation::{self, Descriptor as SegmentDescriptor, SegmentSelector};
use x86::task;

use super::cpuid::cpuid;

pub const GDT_NULL: usize = 0;
pub const GDT_KERNEL_CODE: usize = 1;
pub const GDT_KERNEL_DATA: usize = 2;
pub const GDT_KERNEL_KPCR: usize = 3;
pub const GDT_USER_CODE: usize = 4;
pub const GDT_USER_DATA: usize = 5;
pub const GDT_USER_FS: usize = 6;
pub const GDT_USER_GS: usize = 7;
pub const GDT_TSS: usize = 8;
pub const GDT_CPU_ID_CONTAINER: usize = 9;

pub const GDT_A_PRESENT: u8 = 1 << 7;
pub const GDT_A_RING_0: u8 = 0 << 5;
pub const GDT_A_RING_1: u8 = 1 << 5;
pub const GDT_A_RING_2: u8 = 2 << 5;
pub const GDT_A_RING_3: u8 = 3 << 5;
pub const GDT_A_SYSTEM: u8 = 1 << 4;
pub const GDT_A_EXECUTABLE: u8 = 1 << 3;
pub const GDT_A_CONFORMING: u8 = 1 << 2;
pub const GDT_A_PRIVILEGE: u8 = 1 << 1;
pub const GDT_A_DIRTY: u8 = 1;

pub const GDT_A_TSS_AVAIL: u8 = 0x9;
pub const GDT_A_TSS_BUSY: u8 = 0xB;

pub const GDT_F_PAGE_SIZE: u8 = 1 << 7;
pub const GDT_F_PROTECTED_MODE: u8 = 1 << 6;
pub const GDT_F_LONG_MODE: u8 = 1 << 5;

static mut INIT_GDT: [GdtEntry; 4] = [
    // Null
    GdtEntry::new(0, 0, 0, 0),
    // Kernel code
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // Kernel data
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // Kernel TLS
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
];

#[thread_local]
pub static mut GDT: [GdtEntry; 10] = [
    // Null
    GdtEntry::new(0, 0, 0, 0),
    // Kernel code
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // Kernel data
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // Kernel TLS
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // User (32-bit) code
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // User data
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // User FS (for TLS)
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // User GS (for TLS)
    GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
    // TSS
    GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_TSS_AVAIL, 0),
    // Unused entry which stores the CPU ID. This is necessary for paranoid interrupts as they have
    // no other way of determining it.
    GdtEntry::new(0, 0, 0, 0),
];

#[repr(C, align(16))]
pub struct ProcessorControlRegion {
    pub tcb_end: usize,
    pub user_rsp_tmp: usize,
    pub tss: TssWrapper,
}

// NOTE: Despite not using #[repr(packed)], we do know that while there may be some padding
// inserted before and after the TSS, the main TSS structure will remain intact.
#[repr(C, align(16))]
pub struct TssWrapper(pub TaskStateSegment);

#[thread_local]
pub static mut KPCR: ProcessorControlRegion = ProcessorControlRegion {
    tcb_end: 0,
    user_rsp_tmp: 0,
    tss: TssWrapper(TaskStateSegment::new()),
};

#[cfg(feature = "pti")]
pub unsafe fn set_tss_stack(stack: usize) {
    use super::pti::{PTI_CPU_STACK, PTI_CONTEXT_STACK};
    KPCR.tss.0.ss0 = (GDT_KERNEL_DATA << 3) as u16;
    KPCR.tss.0.esp0 = (PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len()) as u32;
    PTI_CONTEXT_STACK = stack;
}

#[cfg(not(feature = "pti"))]
pub unsafe fn set_tss_stack(stack: usize) {
    KPCR.tss.0.ss0 = (GDT_KERNEL_DATA << 3) as u16;
    KPCR.tss.0.esp0 = stack as u32;
}

// Initialize GDT
pub unsafe fn init() {
    {
        // Setup the initial GDT with TLS, so we can setup the TLS GDT (a little confusing)
        // This means that each CPU will have its own GDT, but we only need to define it once as a thread local

        let limit = (INIT_GDT.len() * mem::size_of::<GdtEntry>() - 1)
            .try_into()
            .expect("initial GDT way too large");
        let base = INIT_GDT.as_ptr() as *const SegmentDescriptor;

        let init_gdtr: DescriptorTablePointer<SegmentDescriptor> = DescriptorTablePointer {
            limit,
            base,
        };

        // Load the initial GDT, before we have access to thread locals
        dtables::lgdt(&init_gdtr);
    }

    // Load the segment descriptors
    load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16, Ring::Ring0));
    segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_KPCR as u16, Ring::Ring0));
    segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
}

/// Initialize GDT with TLS
pub unsafe fn init_paging(cpu_id: u32, tcb_offset: usize, stack_offset: usize) {
    //TODO: will this work with multicore?
    {
        INIT_GDT[GDT_KERNEL_KPCR].set_offset(tcb_offset as u32);
        segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_KPCR as u16, Ring::Ring0));
    }

    // Now that we have access to thread locals, begin by getting a pointer to the Processor
    // Control Region.
    let kpcr = &mut KPCR;

    // Then, setup the AP's individual GDT
    let limit = (GDT.len() * mem::size_of::<GdtEntry>() - 1)
        .try_into()
        .expect("main GDT way too large");
    let base = GDT.as_ptr() as *const SegmentDescriptor;

    let gdtr: DescriptorTablePointer<SegmentDescriptor> = DescriptorTablePointer {
        limit,
        base,
    };

    // Once we have fetched the real KPCR address, set the TLS segment to the TCB pointer there.
    kpcr.tcb_end = (tcb_offset as *const usize).read();

    GDT[GDT_KERNEL_KPCR].set_offset(tcb_offset as u32);

    {
        // We can now access our TSS, via the KPCR, which is a thread local
        let tss = &kpcr.tss.0 as *const _ as usize as u32;

        GDT[GDT_TSS].set_offset(tss);
        GDT[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
    }

    // And finally, populate the last GDT entry with the current CPU ID, to allow paranoid
    // interrupt handlers to safely use TLS.
    (&mut GDT[GDT_CPU_ID_CONTAINER] as *mut GdtEntry).cast::<u32>().write(cpu_id);

    // Set the stack pointer to use when coming back from userspace.
    set_tss_stack(stack_offset);

    // Load the new GDT, which is correctly located in thread local storage.
    dtables::lgdt(&gdtr);

    // Reload the segment descriptors
    load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16, Ring::Ring0));
    segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
    segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_KPCR as u16, Ring::Ring0));
    segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));

    // Load the task register
    task::load_tr(SegmentSelector::new(GDT_TSS as u16, Ring::Ring0));
}

#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct GdtEntry {
    pub limitl: u16,
    pub offsetl: u16,
    pub offsetm: u8,
    pub access: u8,
    pub flags_limith: u8,
    pub offseth: u8
}

impl GdtEntry {
    pub const fn new(offset: u32, limit: u32, access: u8, flags: u8) -> Self {
        GdtEntry {
            limitl: limit as u16,
            offsetl: offset as u16,
            offsetm: (offset >> 16) as u8,
            access,
            flags_limith: flags & 0xF0 | ((limit >> 16) as u8) & 0x0F,
            offseth: (offset >> 24) as u8
        }
    }

    pub fn offset(&self) -> u32 {
        (self.offsetl as u32) |
        ((self.offsetm as u32) << 16) |
        ((self.offseth as u32) << 24)
    }

    pub fn set_offset(&mut self, offset: u32) {
        self.offsetl = offset as u16;
        self.offsetm = (offset >> 16) as u8;
        self.offseth = (offset >> 24) as u8;
    }

    pub fn set_limit(&mut self, limit: u32) {
        self.limitl = limit as u16;
        self.flags_limith = self.flags_limith & 0xF0 | ((limit >> 16) as u8) & 0x0F;
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::{
    io,
    marker::Unpin,
    pin::Pin,
    task::{self, Poll},
};

use {futures_03_dep::ready, partial_io::PartialOp};

pub struct PartialAsyncRead<R> {
    inner: R,
    ops: Box<dyn Iterator<Item = PartialOp> + Send>,
}

impl<R> PartialAsyncRead<R>
where
    R: Unpin,
{
    pub fn new<I>(inner: R, ops: I) -> Self
    where
        I: IntoIterator<Item = PartialOp>,
        I::IntoIter: Send + 'static,
    {
        PartialAsyncRead {
            inner,
            ops: Box::new(ops.into_iter()),
        }
    }
}

impl<R> tokio_02_dep::io::AsyncRead for PartialAsyncRead<R>
where
    R: tokio_02_dep::io::AsyncRead + Unpin,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        match self.ops.next() {
            Some(PartialOp::Limited(n)) => {
                let len = std::cmp::min(n, buf.len());
                Pin::new(&mut self.inner).poll_read(cx, &mut buf[..len])
            }
            Some(PartialOp::Err(err)) => {
                if err == io::ErrorKind::WouldBlock {
                    cx.waker().wake_by_ref();
                    Poll::Pending
                } else {
                    Err(io::Error::new(
                        err,
                        "error during read, generated by partial-io",
                    ))
                    .into()
                }
            }
            Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
        }
    }
}

impl<R> tokio_03_dep::io::AsyncRead for PartialAsyncRead<R>
where
    R: tokio_03_dep::io::AsyncRead + Unpin,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        buf: &mut tokio_03_dep::io::ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        match self.ops.next() {
            Some(PartialOp::Limited(n)) => {
                let len = std::cmp::min(n, buf.remaining());
                buf.initialize_unfilled();
                let mut sub_buf = buf.take(len);
                ready!(Pin::new(&mut self.inner).poll_read(cx, &mut sub_buf))?;
                let initialized = sub_buf.initialized().len();
                buf.advance(initialized);
                Poll::Ready(Ok(()))
            }
            Some(PartialOp::Err(err)) => {
                if err == io::ErrorKind::WouldBlock {
                    cx.waker().wake_by_ref();
                    Poll::Pending
                } else {
                    Err(io::Error::new(
                        err,
                        "error during read, generated by partial-io",
                    ))
                    .into()
                }
            }
            Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
        }
    }
}

pub struct FuturesPartialAsyncRead<R> {
    inner: R,
    ops: Box<dyn Iterator<Item = PartialOp> + Send>,
}

impl<R> FuturesPartialAsyncRead<R>
where
    R: crate::futures::io::AsyncRead + Unpin,
{
    pub fn new<I>(inner: R, ops: I) -> Self
    where
        I: IntoIterator<Item = PartialOp>,
        I::IntoIter: Send + 'static,
    {
        FuturesPartialAsyncRead {
            inner,
            ops: Box::new(ops.into_iter()),
        }
    }
}

impl<R> crate::futures::io::AsyncRead for FuturesPartialAsyncRead<R>
where
    R: crate::futures::io::AsyncRead + Unpin,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        match self.ops.next() {
            Some(PartialOp::Limited(n)) => {
                let len = std::cmp::min(n, buf.len());
                Pin::new(&mut self.inner).poll_read(cx, &mut buf[..len])
            }
            Some(PartialOp::Err(err)) => {
                if err == io::ErrorKind::WouldBlock {
                    cx.waker().wake_by_ref();
                    Poll::Pending
                } else {
                    Err(io::Error::new(
                        err,
                        "error during read, generated by partial-io",
                    ))
                    .into()
                }
            }
            Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
        }
    }
}
<commit_msg>test: Make the REadBuf usage more correct<commit_after>#![allow(dead_code)]

use std::{
    io,
    marker::Unpin,
    pin::Pin,
    task::{self, Poll},
};

use {futures_03_dep::ready, partial_io::PartialOp};

pub struct PartialAsyncRead<R> {
    inner: R,
    ops: Box<dyn Iterator<Item = PartialOp> + Send>,
}

impl<R> PartialAsyncRead<R>
where
    R: Unpin,
{
    pub fn new<I>(inner: R, ops: I) -> Self
    where
        I: IntoIterator<Item = PartialOp>,
        I::IntoIter: Send + 'static,
    {
        PartialAsyncRead {
            inner,
            ops: Box::new(ops.into_iter()),
        }
    }
}

impl<R> tokio_02_dep::io::AsyncRead for PartialAsyncRead<R>
where
    R: tokio_02_dep::io::AsyncRead + Unpin,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        match self.ops.next() {
            Some(PartialOp::Limited(n)) => {
                let len = std::cmp::min(n, buf.len());
                Pin::new(&mut self.inner).poll_read(cx, &mut buf[..len])
            }
            Some(PartialOp::Err(err)) => {
                if err == io::ErrorKind::WouldBlock {
                    cx.waker().wake_by_ref();
                    Poll::Pending
                } else {
                    Err(io::Error::new(
                        err,
                        "error during read, generated by partial-io",
                    ))
                    .into()
                }
            }
            Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
        }
    }
}

impl<R> tokio_03_dep::io::AsyncRead for PartialAsyncRead<R>
where
    R: tokio_03_dep::io::AsyncRead + Unpin,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        buf: &mut tokio_03_dep::io::ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        match self.ops.next() {
            Some(PartialOp::Limited(n)) => {
                let len = std::cmp::min(n, buf.remaining());
                buf.initialize_unfilled();
                let mut sub_buf = buf.take(len);
                ready!(Pin::new(&mut self.inner).poll_read(cx, &mut sub_buf))?;
                let filled = sub_buf.filled().len();
                buf.advance(filled);
                Poll::Ready(Ok(()))
            }
            Some(PartialOp::Err(err)) => {
                if err == io::ErrorKind::WouldBlock {
                    cx.waker().wake_by_ref();
                    Poll::Pending
                } else {
                    Err(io::Error::new(
                        err,
                        "error during read, generated by partial-io",
                    ))
                    .into()
                }
            }
            Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
        }
    }
}

pub struct FuturesPartialAsyncRead<R> {
    inner: R,
    ops: Box<dyn Iterator<Item = PartialOp> + Send>,
}

impl<R> FuturesPartialAsyncRead<R>
where
    R: crate::futures::io::AsyncRead + Unpin,
{
    pub fn new<I>(inner: R, ops: I) -> Self
    where
        I: IntoIterator<Item = PartialOp>,
        I::IntoIter: Send + 'static,
    {
        FuturesPartialAsyncRead {
            inner,
            ops: Box::new(ops.into_iter()),
        }
    }
}

impl<R> crate::futures::io::AsyncRead for FuturesPartialAsyncRead<R>
where
    R: crate::futures::io::AsyncRead + Unpin,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        match self.ops.next() {
            Some(PartialOp::Limited(n)) => {
                let len = std::cmp::min(n, buf.len());
                Pin::new(&mut self.inner).poll_read(cx, &mut buf[..len])
            }
            Some(PartialOp::Err(err)) => {
                if err == io::ErrorKind::WouldBlock {
                    cx.waker().wake_by_ref();
                    Poll::Pending
                } else {
                    Err(io::Error::new(
                        err,
                        "error during read, generated by partial-io",
                    ))
                    .into()
                }
            }
            Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
        }
    }
}
<|endoftext|>


<commit_before>use std::iter::FromIterator;
use std::vec::IntoIter;

use super::Value;

/// A Object value
#[derive(Debug, Clone, PartialEq)]
pub struct Object<S> {
    key_value_list: Vec<(String, Value<S>)>,
}

impl<S> Object<S> {
    /// Create a new Object value with a fixed number of
    /// preallocated slots for field-value pairs
    pub fn with_capacity(size: usize) -> Self {
        Object {
            key_value_list: Vec::with_capacity(size),
        }
    }

    /// Add a new field with a value
    ///
    /// If there is already a field with the same name the old value
    /// is returned
    pub fn add_field<K>(&mut self, k: K, value: Value<S>) -> Option<Value<S>>
    where
        K: Into<String>,
        for<'a> &'a str: PartialEq<K>,
    {
        if let Some(item) = self
            .key_value_list
            .iter_mut()
            .find(|&&mut (ref key, _)| (key as &str) == k)
        {
            return Some(::std::mem::replace(&mut item.1, value));
        }
        self.key_value_list.push((k.into(), value));
        None
    }

    /// Check if the object already contains a field with the given name
    pub fn contains_field<K>(&self, f: K) -> bool
    where
        for<'a> &'a str: PartialEq<K>,
    {
        self.key_value_list
            .iter()
            .any(|&(ref key, _)| (key as &str) == f)
    }

    /// Get a iterator over all field value pairs
    ///
    /// This method returns a iterator over `&'a (String, Value)`
    // TODO: change this to `-> impl Iterator<Item = &(String, Value)>`
    // as soon as juniper bumps the minimal supported rust verion to 1.26
    pub fn iter(&self) -> FieldIter<S> {
        FieldIter {
            inner: self.key_value_list.iter(),
        }
    }

    /// Get a iterator over all mutable field value pairs
    ///
    /// This method returns a iterator over `&mut 'a (String, Value)`
    // TODO: change this to `-> impl Iterator<Item = &mut (String, Value)>`
    // as soon as juniper bumps the minimal supported rust verion to 1.26
    pub fn iter_mut(&mut self) -> FieldIterMut<S> {
        FieldIterMut {
            inner: self.key_value_list.iter_mut(),
        }
    }

    /// Get the current number of fields
    pub fn field_count(&self) -> usize {
        self.key_value_list.len()
    }

    /// Get the value for a given field
    pub fn get_field_value<K>(&self, key: K) -> Option<&Value<S>>
    where
        for<'a> &'a str: PartialEq<K>,
    {
        self.key_value_list
            .iter()
            .find(|&&(ref k, _)| (k as &str) == key)
            .map(|&(_, ref value)| value)
    }
}

impl<S> IntoIterator for Object<S> {
    type Item = (String, Value<S>);
    type IntoIter = IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.key_value_list.into_iter()
    }
}

impl<S> From<Object<S>> for Value<S> {
    fn from(o: Object<S>) -> Self {
        Value::Object(o)
    }
}

impl<K, S> FromIterator<(K, Value<S>)> for Object<S>
where
    K: Into<String>,
    for<'a> &'a str: PartialEq<K>,
{
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = (K, Value<S>)>,
    {
        let iter = iter.into_iter();
        let mut ret = Self {
            key_value_list: Vec::with_capacity(iter.size_hint().0),
        };
        for (k, v) in iter {
            ret.add_field(k, v);
        }
        ret
    }
}

#[doc(hidden)]
pub struct FieldIter<'a, S: 'a> {
    inner: ::std::slice::Iter<'a, (String, Value<S>)>,
}

impl<'a, S> Iterator for FieldIter<'a, S> {
    type Item = &'a (String, Value<S>);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}

#[doc(hidden)]
pub struct FieldIterMut<'a, S: 'a> {
    inner: ::std::slice::IterMut<'a, (String, Value<S>)>,
}

impl<'a, S> Iterator for FieldIterMut<'a, S> {
    type Item = &'a mut (String, Value<S>);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}
<commit_msg>Fix TODO for return type<commit_after>use std::iter::FromIterator;
use std::vec::IntoIter;

use super::Value;

/// A Object value
#[derive(Debug, Clone, PartialEq)]
pub struct Object<S> {
    key_value_list: Vec<(String, Value<S>)>,
}

impl<S> Object<S> {
    /// Create a new Object value with a fixed number of
    /// preallocated slots for field-value pairs
    pub fn with_capacity(size: usize) -> Self {
        Object {
            key_value_list: Vec::with_capacity(size),
        }
    }

    /// Add a new field with a value
    ///
    /// If there is already a field with the same name the old value
    /// is returned
    pub fn add_field<K>(&mut self, k: K, value: Value<S>) -> Option<Value<S>>
    where
        K: Into<String>,
        for<'a> &'a str: PartialEq<K>,
    {
        if let Some(item) = self
            .key_value_list
            .iter_mut()
            .find(|&&mut (ref key, _)| (key as &str) == k)
        {
            return Some(::std::mem::replace(&mut item.1, value));
        }
        self.key_value_list.push((k.into(), value));
        None
    }

    /// Check if the object already contains a field with the given name
    pub fn contains_field<K>(&self, f: K) -> bool
    where
        for<'a> &'a str: PartialEq<K>,
    {
        self.key_value_list
            .iter()
            .any(|&(ref key, _)| (key as &str) == f)
    }

    /// Get a iterator over all field value pairs
    pub fn iter(&self) -> impl Iterator<Item = &(String, Value<S>)> {
        FieldIter {
            inner: self.key_value_list.iter(),
        }
    }

    /// Get a iterator over all mutable field value pairs
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (String, Value<S>)> {
        FieldIterMut {
            inner: self.key_value_list.iter_mut(),
        }
    }

    /// Get the current number of fields
    pub fn field_count(&self) -> usize {
        self.key_value_list.len()
    }

    /// Get the value for a given field
    pub fn get_field_value<K>(&self, key: K) -> Option<&Value<S>>
    where
        for<'a> &'a str: PartialEq<K>,
    {
        self.key_value_list
            .iter()
            .find(|&&(ref k, _)| (k as &str) == key)
            .map(|&(_, ref value)| value)
    }
}

impl<S> IntoIterator for Object<S> {
    type Item = (String, Value<S>);
    type IntoIter = IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.key_value_list.into_iter()
    }
}

impl<S> From<Object<S>> for Value<S> {
    fn from(o: Object<S>) -> Self {
        Value::Object(o)
    }
}

impl<K, S> FromIterator<(K, Value<S>)> for Object<S>
where
    K: Into<String>,
    for<'a> &'a str: PartialEq<K>,
{
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = (K, Value<S>)>,
    {
        let iter = iter.into_iter();
        let mut ret = Self {
            key_value_list: Vec::with_capacity(iter.size_hint().0),
        };
        for (k, v) in iter {
            ret.add_field(k, v);
        }
        ret
    }
}

#[doc(hidden)]
pub struct FieldIter<'a, S: 'a> {
    inner: ::std::slice::Iter<'a, (String, Value<S>)>,
}

impl<'a, S> Iterator for FieldIter<'a, S> {
    type Item = &'a (String, Value<S>);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}

#[doc(hidden)]
pub struct FieldIterMut<'a, S: 'a> {
    inner: ::std::slice::IterMut<'a, (String, Value<S>)>,
}

impl<'a, S> Iterator for FieldIterMut<'a, S> {
    type Item = &'a mut (String, Value<S>);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}
<|endoftext|>


<commit_before>extern crate rz80;

#[cfg(test)]
mod test_zexdoc {
    use rz80;
    use rz80::C as C;
    use rz80::E as E;
    use rz80::DE as DE;
    use rz80::SP as SP;

    static ZEXDOC: &'static [u8] = include_bytes!("zexdoc.com");

    // emulates a CP/M BDOS call, only what's needed by ZEX
    fn cpm_bdos(cpu: &mut rz80::CPU) {
        match cpu.reg[C] {
            2 => {
                // output a character
                print!("{}", cpu.reg[E] as u8 as char)
            },
            9 => {
                // output a string
                let mut addr = cpu.r16_i(DE);
                loop {
                    let c = cpu.mem.r8(addr) as u8 as char;
                    addr = (addr + 1) & 0xFFFF;
                    if c != '$' {
                        print!("{}", c);
                    }
                    else {
                        break;
                    }
                }
            },
            _ => {
                panic!("Unknown CP/M call {}!", cpu.reg[C]);
            }
        }
        // emulate a RET
        let sp = cpu.r16_i(SP);
        cpu.pc = cpu.mem.r16(sp);
        cpu.w16_i(SP, sp + 2);
    }

    #[test]
    #[ignore]
    fn test_zexdoc() {
        let mut cpu = rz80::CPU::new();
        cpu.mem.write(0x0100, &ZEXDOC);
        cpu.w16_i(SP, 0xF000);
        cpu.pc = 0x0100;
        loop {
            cpu.step();
            if cpu.pc == 0x0005 {
                // emulated CP/M BDOS call
                cpm_bdos(&mut cpu);
            }
            else if cpu.pc == 0x0000 {
                break;
            }
        }
    }
}

<commit_msg>Minor code tweaks<commit_after>extern crate rz80;

#[cfg(test)]
mod test_zexdoc {
    use rz80;
    use rz80::C as C;
    use rz80::E as E;
    use rz80::DE as DE;
    use rz80::SP as SP;

    static ZEXDOC: &'static [u8] = include_bytes!("zexdoc.com");

    // emulates a CP/M BDOS call, only what's needed by ZEX
    fn cpm_bdos(cpu: &mut rz80::CPU) {
        match cpu.reg[C] {
            2 => {
                // output a character
                print!("{}", cpu.reg[E] as u8 as char);
            },
            9 => {
                // output a string
                let mut addr = cpu.r16_i(DE);
                loop {
                    let c = cpu.mem.r8(addr) as u8 as char;
                    addr = (addr + 1) & 0xFFFF;
                    if c != '$' {
                        print!("{}", c);
                    }
                    else {
                        break;
                    }
                }
            },
            _ => {
                panic!("Unknown CP/M call {}!", cpu.reg[C]);
            }
        }
        // emulate a RET
        let sp = cpu.r16_i(SP);
        cpu.pc = cpu.mem.r16(sp);
        cpu.w16_i(SP, sp + 2);
    }

    #[test]
    #[ignore]
    fn test_zexdoc() {
        let mut cpu = rz80::CPU::new();
        cpu.mem.write(0x0100, &ZEXDOC);
        cpu.w16_i(SP, 0xF000);
        cpu.pc = 0x0100;
        loop {
            cpu.step();
            if cpu.pc == 0x0005 {
                // emulated CP/M BDOS call
                cpm_bdos(&mut cpu);
            }
            else if cpu.pc == 0x0000 {
                break;
            }
        }
    }
}

<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/tokio-macros/0.2.0")]
#![warn(
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub
)]
#![deny(intra_doc_link_resolution_failure)]
#![doc(test(
    no_crate_inject,
    attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]

//! Macros for use with Tokio

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;

enum Runtime {
    Basic,
    Threaded,
    Auto,
}

/// Marks async function to be executed by selected runtime.
///
/// ## Options:
///
/// - `basic_scheduler` - All tasks are executed on the current thread.
/// - `threaded_scheduler` - Uses the multi-threaded scheduler. Used by default.
///
/// ## Function arguments:
///
/// Arguments are allowed for any functions aside from `main` which is special
///
/// ## Usage
///
/// ### Using default
///
/// ```rust
/// #[tokio::main]
/// async fn main() {
///     println!("Hello world");
/// }
/// ```
///
/// ### Select runtime
///
/// ```rust
/// #[tokio::main(basic_scheduler)]
/// async fn main() {
///     println!("Hello world");
/// }
/// ```
#[proc_macro_attribute]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    let ret = &input.sig.output;
    let name = &input.sig.ident;
    let inputs = &input.sig.inputs;
    let body = &input.block;
    let attrs = &input.attrs;

    if input.sig.asyncness.is_none() {
        let msg = "the async keyword is missing from the function declaration";
        return syn::Error::new_spanned(input.sig.fn_token, msg)
            .to_compile_error()
            .into();
    } else if name == "main" && !inputs.is_empty() {
        let msg = "the main function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    let mut runtime = Runtime::Auto;

    for arg in args {
        if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
            let ident = path.get_ident();
            if ident.is_none() {
                let msg = "Must have specified ident";
                return syn::Error::new_spanned(path, msg).to_compile_error().into();
            }
            match ident.unwrap().to_string().to_lowercase().as_str() {
                "threaded_scheduler" => runtime = Runtime::Threaded,
                "basic_scheduler" => runtime = Runtime::Basic,
                name => {
                    let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                    return syn::Error::new_spanned(path, msg).to_compile_error().into();
                }
            }
        }
    }

    let result = match runtime {
        Runtime::Threaded | Runtime::Auto => quote! {
            #(#attrs)*
            fn #name(#inputs) #ret {
                tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
            }
        },
        Runtime::Basic => quote! {
            #(#attrs)*
            fn #name(#inputs) #ret {
                tokio::runtime::Builder::new()
                    .basic_scheduler()
                    .enable_all()
                    .build()
                    .unwrap()
                    .block_on(async { #body })
            }
        },
    };

    result.into()
}

/// Marks async function to be executed by runtime, suitable to test enviornment
///
/// ## Options:
///
/// - `basic_scheduler` - All tasks are executed on the current thread. Used by default.
/// - `threaded_scheduler` - Use multi-threaded scheduler.
///
/// ## Usage
///
/// ### Select runtime
///
/// ```no_run
/// #[tokio::test(threaded_scheduler)]
/// async fn my_test() {
///     assert!(true);
/// }
/// ```
///
/// ### Using default
///
/// ```no_run
/// #[tokio::test]
/// async fn my_test() {
///     assert!(true);
/// }
/// ```
#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    let ret = &input.sig.output;
    let name = &input.sig.ident;
    let body = &input.block;
    let attrs = &input.attrs;

    for attr in attrs {
        if attr.path.is_ident("test") {
            let msg = "second test attribute is supplied";
            return syn::Error::new_spanned(&attr, msg)
                .to_compile_error()
                .into();
        }
    }

    if input.sig.asyncness.is_none() {
        let msg = "the async keyword is missing from the function declaration";
        return syn::Error::new_spanned(&input.sig.fn_token, msg)
            .to_compile_error()
            .into();
    } else if !input.sig.inputs.is_empty() {
        let msg = "the test function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    let mut runtime = Runtime::Auto;

    for arg in args {
        if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
            let ident = path.get_ident();
            if ident.is_none() {
                let msg = "Must have specified ident";
                return syn::Error::new_spanned(path, msg).to_compile_error().into();
            }
            match ident.unwrap().to_string().to_lowercase().as_str() {
                "threaded_scheduler" => runtime = Runtime::Threaded,
                "basic_scheduler" => runtime = Runtime::Basic,
                name => {
                    let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                    return syn::Error::new_spanned(path, msg).to_compile_error().into();
                }
            }
        }
    }

    let result = match runtime {
        Runtime::Threaded => quote! {
            #[test]
            #(#attrs)*
            fn #name() #ret {
                tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
            }
        },
        Runtime::Basic | Runtime::Auto => quote! {
            #[test]
            #(#attrs)*
            fn #name() #ret {
                tokio::runtime::Builder::new()
                    .basic_scheduler()
                    .enable_all()
                    .build()
                    .unwrap()
                    .block_on(async { #body })
            }
        },
    };

    result.into()
}
<commit_msg>macros: inherit visibility<commit_after>#![doc(html_root_url = "https://docs.rs/tokio-macros/0.2.0")]
#![warn(
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub
)]
#![deny(intra_doc_link_resolution_failure)]
#![doc(test(
    no_crate_inject,
    attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]

//! Macros for use with Tokio

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;

enum Runtime {
    Basic,
    Threaded,
    Auto,
}

/// Marks async function to be executed by selected runtime.
///
/// ## Options:
///
/// - `basic_scheduler` - All tasks are executed on the current thread.
/// - `threaded_scheduler` - Uses the multi-threaded scheduler. Used by default.
///
/// ## Function arguments:
///
/// Arguments are allowed for any functions aside from `main` which is special
///
/// ## Usage
///
/// ### Using default
///
/// ```rust
/// #[tokio::main]
/// async fn main() {
///     println!("Hello world");
/// }
/// ```
///
/// ### Select runtime
///
/// ```rust
/// #[tokio::main(basic_scheduler)]
/// async fn main() {
///     println!("Hello world");
/// }
/// ```
#[proc_macro_attribute]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    let ret = &input.sig.output;
    let name = &input.sig.ident;
    let inputs = &input.sig.inputs;
    let body = &input.block;
    let attrs = &input.attrs;
    let vis = input.vis;

    if input.sig.asyncness.is_none() {
        let msg = "the async keyword is missing from the function declaration";
        return syn::Error::new_spanned(input.sig.fn_token, msg)
            .to_compile_error()
            .into();
    } else if name == "main" && !inputs.is_empty() {
        let msg = "the main function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    let mut runtime = Runtime::Auto;

    for arg in args {
        if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
            let ident = path.get_ident();
            if ident.is_none() {
                let msg = "Must have specified ident";
                return syn::Error::new_spanned(path, msg).to_compile_error().into();
            }
            match ident.unwrap().to_string().to_lowercase().as_str() {
                "threaded_scheduler" => runtime = Runtime::Threaded,
                "basic_scheduler" => runtime = Runtime::Basic,
                name => {
                    let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                    return syn::Error::new_spanned(path, msg).to_compile_error().into();
                }
            }
        }
    }

    let result = match runtime {
        Runtime::Threaded | Runtime::Auto => quote! {
            #(#attrs)*
            #vis fn #name(#inputs) #ret {
                tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
            }
        },
        Runtime::Basic => quote! {
            #(#attrs)*
            #vis fn #name(#inputs) #ret {
                tokio::runtime::Builder::new()
                    .basic_scheduler()
                    .enable_all()
                    .build()
                    .unwrap()
                    .block_on(async { #body })
            }
        },
    };

    result.into()
}

/// Marks async function to be executed by runtime, suitable to test enviornment
///
/// ## Options:
///
/// - `basic_scheduler` - All tasks are executed on the current thread. Used by default.
/// - `threaded_scheduler` - Use multi-threaded scheduler.
///
/// ## Usage
///
/// ### Select runtime
///
/// ```no_run
/// #[tokio::test(threaded_scheduler)]
/// async fn my_test() {
///     assert!(true);
/// }
/// ```
///
/// ### Using default
///
/// ```no_run
/// #[tokio::test]
/// async fn my_test() {
///     assert!(true);
/// }
/// ```
#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    let ret = &input.sig.output;
    let name = &input.sig.ident;
    let body = &input.block;
    let attrs = &input.attrs;
    let vis = input.vis;

    for attr in attrs {
        if attr.path.is_ident("test") {
            let msg = "second test attribute is supplied";
            return syn::Error::new_spanned(&attr, msg)
                .to_compile_error()
                .into();
        }
    }

    if input.sig.asyncness.is_none() {
        let msg = "the async keyword is missing from the function declaration";
        return syn::Error::new_spanned(&input.sig.fn_token, msg)
            .to_compile_error()
            .into();
    } else if !input.sig.inputs.is_empty() {
        let msg = "the test function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    let mut runtime = Runtime::Auto;

    for arg in args {
        if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
            let ident = path.get_ident();
            if ident.is_none() {
                let msg = "Must have specified ident";
                return syn::Error::new_spanned(path, msg).to_compile_error().into();
            }
            match ident.unwrap().to_string().to_lowercase().as_str() {
                "threaded_scheduler" => runtime = Runtime::Threaded,
                "basic_scheduler" => runtime = Runtime::Basic,
                name => {
                    let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                    return syn::Error::new_spanned(path, msg).to_compile_error().into();
                }
            }
        }
    }

    let result = match runtime {
        Runtime::Threaded => quote! {
            #[test]
            #(#attrs)*
            #vis fn #name() #ret {
                tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
            }
        },
        Runtime::Basic | Runtime::Auto => quote! {
            #[test]
            #(#attrs)*
            #vis fn #name() #ret {
                tokio::runtime::Builder::new()
                    .basic_scheduler()
                    .enable_all()
                    .build()
                    .unwrap()
                    .block_on(async { #body })
            }
        },
    };

    result.into()
}
<|endoftext|>


<commit_before>use search_algorithms::board::ExtendedBoard;
use search_algorithms::board::GameResult;
use search_algorithms::alpha_beta::Score;
use search_algorithms::monte_carlo;
use pgn::PgnBoard;
use rayon::prelude::*;

pub trait TunableBoard {
    const PARAMS: &'static [f32];

    fn static_eval_with_params(&self, params: &[f32]) -> f32;
}

pub fn get_critical_positions<B>(positions: &mut [B], params: &[f32]) -> Vec<B>
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {
    positions.into_par_iter()
        .map(|board| {
            if let (Score::Val(_), pv) = qsearch(&mut board.clone(), Score::Loss(0),
                                     Score::Win(0), params) {
                let mut cloned_board = board.clone();

                for mv in pv {
                    cloned_board.do_move(mv);
                }
                cloned_board
            }
            else {
                warn!("Found mate score while tuning {}.", board.to_fen());
                board.clone()
            }

        })
        .collect()
}

pub fn gradient_descent<B>(positions: &mut [B], results: &[GameResult],
                           test_positions: &mut[B], test_results: &[GameResult],
                           params: &[f32]) -> Vec<f32>
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {
    const ETA: f32 = 0.1;

    let mut errors = vec![std::f32::MAX];
    let mut paramss: Vec<Vec<f32>> = vec![params.to_vec()];

    loop {
        let last_params = paramss.last().unwrap().clone();
        let gradients = gradients(positions, results, &last_params);
        println!("Gradients: {:?}", gradients);

        let new_params: Vec<f32> = last_params.iter()
            .zip(gradients)
            .map(|(param, grad)| param + grad * ETA)
            .collect();
        println!("New parameters: {:?}", new_params);

        let error = error_sum(test_positions, test_results, &new_params);
        println!("Error now {}\n", error);

        if !errors.len() > 1 && error > errors[errors.len() - 1] && error > errors[errors.len() - 2] {
            if paramss[paramss.len() - 1] < paramss[paramss.len() - 2] {
                return paramss[paramss.len() - 1].clone()
            }
            else {
                return paramss[paramss.len() - 2].clone()
            }
        }
        else {
            errors.push(error);
            paramss.push(new_params);
        }
    }
}

pub fn gradients<B>(positions: &mut [B], results: &[GameResult], params: &[f32]) -> Vec<f32>
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {

    let critical_positions = get_critical_positions(positions, params);

    const EPSILON : f32 = 0.001;

    params.iter().enumerate()
        .map(|(i, p)| {
            let mut params_hat: Vec<f32> = params.iter().cloned().collect();
            params_hat[i] = p + EPSILON;
            critical_positions.iter()
                .zip(results)
                .map(|(board, &game_result)| {
                    let score1 = board.static_eval_with_params(params);
                    let score2 = board.static_eval_with_params(&params_hat);
                    error(score1, game_result) - error(score2, game_result)
                })
                .sum()
        })
        .collect()
}

pub fn error_sum<B>(positions: &mut [B], results: &[GameResult], params: &[f32]) -> f32
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {
    positions.into_par_iter().zip(results)
        .map(|(board, game_result)| {
            let color = board.side_to_move();
            if let (Score::Val(qsearc_eval), _) = qsearch(&mut board.clone(), Score::Loss(0),
                                                     Score::Win(0), params) {
                let eval = qsearc_eval * color.multiplier() as f32;
                error(eval, game_result.clone())

            }
            else {
                warn!("Found mate score while tuning {}.", board.to_fen());
                0.0
            }
        })
        .sum()
}

pub fn error(eval: f32, game_result: GameResult) -> f32 {
    let answer = match game_result {
        GameResult::WhiteWin => 1.0,
        GameResult::Draw => 0.5,
        GameResult::BlackWin => 0.0,
    };

    let error = f32::powf(answer - monte_carlo::eval_to_win_pct(eval), 2.0);
    error
}

fn qsearch<B: ExtendedBoard>(board: &mut B, mut alpha: Score, beta: Score, params: &[f32])
    -> (Score, Vec<B::Move>)
    where B: TunableBoard + ExtendedBoard {
    let color = board.side_to_move();

    if let Some(result) = board.game_result() {
        return (Score::from_game_result(result, color), vec![])
    }

    let stand_pat = Score::Val(board.static_eval_with_params(params) * color.multiplier() as f32);

    if stand_pat >= beta {
        return (beta, vec![]);
    }

    alpha = alpha.max(stand_pat);
    let mut best_pv = vec![];
    let mut best_move = None;

    let mut active_moves = vec![];
    board.active_moves(&mut active_moves);

    for mv in active_moves {
        let reverse_move = board.do_move(mv.clone());

        let (mut score, mut pv) = qsearch(board, beta, alpha, params);

        score = !score;
        board.reverse_move(reverse_move);

        if score >= beta {
            return (score, vec![mv]);
        }
        if score > alpha {
            alpha = score;
            best_pv = pv;
            best_move = Some(mv);
        }
    }
    best_pv.extend(best_move);
    return (alpha, best_pv);

}<commit_msg>Compute average error rate instead of sum<commit_after>use search_algorithms::board::ExtendedBoard;
use search_algorithms::board::GameResult;
use search_algorithms::alpha_beta::Score;
use search_algorithms::monte_carlo;
use pgn::PgnBoard;
use rayon::prelude::*;

pub trait TunableBoard {
    const PARAMS: &'static [f32];

    fn static_eval_with_params(&self, params: &[f32]) -> f32;
}

pub fn get_critical_positions<B>(positions: &mut [B], params: &[f32]) -> Vec<B>
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {
    positions.into_par_iter()
        .map(|board| {
            if let (Score::Val(_), pv) = qsearch(&mut board.clone(), Score::Loss(0),
                                     Score::Win(0), params) {
                let mut cloned_board = board.clone();

                for mv in pv {
                    cloned_board.do_move(mv);
                }
                cloned_board
            }
            else {
                warn!("Found mate score while tuning {}.", board.to_fen());
                board.clone()
            }

        })
        .collect()
}

pub fn gradient_descent<B>(positions: &mut [B], results: &[GameResult],
                           test_positions: &mut[B], test_results: &[GameResult],
                           params: &[f32]) -> Vec<f32>
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {
    const ETA: f32 = 0.1;

    let mut errors = vec![std::f32::MAX];
    let mut paramss: Vec<Vec<f32>> = vec![params.to_vec()];

    loop {
        let last_params = paramss.last().unwrap().clone();
        let gradients = gradients(positions, results, &last_params);
        println!("Gradients: {:?}", gradients);

        let new_params: Vec<f32> = last_params.iter()
            .zip(gradients)
            .map(|(param, grad)| param + grad * ETA)
            .collect();
        println!("New parameters: {:?}", new_params);

        let error = average_error(test_positions, test_results, &new_params);
        println!("Error now {}\n", error);

        if !errors.len() > 1 && error > errors[errors.len() - 1] && error > errors[errors.len() - 2] {
            if paramss[paramss.len() - 1] < paramss[paramss.len() - 2] {
                return paramss[paramss.len() - 1].clone()
            }
            else {
                return paramss[paramss.len() - 2].clone()
            }
        }
        else {
            errors.push(error);
            paramss.push(new_params);
        }
    }
}

pub fn gradients<B>(positions: &mut [B], results: &[GameResult], params: &[f32]) -> Vec<f32>
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {

    let critical_positions = get_critical_positions(positions, params);

    const EPSILON : f32 = 0.001;

    params.iter().enumerate()
        .map(|(i, p)| {
            let mut params_hat: Vec<f32> = params.iter().cloned().collect();
            params_hat[i] = p + EPSILON;
            critical_positions.iter()
                .zip(results)
                .map(|(board, &game_result)| {
                    let score1 = board.static_eval_with_params(params);
                    let score2 = board.static_eval_with_params(&params_hat);
                    error(score1, game_result) - error(score2, game_result)
                })
                .sum()
        })
        .collect()
}

pub fn average_error<B>(positions: &mut [B], results: &[GameResult], params: &[f32]) -> f32
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {
    positions.into_par_iter().zip(results)
        .map(|(board, game_result)| {
            let color = board.side_to_move();
            if let (Score::Val(qsearc_eval), _) = qsearch(&mut board.clone(), Score::Loss(0),
                                                     Score::Win(0), params) {
                let eval = qsearc_eval * color.multiplier() as f32;
                error(eval, game_result.clone())

            }
            else {
                warn!("Found mate score while tuning {}.", board.to_fen());
                0.0
            }
        })
        .sum::<f32>() / (positions.len() as f32)

}

pub fn error(eval: f32, game_result: GameResult) -> f32 {
    let answer = match game_result {
        GameResult::WhiteWin => 1.0,
        GameResult::Draw => 0.5,
        GameResult::BlackWin => 0.0,
    };

    let error = f32::powf(answer - monte_carlo::eval_to_win_pct(eval), 2.0);
    error
}

fn qsearch<B: ExtendedBoard>(board: &mut B, mut alpha: Score, beta: Score, params: &[f32])
    -> (Score, Vec<B::Move>)
    where B: TunableBoard + ExtendedBoard {
    let color = board.side_to_move();

    if let Some(result) = board.game_result() {
        return (Score::from_game_result(result, color), vec![])
    }

    let stand_pat = Score::Val(board.static_eval_with_params(params) * color.multiplier() as f32);

    if stand_pat >= beta {
        return (beta, vec![]);
    }

    alpha = alpha.max(stand_pat);
    let mut best_pv = vec![];
    let mut best_move = None;

    let mut active_moves = vec![];
    board.active_moves(&mut active_moves);

    for mv in active_moves {
        let reverse_move = board.do_move(mv.clone());

        let (mut score, mut pv) = qsearch(board, beta, alpha, params);

        score = !score;
        board.reverse_move(reverse_move);

        if score >= beta {
            return (score, vec![mv]);
        }
        if score > alpha {
            alpha = score;
            best_pv = pv;
            best_move = Some(mv);
        }
    }
    best_pv.extend(best_move);
    return (alpha, best_pv);

}<|endoftext|>


<commit_before>#![feature(phase)]

extern crate core;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;

use std::os;
use std::io::{BufferedStream, File, Lines};
use std::io::fs::readdir;
use std::collections::HashMap;

use regex::Regex;
use core::iter::Enumerate;

static CRONTAB_DIR: &'static str = "/etc/crontab";
static ANACRONTAB_DIR: &'static str = "/etc/anacrontab";
static USERCRONTAB_DIR: &'static str = "/var/spool/cron";
static ETCCRONTAB_DIR: &'static str = "/etc/cron.d";

static SPACES: Regex = regex!("[ \t]+");

enum Month {
    January,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December,
}

enum DayOfWeek {
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
}

type Minute = u8;
type Day = u8;
type Hour = u8;
type Delay = u8;

enum Period {
    Reboot,
    Hourly,
    Daily,
    Weekly,
    Monthly,
    Yearly,
}

// 'e - lifetime for CrontabEntry
// 'i - lifetime for CrontabIterator

struct CrontabEntry<'e> {
    environment: &'e HashMap<&'e str, &'e str>,
    lineno: uint,
    filename: &'e Path,
    username: &'e str,
    command: &'e str,

    period: Option<Period>,
    delay: Option<Delay>,

    minutes: Option<Vec<Minute>>,
    hours: Option<Vec<Hour>>,
    days: Option<Vec<Day>>,
    dows: Option<Vec<DayOfWeek>>,
    months: Option<Vec<Month>>,
}

struct CrontabIterator<'i> {
    filename: &'i Path,
    lines: Enumerate<Lines<'i, BufferedStream<File>>>,
    environment: HashMap<&'i str, &'i str>,
}

impl<'i> CrontabIterator<'i> {
    fn new(filename: &'i Path) -> CrontabIterator<'i> {
        CrontabIterator {
            filename: filename,
            lines: BufferedStream::new(File::open(filename).unwrap()).lines().enumerate(),
            environment: HashMap::new(),
        }
    }
}

impl<'i> Iterator<CrontabEntry<'i>> for CrontabIterator<'i> {
    fn next<'i>(&mut self) -> Option<CrontabEntry<'i>> {
        match self.lines.next() {
            None => None,
            Some((_, Err(_))) => {
                None
            },

            Some((lineno, Ok(line))) => {
                let parts = SPACES.split(line.as_slice()).collect::<Vec<&str>>();
                Some(CrontabEntry {
                    environment: &self.environment,
                    lineno: lineno,
                    filename: self.filename,
                    username: "root",
                    command: "",

                    period: None,
                    delay: None,

                    minutes: None,
                    hours: None,
                    days: None,
                    dows: None,
                    months: None,
                })
            }
        }
    }
}

fn main() {
    let args: Vec<String> = os::args();

    println!("target dir: {}", args.get(1));
}
<commit_msg>WIP: rust step 1<commit_after>use std::os;
use std::io::{BufferedStream, File, IoResult};

struct CrontabIterator<'i> {
    lines: &'i mut Iterator<IoResult<String>>,
}

impl<'i> CrontabIterator<'i> {
    fn new(iter: &'i mut Iterator<IoResult<String>>) -> CrontabIterator<'i> {
        CrontabIterator {
            lines: iter
        }
    }
}

impl<'i> Iterator<String> for CrontabIterator<'i> {
    fn next(&mut self) -> Option<String> {
        match self.lines.next() {
            None => None,
            Some(Err(_)) => None,
            Some(Ok(line)) => Some(line),
        }
    }
}

fn main() {
    let args: Vec<String> = os::args();

    let file = File::open(&Path::new("/var/spool/cron/kstep")).unwrap();
    let mut buffer = BufferedStream::new(file);
    let mut lines = buffer.lines();
    let mut crontab = CrontabIterator::new(&mut lines);

    println!("target dir: {}", args.get(1));

    for line in crontab {
        println!("line: {}", line);
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::RefCell,
    process::Command,
    rc::Rc,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use slog::Logger;

#[cfg(feature = "udev")]
use smithay::backend::session::auto::AutoSession;
use smithay::{
    backend::input::{
        self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent,
        PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent,
    },
    wayland::{
        seat::{keysyms as xkb, AxisFrame, KeyboardHandle, Keysym, ModifiersState, PointerHandle},
        SERIAL_COUNTER as SCOUNTER,
    },
    wayland_server::protocol::wl_pointer,
};

use shell::MyWindowMap;

pub struct AnvilInputHandler {
    log: Logger,
    pointer: PointerHandle,
    keyboard: KeyboardHandle,
    window_map: Rc<RefCell<MyWindowMap>>,
    pointer_location: Rc<RefCell<(f64, f64)>>,
    screen_size: (u32, u32),
    #[cfg(feature = "udev")]
    session: Option<AutoSession>,
    running: Arc<AtomicBool>,
}

impl AnvilInputHandler {
    pub fn new(
        log: Logger,
        pointer: PointerHandle,
        keyboard: KeyboardHandle,
        window_map: Rc<RefCell<MyWindowMap>>,
        screen_size: (u32, u32),
        running: Arc<AtomicBool>,
        pointer_location: Rc<RefCell<(f64, f64)>>,
    ) -> AnvilInputHandler {
        AnvilInputHandler {
            log,
            pointer,
            keyboard,
            window_map,
            screen_size,
            running,
            pointer_location,
            #[cfg(feature = "udev")]
            session: None,
        }
    }

    #[cfg(feature = "udev")]
    pub fn new_with_session(
        log: Logger,
        pointer: PointerHandle,
        keyboard: KeyboardHandle,
        window_map: Rc<RefCell<MyWindowMap>>,
        screen_size: (u32, u32),
        running: Arc<AtomicBool>,
        pointer_location: Rc<RefCell<(f64, f64)>>,
        session: AutoSession,
    ) -> AnvilInputHandler {
        AnvilInputHandler {
            log,
            pointer,
            keyboard,
            window_map,
            screen_size,
            running,
            pointer_location,
            session: Some(session),
        }
    }
}

impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
    fn on_seat_created(&mut self, _: &input::Seat) {
        /* currently we just create a single static one */
    }

    fn on_seat_destroyed(&mut self, _: &input::Seat) {
        /* currently we just create a single static one */
    }

    fn on_seat_changed(&mut self, _: &input::Seat) {
        /* currently we just create a single static one */
    }

    fn on_keyboard_key(&mut self, _: &input::Seat, evt: B::KeyboardKeyEvent) {
        let keycode = evt.key_code();
        let state = evt.state();
        debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state));
        let serial = SCOUNTER.next_serial();
        let log = &self.log;
        let time = Event::time(&evt);
        let mut action = KeyAction::None;
        self.keyboard
            .input(keycode, state, serial, time, |modifiers, keysym| {
                debug!(log, "keysym";
                    "state" => format!("{:?}", state),
                    "mods" => format!("{:?}", modifiers),
                    "keysym" => ::xkbcommon::xkb::keysym_get_name(keysym)
                );
                action = process_keyboard_shortcut(modifiers, keysym);
                // forward to client only if action == KeyAction::Forward
                // both for pressed and released, to avoid inconsistencies
                if let KeyAction::Forward = action {
                    true
                } else {
                    false
                }
            });
        if let KeyState::Released = state {
            // only process special actions on key press, not release
            return;
        }
        match action {
            KeyAction::Quit => {
                info!(self.log, "Quitting.");
                self.running.store(false, Ordering::SeqCst);
            }
            #[cfg(feature = "tty_lauch")]
            KeyAction::VtSwitch(vt) => if let Some(ref mut session) = self.session {
                info!(log, "Trying to switch to vt {}", vt);
                if let Err(err) = session.change_vt(vt) {
                    error!(log, "Error switching to vt {}: {}", vt, err);
                }
            },
            KeyAction::Run(cmd) => {
                info!(self.log, "Starting program"; "cmd" => cmd.clone());
                if let Err(e) = Command::new(&cmd).spawn() {
                    error!(log,
                        "Failed to start program";
                        "cmd" => cmd,
                        "err" => format!("{:?}", e)
                    );
                }
            }
            _ => (),
        }
    }

    fn on_pointer_move(&mut self, _: &input::Seat, evt: B::PointerMotionEvent) {
        let (x, y) = (evt.delta_x(), evt.delta_y());
        let serial = SCOUNTER.next_serial();
        let mut location = self.pointer_location.borrow_mut();
        location.0 += x as f64;
        location.1 += y as f64;
        // clamp to screen limits
        // this event is never generated by winit so self.screen_size is relevant
        location.0 = (location.0).max(0.0).min(self.screen_size.0 as f64);
        location.1 = (location.1).max(0.0).min(self.screen_size.1 as f64);
        let under = self
            .window_map
            .borrow()
            .get_surface_under((location.0, location.1));
        self.pointer.motion(*location, under, serial, evt.time());
    }

    fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: B::PointerMotionAbsoluteEvent) {
        // different cases depending on the context:
        let (x, y) = {
            #[cfg(feature = "udev")]
            {
                if self.session.is_some() {
                    // we are started on a tty
                    let (ux, uy) = evt.position_transformed(self.screen_size);
                    (ux as f64, uy as f64)
                } else {
                    // we are started in winit
                    evt.position()
                }
            }
            #[cfg(not(feature = "udev"))]
            {
                evt.position()
            }
        };
        *self.pointer_location.borrow_mut() = (x, y);
        let serial = SCOUNTER.next_serial();
        let under = self.window_map.borrow().get_surface_under((x as f64, y as f64));
        self.pointer.motion((x, y), under, serial, evt.time());
    }

    fn on_pointer_button(&mut self, _: &input::Seat, evt: B::PointerButtonEvent) {
        let serial = SCOUNTER.next_serial();
        let button = match evt.button() {
            input::MouseButton::Left => 0x110,
            input::MouseButton::Right => 0x111,
            input::MouseButton::Middle => 0x112,
            input::MouseButton::Other(b) => b as u32,
        };
        let state = match evt.state() {
            input::MouseButtonState::Pressed => {
                // change the keyboard focus unless the pointer is grabbed
                if !self.pointer.is_grabbed() {
                    let under = self
                        .window_map
                        .borrow_mut()
                        .get_surface_and_bring_to_top(*self.pointer_location.borrow());
                    self.keyboard
                        .set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
                }
                wl_pointer::ButtonState::Pressed
            }
            input::MouseButtonState::Released => wl_pointer::ButtonState::Released,
        };
        self.pointer.button(button, state, serial, evt.time());
    }

    fn on_pointer_axis(&mut self, _: &input::Seat, evt: B::PointerAxisEvent) {
        let source = match evt.source() {
            input::AxisSource::Continuous => wl_pointer::AxisSource::Continuous,
            input::AxisSource::Finger => wl_pointer::AxisSource::Finger,
            input::AxisSource::Wheel | input::AxisSource::WheelTilt => wl_pointer::AxisSource::Wheel,
        };
        let horizontal_amount = evt
            .amount(&input::Axis::Horizontal)
            .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0);
        let vertical_amount = evt
            .amount(&input::Axis::Vertical)
            .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0);
        let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal);
        let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical);

        {
            let mut frame = AxisFrame::new(evt.time()).source(source);
            if horizontal_amount != 0.0 {
                frame = frame.value(wl_pointer::Axis::HorizontalScroll, horizontal_amount);
                if let Some(discrete) = horizontal_amount_discrete {
                    frame = frame.discrete(wl_pointer::Axis::HorizontalScroll, discrete as i32);
                }
            } else if source == wl_pointer::AxisSource::Finger {
                frame = frame.stop(wl_pointer::Axis::HorizontalScroll);
            }
            if vertical_amount != 0.0 {
                frame = frame.value(wl_pointer::Axis::VerticalScroll, vertical_amount);
                if let Some(discrete) = vertical_amount_discrete {
                    frame = frame.discrete(wl_pointer::Axis::VerticalScroll, discrete as i32);
                }
            } else if source == wl_pointer::AxisSource::Finger {
                frame = frame.stop(wl_pointer::Axis::VerticalScroll);
            }
            self.pointer.axis(frame);
        }
    }

    fn on_touch_down(&mut self, _: &input::Seat, _: B::TouchDownEvent) {
        /* not done in this example */
    }
    fn on_touch_motion(&mut self, _: &input::Seat, _: B::TouchMotionEvent) {
        /* not done in this example */
    }
    fn on_touch_up(&mut self, _: &input::Seat, _: B::TouchUpEvent) {
        /* not done in this example */
    }
    fn on_touch_cancel(&mut self, _: &input::Seat, _: B::TouchCancelEvent) {
        /* not done in this example */
    }
    fn on_touch_frame(&mut self, _: &input::Seat, _: B::TouchFrameEvent) {
        /* not done in this example */
    }
    fn on_input_config_changed(&mut self, _: &mut B::InputConfig) {
        /* not done in this example */
    }
}

/// Possible results of a keyboard action
enum KeyAction {
    /// Quit the compositor
    Quit,
    /// Trigger a vt-switch
    VtSwitch(i32),
    /// run a command
    Run(String),
    /// Forward the key to the client
    Forward,
    /// Do nothing more
    None,
}

fn process_keyboard_shortcut(modifiers: &ModifiersState, keysym: Keysym) -> KeyAction {
    if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace
        || modifiers.logo && keysym == xkb::KEY_q
    {
        // ctrl+alt+backspace = quit
        // logo + q = quit
        KeyAction::Quit
    } else if keysym >= xkb::KEY_XF86Switch_VT_1 && keysym <= xkb::KEY_XF86Switch_VT_12 {
        // VTSwicth
        KeyAction::VtSwitch((keysym - xkb::KEY_XF86Switch_VT_1 + 1) as i32)
    } else if modifiers.logo && keysym == xkb::KEY_Return {
        // run terminal
        KeyAction::Run("weston-terminal".into())
    } else {
        KeyAction::Forward
    }
}
<commit_msg>anvil: fix tty swap<commit_after>use std::{
    cell::RefCell,
    process::Command,
    rc::Rc,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use slog::Logger;

#[cfg(feature = "udev")]
use smithay::backend::session::{Session, auto::AutoSession};
use smithay::{
    backend::input::{
        self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent,
        PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent,
    },
    wayland::{
        seat::{keysyms as xkb, AxisFrame, KeyboardHandle, Keysym, ModifiersState, PointerHandle},
        SERIAL_COUNTER as SCOUNTER,
    },
    wayland_server::protocol::wl_pointer,
};

use shell::MyWindowMap;

pub struct AnvilInputHandler {
    log: Logger,
    pointer: PointerHandle,
    keyboard: KeyboardHandle,
    window_map: Rc<RefCell<MyWindowMap>>,
    pointer_location: Rc<RefCell<(f64, f64)>>,
    screen_size: (u32, u32),
    #[cfg(feature = "udev")]
    session: Option<AutoSession>,
    running: Arc<AtomicBool>,
}

impl AnvilInputHandler {
    pub fn new(
        log: Logger,
        pointer: PointerHandle,
        keyboard: KeyboardHandle,
        window_map: Rc<RefCell<MyWindowMap>>,
        screen_size: (u32, u32),
        running: Arc<AtomicBool>,
        pointer_location: Rc<RefCell<(f64, f64)>>,
    ) -> AnvilInputHandler {
        AnvilInputHandler {
            log,
            pointer,
            keyboard,
            window_map,
            screen_size,
            running,
            pointer_location,
            #[cfg(feature = "udev")]
            session: None,
        }
    }

    #[cfg(feature = "udev")]
    pub fn new_with_session(
        log: Logger,
        pointer: PointerHandle,
        keyboard: KeyboardHandle,
        window_map: Rc<RefCell<MyWindowMap>>,
        screen_size: (u32, u32),
        running: Arc<AtomicBool>,
        pointer_location: Rc<RefCell<(f64, f64)>>,
        session: AutoSession,
    ) -> AnvilInputHandler {
        AnvilInputHandler {
            log,
            pointer,
            keyboard,
            window_map,
            screen_size,
            running,
            pointer_location,
            session: Some(session),
        }
    }
}

impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
    fn on_seat_created(&mut self, _: &input::Seat) {
        /* currently we just create a single static one */
    }

    fn on_seat_destroyed(&mut self, _: &input::Seat) {
        /* currently we just create a single static one */
    }

    fn on_seat_changed(&mut self, _: &input::Seat) {
        /* currently we just create a single static one */
    }

    fn on_keyboard_key(&mut self, _: &input::Seat, evt: B::KeyboardKeyEvent) {
        let keycode = evt.key_code();
        let state = evt.state();
        debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state));
        let serial = SCOUNTER.next_serial();
        let log = &self.log;
        let time = Event::time(&evt);
        let mut action = KeyAction::None;
        self.keyboard
            .input(keycode, state, serial, time, |modifiers, keysym| {
                debug!(log, "keysym";
                    "state" => format!("{:?}", state),
                    "mods" => format!("{:?}", modifiers),
                    "keysym" => ::xkbcommon::xkb::keysym_get_name(keysym)
                );
                action = process_keyboard_shortcut(modifiers, keysym);
                // forward to client only if action == KeyAction::Forward
                // both for pressed and released, to avoid inconsistencies
                if let KeyAction::Forward = action {
                    true
                } else {
                    false
                }
            });
        if let KeyState::Released = state {
            // only process special actions on key press, not release
            return;
        }
        match action {
            KeyAction::Quit => {
                info!(self.log, "Quitting.");
                self.running.store(false, Ordering::SeqCst);
            }
            #[cfg(feature = "udev")]
            KeyAction::VtSwitch(vt) => if let Some(ref mut session) = self.session {
                info!(log, "Trying to switch to vt {}", vt);
                if let Err(err) = session.change_vt(vt) {
                    error!(log, "Error switching to vt {}: {}", vt, err);
                }
            },
            KeyAction::Run(cmd) => {
                info!(self.log, "Starting program"; "cmd" => cmd.clone());
                if let Err(e) = Command::new(&cmd).spawn() {
                    error!(log,
                        "Failed to start program";
                        "cmd" => cmd,
                        "err" => format!("{:?}", e)
                    );
                }
            }
            _ => (),
        }
    }

    fn on_pointer_move(&mut self, _: &input::Seat, evt: B::PointerMotionEvent) {
        let (x, y) = (evt.delta_x(), evt.delta_y());
        let serial = SCOUNTER.next_serial();
        let mut location = self.pointer_location.borrow_mut();
        location.0 += x as f64;
        location.1 += y as f64;
        // clamp to screen limits
        // this event is never generated by winit so self.screen_size is relevant
        location.0 = (location.0).max(0.0).min(self.screen_size.0 as f64);
        location.1 = (location.1).max(0.0).min(self.screen_size.1 as f64);
        let under = self
            .window_map
            .borrow()
            .get_surface_under((location.0, location.1));
        self.pointer.motion(*location, under, serial, evt.time());
    }

    fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: B::PointerMotionAbsoluteEvent) {
        // different cases depending on the context:
        let (x, y) = {
            #[cfg(feature = "udev")]
            {
                if self.session.is_some() {
                    // we are started on a tty
                    let (ux, uy) = evt.position_transformed(self.screen_size);
                    (ux as f64, uy as f64)
                } else {
                    // we are started in winit
                    evt.position()
                }
            }
            #[cfg(not(feature = "udev"))]
            {
                evt.position()
            }
        };
        *self.pointer_location.borrow_mut() = (x, y);
        let serial = SCOUNTER.next_serial();
        let under = self.window_map.borrow().get_surface_under((x as f64, y as f64));
        self.pointer.motion((x, y), under, serial, evt.time());
    }

    fn on_pointer_button(&mut self, _: &input::Seat, evt: B::PointerButtonEvent) {
        let serial = SCOUNTER.next_serial();
        let button = match evt.button() {
            input::MouseButton::Left => 0x110,
            input::MouseButton::Right => 0x111,
            input::MouseButton::Middle => 0x112,
            input::MouseButton::Other(b) => b as u32,
        };
        let state = match evt.state() {
            input::MouseButtonState::Pressed => {
                // change the keyboard focus unless the pointer is grabbed
                if !self.pointer.is_grabbed() {
                    let under = self
                        .window_map
                        .borrow_mut()
                        .get_surface_and_bring_to_top(*self.pointer_location.borrow());
                    self.keyboard
                        .set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
                }
                wl_pointer::ButtonState::Pressed
            }
            input::MouseButtonState::Released => wl_pointer::ButtonState::Released,
        };
        self.pointer.button(button, state, serial, evt.time());
    }

    fn on_pointer_axis(&mut self, _: &input::Seat, evt: B::PointerAxisEvent) {
        let source = match evt.source() {
            input::AxisSource::Continuous => wl_pointer::AxisSource::Continuous,
            input::AxisSource::Finger => wl_pointer::AxisSource::Finger,
            input::AxisSource::Wheel | input::AxisSource::WheelTilt => wl_pointer::AxisSource::Wheel,
        };
        let horizontal_amount = evt
            .amount(&input::Axis::Horizontal)
            .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0);
        let vertical_amount = evt
            .amount(&input::Axis::Vertical)
            .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0);
        let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal);
        let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical);

        {
            let mut frame = AxisFrame::new(evt.time()).source(source);
            if horizontal_amount != 0.0 {
                frame = frame.value(wl_pointer::Axis::HorizontalScroll, horizontal_amount);
                if let Some(discrete) = horizontal_amount_discrete {
                    frame = frame.discrete(wl_pointer::Axis::HorizontalScroll, discrete as i32);
                }
            } else if source == wl_pointer::AxisSource::Finger {
                frame = frame.stop(wl_pointer::Axis::HorizontalScroll);
            }
            if vertical_amount != 0.0 {
                frame = frame.value(wl_pointer::Axis::VerticalScroll, vertical_amount);
                if let Some(discrete) = vertical_amount_discrete {
                    frame = frame.discrete(wl_pointer::Axis::VerticalScroll, discrete as i32);
                }
            } else if source == wl_pointer::AxisSource::Finger {
                frame = frame.stop(wl_pointer::Axis::VerticalScroll);
            }
            self.pointer.axis(frame);
        }
    }

    fn on_touch_down(&mut self, _: &input::Seat, _: B::TouchDownEvent) {
        /* not done in this example */
    }
    fn on_touch_motion(&mut self, _: &input::Seat, _: B::TouchMotionEvent) {
        /* not done in this example */
    }
    fn on_touch_up(&mut self, _: &input::Seat, _: B::TouchUpEvent) {
        /* not done in this example */
    }
    fn on_touch_cancel(&mut self, _: &input::Seat, _: B::TouchCancelEvent) {
        /* not done in this example */
    }
    fn on_touch_frame(&mut self, _: &input::Seat, _: B::TouchFrameEvent) {
        /* not done in this example */
    }
    fn on_input_config_changed(&mut self, _: &mut B::InputConfig) {
        /* not done in this example */
    }
}

/// Possible results of a keyboard action
enum KeyAction {
    /// Quit the compositor
    Quit,
    /// Trigger a vt-switch
    VtSwitch(i32),
    /// run a command
    Run(String),
    /// Forward the key to the client
    Forward,
    /// Do nothing more
    None,
}

fn process_keyboard_shortcut(modifiers: &ModifiersState, keysym: Keysym) -> KeyAction {
    if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace
        || modifiers.logo && keysym == xkb::KEY_q
    {
        // ctrl+alt+backspace = quit
        // logo + q = quit
        KeyAction::Quit
    } else if keysym >= xkb::KEY_XF86Switch_VT_1 && keysym <= xkb::KEY_XF86Switch_VT_12 {
        // VTSwicth
        KeyAction::VtSwitch((keysym - xkb::KEY_XF86Switch_VT_1 + 1) as i32)
    } else if modifiers.logo && keysym == xkb::KEY_Return {
        // run terminal
        KeyAction::Run("weston-terminal".into())
    } else {
        KeyAction::Forward
    }
}
<|endoftext|>


<commit_before>use scene::{Scene, SceneManager};
use gamestate::GameState;
use conrod::{
    label,
    Color,
    Point,
    widget_matrix,
    Button,
    Callable,
    Colorable,
    Drawable,
    Frameable,
    Labelable,
    Positionable,
    Shapeable,
    TextBox,
};

use piston::{graphics, Render, Event};
use piston::graphics::{AddColor, Draw};

pub struct ConnectScene<'r, T:'r> {
    manager: &'r mut SceneManager<T>,
    pub edit_ip: Vec<String>
}

impl <'r, T> ConnectScene<'r, T> {

    pub fn new<'r> (manager: &'r mut SceneManager<T>) -> ConnectScene<'r, T> {
       ConnectScene {
           manager: manager,
           edit_ip: vec!["127".to_string(), "0".to_string(), "0".to_string(), "1".to_string()]
       }
    }
}

impl <'r, T> Scene<GameState> for ConnectScene <'r, T> {
    fn handle_event(&mut self, e: &Event, state: &mut GameState) {
        match e {
            &Render(args) => {
                let (uic, gl) = state.get_drawables();

                gl.viewport(0, 0, args.width as i32, args.height as i32);

                let c = &graphics::Context::abs(args.width as f64, args.height as f64);

                c.rgb(1.0, 1.0, 1.0).draw(gl);
                label::draw(
                    gl,
                    uic,
                    Point::new(0f64, 0f64, 0f64), // Screen position.
                    48u32, // Font size.
                    Color::new(1.0, 0.0, 0.0, 1.0),
                    "Select a server"
                );

                widget_matrix::draw(
                    4, // cols.
                    1, // rows.
                    Point::new(0.0, 56.0, 0.0), // matrix position.
                    300.0, // width.
                    240.0, // height.
                    |num, _, _, pos, width, _| { // This is called for every widget.
                        // Now draw the widgets with the given callback.
                        uic.text_box(2 + num as u64, self.edit_ip.get_mut(num))
                            .font_size(24u32)
                            .dimensions(width, 36.0)
                            .position(pos.x, pos.y)
                            .frame(2.0, Color::black())
                            .color(Color::black())
                            .draw(gl);

                    }
                );

                uic.button(7u64)
                    .dimensions(90.0, 36.0)
                    .position(0.0, 128.0)
                    .color(Color::black())
                    .frame(2.0, Color::black())
                    .label("Connect", 24u32, Color::white())
                    .callback(|| () )
                    .draw(gl);

            },
            _ => {},
        }
    }
}
<commit_msg>Starting to wire up connection making<commit_after>use scene::{Scene, SceneManager};
use gamestate::GameState;
use conrod::{
    label,
    Color,
    Point,
    widget_matrix,
    Button,
    Callable,
    Colorable,
    Drawable,
    Frameable,
    Labelable,
    Positionable,
    Shapeable,
    TextBox,
};

use piston::{graphics, Render, Event};
use piston::graphics::{AddColor, Draw};

pub struct ConnectScene<'r, T:'r> {
    manager: &'r mut SceneManager<T>,
    pub edit_ip: Vec<String>
}

impl <'r, T> ConnectScene<'r, T> {

    pub fn new<'r> (manager: &'r mut SceneManager<T>) -> ConnectScene<'r, T> {
       ConnectScene {
           manager: manager,
           edit_ip: vec!["127".to_string(), "0".to_string(), "0".to_string(), "1".to_string()]
       }
    }
}

impl <'r, T> Scene<GameState> for ConnectScene <'r, T> {
    fn handle_event(&mut self, e: &Event, state: &mut GameState) {
        match e {
            &Render(args) => {
                let (uic, gl) = state.get_drawables();

                gl.viewport(0, 0, args.width as i32, args.height as i32);

                let c = &graphics::Context::abs(args.width as f64, args.height as f64);

                c.rgb(1.0, 1.0, 1.0).draw(gl);
                label::draw(
                    gl,
                    uic,
                    Point::new(0f64, 0f64, 0f64), // Screen position.
                    48u32, // Font size.
                    Color::new(1.0, 0.0, 0.0, 1.0),
                    "Select a server"
                );

                widget_matrix::draw(
                    4, // cols.
                    1, // rows.
                    Point::new(0.0, 56.0, 0.0), // matrix position.
                    300.0, // width.
                    240.0, // height.
                    |num, _, _, pos, width, _| { // This is called for every widget.
                        // Now draw the widgets with the given callback.
                        uic.text_box(2 + num as u64, self.edit_ip.get_mut(num))
                            .font_size(24u32)
                            .dimensions(width, 36.0)
                            .position(pos.x, pos.y)
                            .frame(2.0, Color::black())
                            .color(Color::black())
                            .draw(gl);

                    }
                );

                uic.button(7u64)
                    .dimensions(90.0, 36.0)
                    .position(0.0, 128.0)
                    .color(Color::black())
                    .frame(2.0, Color::black())
                    .label("Connect", 24u32, Color::white())
                    .callback(|| {
                        let parsed = (from_str(self.edit_ip.get(0)), from_str(self.edit_ip.get(1)), from_str(self.edit_ip.get(2)), from_str(self.edit_ip.get(3)));
                        match parsed {
                            (Some(a), Some(b), Some(c), Some(d)) => {
                                match Client::connect(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 0}, SocketAddr {ip: Ipv4Addr(a, b, c, d), port: 8869}, settings) {
                                    Ok(client) => {
                                        ()
                                    },
                                    Err(e) => fail!("Failed to connect - {}", e)
                                };
                            },
                            _ => ()
                        };
                    })
                    .draw(gl);

            },
            _ => {},
        }
    }
}
<|endoftext|>