<commit_before>use registers::control::Cr3;
use structures::paging::page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags};
use structures::paging::{NotGiantPageSize, Page, PageSize, PhysFrame, Size1GB, Size2MB, Size4KB};
use ux::u9;
use VirtAddr;

pub trait Mapper<S: PageSize> {
    fn map_to<A>(
        &mut self,
        page: Page<S>,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>;

    fn unmap<A>(&mut self, page: Page<S>, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame<S>);
}

pub struct RecursivePageTable<'a> {
    p4: &'a mut PageTable,
    recursive_index: u9,
}

#[derive(Debug)]
pub struct NotRecursivelyMapped;

#[derive(Debug)]
pub enum MapToError {
    FrameAllocationFailed,
    EntryWithInvalidFlagsPresent,
    PageAlreadyInUse,
}

#[derive(Debug)]
pub enum UnmapError {
    EntryWithInvalidFlagsPresent(PageTableFlags),
    PageNotMapped,
    InvalidFrameAddressInPageTable,
}

impl<'a> RecursivePageTable<'a> {
    pub fn new(table: &'a mut PageTable) -> Result<Self, NotRecursivelyMapped> {
        let page = Page::containing_address(VirtAddr::new(table as *const _ as u64));
        let recursive_index = page.p4_index();

        if page.p3_index() != recursive_index || page.p2_index() != recursive_index
            || page.p1_index() != recursive_index
        {
            return Err(NotRecursivelyMapped);
        }
        if Ok(Cr3::read().0) != table[recursive_index].frame() {
            return Err(NotRecursivelyMapped);
        }

        Ok(RecursivePageTable {
            p4: table,
            recursive_index,
        })
    }

    pub fn identity_map<A, S>(
        &mut self,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
        S: PageSize,
        Self: Mapper<S>,
    {
        let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64()));
        self.map_to(page, frame, flags, allocator)
    }

    fn create_next_table<A>(
        entry: &mut PageTableEntry,
        allocator: &mut A,
    ) -> Result<bool, MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;

        if entry.is_unused() {
            if let Some(frame) = allocator() {
                entry.set_frame(frame, Flags::PRESENT | Flags::WRITABLE);
                return Ok(true);
            } else {
                return Err(MapToError::FrameAllocationFailed);
            }
        }
        if entry.flags().contains(Flags::HUGE_PAGE) {
            return Err(MapToError::EntryWithInvalidFlagsPresent);
        }
        Ok(false)
    }
}

impl<'a> Mapper<Size1GB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size1GB>,
        frame: PhysFrame<Size1GB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        if !p3[page.p3_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p3[page.p3_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE);

        Ok(())
    }

    fn unmap<A>(&mut self, page: Page<Size1GB>, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame<Size1GB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];

        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &mut p3[page.p3_index()];
        let flags = p3_entry.flags();

        if !flags.contains(PageTableFlags::PRESENT) {
            return Err(UnmapError::PageNotMapped);
        }
        if !flags.contains(PageTableFlags::HUGE_PAGE) {
            return Err(UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()));
        }

        let frame = PhysFrame::from_start_address(p3_entry.addr())
            .map_err(|()| UnmapError::InvalidFrameAddressInPageTable)?;
        allocator(frame);
        p3_entry.set_unused();
        Ok(())
    }
}

impl<'a> Mapper<Size2MB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size2MB>,
        frame: PhysFrame<Size2MB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        let p2_created = Self::create_next_table(&mut p3[page.p3_index()], allocator)?;
        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        if p2_created {
            p2.zero()
        }

        if !p2[page.p2_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p2[page.p2_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE);

        Ok(())
    }

    fn unmap<A>(&mut self, page: Page<Size2MB>, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame<Size2MB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];
        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &p3[page.p3_index()];
        p3_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        let p2_entry = &mut p2[page.p2_index()];
        let flags = p2_entry.flags();

        if !flags.contains(PageTableFlags::PRESENT) {
            return Err(UnmapError::PageNotMapped);
        }
        if !flags.contains(PageTableFlags::HUGE_PAGE) {
            return Err(UnmapError::EntryWithInvalidFlagsPresent(p2_entry.flags()));
        }

        let frame = PhysFrame::from_start_address(p2_entry.addr())
            .map_err(|()| UnmapError::InvalidFrameAddressInPageTable)?;
        allocator(frame);
        p2_entry.set_unused();
        Ok(())
    }
}

impl<'a> Mapper<Size4KB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size4KB>,
        frame: PhysFrame<Size4KB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        let p2_created = Self::create_next_table(&mut p3[page.p3_index()], allocator)?;
        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        if p2_created {
            p2.zero()
        }

        let p1_created = Self::create_next_table(&mut p2[page.p2_index()], allocator)?;
        let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) };
        if p1_created {
            p1.zero()
        }

        if !p1[page.p1_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p1[page.p1_index()].set_frame(frame, flags);

        Ok(())
    }

    fn unmap<A>(&mut self, page: Page<Size4KB>, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame<Size4KB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];
        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &p3[page.p3_index()];
        p3_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        let p2_entry = &p2[page.p2_index()];
        p2_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) };
        let p1_entry = &mut p1[page.p1_index()];

        let frame = p1_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;
        allocator(frame);
        p1_entry.set_unused();
        Ok(())
    }
}

fn p3_ptr<S: PageSize>(page: Page<S>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        recursive_index,
        recursive_index,
        page.p4_index(),
    ).start_address()
        .as_mut_ptr()
}

fn p2_ptr<S: NotGiantPageSize>(page: Page<S>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        recursive_index,
        page.p4_index(),
        page.p3_index(),
    ).start_address()
        .as_mut_ptr()
}

fn p1_ptr(page: Page<Size4KB>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        page.p4_index(),
        page.p3_index(),
        page.p2_index(),
    ).start_address()
        .as_mut_ptr()
}
<commit_msg>Added return value for RecursivePageTable operations that must be used. (#15)<commit_after>use registers::control::Cr3;
use instructions::tlb;
use structures::paging::page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags};
use structures::paging::{NotGiantPageSize, Page, PageSize, PhysFrame, Size1GB, Size2MB, Size4KB};
use ux::u9;
use VirtAddr;

/// This type must be used and will either flush the modified page or can be unsafely ignored.
#[must_use = "Page Table changes must be flushed or unsafely ignored."]
pub struct MapperFlush<S: PageSize>(Page<S>);

impl<S: PageSize> MapperFlush<S> {
    /// Create a new flush promise
    fn new(page: Page<S>) -> Self {
        MapperFlush(page)
    }

    // Flush
    pub fn flush(self) {
        tlb::flush(self.0.start_address());
    }

    pub unsafe fn ignore(self) {}
}

pub trait Mapper<S: PageSize> {
    fn map_to<A>(
        &mut self,
        page: Page<S>,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError>
    where
        A: FnMut() -> Option<PhysFrame>;

    fn unmap<A>(&mut self, page: Page<S>, allocator: &mut A) -> Result<MapperFlush<S>, UnmapError>
    where
        A: FnMut(PhysFrame<S>);
}

pub struct RecursivePageTable<'a> {
    p4: &'a mut PageTable,
    recursive_index: u9,
}

#[derive(Debug)]
pub struct NotRecursivelyMapped;

#[derive(Debug)]
pub enum MapToError {
    FrameAllocationFailed,
    EntryWithInvalidFlagsPresent,
    PageAlreadyInUse,
}

#[derive(Debug)]
pub enum UnmapError {
    EntryWithInvalidFlagsPresent(PageTableFlags),
    PageNotMapped,
    InvalidFrameAddressInPageTable,
}

impl<'a> RecursivePageTable<'a> {
    pub fn new(table: &'a mut PageTable) -> Result<Self, NotRecursivelyMapped> {
        let page = Page::containing_address(VirtAddr::new(table as *const _ as u64));
        let recursive_index = page.p4_index();

        if page.p3_index() != recursive_index || page.p2_index() != recursive_index
            || page.p1_index() != recursive_index
        {
            return Err(NotRecursivelyMapped);
        }
        if Ok(Cr3::read().0) != table[recursive_index].frame() {
            return Err(NotRecursivelyMapped);
        }

        Ok(RecursivePageTable {
            p4: table,
            recursive_index,
        })
    }

    pub fn identity_map<A, S>(
        &mut self,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
        S: PageSize,
        Self: Mapper<S>,
    {
        let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64()));
        self.map_to(page, frame, flags, allocator)
    }

    fn create_next_table<A>(
        entry: &mut PageTableEntry,
        allocator: &mut A,
    ) -> Result<bool, MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;

        if entry.is_unused() {
            if let Some(frame) = allocator() {
                entry.set_frame(frame, Flags::PRESENT | Flags::WRITABLE);
                return Ok(true);
            } else {
                return Err(MapToError::FrameAllocationFailed);
            }
        }
        if entry.flags().contains(Flags::HUGE_PAGE) {
            return Err(MapToError::EntryWithInvalidFlagsPresent);
        }
        Ok(false)
    }
}

impl<'a> Mapper<Size1GB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size1GB>,
        frame: PhysFrame<Size1GB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<MapperFlush<Size1GB>, MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        if !p3[page.p3_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p3[page.p3_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE);

        Ok(MapperFlush::new(page))
    }

    fn unmap<A>(&mut self, page: Page<Size1GB>, allocator: &mut A) -> Result<MapperFlush<Size1GB>, UnmapError>
    where
        A: FnMut(PhysFrame<Size1GB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];

        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &mut p3[page.p3_index()];
        let flags = p3_entry.flags();

        if !flags.contains(PageTableFlags::PRESENT) {
            return Err(UnmapError::PageNotMapped);
        }
        if !flags.contains(PageTableFlags::HUGE_PAGE) {
            return Err(UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()));
        }

        let frame = PhysFrame::from_start_address(p3_entry.addr())
            .map_err(|()| UnmapError::InvalidFrameAddressInPageTable)?;
        allocator(frame);
        p3_entry.set_unused();
        Ok(MapperFlush::new(page))
    }
}

impl<'a> Mapper<Size2MB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size2MB>,
        frame: PhysFrame<Size2MB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<MapperFlush<Size2MB>, MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        let p2_created = Self::create_next_table(&mut p3[page.p3_index()], allocator)?;
        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        if p2_created {
            p2.zero()
        }

        if !p2[page.p2_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p2[page.p2_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE);

        Ok(MapperFlush::new(page))
    }

    fn unmap<A>(&mut self, page: Page<Size2MB>, allocator: &mut A) -> Result<MapperFlush<Size2MB>, UnmapError>
    where
        A: FnMut(PhysFrame<Size2MB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];
        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &p3[page.p3_index()];
        p3_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        let p2_entry = &mut p2[page.p2_index()];
        let flags = p2_entry.flags();

        if !flags.contains(PageTableFlags::PRESENT) {
            return Err(UnmapError::PageNotMapped);
        }
        if !flags.contains(PageTableFlags::HUGE_PAGE) {
            return Err(UnmapError::EntryWithInvalidFlagsPresent(p2_entry.flags()));
        }

        let frame = PhysFrame::from_start_address(p2_entry.addr())
            .map_err(|()| UnmapError::InvalidFrameAddressInPageTable)?;
        allocator(frame);
        p2_entry.set_unused();
        Ok(MapperFlush::new(page))
    }
}

impl<'a> Mapper<Size4KB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size4KB>,
        frame: PhysFrame<Size4KB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<MapperFlush<Size4KB>, MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        let p2_created = Self::create_next_table(&mut p3[page.p3_index()], allocator)?;
        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        if p2_created {
            p2.zero()
        }

        let p1_created = Self::create_next_table(&mut p2[page.p2_index()], allocator)?;
        let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) };
        if p1_created {
            p1.zero()
        }

        if !p1[page.p1_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p1[page.p1_index()].set_frame(frame, flags);

        Ok(MapperFlush::new(page))
    }

    fn unmap<A>(&mut self, page: Page<Size4KB>, allocator: &mut A) -> Result<MapperFlush<Size4KB>, UnmapError>
    where
        A: FnMut(PhysFrame<Size4KB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];
        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &p3[page.p3_index()];
        p3_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        let p2_entry = &p2[page.p2_index()];
        p2_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) };
        let p1_entry = &mut p1[page.p1_index()];

        let frame = p1_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;
        allocator(frame);
        p1_entry.set_unused();
        Ok(MapperFlush::new(page))
    }
}

fn p3_ptr<S: PageSize>(page: Page<S>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        recursive_index,
        recursive_index,
        page.p4_index(),
    ).start_address()
        .as_mut_ptr()
}

fn p2_ptr<S: NotGiantPageSize>(page: Page<S>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        recursive_index,
        page.p4_index(),
        page.p3_index(),
    ).start_address()
        .as_mut_ptr()
}

fn p1_ptr(page: Page<Size4KB>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        page.p4_index(),
        page.p3_index(),
        page.p2_index(),
    ).start_address()
        .as_mut_ptr()
}
<|endoftext|>


<commit_before>use board::sjadam_board::SjadamBoard;
use uci::UciBoard;
use board::sjadam_move::SjadamMove;
use search_algorithms::game_move::Move;
use search_algorithms::board::{GameResult, EvalBoard};
use tests::move_gen_tests;

#[test]
fn correct_move_gen_start_pos() {
    let start_board = SjadamBoard::start_board().clone();
    let moves = start_board.all_legal_moves();
    assert_eq!(moves.len(), 146, "Found {} moves: {:?}, expected 146",
               moves.len(), moves);
}

/// Tests whether a pawn is allowed to sjadam over an opponent pawn
#[test]
fn jump_over_opponent() {
    let board = SjadamBoard::from_fen("8/8/8/7p/7P/8/8/K1k5 w - - 1 1").unwrap();
    assert_eq!(board.game_result(), None);
    let moves = board.all_legal_moves();
    assert_eq!(board.all_legal_moves().len(), 5,
               "Expected 5 legal moves, found {} moves: {:?}\n{:?}",
               moves.len(), moves, board);
}

#[test]
fn no_stalemate_test() {
    let board = SjadamBoard::from_fen("8/8/8/5p1k/3p1Q2/3P2R1/P3p2P/4K3 b - - 2 39").unwrap();
    assert_eq!(board.game_result(), None);
    let moves = board.all_legal_moves();
    // The exact number may be wrong due to other bugs
    // So don't trust this test
    assert_eq!(board.all_legal_moves().len(), 13,
               "Expected 13 legal moves, found {} moves: {:?}\n{:?}",
               moves.len(), moves, board);
}

#[test]
fn can_take_king_while_checked() {
    let board = SjadamBoard::from_fen("r2q2n1/pp4pp/6k1/2Nb4/8/5P2/P1P1PK2/2B3q1 w - - 0 1").unwrap();
    // Black is really sjadammated, so this is also a possible outcome
    if board.game_result() != Some(GameResult::WhiteWin) {
        let moves = board.all_legal_moves();

        let correct_move = SjadamMove::from_alg("c5e5g6").unwrap();
        assert!(board.all_legal_moves().contains(&correct_move),
                "White couldn't take king on board:\n{:?}Moves: {:?}",
                board, moves);
    }
}

#[test]
fn sjadam_move_to_promote_pawn() {
    let board = SjadamBoard::from_fen("k7/5R2/5P2/8/8/8/8/7K w - - 0 1").unwrap();
    let moves = board.all_legal_moves();

    let correct_move = SjadamMove::from_alg("f6f8-").unwrap();
    assert!(board.all_legal_moves().contains(&correct_move),
            "White couldn't promote in sjadam on board:\n{:?}Moves: {:?}",
            board, moves);
}

#[test]
fn no_moves_on_back_rank() {
    let board = SjadamBoard::from_fen("8/K7/P7/8/8/8/8/7k w - - 0 1").unwrap();
    let moves = board.all_legal_moves();
    assert_eq!(moves.len(), 9, "Expected to find {} moves, found {}: {:?}", 9, moves.len(), moves);
}

#[test]
fn startpos_perf_test() {
    let mut board = SjadamBoard::start_board();
    for (n, &moves) in (1..4).zip([146, 21_469, 3_268_163].iter()) {
        assert_eq!(move_gen_tests::legal_moves_after_plies(&mut board, n), moves);
    }
}

#[test]
#[ignore]
fn startpos_perf_test_long() {
    let mut board = SjadamBoard::start_board();
    assert_eq!(move_gen_tests::legal_moves_after_plies(&mut board, 4), 500_951_687);
}

#[test]
fn castling_en_passant_perf_test() {
    let mut board = SjadamBoard::start_board();
    board.do_move(SjadamMove::from_alg("g1e3-").unwrap());
    board.do_move(SjadamMove::from_alg("g8e6-").unwrap());
    board.do_move(SjadamMove::from_alg("f1d3c4").unwrap());
    board.do_move(SjadamMove::from_alg("e8g8-").unwrap());
    board.do_move(SjadamMove::from_alg("-c2c3").unwrap());
    board.do_move(SjadamMove::from_alg("-d7d5").unwrap());
    board.do_move(SjadamMove::from_alg("c1a3-").unwrap());
    board.do_move(SjadamMove::from_alg("-b7b5").unwrap());
    for (n, &moves) in (1..4).zip([160, 26_959, 4_259_773].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}

#[test]
fn perf_test_3() {
    let mut board = SjadamBoard::from_fen("1nbqkb1r/pppppppp/4r3/8/8/4N3/PPPPPPPP/RNBQ1RK1 b k - 0 1").unwrap();
    for (n, &moves) in (1..4).zip([144, 22_645, 3_368_765].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}

#[test]
fn perf_test_4() {
    let mut board = SjadamBoard::from_fen("rnbqkbnr/pppppppp/8/8/8/5N2/PPPPPPPP/RNBQKB1R b KQkq - 1 1").unwrap();
    for (n, &moves) in (1..4).zip([144, 18_152, 2_750_259].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}
<commit_msg>Added 3 more sjadam perf tests<commit_after>use board::sjadam_board::SjadamBoard;
use uci::UciBoard;
use board::sjadam_move::SjadamMove;
use search_algorithms::game_move::Move;
use search_algorithms::board::{GameResult, EvalBoard};
use tests::move_gen_tests;

#[test]
fn correct_move_gen_start_pos() {
    let start_board = SjadamBoard::start_board().clone();
    let moves = start_board.all_legal_moves();
    assert_eq!(moves.len(), 146, "Found {} moves: {:?}, expected 146",
               moves.len(), moves);
}

/// Tests whether a pawn is allowed to sjadam over an opponent pawn
#[test]
fn jump_over_opponent() {
    let board = SjadamBoard::from_fen("8/8/8/7p/7P/8/8/K1k5 w - - 1 1").unwrap();
    assert_eq!(board.game_result(), None);
    let moves = board.all_legal_moves();
    assert_eq!(board.all_legal_moves().len(), 5,
               "Expected 5 legal moves, found {} moves: {:?}\n{:?}",
               moves.len(), moves, board);
}

#[test]
fn no_stalemate_test() {
    let board = SjadamBoard::from_fen("8/8/8/5p1k/3p1Q2/3P2R1/P3p2P/4K3 b - - 2 39").unwrap();
    assert_eq!(board.game_result(), None);
    let moves = board.all_legal_moves();
    // The exact number may be wrong due to other bugs
    // So don't trust this test
    assert_eq!(board.all_legal_moves().len(), 13,
               "Expected 13 legal moves, found {} moves: {:?}\n{:?}",
               moves.len(), moves, board);
}

#[test]
fn can_take_king_while_checked() {
    let board = SjadamBoard::from_fen("r2q2n1/pp4pp/6k1/2Nb4/8/5P2/P1P1PK2/2B3q1 w - - 0 1").unwrap();
    // Black is really sjadammated, so this is also a possible outcome
    if board.game_result() != Some(GameResult::WhiteWin) {
        let moves = board.all_legal_moves();

        let correct_move = SjadamMove::from_alg("c5e5g6").unwrap();
        assert!(board.all_legal_moves().contains(&correct_move),
                "White couldn't take king on board:\n{:?}Moves: {:?}",
                board, moves);
    }
}

#[test]
fn sjadam_move_to_promote_pawn() {
    let board = SjadamBoard::from_fen("k7/5R2/5P2/8/8/8/8/7K w - - 0 1").unwrap();
    let moves = board.all_legal_moves();

    let correct_move = SjadamMove::from_alg("f6f8-").unwrap();
    assert!(board.all_legal_moves().contains(&correct_move),
            "White couldn't promote in sjadam on board:\n{:?}Moves: {:?}",
            board, moves);
}

#[test]
fn no_moves_on_back_rank() {
    let board = SjadamBoard::from_fen("8/K7/P7/8/8/8/8/7k w - - 0 1").unwrap();
    let moves = board.all_legal_moves();
    assert_eq!(moves.len(), 9, "Expected to find {} moves, found {}: {:?}", 9, moves.len(), moves);
}

#[test]
fn startpos_perf_test() {
    let mut board = SjadamBoard::start_board();
    for (n, &moves) in (1..4).zip([146, 21_469, 3_268_163].iter()) {
        assert_eq!(move_gen_tests::legal_moves_after_plies(&mut board, n), moves);
    }
}

#[test]
#[ignore]
fn startpos_perf_test_long() {
    let mut board = SjadamBoard::start_board();
    assert_eq!(move_gen_tests::legal_moves_after_plies(&mut board, 4), 500_951_687);
}

#[test]
fn castling_en_passant_perf_test() {
    let mut board = SjadamBoard::start_board();
    board.do_move(SjadamMove::from_alg("g1e3-").unwrap());
    board.do_move(SjadamMove::from_alg("g8e6-").unwrap());
    board.do_move(SjadamMove::from_alg("f1d3c4").unwrap());
    board.do_move(SjadamMove::from_alg("e8g8-").unwrap());
    board.do_move(SjadamMove::from_alg("-c2c3").unwrap());
    board.do_move(SjadamMove::from_alg("-d7d5").unwrap());
    board.do_move(SjadamMove::from_alg("c1a3-").unwrap());
    board.do_move(SjadamMove::from_alg("-b7b5").unwrap());
    for (n, &moves) in (1..4).zip([160, 26_959, 4_259_773].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}

#[test]
fn perf_test_3() {
    let mut board = SjadamBoard::from_fen("1nbqkb1r/pppppppp/4r3/8/8/4N3/PPPPPPPP/RNBQ1RK1 b k - 0 1").unwrap();
    for (n, &moves) in (1..4).zip([144, 22_645, 3_368_765].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}

#[test]
fn perf_test_4() {
    let mut board = SjadamBoard::from_fen("rnbqkbnr/pppppppp/8/8/8/5N2/PPPPPPPP/RNBQKB1R b KQkq - 1 1").unwrap();
    for (n, &moves) in (1..4).zip([144, 18_152, 2_750_259].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}

#[test]
fn perf_test_5() {
    let mut board = SjadamBoard::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 1 1").unwrap();
    for (n, &moves) in (1..4).zip([145, 25_359, 3_865_242].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}

#[test]
fn perf_test_6() {
    let mut board = SjadamBoard::from_fen("rnbqkbnr/pppppppp/8/8/2P5/8/PP1PPPPP/RNBQKBNR b KQkq - 0 1").unwrap();
    for (n, &moves) in (1..4).zip([140, 22_867, 3_417_912].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}
<|endoftext|>


<commit_before>// The example only works on Linux since Termion does not yet support
// Windows: https://gitlab.redox-os.org/redox-os/termion/-/issues/103
// The precise library doesn't matter much, so feel free to send a PR
// if there is a library with good Windows support.

fn main() -> Result<(), std::io::Error> {
    #[cfg(not(unix))]
    panic!("Sorry, this example currently only works on Unix!");

    #[cfg(unix)]
    unix_only::main()
}

#[cfg(unix)]
mod unix_only {
    use std::io::{self, Write};
    use termion::event::Key;
    use termion::input::TermRead;
    use termion::raw::{IntoRawMode, RawTerminal};
    use termion::screen::AlternateScreen;
    use termion::{color, cursor, style};
    use textwrap::core::WrapAlgorithm::{FirstFit, OptimalFit};
    use textwrap::{wrap, HyphenSplitter, NoHyphenation, Options, WordSplitter};

    #[cfg(feature = "hyphenation")]
    use hyphenation::{Language, Load, Standard};

    fn draw_margins(
        row: u16,
        col: u16,
        line_width: u16,
        left: char,
        right: char,
        stdout: &mut RawTerminal<io::Stdout>,
    ) -> Result<(), io::Error> {
        write!(
            stdout,
            "{}{}{}{}",
            cursor::Goto(col - 1, row),
            color::Fg(color::Red),
            left,
            color::Fg(color::Reset),
        )?;
        write!(
            stdout,
            "{}{}{}{}",
            cursor::Goto(col + line_width, row),
            color::Fg(color::Red),
            right,
            color::Fg(color::Reset),
        )?;

        Ok(())
    }

    fn draw_text<'a>(
        text: &str,
        options: &Options<'a>,
        splitter_label: &str,
        stdout: &mut RawTerminal<io::Stdout>,
    ) -> Result<(), io::Error> {
        let mut left_row: u16 = 1;
        let left_col: u16 = 3;

        write!(stdout, "{}", termion::clear::All)?;
        write!(
            stdout,
            "{}{}Options:{}",
            cursor::Goto(left_col, left_row),
            style::Bold,
            style::Reset,
        )?;
        left_row += 1;

        write!(
            stdout,
            "{}- width: {}{}{} (use ← and → to change)",
            cursor::Goto(left_col, left_row),
            style::Bold,
            options.width,
            style::Reset,
        )?;
        left_row += 1;

        write!(
            stdout,
            "{}- break_words: {}{:?}{} (toggle with Ctrl-b)",
            cursor::Goto(left_col, left_row),
            style::Bold,
            options.break_words,
            style::Reset,
        )?;
        left_row += 1;

        write!(
            stdout,
            "{}- splitter: {}{}{} (cycle with Ctrl-s)",
            cursor::Goto(left_col, left_row),
            style::Bold,
            splitter_label,
            style::Reset,
        )?;
        left_row += 1;

        write!(
            stdout,
            "{}- algorithm: {}{:?}{} (toggle with Ctrl-o)",
            cursor::Goto(left_col, left_row),
            style::Bold,
            options.wrap_algorithm,
            style::Reset,
        )?;
        left_row += 1;

        let now = std::time::Instant::now();
        let mut lines = wrap(text, options);
        let elapsed = now.elapsed();

        let right_col: u16 = 55;
        let mut right_row: u16 = 1;
        write!(
            stdout,
            "{}{}Performance:{}",
            cursor::Goto(right_col, right_row),
            style::Bold,
            style::Reset,
        )?;
        right_row += 1;

        write!(
            stdout,
            "{}- words: {}{}{}",
            cursor::Goto(right_col, right_row),
            style::Bold,
            text.split_whitespace().count(),
            style::Reset,
        )?;
        right_row += 1;

        write!(
            stdout,
            "{}- characters: {}{}{}",
            cursor::Goto(right_col, right_row),
            style::Bold,
            text.chars().count(),
            style::Reset,
        )?;
        right_row += 1;

        write!(
            stdout,
            "{}- latency: {}{} usec{}",
            cursor::Goto(right_col, right_row),
            style::Bold,
            elapsed.as_micros(),
            style::Reset,
        )?;

        // Empty line.
        left_row += 1;

        if let Some(line) = lines.last_mut() {
            let trailing_whitespace = &text[text.trim_end_matches(' ').len()..];
            if !trailing_whitespace.is_empty() {
                // Trailing whitespace is discarded by
                // `textwrap::wrap`. We reinsert it here. If multiple
                // spaces are added, this can overflow the margins
                // which look a bit odd. Handling this would require
                // some more tinkering...
                *line = format!("{}{}", line, trailing_whitespace).into();
            } else if line.ends_with('\n') {
                // If `text` ends with a newline, the final wrapped line
                // contains this newline. This will in turn leave the
                // cursor hanging in the middle of the line. Pushing an
                // extra empty line fixes this.
                lines.push("".into());
            }
        } else {
            // No lines -> we add an empty line so we have a place
            // where we can display the cursor.
            lines.push("".into());
        }

        // Draw margins above and below the wrapped text. We draw the
        // margin before the text so that 1) the text can overwrite
        // the margin if `break_words` is `false` and `width` is very
        // small and 2) so the cursor remains at the end of the last
        // line of text.
        draw_margins(left_row, left_col, options.width as u16, '┌', '┐', stdout)?;
        left_row += 1;
        let final_row = left_row + lines.len() as u16;
        draw_margins(final_row, left_col, options.width as u16, '└', '┘', stdout)?;

        let (_, rows) = termion::terminal_size()?;
        write!(stdout, "{}", cursor::Show)?;
        for line in lines {
            if left_row > rows {
                // The text does not fits on the terminal -- we hide
                // the cursor since it's supposed to be "below" the
                // bottom of the terminal.
                write!(stdout, "{}", cursor::Hide)?;
                break;
            }
            draw_margins(left_row, left_col, options.width as u16, '│', '│', stdout)?;
            write!(stdout, "{}{}", cursor::Goto(left_col, left_row), line)?;
            left_row += 1;
        }

        stdout.flush()
    }

    pub fn main() -> Result<(), io::Error> {
        let initial_width = 20;

        let mut labels = vec![
            String::from("HyphenSplitter"),
            String::from("NoHyphenation"),
        ];

        let mut splitters: Vec<Box<dyn WordSplitter>> =
            vec![Box::new(HyphenSplitter), Box::new(NoHyphenation)];

        // If you like, you can download more dictionaries from
        // https://github.com/tapeinosyne/hyphenation/tree/master/dictionaries
        // Place the dictionaries in the examples/ directory. Here we
        // just load the embedded en-us dictionary.
        #[cfg(feature = "hyphenation")]
        for lang in &[Language::EnglishUS] {
            let dictionary = Standard::from_embedded(*lang).or_else(|_| {
                let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
                    .join("examples")
                    .join(format!("{}.standard.bincode", lang.code()));
                Standard::from_path(*lang, &path)
            });

            if let Ok(dict) = dictionary {
                labels.push(format!("{} hyphenation", lang.code()));
                splitters.push(Box::new(dict));
            }
        }

        let mut label = labels.pop().unwrap();
        let mut options: Options = Options::new(initial_width).splitter(Box::new(HyphenSplitter));
        options.break_words = false;
        options.splitter = splitters.pop().unwrap();

        let mut idx_iter = (0..splitters.len()).collect::<Vec<_>>().into_iter().cycle();

        let mut text = String::from(
            "Welcome to the interactive word-wrapping demo! Use the arrow \
        keys to change the line length and try typing your own text!",
        );

        let stdin = io::stdin();
        let mut screen = AlternateScreen::from(io::stdout().into_raw_mode()?);
        write!(screen, "{}", cursor::BlinkingUnderline)?;
        draw_text(&text, &options, &label, &mut screen)?;

        for c in stdin.keys() {
            match c? {
                Key::Esc | Key::Ctrl('c') => break,
                Key::Left => options.width = options.width.saturating_sub(1),
                Key::Right => options.width = options.width.saturating_add(1),
                Key::Ctrl('b') => options.break_words = !options.break_words,
                Key::Ctrl('o') => {
                    options.wrap_algorithm = match options.wrap_algorithm {
                        OptimalFit => FirstFit,
                        FirstFit => OptimalFit,
                    }
                }
                Key::Ctrl('s') => {
                    let idx = idx_iter.next().unwrap();
                    std::mem::swap(&mut options.splitter, &mut splitters[idx]);
                    std::mem::swap(&mut label, &mut labels[idx]);
                }
                Key::Char(c) => text.push(c),
                Key::Backspace => {
                    text.pop();
                }
                _ => {}
            }

            draw_text(&text, &options, &label, &mut screen)?;
        }

        // TODO: change to cursor::DefaultStyle if
        // https://github.com/redox-os/termion/pull/157 is merged.
        screen.write_all(b"\x1b[0 q")?;
        screen.flush()
    }
}
<commit_msg>Add start of Emperor’s New Clothes to interactive demo text<commit_after>// The example only works on Linux since Termion does not yet support
// Windows: https://gitlab.redox-os.org/redox-os/termion/-/issues/103
// The precise library doesn't matter much, so feel free to send a PR
// if there is a library with good Windows support.

fn main() -> Result<(), std::io::Error> {
    #[cfg(not(unix))]
    panic!("Sorry, this example currently only works on Unix!");

    #[cfg(unix)]
    unix_only::main()
}

#[cfg(unix)]
mod unix_only {
    use std::io::{self, Write};
    use termion::event::Key;
    use termion::input::TermRead;
    use termion::raw::{IntoRawMode, RawTerminal};
    use termion::screen::AlternateScreen;
    use termion::{color, cursor, style};
    use textwrap::core::WrapAlgorithm::{FirstFit, OptimalFit};
    use textwrap::{wrap, HyphenSplitter, NoHyphenation, Options, WordSplitter};

    #[cfg(feature = "hyphenation")]
    use hyphenation::{Language, Load, Standard};

    fn draw_margins(
        row: u16,
        col: u16,
        line_width: u16,
        left: char,
        right: char,
        stdout: &mut RawTerminal<io::Stdout>,
    ) -> Result<(), io::Error> {
        write!(
            stdout,
            "{}{}{}{}",
            cursor::Goto(col - 1, row),
            color::Fg(color::Red),
            left,
            color::Fg(color::Reset),
        )?;
        write!(
            stdout,
            "{}{}{}{}",
            cursor::Goto(col + line_width, row),
            color::Fg(color::Red),
            right,
            color::Fg(color::Reset),
        )?;

        Ok(())
    }

    fn draw_text<'a>(
        text: &str,
        options: &Options<'a>,
        splitter_label: &str,
        stdout: &mut RawTerminal<io::Stdout>,
    ) -> Result<(), io::Error> {
        let mut left_row: u16 = 1;
        let left_col: u16 = 3;

        write!(stdout, "{}", termion::clear::All)?;
        write!(
            stdout,
            "{}{}Options:{}",
            cursor::Goto(left_col, left_row),
            style::Bold,
            style::Reset,
        )?;
        left_row += 1;

        write!(
            stdout,
            "{}- width: {}{}{} (use ← and → to change)",
            cursor::Goto(left_col, left_row),
            style::Bold,
            options.width,
            style::Reset,
        )?;
        left_row += 1;

        write!(
            stdout,
            "{}- break_words: {}{:?}{} (toggle with Ctrl-b)",
            cursor::Goto(left_col, left_row),
            style::Bold,
            options.break_words,
            style::Reset,
        )?;
        left_row += 1;

        write!(
            stdout,
            "{}- splitter: {}{}{} (cycle with Ctrl-s)",
            cursor::Goto(left_col, left_row),
            style::Bold,
            splitter_label,
            style::Reset,
        )?;
        left_row += 1;

        write!(
            stdout,
            "{}- algorithm: {}{:?}{} (toggle with Ctrl-o)",
            cursor::Goto(left_col, left_row),
            style::Bold,
            options.wrap_algorithm,
            style::Reset,
        )?;
        left_row += 1;

        let now = std::time::Instant::now();
        let mut lines = wrap(text, options);
        let elapsed = now.elapsed();

        let right_col: u16 = 55;
        let mut right_row: u16 = 1;
        write!(
            stdout,
            "{}{}Performance:{}",
            cursor::Goto(right_col, right_row),
            style::Bold,
            style::Reset,
        )?;
        right_row += 1;

        write!(
            stdout,
            "{}- words: {}{}{}",
            cursor::Goto(right_col, right_row),
            style::Bold,
            text.split_whitespace().count(),
            style::Reset,
        )?;
        right_row += 1;

        write!(
            stdout,
            "{}- characters: {}{}{}",
            cursor::Goto(right_col, right_row),
            style::Bold,
            text.chars().count(),
            style::Reset,
        )?;
        right_row += 1;

        write!(
            stdout,
            "{}- latency: {}{} usec{}",
            cursor::Goto(right_col, right_row),
            style::Bold,
            elapsed.as_micros(),
            style::Reset,
        )?;

        // Empty line.
        left_row += 1;

        if let Some(line) = lines.last_mut() {
            let trailing_whitespace = &text[text.trim_end_matches(' ').len()..];
            if !trailing_whitespace.is_empty() {
                // Trailing whitespace is discarded by
                // `textwrap::wrap`. We reinsert it here. If multiple
                // spaces are added, this can overflow the margins
                // which look a bit odd. Handling this would require
                // some more tinkering...
                *line = format!("{}{}", line, trailing_whitespace).into();
            } else if line.ends_with('\n') {
                // If `text` ends with a newline, the final wrapped line
                // contains this newline. This will in turn leave the
                // cursor hanging in the middle of the line. Pushing an
                // extra empty line fixes this.
                lines.push("".into());
            }
        } else {
            // No lines -> we add an empty line so we have a place
            // where we can display the cursor.
            lines.push("".into());
        }

        // Draw margins above and below the wrapped text. We draw the
        // margin before the text so that 1) the text can overwrite
        // the margin if `break_words` is `false` and `width` is very
        // small and 2) so the cursor remains at the end of the last
        // line of text.
        draw_margins(left_row, left_col, options.width as u16, '┌', '┐', stdout)?;
        left_row += 1;
        let final_row = left_row + lines.len() as u16;
        draw_margins(final_row, left_col, options.width as u16, '└', '┘', stdout)?;

        let (_, rows) = termion::terminal_size()?;
        write!(stdout, "{}", cursor::Show)?;
        for line in lines {
            if left_row > rows {
                // The text does not fits on the terminal -- we hide
                // the cursor since it's supposed to be "below" the
                // bottom of the terminal.
                write!(stdout, "{}", cursor::Hide)?;
                break;
            }
            draw_margins(left_row, left_col, options.width as u16, '│', '│', stdout)?;
            write!(stdout, "{}{}", cursor::Goto(left_col, left_row), line)?;
            left_row += 1;
        }

        stdout.flush()
    }

    pub fn main() -> Result<(), io::Error> {
        let mut labels = vec![
            String::from("HyphenSplitter"),
            String::from("NoHyphenation"),
        ];

        let mut splitters: Vec<Box<dyn WordSplitter>> =
            vec![Box::new(HyphenSplitter), Box::new(NoHyphenation)];

        // If you like, you can download more dictionaries from
        // https://github.com/tapeinosyne/hyphenation/tree/master/dictionaries
        // Place the dictionaries in the examples/ directory. Here we
        // just load the embedded en-us dictionary.
        #[cfg(feature = "hyphenation")]
        for lang in &[Language::EnglishUS] {
            let dictionary = Standard::from_embedded(*lang).or_else(|_| {
                let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
                    .join("examples")
                    .join(format!("{}.standard.bincode", lang.code()));
                Standard::from_path(*lang, &path)
            });

            if let Ok(dict) = dictionary {
                labels.push(format!("{} hyphenation", lang.code()));
                splitters.push(Box::new(dict));
            }
        }

        let mut label = labels.pop().unwrap();
        let mut options: Options = Options::new(35).splitter(Box::new(HyphenSplitter));
        options.break_words = false;
        options.splitter = splitters.pop().unwrap();

        let mut idx_iter = (0..splitters.len()).collect::<Vec<_>>().into_iter().cycle();

        let mut text = String::from(
            "Welcome to the interactive demo! The following is from The \
            Emperor’s New Clothes by Hans Christian Andersen. You can edit the \
            text!\n\n\
            Many years ago there was an Emperor, who was so excessively fond \
            of new clothes that he spent all his money on them. He cared \
            nothing about his soldiers, nor for the theatre, nor for driving \
            in the woods except for the sake of showing off his new clothes. \
            He had a costume for every hour in the day, and instead of saying, \
            as one does about any other king or emperor, ‘He is in his council \
            chamber,’ here one always said, ‘The Emperor is in his \
            dressing-room.’",
        );

        let stdin = io::stdin();
        let mut screen = AlternateScreen::from(io::stdout().into_raw_mode()?);
        write!(screen, "{}", cursor::BlinkingUnderline)?;
        draw_text(&text, &options, &label, &mut screen)?;

        for c in stdin.keys() {
            match c? {
                Key::Esc | Key::Ctrl('c') => break,
                Key::Left => options.width = options.width.saturating_sub(1),
                Key::Right => options.width = options.width.saturating_add(1),
                Key::Ctrl('b') => options.break_words = !options.break_words,
                Key::Ctrl('o') => {
                    options.wrap_algorithm = match options.wrap_algorithm {
                        OptimalFit => FirstFit,
                        FirstFit => OptimalFit,
                    }
                }
                Key::Ctrl('s') => {
                    let idx = idx_iter.next().unwrap();
                    std::mem::swap(&mut options.splitter, &mut splitters[idx]);
                    std::mem::swap(&mut label, &mut labels[idx]);
                }
                Key::Char(c) => text.push(c),
                Key::Backspace => {
                    text.pop();
                }
                _ => {}
            }

            draw_text(&text, &options, &label, &mut screen)?;
        }

        // TODO: change to cursor::DefaultStyle if
        // https://github.com/redox-os/termion/pull/157 is merged.
        screen.write_all(b"\x1b[0 q")?;
        screen.flush()
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "Sync", "Send".
//
// * Traits that represent operators; e.g. "Add", "Sub", "Index".
//
// * Functions called by the compiler itself.

pub use self::LangItem::*;

use hir::def_id::DefId;
use ty::{self, TyCtxt};
use middle::weak_lang_items;
use util::nodemap::FxHashMap;

use syntax::ast;
use syntax::symbol::Symbol;
use hir::itemlikevisit::ItemLikeVisitor;
use hir;

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
    (
        $( $variant:ident, $name:expr, $method:ident; )*
    ) => {

enum_from_u32! {
    #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
    pub enum LangItem {
        $($variant,)*
    }
}

impl LangItem {
    fn name(self) -> &'static str {
        match self {
            $( $variant => $name, )*
        }
    }
}

pub struct LanguageItems {
    pub items: Vec<Option<DefId>>,
    pub missing: Vec<LangItem>,
}

impl LanguageItems {
    pub fn new() -> LanguageItems {
        fn foo(_: LangItem) -> Option<DefId> { None }

        LanguageItems {
            items: vec![$(foo($variant)),*],
            missing: Vec::new(),
        }
    }

    pub fn items(&self) -> &[Option<DefId>] {
        &*self.items
    }

    pub fn require(&self, it: LangItem) -> Result<DefId, String> {
        self.items[it as usize].ok_or(format!("requires `{}` lang_item", it.name()))
    }

    pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
        match Some(id) {
            x if x == self.fn_trait() => Some(ty::ClosureKind::Fn),
            x if x == self.fn_mut_trait() => Some(ty::ClosureKind::FnMut),
            x if x == self.fn_once_trait() =>  Some(ty::ClosureKind::FnOnce),
            _ => None
        }
    }

    $(
        #[allow(dead_code)]
        pub fn $method(&self) -> Option<DefId> {
            self.items[$variant as usize]
        }
    )*
}

struct LanguageItemCollector<'a, 'tcx: 'a> {
    items: LanguageItems,

    tcx: TyCtxt<'a, 'tcx, 'tcx>,

    item_refs: FxHashMap<&'static str, usize>,
}

impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        if let Some(value) = extract(&item.attrs) {
            let item_index = self.item_refs.get(&*value.as_str()).cloned();

            if let Some(item_index) = item_index {
                let def_id = self.tcx.hir.local_def_id(item.id);
                self.collect_item(item_index, def_id);
            } else {
                let span = self.tcx.hir.span(item.id);
                span_err!(self.tcx.sess, span, E0522,
                          "definition of an unknown language item: `{}`.",
                          value);
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
        // at present, lang items are always items, not trait items
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
        // at present, lang items are always items, not impl items
    }
}

impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItemCollector<'a, 'tcx> {
        let mut item_refs = FxHashMap();

        $( item_refs.insert($name, $variant as usize); )*

        LanguageItemCollector {
            tcx,
            items: LanguageItems::new(),
            item_refs,
        }
    }

    fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
        // Check for duplicates.
        match self.items.items[item_index] {
            Some(original_def_id) if original_def_id != item_def_id => {
                let name = LangItem::from_u32(item_index as u32).unwrap().name();
                let mut err = match self.tcx.hir.span_if_local(item_def_id) {
                    Some(span) => struct_span_err!(
                        self.tcx.sess,
                        span,
                        E0152,
                        "duplicate lang item found: `{}`.",
                        name),
                    None => self.tcx.sess.struct_err(&format!(
                            "duplicate lang item in crate `{}`: `{}`.",
                            self.tcx.crate_name(item_def_id.krate),
                            name)),
                };
                if let Some(span) = self.tcx.hir.span_if_local(original_def_id) {
                    span_note!(&mut err, span,
                               "first defined here.");
                } else {
                    err.note(&format!("first defined in crate `{}`.",
                                      self.tcx.crate_name(original_def_id.krate)));
                }
                err.emit();
            }
            _ => {
                // OK.
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
    }
}

pub fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
    for attribute in attrs {
        if attribute.check_name("lang") {
            if let Some(value) = attribute.value_str() {
                return Some(value)
            }
        }
    }

    return None;
}

pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
    let mut collector = LanguageItemCollector::new(tcx);
    for &cnum in tcx.crates().iter() {
        for &(index, item_index) in tcx.defined_lang_items(cnum).iter() {
            let def_id = DefId { krate: cnum, index: index };
            collector.collect_item(item_index, def_id);
        }
    }
    tcx.hir.krate().visit_all_item_likes(&mut collector);
    let LanguageItemCollector { mut items, .. } = collector;
    weak_lang_items::check_crate(tcx, &mut items);
    items
}

// End of the macro
    }
}

language_item_table! {
//  Variant name,                    Name,                      Method name;
    CharImplItem,                    "char",                    char_impl;
    StrImplItem,                     "str",                     str_impl;
    SliceImplItem,                   "slice",                   slice_impl;
    ConstPtrImplItem,                "const_ptr",               const_ptr_impl;
    MutPtrImplItem,                  "mut_ptr",                 mut_ptr_impl;
    I8ImplItem,                      "i8",                      i8_impl;
    I16ImplItem,                     "i16",                     i16_impl;
    I32ImplItem,                     "i32",                     i32_impl;
    I64ImplItem,                     "i64",                     i64_impl;
    I128ImplItem,                     "i128",                   i128_impl;
    IsizeImplItem,                   "isize",                   isize_impl;
    U8ImplItem,                      "u8",                      u8_impl;
    U16ImplItem,                     "u16",                     u16_impl;
    U32ImplItem,                     "u32",                     u32_impl;
    U64ImplItem,                     "u64",                     u64_impl;
    U128ImplItem,                    "u128",                    u128_impl;
    UsizeImplItem,                   "usize",                   usize_impl;
    F32ImplItem,                     "f32",                     f32_impl;
    F64ImplItem,                     "f64",                     f64_impl;

    SendTraitLangItem,               "send",                    send_trait;
    SizedTraitLangItem,              "sized",                   sized_trait;
    UnsizeTraitLangItem,             "unsize",                  unsize_trait;
    CopyTraitLangItem,               "copy",                    copy_trait;
    CloneTraitLangItem,              "clone",                   clone_trait;
    SyncTraitLangItem,               "sync",                    sync_trait;
    FreezeTraitLangItem,             "freeze",                  freeze_trait;

    DropTraitLangItem,               "drop",                    drop_trait;

    CoerceUnsizedTraitLangItem,      "coerce_unsized",          coerce_unsized_trait;

    AddTraitLangItem,                "add",                     add_trait;
    SubTraitLangItem,                "sub",                     sub_trait;
    MulTraitLangItem,                "mul",                     mul_trait;
    DivTraitLangItem,                "div",                     div_trait;
    RemTraitLangItem,                "rem",                     rem_trait;
    NegTraitLangItem,                "neg",                     neg_trait;
    NotTraitLangItem,                "not",                     not_trait;
    BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
    BitAndTraitLangItem,             "bitand",                  bitand_trait;
    BitOrTraitLangItem,              "bitor",                   bitor_trait;
    ShlTraitLangItem,                "shl",                     shl_trait;
    ShrTraitLangItem,                "shr",                     shr_trait;
    AddAssignTraitLangItem,          "add_assign",              add_assign_trait;
    SubAssignTraitLangItem,          "sub_assign",              sub_assign_trait;
    MulAssignTraitLangItem,          "mul_assign",              mul_assign_trait;
    DivAssignTraitLangItem,          "div_assign",              div_assign_trait;
    RemAssignTraitLangItem,          "rem_assign",              rem_assign_trait;
    BitXorAssignTraitLangItem,       "bitxor_assign",           bitxor_assign_trait;
    BitAndAssignTraitLangItem,       "bitand_assign",           bitand_assign_trait;
    BitOrAssignTraitLangItem,        "bitor_assign",            bitor_assign_trait;
    ShlAssignTraitLangItem,          "shl_assign",              shl_assign_trait;
    ShrAssignTraitLangItem,          "shr_assign",              shr_assign_trait;
    IndexTraitLangItem,              "index",                   index_trait;
    IndexMutTraitLangItem,           "index_mut",               index_mut_trait;

    UnsafeCellTypeLangItem,          "unsafe_cell",             unsafe_cell_type;

    DerefTraitLangItem,              "deref",                   deref_trait;
    DerefMutTraitLangItem,           "deref_mut",               deref_mut_trait;

    FnTraitLangItem,                 "fn",                      fn_trait;
    FnMutTraitLangItem,              "fn_mut",                  fn_mut_trait;
    FnOnceTraitLangItem,             "fn_once",                 fn_once_trait;

    GeneratorStateLangItem,          "generator_state",         gen_state;
    GeneratorTraitLangItem,          "generator",               gen_trait;

    EqTraitLangItem,                 "eq",                      eq_trait;
    OrdTraitLangItem,                "ord",                     ord_trait;

    StrEqFnLangItem,                 "str_eq",                  str_eq_fn;

    // A number of panic-related lang items. The `panic` item corresponds to
    // divide-by-zero and various panic cases with `match`. The
    // `panic_bounds_check` item is for indexing arrays.
    //
    // The `begin_unwind` lang item has a predefined symbol name and is sort of
    // a "weak lang item" in the sense that a crate is not required to have it
    // defined to use it, but a final product is required to define it
    // somewhere. Additionally, there are restrictions on crates that use a weak
    // lang item, but do not have it defined.
    PanicFnLangItem,                 "panic",                   panic_fn;
    PanicBoundsCheckFnLangItem,      "panic_bounds_check",      panic_bounds_check_fn;
    PanicFmtLangItem,                "panic_fmt",               panic_fmt;

    ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
    BoxFreeFnLangItem,               "box_free",                box_free_fn;
    DropInPlaceFnLangItem,             "drop_in_place",           drop_in_place_fn;

    StartFnLangItem,                 "start",                   start_fn;

    EhPersonalityLangItem,           "eh_personality",          eh_personality;
    EhUnwindResumeLangItem,          "eh_unwind_resume",        eh_unwind_resume;
    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;

    OwnedBoxLangItem,                "owned_box",               owned_box;

    PhantomDataItem,                 "phantom_data",            phantom_data;

    NonZeroItem,                     "non_zero",                non_zero;

    DebugTraitLangItem,              "debug_trait",             debug_trait;
}

impl<'a, 'tcx, 'gcx> ty::TyCtxt<'a, 'tcx, 'gcx> {
    pub fn require_lang_item(&self, lang_item: LangItem) -> DefId {
        self.lang_items().require(lang_item).unwrap_or_else(|msg| {
            self.sess.fatal(&msg)
        })
    }
}
<commit_msg>Fix initial review<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "Sync", "Send".
//
// * Traits that represent operators; e.g. "Add", "Sub", "Index".
//
// * Functions called by the compiler itself.

pub use self::LangItem::*;

use hir::def_id::DefId;
use ty::{self, TyCtxt};
use middle::weak_lang_items;
use util::nodemap::FxHashMap;

use syntax::ast;
use syntax::symbol::Symbol;
use hir::itemlikevisit::ItemLikeVisitor;
use hir;

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
    (
        $( $variant:ident, $name:expr, $method:ident; )*
    ) => {

enum_from_u32! {
    #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
    pub enum LangItem {
        $($variant,)*
    }
}

impl LangItem {
    fn name(self) -> &'static str {
        match self {
            $( $variant => $name, )*
        }
    }
}

pub struct LanguageItems {
    pub items: Vec<Option<DefId>>,
    pub missing: Vec<LangItem>,
}

impl LanguageItems {
    pub fn new() -> LanguageItems {
        fn foo(_: LangItem) -> Option<DefId> { None }

        LanguageItems {
            items: vec![$(foo($variant)),*],
            missing: Vec::new(),
        }
    }

    pub fn items(&self) -> &[Option<DefId>] {
        &*self.items
    }

    pub fn require(&self, it: LangItem) -> Result<DefId, String> {
        self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
    }

    pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
        match Some(id) {
            x if x == self.fn_trait() => Some(ty::ClosureKind::Fn),
            x if x == self.fn_mut_trait() => Some(ty::ClosureKind::FnMut),
            x if x == self.fn_once_trait() => Some(ty::ClosureKind::FnOnce),
            _ => None
        }
    }

    $(
        #[allow(dead_code)]
        pub fn $method(&self) -> Option<DefId> {
            self.items[$variant as usize]
        }
    )*
}

struct LanguageItemCollector<'a, 'tcx: 'a> {
    items: LanguageItems,

    tcx: TyCtxt<'a, 'tcx, 'tcx>,

    item_refs: FxHashMap<&'static str, usize>,
}

impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        if let Some(value) = extract(&item.attrs) {
            let item_index = self.item_refs.get(&*value.as_str()).cloned();

            if let Some(item_index) = item_index {
                let def_id = self.tcx.hir.local_def_id(item.id);
                self.collect_item(item_index, def_id);
            } else {
                let span = self.tcx.hir.span(item.id);
                span_err!(self.tcx.sess, span, E0522,
                          "definition of an unknown language item: `{}`.",
                          value);
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
        // at present, lang items are always items, not trait items
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
        // at present, lang items are always items, not impl items
    }
}

impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItemCollector<'a, 'tcx> {
        let mut item_refs = FxHashMap();

        $( item_refs.insert($name, $variant as usize); )*

        LanguageItemCollector {
            tcx,
            items: LanguageItems::new(),
            item_refs,
        }
    }

    fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
        // Check for duplicates.
        match self.items.items[item_index] {
            Some(original_def_id) if original_def_id != item_def_id => {
                let name = LangItem::from_u32(item_index as u32).unwrap().name();
                let mut err = match self.tcx.hir.span_if_local(item_def_id) {
                    Some(span) => struct_span_err!(
                        self.tcx.sess,
                        span,
                        E0152,
                        "duplicate lang item found: `{}`.",
                        name),
                    None => self.tcx.sess.struct_err(&format!(
                            "duplicate lang item in crate `{}`: `{}`.",
                            self.tcx.crate_name(item_def_id.krate),
                            name)),
                };
                if let Some(span) = self.tcx.hir.span_if_local(original_def_id) {
                    span_note!(&mut err, span,
                               "first defined here.");
                } else {
                    err.note(&format!("first defined in crate `{}`.",
                                      self.tcx.crate_name(original_def_id.krate)));
                }
                err.emit();
            }
            _ => {
                // OK.
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
    }
}

pub fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
    for attribute in attrs {
        if attribute.check_name("lang") {
            if let Some(value) = attribute.value_str() {
                return Some(value)
            }
        }
    }

    return None;
}

pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
    let mut collector = LanguageItemCollector::new(tcx);
    for &cnum in tcx.crates().iter() {
        for &(index, item_index) in tcx.defined_lang_items(cnum).iter() {
            let def_id = DefId { krate: cnum, index: index };
            collector.collect_item(item_index, def_id);
        }
    }
    tcx.hir.krate().visit_all_item_likes(&mut collector);
    let LanguageItemCollector { mut items, .. } = collector;
    weak_lang_items::check_crate(tcx, &mut items);
    items
}

// End of the macro
    }
}

language_item_table! {
//  Variant name,                    Name,                      Method name;
    CharImplItem,                    "char",                    char_impl;
    StrImplItem,                     "str",                     str_impl;
    SliceImplItem,                   "slice",                   slice_impl;
    ConstPtrImplItem,                "const_ptr",               const_ptr_impl;
    MutPtrImplItem,                  "mut_ptr",                 mut_ptr_impl;
    I8ImplItem,                      "i8",                      i8_impl;
    I16ImplItem,                     "i16",                     i16_impl;
    I32ImplItem,                     "i32",                     i32_impl;
    I64ImplItem,                     "i64",                     i64_impl;
    I128ImplItem,                     "i128",                   i128_impl;
    IsizeImplItem,                   "isize",                   isize_impl;
    U8ImplItem,                      "u8",                      u8_impl;
    U16ImplItem,                     "u16",                     u16_impl;
    U32ImplItem,                     "u32",                     u32_impl;
    U64ImplItem,                     "u64",                     u64_impl;
    U128ImplItem,                    "u128",                    u128_impl;
    UsizeImplItem,                   "usize",                   usize_impl;
    F32ImplItem,                     "f32",                     f32_impl;
    F64ImplItem,                     "f64",                     f64_impl;

    SendTraitLangItem,               "send",                    send_trait;
    SizedTraitLangItem,              "sized",                   sized_trait;
    UnsizeTraitLangItem,             "unsize",                  unsize_trait;
    CopyTraitLangItem,               "copy",                    copy_trait;
    CloneTraitLangItem,              "clone",                   clone_trait;
    SyncTraitLangItem,               "sync",                    sync_trait;
    FreezeTraitLangItem,             "freeze",                  freeze_trait;

    DropTraitLangItem,               "drop",                    drop_trait;

    CoerceUnsizedTraitLangItem,      "coerce_unsized",          coerce_unsized_trait;

    AddTraitLangItem,                "add",                     add_trait;
    SubTraitLangItem,                "sub",                     sub_trait;
    MulTraitLangItem,                "mul",                     mul_trait;
    DivTraitLangItem,                "div",                     div_trait;
    RemTraitLangItem,                "rem",                     rem_trait;
    NegTraitLangItem,                "neg",                     neg_trait;
    NotTraitLangItem,                "not",                     not_trait;
    BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
    BitAndTraitLangItem,             "bitand",                  bitand_trait;
    BitOrTraitLangItem,              "bitor",                   bitor_trait;
    ShlTraitLangItem,                "shl",                     shl_trait;
    ShrTraitLangItem,                "shr",                     shr_trait;
    AddAssignTraitLangItem,          "add_assign",              add_assign_trait;
    SubAssignTraitLangItem,          "sub_assign",              sub_assign_trait;
    MulAssignTraitLangItem,          "mul_assign",              mul_assign_trait;
    DivAssignTraitLangItem,          "div_assign",              div_assign_trait;
    RemAssignTraitLangItem,          "rem_assign",              rem_assign_trait;
    BitXorAssignTraitLangItem,       "bitxor_assign",           bitxor_assign_trait;
    BitAndAssignTraitLangItem,       "bitand_assign",           bitand_assign_trait;
    BitOrAssignTraitLangItem,        "bitor_assign",            bitor_assign_trait;
    ShlAssignTraitLangItem,          "shl_assign",              shl_assign_trait;
    ShrAssignTraitLangItem,          "shr_assign",              shr_assign_trait;
    IndexTraitLangItem,              "index",                   index_trait;
    IndexMutTraitLangItem,           "index_mut",               index_mut_trait;

    UnsafeCellTypeLangItem,          "unsafe_cell",             unsafe_cell_type;

    DerefTraitLangItem,              "deref",                   deref_trait;
    DerefMutTraitLangItem,           "deref_mut",               deref_mut_trait;

    FnTraitLangItem,                 "fn",                      fn_trait;
    FnMutTraitLangItem,              "fn_mut",                  fn_mut_trait;
    FnOnceTraitLangItem,             "fn_once",                 fn_once_trait;

    GeneratorStateLangItem,          "generator_state",         gen_state;
    GeneratorTraitLangItem,          "generator",               gen_trait;

    EqTraitLangItem,                 "eq",                      eq_trait;
    OrdTraitLangItem,                "ord",                     ord_trait;

    StrEqFnLangItem,                 "str_eq",                  str_eq_fn;

    // A number of panic-related lang items. The `panic` item corresponds to
    // divide-by-zero and various panic cases with `match`. The
    // `panic_bounds_check` item is for indexing arrays.
    //
    // The `begin_unwind` lang item has a predefined symbol name and is sort of
    // a "weak lang item" in the sense that a crate is not required to have it
    // defined to use it, but a final product is required to define it
    // somewhere. Additionally, there are restrictions on crates that use a weak
    // lang item, but do not have it defined.
    PanicFnLangItem,                 "panic",                   panic_fn;
    PanicBoundsCheckFnLangItem,      "panic_bounds_check",      panic_bounds_check_fn;
    PanicFmtLangItem,                "panic_fmt",               panic_fmt;

    ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
    BoxFreeFnLangItem,               "box_free",                box_free_fn;
    DropInPlaceFnLangItem,             "drop_in_place",           drop_in_place_fn;

    StartFnLangItem,                 "start",                   start_fn;

    EhPersonalityLangItem,           "eh_personality",          eh_personality;
    EhUnwindResumeLangItem,          "eh_unwind_resume",        eh_unwind_resume;
    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;

    OwnedBoxLangItem,                "owned_box",               owned_box;

    PhantomDataItem,                 "phantom_data",            phantom_data;

    NonZeroItem,                     "non_zero",                non_zero;

    DebugTraitLangItem,              "debug_trait",             debug_trait;
}

impl<'a, 'tcx, 'gcx> ty::TyCtxt<'a, 'tcx, 'gcx> {
    pub fn require_lang_item(&self, lang_item: LangItem) -> DefId {
        self.lang_items().require(lang_item).unwrap_or_else(|msg| {
            self.sess.fatal(&msg)
        })
    }
}
<|endoftext|>


<commit_before>extern crate tropix;
extern crate rustc_serialize;
extern crate time;

use tropix::poloniex::public::*;
use tropix::poloniex::private::*;
use rustc_serialize::{Decodable, Decoder};
use rustc_serialize::json::{self, ToJson, Json};

use std::io;
use std::io::Read;
use std::thread::sleep;
use std::time::Duration;
use std::io::{BufRead};
use std::rc::Rc;
use std::cell::RefCell;

fn main() {
	let mut pair_vec = Vec::new();
    pair_vec.push("BTC_ETC".to_string());
    pair_vec.push("BTC_AMP".to_string());
	pair_vec.push("BTC_LTC".to_string());
    pair_vec.push("BTC_DAO".to_string());
    pair_vec.push("BTC_LSK".to_string());
	pair_vec.push("BTC_MAID".to_string());
	pair_vec.push("BTC_DOGE".to_string());
	pair_vec.push("BTC_XMR".to_string());
	pair_vec.push("BTC_ETH".to_string());
	pair_vec.push("BTC_FCT".to_string());
	pair_vec.push("BTC_OMNI".to_string());
	pair_vec.push("BTC_QORA".to_string());
	pair_vec.push("BTC_DASH".to_string());
	pair_vec.push("BTC_SYS".to_string());
	pair_vec.push("BTC_XRP".to_string());
	pair_vec.push("BTC_DCR".to_string());
	pair_vec.push("BTC_ZEC".to_string());
	//api Key

    println!("This robot will automatically sell a pair you will select on Poloniex\nYou will enter a maxmimum sell amount per interval\nand a frequency to buy, \n
    	every x seconds the robot will sell up to the maximum quantity");
    println!("Enter Your Poloniex Api Key");
    let mut input1 = String::new();
    let stdin1 = io::stdin();
    stdin1.lock().read_line(&mut input1).unwrap();

    let next_string = &input1.trim_right_matches("\n");

	let the_api_key = &next_string;

	let the_api_keyclone = the_api_key.clone();
//secret Key
	println!("Enter Your Poloniex Secret Key");
    let mut input2 = String::new();
    let stdin2 = io::stdin();
    stdin2.lock().read_line(&mut input2).unwrap();

    let the_secret_trimmed = input2.trim_right_matches("\n");

    let mut intd = 0;
    for pair in &pair_vec {
    	println!("{:?}, : {:?}", intd, pair);
    	intd += 1;
    }
    println!("choose a pair to trade by its index., enter the number before the pair you want to trade");
    let mut input5 = String::new();
    let stdin5 = io::stdin();
    stdin5.lock().read_line(&mut input5).unwrap();

    let pair_ind = input5.trim_right_matches("\n");

    let pair_ind2: usize = pair_ind.parse().ok().expect("pair index is not a number");

    println!("Enter a maximum position limit in the alt coin quantity \n the bot will sell only up to this much at a time");
    let mut input3 = String::new();
    let stdin3 = io::stdin();
    stdin3.lock().read_line(&mut input3).unwrap();

    let maxposition = input3.trim_right_matches("\n").to_string();
    let position_clone = maxposition.clone();

    println!("Enter a buy frequency in seconds a value of 60 will mean 1 minute");
    let mut input4 = String::new();
    let stdin4 = io::stdin();
    stdin4.lock().read_line(&mut input4).unwrap();

    let frequency = input4.trim_right_matches("\n").to_string();

    let frequency: u64 = frequency.parse().ok().expect("frequency is not a number");

    println!("for margin trading enter 1 \n for non margin trading enter 0");
    let mut input6 = String::new();
    let stdin6 = io::stdin();
    stdin6.lock().read_line(&mut input6).unwrap();

    let margin_ind = input6.trim_right_matches("\n").to_string();

    let margin_ind: u64 = margin_ind.parse().ok().expect("frequency is not a number");

	let mut xyz = 0;
	while xyz == 0 {

		let all_orders = returnOrderBook(pair_vec[pair_ind2].to_string());
		let json = Json::from_str(&all_orders).unwrap();

   		let ticker_result = json.find_path(&[&"bids"]).unwrap();

		let ticker_result_string: String = json::encode(&ticker_result).unwrap();

		let bids_results: Vec<(f64, f64)> = json::decode(&ticker_result_string).unwrap();

		let timespec = time::get_time();
		let mut mills = timespec.sec * 100;

		if bids_results[0].1 < position_clone.parse().ok().expect("max position turned out to not be a number either") {
            if margin_ind == 0 {
                sell(the_api_keyclone.to_string(), the_secret_trimmed, pair_vec[pair_ind2].to_string(), bids_results[0].0.to_string(), bids_results[0].1.to_string(), mills.to_string());
            } else {
                marginSell(the_api_keyclone.to_string(), the_secret_trimmed, pair_vec[pair_ind2].to_string(), bids_results[0].0.to_string(), bids_results[0].1.to_string(), mills.to_string());
            }
		}	else {
            if margin_ind == 0 {
                sell(the_api_keyclone.to_string(), the_secret_trimmed, pair_vec[pair_ind2].to_string(), bids_results[0].0.to_string(), maxposition.to_string(), mills.to_string());
            } else {
                marginSell(the_api_keyclone.to_string(), the_secret_trimmed, pair_vec[pair_ind2].to_string(), bids_results[0].0.to_string(), maxposition.to_string(), mills.to_string());
            }
		}

		let the_seconds = Duration::new(frequency, 0);
		sleep(the_seconds);

	}
}
<commit_msg>fix an error that made confusion in cli steps<commit_after>extern crate tropix;
extern crate rustc_serialize;
extern crate time;

use tropix::poloniex::public::*;
use tropix::poloniex::private::*;
use rustc_serialize::{Decodable, Decoder};
use rustc_serialize::json::{self, ToJson, Json};

use std::io;
use std::io::Read;
use std::thread::sleep;
use std::time::Duration;
use std::io::{BufRead};
use std::rc::Rc;
use std::cell::RefCell;

fn main() {
	let mut pair_vec = Vec::new();
    pair_vec.push("BTC_ETC".to_string());
    pair_vec.push("BTC_AMP".to_string());
	pair_vec.push("BTC_LTC".to_string());
    pair_vec.push("BTC_DAO".to_string());
    pair_vec.push("BTC_LSK".to_string());
	pair_vec.push("BTC_MAID".to_string());
	pair_vec.push("BTC_DOGE".to_string());
	pair_vec.push("BTC_XMR".to_string());
	pair_vec.push("BTC_ETH".to_string());
	pair_vec.push("BTC_FCT".to_string());
	pair_vec.push("BTC_OMNI".to_string());
	pair_vec.push("BTC_QORA".to_string());
	pair_vec.push("BTC_DASH".to_string());
	pair_vec.push("BTC_SYS".to_string());
	pair_vec.push("BTC_XRP".to_string());
	pair_vec.push("BTC_DCR".to_string());
	pair_vec.push("BTC_ZEC".to_string());
	//api Key

    println!("This robot will automatically sell a pair you will select on Poloniex\nYou will enter a maxmimum sell amount per interval\nand a frequency to buy, \n
    	every x seconds the robot will sell up to the maximum quantity");
    println!("Enter Your Poloniex Api Key");
    let mut input1 = String::new();
    let stdin1 = io::stdin();
    stdin1.lock().read_line(&mut input1).unwrap();

    let next_string = &input1.trim_right_matches("\n");

	let the_api_key = &next_string;

	let the_api_keyclone = the_api_key.clone();
//secret Key
	println!("Enter Your Poloniex Secret Key");
    let mut input2 = String::new();
    let stdin2 = io::stdin();
    stdin2.lock().read_line(&mut input2).unwrap();

    let the_secret_trimmed = input2.trim_right_matches("\n");

    let mut intd = 0;
    for pair in &pair_vec {
    	println!("{:?}, : {:?}", intd, pair);
    	intd += 1;
    }
    println!("choose a pair to trade by its index., enter the number before the pair you want to trade");
    let mut input5 = String::new();
    let stdin5 = io::stdin();
    stdin5.lock().read_line(&mut input5).unwrap();

    let pair_ind = input5.trim_right_matches("\n");

    let pair_ind2: usize = pair_ind.parse().ok().expect("pair index is not a number");

    println!("Enter a maximum position limit in the alt coin quantity \n the bot will sell only up to this much at a time");
    let mut input3 = String::new();
    let stdin3 = io::stdin();
    stdin3.lock().read_line(&mut input3).unwrap();

    let maxposition = input3.trim_right_matches("\n").to_string();
    let position_clone = maxposition.clone();

    println!("Enter a sell frequency in seconds a value of 60 will mean 1 minute");
    let mut input4 = String::new();
    let stdin4 = io::stdin();
    stdin4.lock().read_line(&mut input4).unwrap();

    let frequency = input4.trim_right_matches("\n").to_string();

    let frequency: u64 = frequency.parse().ok().expect("frequency is not a number");

    println!("for margin trading enter 1 \n for non margin trading enter 0");
    let mut input6 = String::new();
    let stdin6 = io::stdin();
    stdin6.lock().read_line(&mut input6).unwrap();

    let margin_ind = input6.trim_right_matches("\n").to_string();

    let margin_ind: u64 = margin_ind.parse().ok().expect("frequency is not a number");

	let mut xyz = 0;
	while xyz == 0 {

		let all_orders = returnOrderBook(pair_vec[pair_ind2].to_string());
		let json = Json::from_str(&all_orders).unwrap();

   		let ticker_result = json.find_path(&[&"bids"]).unwrap();

		let ticker_result_string: String = json::encode(&ticker_result).unwrap();

		let bids_results: Vec<(f64, f64)> = json::decode(&ticker_result_string).unwrap();

		let timespec = time::get_time();
		let mut mills = timespec.sec * 100;

		if bids_results[0].1 < position_clone.parse().ok().expect("max position turned out to not be a number either") {
            if margin_ind == 0 {
                sell(the_api_keyclone.to_string(), the_secret_trimmed, pair_vec[pair_ind2].to_string(), bids_results[0].0.to_string(), bids_results[0].1.to_string(), mills.to_string());
            } else {
                marginSell(the_api_keyclone.to_string(), the_secret_trimmed, pair_vec[pair_ind2].to_string(), bids_results[0].0.to_string(), bids_results[0].1.to_string(), mills.to_string());
            }
		}	else {
            if margin_ind == 0 {
                sell(the_api_keyclone.to_string(), the_secret_trimmed, pair_vec[pair_ind2].to_string(), bids_results[0].0.to_string(), maxposition.to_string(), mills.to_string());
            } else {
                marginSell(the_api_keyclone.to_string(), the_secret_trimmed, pair_vec[pair_ind2].to_string(), bids_results[0].0.to_string(), maxposition.to_string(), mills.to_string());
            }
		}

		let the_seconds = Duration::new(frequency, 0);
		sleep(the_seconds);

	}
}
<|endoftext|>