<commit_before>
// Copyright 2017 The gltf Library Developers
//
// 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.

use v2::{Extras, Index, Root};

enum_number! {
    Target {
        ArrayBuffer = 34962,
        ElementArrayBuffer = 34963,
    }
}

/// A buffer points to binary data representing geometry, animations, or skins.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Buffer<E: Extras> {
    /// The length of the buffer in bytes.
    #[serde(default, rename = "byteLength")]
    pub byte_length: u32,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// Uniform resource locator of the buffer.
    ///
    /// Relative paths are relative to the .gltf file.
    pub uri: String,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: BufferExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: <E as Extras>::Buffer,
}

/// Extension specific data for `Buffer`.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct BufferExtensions {
    #[serde(default)]
    _allow_extra_fields: (),
}

/// A view into a buffer generally representing a subset of the buffer.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct BufferView<E: Extras> {
    /// The parent `Buffer`.
    pub buffer: Index<Buffer<E>>,

    /// The length of the `BufferView` in bytes.
    #[serde(rename = "byteLength")]
    pub byte_length: u32,

    /// Offset into the parent buffer in bytes.
    #[serde(rename = "byteOffset")]
    pub byte_offset: u32,

    /// The stride in bytes between vertex attributes or other interleavable data.
    ///
    /// When zero, data is assumed to be tightly packed.
    #[serde(default)]
    pub byte_stride: u32,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// Optional target the buffer should be bound to.
    pub target: Option<Target>,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: BufferViewExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: <E as Extras>::BufferView,
}

/// Extension specific data for `BufferView`.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct BufferViewExtensions {
    #[serde(default)]
    _allow_extra_fields: (),
}

impl<E: Extras> Buffer<E> {
    #[doc(hidden)]
    pub fn range_check(&self, _root: &Root<E>) -> Result<(), ()> {
        Ok(())
    }
}

impl<E: Extras> BufferView<E> {
    #[doc(hidden)]
    pub fn range_check(&self, root: &Root<E>) -> Result<(), ()> {
        let _ = root.try_get(&self.buffer)?;
        Ok(())
    }
}
<commit_msg>Added default value for `bufferView.byteOffset`<commit_after>
// Copyright 2017 The gltf Library Developers
//
// 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.

use v2::{Extras, Index, Root};

enum_number! {
    Target {
        ArrayBuffer = 34962,
        ElementArrayBuffer = 34963,
    }
}

/// A buffer points to binary data representing geometry, animations, or skins.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Buffer<E: Extras> {
    /// The length of the buffer in bytes.
    #[serde(default, rename = "byteLength")]
    pub byte_length: u32,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// Uniform resource locator of the buffer.
    ///
    /// Relative paths are relative to the .gltf file.
    pub uri: String,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: BufferExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: <E as Extras>::Buffer,
}

/// Extension specific data for `Buffer`.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct BufferExtensions {
    #[serde(default)]
    _allow_extra_fields: (),
}

/// A view into a buffer generally representing a subset of the buffer.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct BufferView<E: Extras> {
    /// The parent `Buffer`.
    pub buffer: Index<Buffer<E>>,

    /// The length of the `BufferView` in bytes.
    #[serde(rename = "byteLength")]
    pub byte_length: u32,

    /// Offset into the parent buffer in bytes.
    #[serde(default, rename = "byteOffset")]
    pub byte_offset: u32,

    /// The stride in bytes between vertex attributes or other interleavable data.
    ///
    /// When zero, data is assumed to be tightly packed.
    #[serde(default)]
    pub byte_stride: u32,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// Optional target the buffer should be bound to.
    pub target: Option<Target>,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: BufferViewExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: <E as Extras>::BufferView,
}

/// Extension specific data for `BufferView`.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct BufferViewExtensions {
    #[serde(default)]
    _allow_extra_fields: (),
}

impl<E: Extras> Buffer<E> {
    #[doc(hidden)]
    pub fn range_check(&self, _root: &Root<E>) -> Result<(), ()> {
        Ok(())
    }
}

impl<E: Extras> BufferView<E> {
    #[doc(hidden)]
    pub fn range_check(&self, root: &Root<E>) -> Result<(), ()> {
        let _ = root.try_get(&self.buffer)?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Phillip Oppermann, Calvin Lee and JJ Garzella.
// See the README.md file at the top-level directory of this
// distribution.
//
// Licensed under the MIT license <LICENSE or
// http://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed
// except according to those terms.

use core::ops::{Deref, DerefMut};
use core::ops::Add;

use multiboot2::{BootInformation, StringTable};
use spin::Mutex;

pub use self::entry::*;
pub use self::mapper::Mapper;
pub use self::temporary_page::{TemporaryPage, TinyAllocator};
use memory::{PAGE_SIZE, Frame, FrameAllocate};
use memory::{MemoryController, MEMORY_CONTROLLER};

use memory::frame_bitmap::FrameBitmap;

/// An entry in the page table.
mod entry;
/// Abstraction of the page table.
mod table;
/// A page to temporarily map a frame.
mod temporary_page;
/// An interface to the active page table.
mod mapper;

/// How many entries are in each table.
const ENTRY_COUNT: usize = 512;

/// This is the _only_ ActivePageTable that should be used in the system. Any others
/// would violate the assumptions of `Unique`.
pub static ACTIVE_TABLE: Mutex<ActivePageTable> = Mutex::new(unsafe {
    ActivePageTable::new()
});

// TODO FIXME Make conversions between the PhysicalAddress and VirtualAddress types
// unsafe. All addresses in this module have to be explicitly physical or virtual.
//
// Possibly make physical and virtual traits and apply them to numbers, pointers,
// etc.?
/// A _physical_ address on the machine. *_These should only be known to the kernel_*.
/// The userspace should never recieve a physical addresss.
pub type PhysicalAddress = usize;
/// A _virtual_ address on the machine. _All_ pointers are of this type. It is
/// undefined behaviour to convert a virtual to a physical address except through
/// the specific page table methods.
pub type VirtualAddress = usize;

/// A representation of a virtual page.
#[derive(Debug, Copy, Clone)]
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Page(usize);

impl Page {
    /// Returns the first address in the `Page`
    pub fn start_address(&self) -> VirtualAddress {
        self.0 * PAGE_SIZE
    }

    /// Returns a `Page` containing the VirtualAddress given
    ///
    /// # Panics
    /// A panic will occur if the address is not canonical. For the address
    /// to be canonical the first 48 bits must be sign extended.
    pub fn containing_address(address: VirtualAddress) -> Page {
        // Address must be canonical
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
                "invalid address: 0x{:x}",
                address);
        Page(address / PAGE_SIZE)
    }

    /// Returns `Page`'s index into the p4 table.
    ///
    /// The value must be from 0 to `ENTRY_COUNT`
    fn p4_index(&self) -> usize {
        (self.0 >> 27) & 0o777
    }

    /// Returns `Page`'s index into the p3 table.
    ///
    /// The value must be from 0 to `ENTRY_COUNT`
    fn p3_index(&self) -> usize {
        (self.0 >> 18) & 0o777
    }

    /// Returns `Page`'s index into the p2 table.
    ///
    /// The value must be from 0 to `ENTRY_COUNT`
    fn p2_index(&self) -> usize {
        (self.0 >> 9) & 0o777
    }

    /// Returns `Page`'s index into the p1 table.
    ///
    /// The value must be from 0 to `ENTRY_COUNT`
    fn p1_index(&self) -> usize {
        (self.0 >> 0) & 0o777
    }

    /// Returns a `Page` iterator from `start` to `end`.
    pub fn range_inclusive(start: Page, end: Page) -> PageIter {
        PageIter {
            start: start,
            end: end,
        }
    }

    /// Map this `Page` to the given `Frame`
    pub fn map_to(self, frame: Frame, flags: EntryFlags) {
        let mut lock = MEMORY_CONTROLLER.lock();
        let &mut MemoryController {
            ref mut active_table,
            ref mut frame_allocator,
            stack_allocator: _,
        } = lock.as_mut().unwrap();
        active_table.map_to(self, frame, flags, frame_allocator).expect("Unable to map frame because page is already taken");
    }

    /// Map this `Page` to any availible `Frame`.
    ///
    /// # Panics
    /// Panics if OOM
    pub fn map(self, flags: EntryFlags) {
        let mut lock = MEMORY_CONTROLLER.lock();
        let &mut MemoryController {
            ref mut active_table,
            ref mut frame_allocator,
            stack_allocator: _,
        } = lock.as_mut().unwrap();
        active_table.map(self, flags, frame_allocator);

    }

    /// Unmap this `Page`
    pub fn unmap(self) {
        let mut lock = MEMORY_CONTROLLER.lock();
        let &mut MemoryController {
            ref mut active_table,
            ref mut frame_allocator,
            stack_allocator: _,
        } = lock.as_mut().unwrap();

        active_table.unmap(self, frame_allocator);
    }
}

impl Add<usize> for Page {
    type Output = Page;

    fn add(self, rhs: usize) -> Page {
        Page(self.0 + rhs)
    }
}

/// Identity map the given `Frame`
fn identity_map(frame: Frame, flags: EntryFlags) {
        let page = Page::containing_address(frame.start_address());
        page.map_to(frame, flags);
}

/// An iterator across `Page`s
#[derive(Clone)]
pub struct PageIter {
    start: Page,
    end: Page,
}

impl Iterator for PageIter {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        if self.start <= self.end {
            let page = self.start;
            self.start.0 += 1;
            Some(page)
        } else {
            None
        }
    }
}

/// An abstraction to the Active table, dereferences to the `Mapper` type.
pub struct ActivePageTable {
    mapper: Mapper,
}

impl Deref for ActivePageTable {
    type Target = Mapper;

    fn deref(&self) -> &Mapper {
        &self.mapper
    }
}

impl DerefMut for ActivePageTable {
    fn deref_mut(&mut self) -> &mut Mapper {
        &mut self.mapper
    }
}

impl ActivePageTable {
    /// Creates a new `ActivePageTable`.
    ///
    /// # Safety
    /// The page table must be recursively mapped, if it is not any methods using
    /// the active page table will most likely produce undefined behaviour.
    pub const unsafe fn new() -> ActivePageTable {
        ActivePageTable { mapper: Mapper::new() }
    }

    /// Temporarily change the recursive mapping to the given table
    /// and execute the given closure in the new context.
    /// By return the table's state is restored.
    pub fn with<F>(&mut self,
                   table: &mut InactivePageTable,
                   temporary_page: &mut TemporaryPage,
                   f: F)
        where F: FnOnce(&mut Mapper)
    {
        use x86_64::registers::control_regs;
        use x86_64::instructions::tlb;

        {
            // Save table
            let backup = Frame::containing_address(control_regs::cr3().0 as usize);

            // Map temporary_page to the current table
            let p4_table = temporary_page.map_table_frame(backup.clone(), self);

            // Overwrite recursive mapping
            self.p4_mut()[510].set(table.p4_frame.clone(), PRESENT | WRITABLE);
            tlb::flush_all();

            // Execute the closure in the new context
            f(self);

            // Restore recursive mapping
            p4_table[510].set(backup, PRESENT | WRITABLE);
            tlb::flush_all();
        }

        temporary_page.unmap(self);
        temporary_page.allocator.flush(|_| {});
    }

    /// Activates the `InactivePageTable` given.
    /// Returns the previous ActivePageTable
    pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
        use x86_64::PhysicalAddress;
        use x86_64::registers::control_regs;

        let old_table = InactivePageTable {
            p4_frame: Frame::containing_address(control_regs::cr3().0 as usize),
        };

        unsafe {
            control_regs::cr3_write(PhysicalAddress(new_table.p4_frame.start_address() as u64));
        }
        old_table
    }
}

/// A level 4 table that is not yet used
pub struct InactivePageTable {
    p4_frame: Frame,
}

impl InactivePageTable {
    /// Creates a new `InactivePageTable`
    ///
    /// The `frame` is consumed and used to hold the inactive level 4 table. The table
    /// that is returned has recursive mapping, so activating it is safe.
    pub fn new(frame: Frame,
               active_table: &mut ActivePageTable,
               temporary_page: &mut TemporaryPage)
               -> InactivePageTable {
        {
            let table = temporary_page.map_table_frame(frame.clone(), active_table);
            // Now that it's mapped we can zero it
            table.zero();
            // Now set up recursive mapping for the table
            table[510].set(frame.clone(), PRESENT | WRITABLE);
        }

        temporary_page.unmap(active_table);
        // At this point, the p4 table still remains in the allocator, flush it
        // to make sure that the `InactivePageTable` is the only owner
        temporary_page.allocator.flush(|_| {});

        InactivePageTable { p4_frame: frame }
    }
}

/// Remaps the kernel using the given `ActivePageTable`
///
/// Each kernel section is mapped to the higher half with the correct permissions.
/// This function also identity maps the VGA text buffer and maps the multiboot2
/// information structure to the higher half.
pub fn remap_the_kernel<FA>(active_table: &mut ActivePageTable,
                            mut allocator: FA,
                            boot_info: &BootInformation) -> FrameBitmap
    where FA: FrameAllocate
{
    use memory::KERNEL_BASE;

    // Create new inactive table using a temporary page
    let mut temporary_page =
        TemporaryPage::new(Page(0xdeadbeef), &mut allocator);
    let mut new_table = {
        let frame = allocator.allocate_frame()
            .expect("No more frames");
        InactivePageTable::new(frame, &mut ACTIVE_TABLE.lock(), &mut temporary_page)
    };

    active_table.with(&mut new_table, &mut temporary_page, |mapper| {

        let elf_sections_tag = boot_info.elf_sections_tag()
            .expect("Memory map tag required");

        let string_table = unsafe {
            &*((elf_sections_tag.string_table() as *const StringTable).offset(KERNEL_BASE as isize))
        };

        // Map the allocated kernel sections to the higher half
        for section in elf_sections_tag.sections() {
            if !section.is_allocated() {
                // Section is not loaded to memory
                continue;
            }
            if string_table.section_name(&section) == ".init" {
                // We do not map the init section because it is not
                // used after boot
                continue;
            }
            assert!(section.addr as usize % PAGE_SIZE == 0,
                    "Section needs to be page aligned");

            let flags = EntryFlags::from_elf_section_flags(section);

            let start_frame = Frame::containing_address(section.start_address() - KERNEL_BASE);
            let end_frame = Frame::containing_address((section.end_address() - KERNEL_BASE) - 2);

            for frame in Frame::range_inclusive(start_frame, end_frame) {
                let new_page = Page::containing_address(frame.start_address() + KERNEL_BASE);
                mapper.map_to(new_page, frame, flags, &mut allocator).expect("Unable to map elf section frame");
            }
        }

        // Identity map the VGA buffer
        let vga_buffer = Frame::containing_address(0xb8000);
        mapper.identity_map(vga_buffer, WRITABLE, &mut allocator);

        // Map the multiboot info structure to the higher half
        let multiboot_start = Frame::containing_address(boot_info.start_address() - KERNEL_BASE);
        let multiboot_end = Frame::containing_address((boot_info.end_address() - KERNEL_BASE) - 1);

        for frame in Frame::range_inclusive(multiboot_start, multiboot_end) {
            let new_page = Page::containing_address(frame.start_address() + KERNEL_BASE);
            // if we have already mapped this page, it must have been
            // already mapped when we mapped the elf sections.
            let _ = mapper.map_to(new_page, frame, PRESENT, &mut allocator);
        }
    });
    let old_table = active_table.switch(new_table);
    println!("New page table loaded");

    // Now, we're done allocating and need a struct with FrameDeallocate. Init
    // the FrameBitmap
    let mut frame_bitmap = FrameBitmap::new(allocator, active_table);

    temporary_page.consume(&mut frame_bitmap);

    // Use the previous table as a guard page for the kernel stack
    let old_p4_page = Page::containing_address(old_table.p4_frame.start_address() + KERNEL_BASE);
    active_table.unmap(old_p4_page, &mut frame_bitmap);

    println!("New guard page at {:#x}", old_p4_page.start_address());

    frame_bitmap
}

//pub fn test_paging<A>(page_table: &mut ActivePageTable, allocator: &mut A)
//    where A: FrameAllocator
//{
//    // Address 0 is mapped
//    println!("Some = {:?}", page_table.translate(0));
//    // Second P1 entry
//    println!("Some = {:?}", page_table.translate(4096));
//    // Second P2 entry
//    println!("Some = {:?}", page_table.translate(4096 * 512));
//    // 300th P2 entry
//    println!("Some = {:?}", page_table.translate(4096 * 512 * 300));
//    // Second P3 entry
//    println!("None = {:?}", page_table.translate(4096 * 512 * 512));
//    // Last entry
//    println!("Some = {:?}", page_table.translate(4096 * 512 * 512 - 1));
//
//    // Test map_to
//    let addr = 4096 * 512 * 512 * 12; // 12th p3 entry
//    let page = Page::containing_address(addr);
//    let frame = allocator.allocate_frame()
//        .expect("No more frames :(");
//    println!("None = {:?}, map to {:?}",
//             page_table.translate(addr),
//             frame);
//    map_to(page, frame, EntryFlags::empty(), allocator);
//    println!("Some = {:?}", page_table.translate(addr));
//    println!("Next free frame: {:?}", allocator.allocate_frame());
//
//    // Test unmap
//    unmap(Page::containing_address(addr), allocator);
//    println!("None = {:?}", page_table.translate(addr));
//}
<commit_msg>Rewrite test_paging to use tap<commit_after>// Copyright 2016 Phillip Oppermann, Calvin Lee and JJ Garzella.
// See the README.md file at the top-level directory of this
// distribution.
//
// Licensed under the MIT license <LICENSE or
// http://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed
// except according to those terms.

use core::ops::{Deref, DerefMut};
use core::ops::Add;

use multiboot2::{BootInformation, StringTable};
use spin::Mutex;

pub use self::entry::*;
pub use self::mapper::Mapper;
pub use self::temporary_page::{TemporaryPage, TinyAllocator};
use memory::{PAGE_SIZE, Frame, FrameAllocate};
use memory::{MemoryController, MEMORY_CONTROLLER};

use memory::frame_bitmap::FrameBitmap;

/// An entry in the page table.
mod entry;
/// Abstraction of the page table.
mod table;
/// A page to temporarily map a frame.
mod temporary_page;
/// An interface to the active page table.
mod mapper;

/// How many entries are in each table.
const ENTRY_COUNT: usize = 512;

/// This is the _only_ ActivePageTable that should be used in the system. Any others
/// would violate the assumptions of `Unique`.
pub static ACTIVE_TABLE: Mutex<ActivePageTable> = Mutex::new(unsafe {
    ActivePageTable::new()
});

// TODO FIXME Make conversions between the PhysicalAddress and VirtualAddress types
// unsafe. All addresses in this module have to be explicitly physical or virtual.
//
// Possibly make physical and virtual traits and apply them to numbers, pointers,
// etc.?
/// A _physical_ address on the machine. *_These should only be known to the kernel_*.
/// The userspace should never recieve a physical addresss.
pub type PhysicalAddress = usize;
/// A _virtual_ address on the machine. _All_ pointers are of this type. It is
/// undefined behaviour to convert a virtual to a physical address except through
/// the specific page table methods.
pub type VirtualAddress = usize;

/// A representation of a virtual page.
#[derive(Debug, Copy, Clone)]
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Page(usize);

impl Page {
    /// Returns the first address in the `Page`
    pub fn start_address(&self) -> VirtualAddress {
        self.0 * PAGE_SIZE
    }

    /// Returns a `Page` containing the VirtualAddress given
    ///
    /// # Panics
    /// A panic will occur if the address is not canonical. For the address
    /// to be canonical the first 48 bits must be sign extended.
    pub fn containing_address(address: VirtualAddress) -> Page {
        // Address must be canonical
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
                "invalid address: 0x{:x}",
                address);
        Page(address / PAGE_SIZE)
    }

    /// Returns `Page`'s index into the p4 table.
    ///
    /// The value must be from 0 to `ENTRY_COUNT`
    fn p4_index(&self) -> usize {
        (self.0 >> 27) & 0o777
    }

    /// Returns `Page`'s index into the p3 table.
    ///
    /// The value must be from 0 to `ENTRY_COUNT`
    fn p3_index(&self) -> usize {
        (self.0 >> 18) & 0o777
    }

    /// Returns `Page`'s index into the p2 table.
    ///
    /// The value must be from 0 to `ENTRY_COUNT`
    fn p2_index(&self) -> usize {
        (self.0 >> 9) & 0o777
    }

    /// Returns `Page`'s index into the p1 table.
    ///
    /// The value must be from 0 to `ENTRY_COUNT`
    fn p1_index(&self) -> usize {
        (self.0 >> 0) & 0o777
    }

    /// Returns a `Page` iterator from `start` to `end`.
    pub fn range_inclusive(start: Page, end: Page) -> PageIter {
        PageIter {
            start: start,
            end: end,
        }
    }

    /// Map this `Page` to the given `Frame`
    pub fn map_to(self, frame: Frame, flags: EntryFlags) {
        let mut lock = MEMORY_CONTROLLER.lock();
        let &mut MemoryController {
            ref mut active_table,
            ref mut frame_allocator,
            stack_allocator: _,
        } = lock.as_mut().unwrap();
        active_table.map_to(self, frame, flags, frame_allocator).expect("Unable to map frame because page is already taken");
    }

    /// Map this `Page` to any availible `Frame`.
    ///
    /// # Panics
    /// Panics if OOM
    pub fn map(self, flags: EntryFlags) {
        let mut lock = MEMORY_CONTROLLER.lock();
        let &mut MemoryController {
            ref mut active_table,
            ref mut frame_allocator,
            stack_allocator: _,
        } = lock.as_mut().unwrap();
        active_table.map(self, flags, frame_allocator);

    }

    /// Unmap this `Page`
    pub fn unmap(self) {
        let mut lock = MEMORY_CONTROLLER.lock();
        let &mut MemoryController {
            ref mut active_table,
            ref mut frame_allocator,
            stack_allocator: _,
        } = lock.as_mut().unwrap();

        active_table.unmap(self, frame_allocator);
    }
}

impl Add<usize> for Page {
    type Output = Page;

    fn add(self, rhs: usize) -> Page {
        Page(self.0 + rhs)
    }
}

/// Identity map the given `Frame`
fn identity_map(frame: Frame, flags: EntryFlags) {
        let page = Page::containing_address(frame.start_address());
        page.map_to(frame, flags);
}

/// An iterator across `Page`s
#[derive(Clone)]
pub struct PageIter {
    start: Page,
    end: Page,
}

impl Iterator for PageIter {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        if self.start <= self.end {
            let page = self.start;
            self.start.0 += 1;
            Some(page)
        } else {
            None
        }
    }
}

/// An abstraction to the Active table, dereferences to the `Mapper` type.
pub struct ActivePageTable {
    mapper: Mapper,
}

impl Deref for ActivePageTable {
    type Target = Mapper;

    fn deref(&self) -> &Mapper {
        &self.mapper
    }
}

impl DerefMut for ActivePageTable {
    fn deref_mut(&mut self) -> &mut Mapper {
        &mut self.mapper
    }
}

impl ActivePageTable {
    /// Creates a new `ActivePageTable`.
    ///
    /// # Safety
    /// The page table must be recursively mapped, if it is not any methods using
    /// the active page table will most likely produce undefined behaviour.
    pub const unsafe fn new() -> ActivePageTable {
        ActivePageTable { mapper: Mapper::new() }
    }

    /// Temporarily change the recursive mapping to the given table
    /// and execute the given closure in the new context.
    /// By return the table's state is restored.
    pub fn with<F>(&mut self,
                   table: &mut InactivePageTable,
                   temporary_page: &mut TemporaryPage,
                   f: F)
        where F: FnOnce(&mut Mapper)
    {
        use x86_64::registers::control_regs;
        use x86_64::instructions::tlb;

        {
            // Save table
            let backup = Frame::containing_address(control_regs::cr3().0 as usize);

            // Map temporary_page to the current table
            let p4_table = temporary_page.map_table_frame(backup.clone(), self);

            // Overwrite recursive mapping
            self.p4_mut()[510].set(table.p4_frame.clone(), PRESENT | WRITABLE);
            tlb::flush_all();

            // Execute the closure in the new context
            f(self);

            // Restore recursive mapping
            p4_table[510].set(backup, PRESENT | WRITABLE);
            tlb::flush_all();
        }

        temporary_page.unmap(self);
        temporary_page.allocator.flush(|_| {});
    }

    /// Activates the `InactivePageTable` given.
    /// Returns the previous ActivePageTable
    pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
        use x86_64::PhysicalAddress;
        use x86_64::registers::control_regs;

        let old_table = InactivePageTable {
            p4_frame: Frame::containing_address(control_regs::cr3().0 as usize),
        };

        unsafe {
            control_regs::cr3_write(PhysicalAddress(new_table.p4_frame.start_address() as u64));
        }
        old_table
    }
}

/// A level 4 table that is not yet used
pub struct InactivePageTable {
    p4_frame: Frame,
}

impl InactivePageTable {
    /// Creates a new `InactivePageTable`
    ///
    /// The `frame` is consumed and used to hold the inactive level 4 table. The table
    /// that is returned has recursive mapping, so activating it is safe.
    pub fn new(frame: Frame,
               active_table: &mut ActivePageTable,
               temporary_page: &mut TemporaryPage)
               -> InactivePageTable {
        {
            let table = temporary_page.map_table_frame(frame.clone(), active_table);
            // Now that it's mapped we can zero it
            table.zero();
            // Now set up recursive mapping for the table
            table[510].set(frame.clone(), PRESENT | WRITABLE);
        }

        temporary_page.unmap(active_table);
        // At this point, the p4 table still remains in the allocator, flush it
        // to make sure that the `InactivePageTable` is the only owner
        temporary_page.allocator.flush(|_| {});

        InactivePageTable { p4_frame: frame }
    }
}

/// Remaps the kernel using the given `ActivePageTable`
///
/// Each kernel section is mapped to the higher half with the correct permissions.
/// This function also identity maps the VGA text buffer and maps the multiboot2
/// information structure to the higher half.
pub fn remap_the_kernel<FA>(active_table: &mut ActivePageTable,
                            mut allocator: FA,
                            boot_info: &BootInformation) -> FrameBitmap
    where FA: FrameAllocate
{
    use memory::KERNEL_BASE;

    // Create new inactive table using a temporary page
    let mut temporary_page =
        TemporaryPage::new(Page(0xdeadbeef), &mut allocator);
    let mut new_table = {
        let frame = allocator.allocate_frame()
            .expect("No more frames");
        InactivePageTable::new(frame, &mut ACTIVE_TABLE.lock(), &mut temporary_page)
    };

    active_table.with(&mut new_table, &mut temporary_page, |mapper| {

        let elf_sections_tag = boot_info.elf_sections_tag()
            .expect("Memory map tag required");

        let string_table = unsafe {
            &*((elf_sections_tag.string_table() as *const StringTable).offset(KERNEL_BASE as isize))
        };

        // Map the allocated kernel sections to the higher half
        for section in elf_sections_tag.sections() {
            if !section.is_allocated() {
                // Section is not loaded to memory
                continue;
            }
            if string_table.section_name(&section) == ".init" {
                // We do not map the init section because it is not
                // used after boot
                continue;
            }
            assert!(section.addr as usize % PAGE_SIZE == 0,
                    "Section needs to be page aligned");

            let flags = EntryFlags::from_elf_section_flags(section);

            let start_frame = Frame::containing_address(section.start_address() - KERNEL_BASE);
            let end_frame = Frame::containing_address((section.end_address() - KERNEL_BASE) - 2);

            for frame in Frame::range_inclusive(start_frame, end_frame) {
                let new_page = Page::containing_address(frame.start_address() + KERNEL_BASE);
                mapper.map_to(new_page, frame, flags, &mut allocator).expect("Unable to map elf section frame");
            }
        }

        // Identity map the VGA buffer
        let vga_buffer = Frame::containing_address(0xb8000);
        mapper.identity_map(vga_buffer, WRITABLE, &mut allocator);

        // Map the multiboot info structure to the higher half
        let multiboot_start = Frame::containing_address(boot_info.start_address() - KERNEL_BASE);
        let multiboot_end = Frame::containing_address((boot_info.end_address() - KERNEL_BASE) - 1);

        for frame in Frame::range_inclusive(multiboot_start, multiboot_end) {
            let new_page = Page::containing_address(frame.start_address() + KERNEL_BASE);
            // if we have already mapped this page, it must have been
            // already mapped when we mapped the elf sections.
            let _ = mapper.map_to(new_page, frame, PRESENT, &mut allocator);
        }
    });
    let old_table = active_table.switch(new_table);
    println!("New page table loaded");

    // Now, we're done allocating and need a struct with FrameDeallocate. Init
    // the FrameBitmap
    let mut frame_bitmap = FrameBitmap::new(allocator, active_table);

    temporary_page.consume(&mut frame_bitmap);

    // Use the previous table as a guard page for the kernel stack
    let old_p4_page = Page::containing_address(old_table.p4_frame.start_address() + KERNEL_BASE);
    active_table.unmap(old_p4_page, &mut frame_bitmap);

    println!("New guard page at {:#x}", old_p4_page.start_address());

    frame_bitmap
}

use memory::FrameDeallocate;

pub fn test_paging<A>(page_table: &mut ActivePageTable, allocator: &mut A)
    where A: FrameAllocate + FrameDeallocate
{
    use super::super::tap::TAPTestGroup;
    let mut tap = TAPTestGroup::new();

    // Address 0 is mapped
    tap.assert_tap(page_table.mapper.translate(0).is_some(),
                   "Address 0 not mapped");
    // Second P1 entry
    tap.assert_tap(page_table.mapper.translate(4096).is_some(),
                   "Failed to translate second P1 entry");
    // Second P2 entry
    tap.assert_tap(page_table.mapper.translate(4096 * 512).is_some(),
                   "Failed to translate second P2 entry");
    // 300th P2 entry
    tap.assert_tap(page_table.mapper.translate(4096 * 512 * 300).is_some(),
                   "Failed to translate 300th P2 entry");
    // Second P3 entry
    tap.assert_tap(page_table.mapper.translate(4096 * 512 * 512).is_none(),
                   "Should not have been able to translate second P3 entry");
    // Last entry
    tap.assert_tap(page_table.mapper.translate(4096 * 512 * 512 - 1).is_some(),
                   "Failed to translate last entry");

    // Test map_to
    let addr = 4096 * 512 * 512 * 12; // 12th p3 entry
    let page = Page::containing_address(addr);
    let frame = allocator.allocate_frame()
        .expect("No more frames :(");
    tap.assert_tap(page_table.mapper.translate(addr).is_none(),
             "Test page (12th P3), was unexpecteldly already mapped");
    page_table.map_to(page, frame, EntryFlags::empty(), allocator);
    tap.assert_tap(page_table.mapper.translate(addr).is_some(),
                   "Unable to successfully use map_to() to map 12th P3 entry");
    //println!("Next free frame: {:?}", allocator.allocate_frame());

    // Test unmap
    page_table.unmap(Page::containing_address(addr), allocator);
    tap.assert_tap(page_table.mapper.translate(addr).is_none(),
                   "Did non successfully unmap test page (12th P3)");
}
<|endoftext|>


<commit_before>pub use self::entry::*;
use memory::{PAGE_SIZE, Frame, FrameAllocator};
use self::table::{Table, Level4};
use core::ptr::Unique;

mod entry;
mod table;

const ENTRY_COUNT: usize = 512;

pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;

pub struct Page {
    number: usize,
}

impl Page {
    fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
                "invalid address: 0x{:x}",
                address);
        Page { number: address / PAGE_SIZE }
    }

    fn start_address(&self) -> usize {
        self.number * PAGE_SIZE
    }

    fn p4_index(&self) -> usize {
        (self.number >> 27) & 0o777
    }
    fn p3_index(&self) -> usize {
        (self.number >> 18) & 0o777
    }
    fn p2_index(&self) -> usize {
        (self.number >> 9) & 0o777
    }
    fn p1_index(&self) -> usize {
        (self.number >> 0) & 0o777
    }
}

pub struct RecursivePageTable {
    p4: Unique<Table<Level4>>,
}

impl RecursivePageTable {
    pub unsafe fn new() -> RecursivePageTable {
        RecursivePageTable { p4: Unique::new(table::P4) }
    }

    fn p4(&self) -> &Table<Level4> {
        unsafe { self.p4.get() }
    }

    fn p4_mut(&mut self) -> &mut Table<Level4> {
        unsafe { self.p4.get_mut() }
    }
}

pub unsafe fn translate(virtual_address: VirtualAddress) -> Option<PhysicalAddress> {
    let offset = virtual_address % PAGE_SIZE;
    translate_page(Page::containing_address(virtual_address))
        .map(|frame| frame.number * PAGE_SIZE + offset)
}

unsafe fn translate_page(page: Page) -> Option<Frame> {

    let p3 = unsafe { &*table::P4 }.next_table(page.p4_index());

    let huge_page = || {
        p3.and_then(|p3| {
            let p3_entry = &p3[page.p3_index()];
            // 1GiB page?
            if let Some(start_frame) = p3_entry.pointed_frame() {
                if p3_entry.flags().contains(HUGE_PAGE) {
                    // address must be 1GiB aligned
                    assert!(start_frame.number % (ENTRY_COUNT * ENTRY_COUNT) == 0);
                    return Some(Frame {
                        number: start_frame.number + page.p2_index() * ENTRY_COUNT +
                                page.p1_index(),
                    });
                }
            }
            if let Some(p2) = p3.next_table(page.p3_index()) {
                let p2_entry = &p2[page.p2_index()];
                // 2MiB page?
                if let Some(start_frame) = p2_entry.pointed_frame() {
                    if p2_entry.flags().contains(HUGE_PAGE) {
                        // address must be 2MiB aligned
                        assert!(start_frame.number % ENTRY_COUNT == 0);
                        return Some(Frame { number: start_frame.number + page.p1_index() });
                    }
                }
            }
            None
        })
    };

    p3.and_then(|p3| p3.next_table(page.p3_index()))
      .and_then(|p2| p2.next_table(page.p2_index()))
      .and_then(|p1| p1[page.p1_index()].pointed_frame())
      .or_else(huge_page)
}

pub unsafe fn map_to<A>(page: Page, frame: Frame, flags: EntryFlags, allocator: &mut A)
    where A: FrameAllocator
{
    let p4 = unsafe { &mut *table::P4 };
    let mut p3 = p4.next_table_create(page.p4_index(), allocator);
    let mut p2 = p3.next_table_create(page.p3_index(), allocator);
    let mut p1 = p2.next_table_create(page.p2_index(), allocator);

    assert!(p1[page.p1_index()].is_unused());
    p1[page.p1_index()].set(frame, flags | PRESENT);
}
<commit_msg>Make translate and map_to safe by making them RecursivePageTable methods<commit_after>pub use self::entry::*;
use memory::{PAGE_SIZE, Frame, FrameAllocator};
use self::table::{Table, Level4};
use core::ptr::Unique;

mod entry;
mod table;

const ENTRY_COUNT: usize = 512;

pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;

pub struct Page {
    number: usize,
}

impl Page {
    fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
                "invalid address: 0x{:x}",
                address);
        Page { number: address / PAGE_SIZE }
    }

    fn start_address(&self) -> usize {
        self.number * PAGE_SIZE
    }

    fn p4_index(&self) -> usize {
        (self.number >> 27) & 0o777
    }
    fn p3_index(&self) -> usize {
        (self.number >> 18) & 0o777
    }
    fn p2_index(&self) -> usize {
        (self.number >> 9) & 0o777
    }
    fn p1_index(&self) -> usize {
        (self.number >> 0) & 0o777
    }
}

pub struct RecursivePageTable {
    p4: Unique<Table<Level4>>,
}

impl RecursivePageTable {
    pub unsafe fn new() -> RecursivePageTable {
        RecursivePageTable { p4: Unique::new(table::P4) }
    }

    fn p4(&self) -> &Table<Level4> {
        unsafe { self.p4.get() }
    }

    fn p4_mut(&mut self) -> &mut Table<Level4> {
        unsafe { self.p4.get_mut() }
    }

    pub fn translate(&self, virtual_address: VirtualAddress) -> Option<PhysicalAddress> {
        let offset = virtual_address % PAGE_SIZE;
        self.translate_page(Page::containing_address(virtual_address))
            .map(|frame| frame.number * PAGE_SIZE + offset)
    }

    fn translate_page(&self, page: Page) -> Option<Frame> {
        let p3 = self.p4().next_table(page.p4_index());

        let huge_page = || {
            p3.and_then(|p3| {
                let p3_entry = &p3[page.p3_index()];
                // 1GiB page?
                if let Some(start_frame) = p3_entry.pointed_frame() {
                    if p3_entry.flags().contains(HUGE_PAGE) {
                        // address must be 1GiB aligned
                        assert!(start_frame.number % (ENTRY_COUNT * ENTRY_COUNT) == 0);
                        return Some(Frame {
                            number: start_frame.number + page.p2_index() * ENTRY_COUNT +
                                    page.p1_index(),
                        });
                    }
                }
                if let Some(p2) = p3.next_table(page.p3_index()) {
                    let p2_entry = &p2[page.p2_index()];
                    // 2MiB page?
                    if let Some(start_frame) = p2_entry.pointed_frame() {
                        if p2_entry.flags().contains(HUGE_PAGE) {
                            // address must be 2MiB aligned
                            assert!(start_frame.number % ENTRY_COUNT == 0);
                            return Some(Frame { number: start_frame.number + page.p1_index() });
                        }
                    }
                }
                None
            })
        };

        p3.and_then(|p3| p3.next_table(page.p3_index()))
          .and_then(|p2| p2.next_table(page.p2_index()))
          .and_then(|p1| p1[page.p1_index()].pointed_frame())
          .or_else(huge_page)
    }

    pub fn map_to<A>(&mut self, page: Page, frame: Frame, flags: EntryFlags, allocator: &mut A)
        where A: FrameAllocator
    {
        let mut p3 = self.p4_mut().next_table_create(page.p4_index(), allocator);
        let mut p2 = p3.next_table_create(page.p3_index(), allocator);
        let mut p1 = p2.next_table_create(page.p2_index(), allocator);

        assert!(p1[page.p1_index()].is_unused());
        p1[page.p1_index()].set(frame, flags | PRESENT);
    }
}
<|endoftext|>


<commit_before>use prometheus::{Registry, Gauge, Encoder, TextEncoder};

use super::*;
pub struct PrometheusRenderer {
    pub buffer: Vec<u8>,
    registry: prometheus::Registry,
    encoder: prometheus::TextEncoder,
    count: prometheus::Gauge,
}

impl PrometheusRenderer {
    pub fn new() -> PrometheusRenderer {
        let registry = prometheus::Registry::new();

        let count = prometheus::Gauge::new("request_count", "The number of responses observed")
            .unwrap();

        registry.register(Box::new(count.clone()));

        PrometheusRenderer {
            registry: registry,
            buffer: Vec::new(),
            encoder: prometheus::TextEncoder::new(),
            count: count,
        }
    }
}

impl Renderer for PrometheusRenderer {
    fn render(&mut self, result: analyzer::RequestLogAnalyzerResult) {
        self.count.set(result.count as f64);

        let metric_familys = self.registry.gather();

        self.encoder.encode(&metric_familys, &mut self.buffer);
    }
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::prelude::*;
    use std::str;

    use super::*;

    struct MockBuffer {
        write_calls: Vec<String>,
    }

    impl Write for MockBuffer {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            self.write_calls.push(str::from_utf8(buf).unwrap().to_string());
            Ok(buf.len())
        }

        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    fn get_result_fixture() -> analyzer::RequestLogAnalyzerResult {
        analyzer::RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        }
    }

    #[test]
    fn test_instantiation() {
        let renderer = PrometheusRenderer::new();
    }

    #[test]
    fn test_render() {
        let result = get_result_fixture();

        let mut renderer = PrometheusRenderer::new();

        renderer.render(result);

        let buffer_text = str::from_utf8(&renderer.buffer).unwrap();
        assert!(buffer_text.contains("request_count 3"))
    }
}
<commit_msg>Render all Result fields<commit_after>use prometheus::{Registry, Gauge, Encoder, TextEncoder};
use std::collections::HashMap;

use super::*;
pub struct PrometheusRenderer {
    pub buffer: Vec<u8>,
    registry: prometheus::Registry,
    encoder: prometheus::TextEncoder,
    count: prometheus::Gauge,
    max: prometheus::Gauge,
    min: prometheus::Gauge,
    avg: prometheus::Gauge,
    median: prometheus::Gauge,
    percentile90: prometheus::Gauge,
}

impl PrometheusRenderer {
    pub fn new() -> PrometheusRenderer {
        let registry = prometheus::Registry::new();

        let gauge_names =
            vec!["count", "time_max", "time_min", "time_avg", "time_median", "time_percentile90"];
        let mut gauges = HashMap::new();

        for gauge_name in gauge_names {
            let gauge_name = format!("request_{}", gauge_name);
            let gauge = prometheus::Gauge::new(gauge_name.clone(),
                                               format!("The {} of response times.", gauge_name))
                .unwrap();
            registry.register(Box::new(gauge.clone()));
            gauges.insert(gauge_name, gauge);
        }

        PrometheusRenderer {
            registry: registry,
            buffer: Vec::new(),
            encoder: prometheus::TextEncoder::new(),
            count: gauges.remove("request_count").unwrap(),
            max: gauges.remove("request_time_max").unwrap(),
            min: gauges.remove("request_time_min").unwrap(),
            avg: gauges.remove("request_time_avg").unwrap(),
            median: gauges.remove("request_time_median").unwrap(),
            percentile90: gauges.remove("request_time_percentile90").unwrap(),
        }
    }
}

impl Renderer for PrometheusRenderer {
    fn render(&mut self, result: analyzer::RequestLogAnalyzerResult) {
        self.count.set(result.count as f64);
        self.max.set(result.max as f64);
        self.min.set(result.min as f64);
        self.avg.set(result.avg as f64);
        self.median.set(result.median as f64);
        self.percentile90.set(result.percentile90 as f64);

        let metric_familys = self.registry.gather();

        self.encoder.encode(&metric_familys, &mut self.buffer);
    }
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::prelude::*;
    use std::str;

    use super::*;

    struct MockBuffer {
        write_calls: Vec<String>,
    }

    impl Write for MockBuffer {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            self.write_calls.push(str::from_utf8(buf).unwrap().to_string());
            Ok(buf.len())
        }

        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    fn get_result_fixture() -> analyzer::RequestLogAnalyzerResult {
        analyzer::RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        }
    }

    #[test]
    fn test_instantiation() {
        let renderer = PrometheusRenderer::new();
    }

    #[test]
    fn test_render() {
        let result = get_result_fixture();

        let mut renderer = PrometheusRenderer::new();

        renderer.render(result);

        let buffer_text = str::from_utf8(&renderer.buffer).unwrap();
        assert!(buffer_text.contains("request_count 3"));
        assert!(buffer_text.contains("request_time_max 100"));
        assert!(buffer_text.contains("request_time_min 1"));
        assert!(buffer_text.contains("request_time_avg 37"));
        assert!(buffer_text.contains("request_time_median 10"));
        assert!(buffer_text.contains("request_time_percentile90 100"));
    }
}
<|endoftext|>


<commit_before>use clap::Arg;
use clap::App;
use clap::ArgMatches;
use autoconf;
use rusqlite::Connection;

pub fn cli_clap(number: &u32) -> ArgMatches {

    let application = App::new(autoconf::package())
        .about("Parses an input file to do awesome things")
        .version(autoconf::version_cli())
        .author("Owen Synge <osynge@googlemail.com>")
        .arg(
            Arg::with_name("verbose")
                .help("Increase log output.")
                .short("v")
                .multiple(true)
                .long("verbose"),
        )
        .arg(
            Arg::with_name("quiet")
                .help("Decrease log output.")
                .short("q")
                .multiple(true)
                .long("quiet"),
        )
        .arg(
            Arg::with_name("env")
                .short("e")
                .long("env")
                .value_name("ENVIROMENT_VARIABLE")
                .help("Which enviroment variables to process")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-jobs")
                .long("dir-jobs")
                .value_name("DIR_JOB")
                .help("directory storing json jobs.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-sh")
                .long("dir-sh")
                .value_name("DIR_SHELL")
                .help("directory storing jobs shell scripts.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-py")
                .long("dir-py")
                .value_name("DIR_PYTHON")
                .help("directory storing jobs python scripts.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("config")
                .short("c")
                .long("config")
                .value_name("FILE")
                .help("Sets a custom config file")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("TARGET")
                .help("Sets the provider to be selected.")
                .takes_value(true),
        )
        .arg(Arg::with_name("list-provides").long("list-provides").help(
            "list-provides",
        ))
        .arg(Arg::with_name("session").long("session").help("session"));
    let matches = application.get_matches();
    return matches;
}
<commit_msg>Add rdbms option<commit_after>use clap::Arg;
use clap::App;
use clap::ArgMatches;
use autoconf;

pub fn cli_clap(number: &u32) -> ArgMatches {

    let application = App::new(autoconf::package())
        .about("Parses an input file to do awesome things")
        .version(autoconf::version_cli())
        .author("Owen Synge <osynge@googlemail.com>")
        .arg(
            Arg::with_name("verbose")
                .help("Increase log output.")
                .short("v")
                .multiple(true)
                .long("verbose"),
        )
        .arg(
            Arg::with_name("quiet")
                .help("Decrease log output.")
                .short("q")
                .multiple(true)
                .long("quiet"),
        )
        .arg(
            Arg::with_name("rdbms")
                .long("rdbms")
                .value_name("FILE_RDBMS")
                .help("sqlite rdbms file.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("env")
                .short("e")
                .long("env")
                .value_name("ENVIROMENT_VARIABLE")
                .help("Which enviroment variables to process")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-jobs")
                .long("dir-jobs")
                .value_name("DIR_JOB")
                .help("directory storing json jobs.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-sh")
                .long("dir-sh")
                .value_name("DIR_SHELL")
                .help("directory storing jobs shell scripts.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-py")
                .long("dir-py")
                .value_name("DIR_PYTHON")
                .help("directory storing jobs python scripts.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("config")
                .short("c")
                .long("config")
                .value_name("FILE")
                .help("Sets a custom config file")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("TARGET")
                .help("Sets the provider to be selected.")
                .takes_value(true),
        )
        .arg(Arg::with_name("list-provides").long("list-provides").help(
            "list-provides",
        ))
        .arg(Arg::with_name("session").long("session").help("session"));
    let matches = application.get_matches();
    return matches;
}
<|endoftext|>


<commit_before>use actix::Recipient;
use euclid::{Point2D, Vector2D};
use serde_derive::{Deserialize, Serialize};
use uuid::Uuid;

use crate::server::MessageOut;

pub type ClientId = Uuid;
pub type PlayerId = Uuid;
pub type ArenaId = Uuid;

/// The euclidian space in which ArenaVectors and ArenaPoints operate.
pub struct ArenaSpace;
/// Represents a direction in the ArenaSpace
pub type ArenaVector = Vector2D<isize, ArenaSpace>;
/// Represents a position in the ArenaSpace
pub type ArenaPoint = Point2D<isize, ArenaSpace>;
/// Represents a line between two points in the ArenaSpace
pub struct Line(pub ArenaPoint, pub ArenaPoint);

#[derive(Debug)]
pub struct Client {
    pub id: ClientId,
    pub ip_address: Option<String>,
    pub address: Recipient<MessageOut>,
    pub player: Option<PlayerId>,
    pub arena: Option<ArenaId>,
    pub updates_sent_so_far: usize,
}

#[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
pub struct Player {
    #[serde(skip_deserializing)]
    pub id: PlayerId,
    pub name: String,
    pub color: PlayerColor,
}

impl Default for Player {
    fn default() -> Self {
        Self {
            id: Uuid::new_v4(),
            name: Default::default(),
            color: Default::default(),
        }
    }
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PlayerColor {
    Blue,
    Green,
    Orange,
    Purple,
    Red,
    White,
}

impl Default for PlayerColor {
    fn default() -> Self {
        PlayerColor::White
    }
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Direction {
    Up,
    Left,
    Right,
    Down,
}

impl Direction {
    pub fn as_velocity(self) -> ArenaVector {
        match self {
            Direction::Up => ArenaVector::new(0, 1),
            Direction::Down => ArenaVector::new(0, -1),
            Direction::Left => ArenaVector::new(-1, 0),
            Direction::Right => ArenaVector::new(1, 0),
        }
    }

    pub fn is_opposite(self, to: Direction) -> bool {
        match self {
            Direction::Up => to == Direction::Down,
            Direction::Left => to == Direction::Right,
            Direction::Right => to == Direction::Left,
            Direction::Down => to == Direction::Up,
        }
    }
}
<commit_msg>fixed deserialized players having zeroed-out player ids<commit_after>use actix::Recipient;
use euclid::{Point2D, Vector2D};
use serde_derive::{Deserialize, Serialize};
use uuid::Uuid;

use crate::server::MessageOut;

pub type ClientId = Uuid;
pub type PlayerId = Uuid;
pub type ArenaId = Uuid;

/// The euclidian space in which ArenaVectors and ArenaPoints operate.
pub struct ArenaSpace;
/// Represents a direction in the ArenaSpace
pub type ArenaVector = Vector2D<isize, ArenaSpace>;
/// Represents a position in the ArenaSpace
pub type ArenaPoint = Point2D<isize, ArenaSpace>;
/// Represents a line between two points in the ArenaSpace
pub struct Line(pub ArenaPoint, pub ArenaPoint);

#[derive(Debug)]
pub struct Client {
    pub id: ClientId,
    pub ip_address: Option<String>,
    pub address: Recipient<MessageOut>,
    pub player: Option<PlayerId>,
    pub arena: Option<ArenaId>,
    pub updates_sent_so_far: usize,
}

#[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize)]
pub struct Player {
    #[serde(skip_serializing, skip_deserializing, default = "PlayerId::new_v4")]
    pub id: PlayerId,
    pub name: String,
    pub color: PlayerColor,
}

impl Default for Player {
    fn default() -> Self {
        Self {
            id: Uuid::new_v4(),
            name: Default::default(),
            color: Default::default(),
        }
    }
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PlayerColor {
    Blue,
    Green,
    Orange,
    Purple,
    Red,
    White,
}

impl Default for PlayerColor {
    fn default() -> Self {
        PlayerColor::White
    }
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Direction {
    Up,
    Left,
    Right,
    Down,
}

impl Direction {
    pub fn as_velocity(self) -> ArenaVector {
        match self {
            Direction::Up => ArenaVector::new(0, 1),
            Direction::Down => ArenaVector::new(0, -1),
            Direction::Left => ArenaVector::new(-1, 0),
            Direction::Right => ArenaVector::new(1, 0),
        }
    }

    pub fn is_opposite(self, to: Direction) -> bool {
        match self {
            Direction::Up => to == Direction::Down,
            Direction::Left => to == Direction::Right,
            Direction::Right => to == Direction::Left,
            Direction::Down => to == Direction::Up,
        }
    }
}
<|endoftext|>


<commit_before>use std::vec;
use naulang::objectspace::primitives::{Object};

#[derive(Clone)]
pub struct Frame {
	stack: vec::Vec<Object>,
	stack_pointer: u32,
	previous_frame: Option<Box<Frame>>,
	access_link: Option<Box<Frame>>,
	pc: u32,
	locals: vec::Vec<Object>,
}

impl Frame {
	pub fn new(stack_size: u32, local_count: u32) -> Box<Frame> {
		let mut new_frame = Frame {
			stack: vec::Vec::new(),
			stack_pointer: 0,
			pc: 0,
			access_link: Option::None,
			previous_frame: Option::None,
			locals: vec::Vec::new()
		};

		for x in 0..local_count {
			new_frame.locals.push(Object::None);
		}

		return Box::new(new_frame);
	}

	pub fn pop(&mut self) -> Option<Object> {
		self.stack.pop()
	}

	pub fn set_local_at(&mut self, index: usize, object: Object) -> () {
		self.locals[index] = object;
	}

	pub fn get_local_at(&self, index: usize) -> Option<Object> {
		if index >= self.locals.len() || index < 0 {
			Option::None
		} else {
			Option::Some(self.locals[index].clone())
		}
	}
}

#[cfg(test)]
mod tests {
	use super::Frame;
	use naulang::objectspace::primitives::{Object,IntegerObject};

	#[test]
	fn test_set_get_local_at() {
		let mut frame = Frame::new(3, 1);
		let integer_object = IntegerObject::new(42);
		frame.set_local_at(0, Object::Integer(integer_object));
		let local = frame.get_local_at(0);

		let internal_value = match local {
			Some(object) => match object {
				Object::Integer(i_obj) => i_obj.get_value(),
				_ => 0,
			},
			None => 0
		};

		assert!(internal_value == 42);
	}
}
<commit_msg>Test push/pop off of stack frame<commit_after>use std::vec;
use naulang::objectspace::primitives::{Object};

#[derive(Clone)]
pub struct Frame {
	stack: vec::Vec<Object>,
	stack_pointer: u32,
	previous_frame: Option<Box<Frame>>,
	access_link: Option<Box<Frame>>,
	pc: u32,
	locals: vec::Vec<Object>,
}

impl Frame {
	pub fn new(stack_size: u32, local_count: u32) -> Box<Frame> {
		let mut new_frame = Frame {
			stack: vec::Vec::new(),
			stack_pointer: 0,
			pc: 0,
			access_link: Option::None,
			previous_frame: Option::None,
			locals: vec::Vec::new()
		};

		for x in 0..local_count {
			new_frame.locals.push(Object::None);
		}

		return Box::new(new_frame);
	}

	pub fn pop(&mut self) -> Option<Object> {
		self.stack.pop()
	}

	pub fn push(&mut self, object: Object) -> () {
		self.stack.push(object);
	}

	pub fn set_local_at(&mut self, index: usize, object: Object) -> () {
		self.locals[index] = object;
	}

	pub fn get_local_at(&self, index: usize) -> Option<Object> {
		if index >= self.locals.len() || index < 0 {
			Option::None
		} else {
			Option::Some(self.locals[index].clone())
		}
	}
}

#[cfg(test)]
mod tests {
	use super::Frame;
	use naulang::objectspace::primitives::{Object,IntegerObject};

	#[test]
	fn test_set_get_local_at() {
		let mut frame = Frame::new(3, 1);
		let integer_object = IntegerObject::new(42);
		frame.set_local_at(0, Object::Integer(integer_object));
		let local = frame.get_local_at(0);

		let internal_value = match local {
			Some(object) => match object {
				Object::Integer(i_obj) => i_obj.get_value(),
				_ => 0,
			},
			None => 0
		};

		assert!(internal_value == 42);
	}

	#[test]
	fn test_push_pop() {
		let mut frame = Frame::new(3, 1);
		let integer_object = IntegerObject::new(42);
		frame.push(Object::Integer(integer_object));
		let popped_object = frame.pop();

		let internal_value = match popped_object {
			Some(object) => match object {
				Object::Integer(i_obj) => i_obj.get_value(),
				_ => 0,
			},
			None => 0
		};

		assert!(internal_value == 42);

	}
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Naive implementation of area rectangle<commit_after>fn main() {
    let length = 50;
    let width = 30;

    println!(
        "Area of rectangle with length: {} and width: {} is equal to: {}",
        length, width, area(length, width)
    );
}

fn area(length: u32, width: u32) -> u32 {
    length * width
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: MIT

use std::collections::HashMap;
// use std::convert::TryFrom;

use clap::{Arg, App};

static DIRECTIONS : [(i64,i64); 8] = [
    (-1,-1), ( 0,-1), ( 1,-1),
    (-1, 0),          ( 1, 0),
    (-1, 1), ( 0, 1), ( 1, 1),
];

#[derive(Copy, Clone)]
pub struct BBox(i64,i64,i64,i64);// xmin, xmax, ymin, ymax
impl BBox {
    pub fn new() -> BBox {
        BBox(0,0,0,0)
    }

    #[inline]
    pub fn xmin(&self) -> i64 { self.0 }
    #[inline]
    pub fn xmax(&self) -> i64 { self.1 }
    #[inline]
    pub fn ymin(&self) -> i64 { self.2 }
    #[inline]
    pub fn ymax(&self) -> i64 { self.3 }

    #[inline]
    pub fn in_bounds(&self, x: i64, y: i64) -> bool {
        x >= self.0 && x <= self.1 && y >= self.2 && y <= self.3
    }

    #[inline]
    pub fn update(&mut self, x: i64, y: i64) {
        if x < self.0 { self.0 = x; }
        if x > self.1 { self.1 = x; }
        if y < self.2 { self.2 = y; }
        if y > self.3 { self.3 = y; }
    }
}
impl std::fmt::Display for BBox {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "BBox: {}, {}, {}, {}", self.0, self.1, self.2, self.3)
    }
}

#[derive(Clone)]
pub struct Floorplan {
    pub map: HashMap<(i64, i64), char>,
    pub bbox: BBox,
}
impl Floorplan {
    pub fn new() -> Floorplan {
        Floorplan { map: HashMap::new(), bbox: BBox::new() }
    }

    pub fn load(fname: &str) -> Floorplan {
        let mut plan = Floorplan::new();
        let contents = std::fs::read_to_string(fname)
            .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

        for (j, line) in contents.trim_end_matches('\n').split('\n').enumerate() {
            for (i, ch) in line.chars().enumerate() {
                if ch != '.' {
                    plan.insert((i as i64, j as i64), ch);
                }
                plan.bbox.update(i as i64, j as i64);
            }
        }
        return plan;
    }

    pub fn step1(&mut self) -> bool {
        let mut add = Vec::new();
        let mut rm  = Vec::new();

        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match (self.at(x, y), self.count_neighbors(x, y)) {
                    ('L', 0)           => { add.push((x,y)); },
                    ('#', n) if n >= 4 => {  rm.push((x,y)); },
                    _ => { },
                }
            }
        }

        if add.is_empty() && rm.is_empty() { return false; }

        for (i, j) in add { self.insert((i, j), '#'); }
        for (i, j) in rm  { self.insert((i, j), 'L'); }
        return true;
    }

    pub fn step2(&mut self) -> bool {
        let mut add = Vec::new();
        let mut rm  = Vec::new();

        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match (self.at(x, y), self.count_visible(x, y)) {
                    ('L', 0)           => { add.push((x,y)); },
                    ('#', n) if n >= 5 => {  rm.push((x,y)); },
                    _ => { },
                }
            }
        }

        if add.is_empty() && rm.is_empty() { return false; }

        for (i, j) in add { self.insert((i, j), '#'); }
        for (i, j) in rm  { self.insert((i, j), 'L'); }
        return true;
    }

    #[inline]
    pub fn count_neighbors(&self, x: i64, y: i64) -> u8 {
        let mut seated = 0;
        for (dx, dy) in DIRECTIONS.iter() {
            if '#' == self.at(x+dx, y+dy) { seated += 1; }
        }
        return seated;
    }

    #[inline]
    pub fn count_visible(&self, x: i64, y: i64) -> u8 {
        let mut seated = 0;
        for (dx, dy) in DIRECTIONS.iter() {
            let (mut x, mut y) = (x+dx, y+dy);
            while self.bbox.in_bounds(x, y) {
                match self.at(x, y) {
                    '#' => { seated += 1; break; },
                    'L' => { break; },
                    _   => { },
                }
                x += dx; y += dy;
            }
        }
        return seated;
    }

    #[inline]
    pub fn count(&self, ch: &char) -> u64 {
        let mut n = 0;
        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match self.map.get(&(x,y)) {
                    Some(x) if x == ch => { n += 1; },
                    _ => { },
                }
            }
        }
        return n;
    }

    #[inline]
    pub fn at(&self, x: i64, y: i64) -> char {
        match self.map.get(&(x,y)) {
            Some(x) => *x,
            None    => '.',
        }
    }
}
impl std::ops::Deref for Floorplan {
    type Target = HashMap<(i64, i64), char>;
    fn deref(&self) -> &Self::Target { &self.map }
}
impl std::ops::DerefMut for Floorplan {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.map }
}
impl std::fmt::Display for Floorplan {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                write!(f, "{}", self.at(x, y))?;
            }
            write!(f, "{}", "\n")?;
        }
        Ok(())
    }
}

fn main() {
    let matches = App::new("Advent of code 2020, Day 11 Solution")
        .arg(Arg::with_name("FILE").help("Input file to process").index(1))
        .get_matches();
    let fname = matches.value_of("FILE").unwrap_or("11.in");
    let mut plan = Floorplan::load(fname);
//     println!("{}", plan);
    while plan.step1() { }
    println!("Part 1: {} occupied seats", plan.count(&'#'));
//     println!("{}", plan);

    let mut plan = Floorplan::load(fname);
//     println!("{}", plan);
    while plan.step2() { }
    println!("Part 2: {} occupied seats", plan.count(&'#'));
//     println!("{}", plan);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test1() {
        let mut plan = Floorplan::load("11.in");
        while plan.step1() { }
        assert_eq!(plan.count(&'#'), 2476);
    }

    #[test]
    fn test2() {
        let mut plan = Floorplan::load("11.in");
        while plan.step2() { }
        assert_eq!(plan.count(&'#'), 2257);
    }
}

<commit_msg>Day 11, HashMap -> Vec for 500ms -> 67ms<commit_after>// SPDX-License-Identifier: MIT

use clap::{Arg, App};

static DIRECTIONS : [(i64,i64); 8] = [
    (-1,-1), ( 0,-1), ( 1,-1),
    (-1, 0),          ( 1, 0),
    (-1, 1), ( 0, 1), ( 1, 1),
];

#[derive(Clone)]
pub struct Floorplan {
    pub map: Vec<Vec<char>>,
}
impl Floorplan {
    pub fn new() -> Floorplan {
        Floorplan { map: Vec::new() }
    }

    pub fn load(fname: &str) -> Floorplan {
        let mut plan = Floorplan::new();
        let contents = std::fs::read_to_string(fname)
            .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

        for line in contents.trim_end_matches('\n').split('\n') {
            plan.map.push(line.chars().collect());
        }
        return plan;
    }

    pub fn step1(&mut self) -> bool {
        let mut add = Vec::new();
        let mut rm  = Vec::new();

        for y in 0..self.map.len() {
            for x in 0..self.map[y].len() {
                match (self.map[y][x], self.count_neighbors(x, y)) {
                    ('L', 0)           => { add.push((x,y)); },
                    ('#', n) if n >= 4 => {  rm.push((x,y)); },
                    _ => { },
                }
            }
        }

        if add.is_empty() && rm.is_empty() { return false; }

        for (i, j) in add { self.map[j][i] = '#'; }
        for (i, j) in rm  { self.map[j][i] = 'L'; }
        return true;
    }

    pub fn step2(&mut self) -> bool {
        let mut add = Vec::new();
        let mut rm  = Vec::new();

        for y in 0..self.map.len() {
            for x in 0..self.map[y].len() {
                match (self.map[y][x], self.count_visible(x, y)) {
                    ('L', 0)           => { add.push((x,y)); },
                    ('#', n) if n >= 5 => {  rm.push((x,y)); },
                    _ => { },
                }
            }
        }

        if add.is_empty() && rm.is_empty() { return false; }

        for (i, j) in add { self.map[j][i] = '#'; }
        for (i, j) in rm  { self.map[j][i] = 'L'; }
        return true;
    }

    #[inline]
    pub fn count_neighbors(&self, x: usize, y: usize) -> u8 {
        let mut seated = 0;
        for (dx, dy) in DIRECTIONS.iter() {
            let (x, y) = ((x as i64+dx) as usize, (y as i64+dy) as usize);
            if y < self.map.len() {
                let row = &self.map[y];
                if x < row.len() && '#' == row[x] { seated += 1; }
            }
        }
        return seated;
    }

    #[inline]
    pub fn count_visible(&self, x: usize, y: usize) -> u8 {
        let mut seated = 0;
        let ymax = self.map.len() as i64;
        let xmax = self.map[0].len() as i64;
        for (dx, dy) in DIRECTIONS.iter() {
            let (mut x, mut y) = (x as i64+dx, y as i64+dy);
            while x >= 0 && y >= 0 && x < xmax && y < ymax {
                match self.map[y as usize][x as usize] {
                    '#' => { seated += 1; break; },
                    'L' => { break; },
                    _   => { },
                }
                x += dx; y += dy;
            }
        }
        return seated;
    }

    #[inline]
    pub fn count(&self, ch: &char) -> u64 {
        let mut n = 0;
        for row in self.map.iter() {
            for c in row.iter() {
                if c == ch { n += 1; }
            }
        }
        return n;
    }
}
impl std::fmt::Display for Floorplan {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for row in self.map.iter() {
            for c in row.iter() {
                write!(f, "{}", c)?;
            }
            write!(f, "{}", "\n")?;
        }
        Ok(())
    }
}

fn main() {
    let matches = App::new("Advent of code 2020, Day 11 Solution")
        .arg(Arg::with_name("FILE").help("Input file to process").index(1))
        .get_matches();
    let fname = matches.value_of("FILE").unwrap_or("11.in");
    let mut plan = Floorplan::load(fname);
//     println!("{}", plan);
    while plan.step1() { }
    println!("Part 1: {} occupied seats", plan.count(&'#'));
//     println!("{}", plan);

    let mut plan = Floorplan::load(fname);
//     println!("{}", plan);
    while plan.step2() { }
    println!("Part 2: {} occupied seats", plan.count(&'#'));
//     println!("{}", plan);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test1() {
        let mut plan = Floorplan::load("11.in");
        while plan.step1() { }
        assert_eq!(plan.count(&'#'), 2476);
    }

    #[test]
    fn test2() {
        let mut plan = Floorplan::load("11.in");
        while plan.step2() { }
        assert_eq!(plan.count(&'#'), 2257);
    }
}
<|endoftext|>


<commit_before>//! Describes items defined or visible (ie, imported) in a certain scope.
//! This is shared between modules and blocks.

use hir_expand::name::Name;
use once_cell::sync::Lazy;
use rustc_hash::FxHashMap;

use crate::{
    per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId,
    TraitId,
};

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ItemScope {
    visible: FxHashMap<Name, PerNs>,
    defs: Vec<ModuleDefId>,
    impls: Vec<ImplId>,
    /// Macros visible in current module in legacy textual scope
    ///
    /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
    /// If it yields no result, then it turns to module scoped `macros`.
    /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
    /// and only normal scoped `macros` will be searched in.
    ///
    /// Note that this automatically inherit macros defined textually before the definition of module itself.
    ///
    /// Module scoped macros will be inserted into `items` instead of here.
    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
    // be all resolved to the last one defined if shadowing happens.
    legacy_macros: FxHashMap<Name, MacroDefId>,
}

pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
    BuiltinType::ALL
        .iter()
        .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
        .collect()
});

/// Shadow mode for builtin type which can be shadowed by module.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum BuiltinShadowMode {
    /// Prefer user-defined modules (or other types) over builtins.
    Module,
    /// Prefer builtins over user-defined modules (but not other types).
    Other,
}

/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ItemScope {
    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
        //FIXME: shadowing
        self.visible.iter().map(|(n, def)| (n, *def))
    }

    pub fn entries_without_primitives<'a>(
        &'a self,
    ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
        self.visible.iter().map(|(n, def)| (n, *def))
    }

    pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
        self.defs.iter().copied()
    }

    pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
        self.impls.iter().copied()
    }

    pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> {
        self.name_of(ItemInNs::Types(def))
            .or_else(|| self.name_of(ItemInNs::Values(def)))
            .map(|(_, v)| v)
    }

    /// Iterate over all module scoped macros
    pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
    }

    /// Iterate over all legacy textual scoped macros visible at the end of the module
    pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.legacy_macros.iter().map(|(name, def)| (name, *def))
    }

    /// Get a name from current module scope, legacy macros are not included
    pub(crate) fn get(&self, name: &Name) -> PerNs {
        self.visible.get(name).copied().unwrap_or_else(PerNs::none)
    }

    pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
        for (name, per_ns) in &self.visible {
            if let Some(vis) = item.match_with(*per_ns) {
                return Some((name, vis));
            }
        }
        None
    }

    pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
        self.visible.values().filter_map(|def| match def.take_types() {
            Some(ModuleDefId::TraitId(t)) => Some(t),
            _ => None,
        })
    }

    pub(crate) fn define_def(&mut self, def: ModuleDefId) {
        self.defs.push(def)
    }

    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
        self.legacy_macros.get(name).copied()
    }

    pub(crate) fn define_impl(&mut self, imp: ImplId) {
        self.impls.push(imp)
    }

    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
        self.legacy_macros.insert(name, mac);
    }

    pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
        let mut changed = false;
        let existing = self.visible.entry(name).or_default();

        if existing.types.is_none() && def.types.is_some() {
            existing.types = def.types;
            changed = true;
        }
        if existing.values.is_none() && def.values.is_some() {
            existing.values = def.values;
            changed = true;
        }
        if existing.macros.is_none() && def.macros.is_some() {
            existing.macros = def.macros;
            changed = true;
        }

        changed
    }

    pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
        self.visible.iter().map(|(name, res)| (name.clone(), *res))
    }

    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
        self.legacy_macros.clone()
    }
}

impl PerNs {
    pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
        match def {
            ModuleDefId::ModuleId(_) => PerNs::types(def, v),
            ModuleDefId::FunctionId(_) => PerNs::values(def, v),
            ModuleDefId::AdtId(adt) => match adt {
                AdtId::UnionId(_) => PerNs::types(def, v),
                AdtId::EnumId(_) => PerNs::types(def, v),
                AdtId::StructId(_) => {
                    if !has_constructor {
                        PerNs::types(def, v)
                    } else {
                        PerNs::both(def, def, v)
                    }
                }
            },
            ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
            ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
            ModuleDefId::TraitId(_) => PerNs::types(def, v),
            ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
            ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
        }
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum ItemInNs {
    Types(ModuleDefId),
    Values(ModuleDefId),
    Macros(MacroDefId),
}

impl ItemInNs {
    fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
        match self {
            ItemInNs::Types(def) => {
                per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
            ItemInNs::Values(def) => {
                per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
            ItemInNs::Macros(def) => {
                per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
        }
    }

    pub fn as_module_def_id(self) -> Option<ModuleDefId> {
        match self {
            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
            ItemInNs::Macros(_) => None,
        }
    }
}
<commit_msg>invert if<commit_after>//! Describes items defined or visible (ie, imported) in a certain scope.
//! This is shared between modules and blocks.

use hir_expand::name::Name;
use once_cell::sync::Lazy;
use rustc_hash::FxHashMap;

use crate::{
    per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId,
    TraitId,
};

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ItemScope {
    visible: FxHashMap<Name, PerNs>,
    defs: Vec<ModuleDefId>,
    impls: Vec<ImplId>,
    /// Macros visible in current module in legacy textual scope
    ///
    /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
    /// If it yields no result, then it turns to module scoped `macros`.
    /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
    /// and only normal scoped `macros` will be searched in.
    ///
    /// Note that this automatically inherit macros defined textually before the definition of module itself.
    ///
    /// Module scoped macros will be inserted into `items` instead of here.
    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
    // be all resolved to the last one defined if shadowing happens.
    legacy_macros: FxHashMap<Name, MacroDefId>,
}

pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
    BuiltinType::ALL
        .iter()
        .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
        .collect()
});

/// Shadow mode for builtin type which can be shadowed by module.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum BuiltinShadowMode {
    /// Prefer user-defined modules (or other types) over builtins.
    Module,
    /// Prefer builtins over user-defined modules (but not other types).
    Other,
}

/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ItemScope {
    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
        //FIXME: shadowing
        self.visible.iter().map(|(n, def)| (n, *def))
    }

    pub fn entries_without_primitives<'a>(
        &'a self,
    ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
        self.visible.iter().map(|(n, def)| (n, *def))
    }

    pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
        self.defs.iter().copied()
    }

    pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
        self.impls.iter().copied()
    }

    pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> {
        self.name_of(ItemInNs::Types(def))
            .or_else(|| self.name_of(ItemInNs::Values(def)))
            .map(|(_, v)| v)
    }

    /// Iterate over all module scoped macros
    pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
    }

    /// Iterate over all legacy textual scoped macros visible at the end of the module
    pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.legacy_macros.iter().map(|(name, def)| (name, *def))
    }

    /// Get a name from current module scope, legacy macros are not included
    pub(crate) fn get(&self, name: &Name) -> PerNs {
        self.visible.get(name).copied().unwrap_or_else(PerNs::none)
    }

    pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
        for (name, per_ns) in &self.visible {
            if let Some(vis) = item.match_with(*per_ns) {
                return Some((name, vis));
            }
        }
        None
    }

    pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
        self.visible.values().filter_map(|def| match def.take_types() {
            Some(ModuleDefId::TraitId(t)) => Some(t),
            _ => None,
        })
    }

    pub(crate) fn define_def(&mut self, def: ModuleDefId) {
        self.defs.push(def)
    }

    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
        self.legacy_macros.get(name).copied()
    }

    pub(crate) fn define_impl(&mut self, imp: ImplId) {
        self.impls.push(imp)
    }

    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
        self.legacy_macros.insert(name, mac);
    }

    pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
        let mut changed = false;
        let existing = self.visible.entry(name).or_default();

        if existing.types.is_none() && def.types.is_some() {
            existing.types = def.types;
            changed = true;
        }
        if existing.values.is_none() && def.values.is_some() {
            existing.values = def.values;
            changed = true;
        }
        if existing.macros.is_none() && def.macros.is_some() {
            existing.macros = def.macros;
            changed = true;
        }

        changed
    }

    pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
        self.visible.iter().map(|(name, res)| (name.clone(), *res))
    }

    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
        self.legacy_macros.clone()
    }
}

impl PerNs {
    pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
        match def {
            ModuleDefId::ModuleId(_) => PerNs::types(def, v),
            ModuleDefId::FunctionId(_) => PerNs::values(def, v),
            ModuleDefId::AdtId(adt) => match adt {
                AdtId::UnionId(_) => PerNs::types(def, v),
                AdtId::EnumId(_) => PerNs::types(def, v),
                AdtId::StructId(_) => {
                    if has_constructor {
                        PerNs::both(def, def, v)
                    } else {
                        PerNs::types(def, v)
                    }
                }
            },
            ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
            ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
            ModuleDefId::TraitId(_) => PerNs::types(def, v),
            ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
            ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
        }
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum ItemInNs {
    Types(ModuleDefId),
    Values(ModuleDefId),
    Macros(MacroDefId),
}

impl ItemInNs {
    fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
        match self {
            ItemInNs::Types(def) => {
                per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
            ItemInNs::Values(def) => {
                per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
            ItemInNs::Macros(def) => {
                per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
        }
    }

    pub fn as_module_def_id(self) -> Option<ModuleDefId> {
        match self {
            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
            ItemInNs::Macros(_) => None,
        }
    }
}
<|endoftext|>


<commit_before>//! Endpoints for spaces.

use js_int::UInt;
use ruma_common::{
    directory::PublicRoomJoinRule, events::space::child::HierarchySpaceChildStateEvent,
    room::RoomType, serde::Raw, MxcUri, RoomAliasId, RoomId, RoomName,
};
use serde::{Deserialize, Serialize};

pub mod get_hierarchy;

/// A chunk of a space hierarchy response, describing one room.
///
/// To create an instance of this type, first create a `SpaceHierarchyRoomsChunkInit` and convert it
/// via `SpaceHierarchyRoomsChunk::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SpaceHierarchyRoomsChunk {
    /// The canonical alias of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "compat",
        serde(default, deserialize_with = "ruma_common::serde::empty_string_as_none")
    )]
    pub canonical_alias: Option<Box<RoomAliasId>>,

    /// The name of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<Box<RoomName>>,

    /// The number of members joined to the room.
    pub num_joined_members: UInt,

    /// The ID of the room.
    pub room_id: Box<RoomId>,

    /// The topic of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub topic: Option<String>,

    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,

    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,

    /// The URL for the room's avatar, if one is set.
    ///
    /// If you activate the `compat` feature, this field being an empty string in JSON will result
    /// in `None` here during deserialization.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "compat",
        serde(default, deserialize_with = "ruma_common::serde::empty_string_as_none")
    )]
    pub avatar_url: Option<Box<MxcUri>>,

    /// The join rule of the room.
    #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
    pub join_rule: PublicRoomJoinRule,

    /// The type of room from `m.room.create`, if any.
    pub room_type: Option<RoomType>,

    /// The stripped `m.space.child` events of the space-room.
    ///
    /// If the room is not a space-room, this should be empty.
    pub children_state: Vec<Raw<HierarchySpaceChildStateEvent>>,
}

/// Initial set of mandatory fields of `SpaceHierarchyRoomsChunk`.
///
/// This struct will not be updated even if additional fields are added to
/// `SpaceHierarchyRoomsChunk` in a new (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct SpaceHierarchyRoomsChunkInit {
    /// The number of members joined to the room.
    pub num_joined_members: UInt,

    /// The ID of the room.
    pub room_id: Box<RoomId>,

    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,

    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,

    /// The join rule of the room.
    pub join_rule: PublicRoomJoinRule,

    /// The stripped `m.space.child` events of the space-room.
    ///
    /// If the room is not a space-room, this should be empty.
    pub children_state: Vec<Raw<HierarchySpaceChildStateEvent>>,
}

impl From<SpaceHierarchyRoomsChunkInit> for SpaceHierarchyRoomsChunk {
    fn from(init: SpaceHierarchyRoomsChunkInit) -> Self {
        let SpaceHierarchyRoomsChunkInit {
            num_joined_members,
            room_id,
            world_readable,
            guest_can_join,
            join_rule,
            children_state,
        } = init;

        Self {
            canonical_alias: None,
            name: None,
            num_joined_members,
            room_id,
            topic: None,
            world_readable,
            guest_can_join,
            avatar_url: None,
            join_rule,
            room_type: None,
            children_state,
        }
    }
}
<commit_msg>client-api: Link to spaces spec section<commit_after>//! Endpoints for spaces.
//!
//! See the [Matrix specification][spec] for more details about spaces.
//!
//! [spec]: https://spec.matrix.org/v1.2/client-server-api/#spaces

use js_int::UInt;
use ruma_common::{
    directory::PublicRoomJoinRule, events::space::child::HierarchySpaceChildStateEvent,
    room::RoomType, serde::Raw, MxcUri, RoomAliasId, RoomId, RoomName,
};
use serde::{Deserialize, Serialize};

pub mod get_hierarchy;

/// A chunk of a space hierarchy response, describing one room.
///
/// To create an instance of this type, first create a `SpaceHierarchyRoomsChunkInit` and convert it
/// via `SpaceHierarchyRoomsChunk::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SpaceHierarchyRoomsChunk {
    /// The canonical alias of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "compat",
        serde(default, deserialize_with = "ruma_common::serde::empty_string_as_none")
    )]
    pub canonical_alias: Option<Box<RoomAliasId>>,

    /// The name of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<Box<RoomName>>,

    /// The number of members joined to the room.
    pub num_joined_members: UInt,

    /// The ID of the room.
    pub room_id: Box<RoomId>,

    /// The topic of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub topic: Option<String>,

    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,

    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,

    /// The URL for the room's avatar, if one is set.
    ///
    /// If you activate the `compat` feature, this field being an empty string in JSON will result
    /// in `None` here during deserialization.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "compat",
        serde(default, deserialize_with = "ruma_common::serde::empty_string_as_none")
    )]
    pub avatar_url: Option<Box<MxcUri>>,

    /// The join rule of the room.
    #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
    pub join_rule: PublicRoomJoinRule,

    /// The type of room from `m.room.create`, if any.
    pub room_type: Option<RoomType>,

    /// The stripped `m.space.child` events of the space-room.
    ///
    /// If the room is not a space-room, this should be empty.
    pub children_state: Vec<Raw<HierarchySpaceChildStateEvent>>,
}

/// Initial set of mandatory fields of `SpaceHierarchyRoomsChunk`.
///
/// This struct will not be updated even if additional fields are added to
/// `SpaceHierarchyRoomsChunk` in a new (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct SpaceHierarchyRoomsChunkInit {
    /// The number of members joined to the room.
    pub num_joined_members: UInt,

    /// The ID of the room.
    pub room_id: Box<RoomId>,

    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,

    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,

    /// The join rule of the room.
    pub join_rule: PublicRoomJoinRule,

    /// The stripped `m.space.child` events of the space-room.
    ///
    /// If the room is not a space-room, this should be empty.
    pub children_state: Vec<Raw<HierarchySpaceChildStateEvent>>,
}

impl From<SpaceHierarchyRoomsChunkInit> for SpaceHierarchyRoomsChunk {
    fn from(init: SpaceHierarchyRoomsChunkInit) -> Self {
        let SpaceHierarchyRoomsChunkInit {
            num_joined_members,
            room_id,
            world_readable,
            guest_can_join,
            join_rule,
            children_state,
        } = init;

        Self {
            canonical_alias: None,
            name: None,
            num_joined_members,
            room_id,
            topic: None,
            world_readable,
            guest_can_join,
            avatar_url: None,
            join_rule,
            room_type: None,
            children_state,
        }
    }
}
<|endoftext|>