<commit_before>#![feature(lang_items)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(naked_functions)]
#![feature(associated_consts)]
#![feature(type_ascription)]
#![feature(core_intrinsics)]
#![feature(optin_builtin_traits)]
#![feature(drop_types_in_const)]
#![feature(thread_local)]
#![feature(nonzero)]
#![feature(unsize)]
#![feature(coerce_unsized)]
#![feature(core_slice_ext)]
#![feature(reflect_marker)]
#![feature(relaxed_adts)]
#![no_std]

extern crate x86;
extern crate spin;
extern crate rlibc;
extern crate abi;

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate bitflags;

/// Macros, need to be loaded before everything else due to how rust parses
#[macro_use]
mod macros;

/// Achitecture-specific modules
#[cfg(target_arch="x86_64")] #[path="arch/x86_64/mod.rs"]
pub mod arch;

/// Exception handling (panic)
pub mod unwind;

/// Logging code
mod logging;

#[macro_use]
mod util;
mod common;
mod elf;
mod cap;

use core::mem;
use core::slice;
use common::*;
use arch::{InitInfo, inportb, outportb, Exception};
use cap::{UntypedCap, CPoolCap, CPoolDescriptor, RawPageCap, TaskBufferPageCap, TopPageTableCap, TaskCap, TaskDescriptor, TaskStatus, ChannelCap, ChannelDescriptor, PAGE_LENGTH};
use core::ops::{Deref, DerefMut};
use abi::{SystemCall, TaskBuffer};
use util::{MemoryObject};
use core::any::{Any, TypeId};

fn bootstrap_rinit_paging(archinfo: &InitInfo, cpool: &mut CPoolCap, untyped: &mut UntypedCap) -> (TopPageTableCap, TaskBufferPageCap, VAddr, VAddr) {
    use elf::{ElfBinary};

    let rinit_stack_vaddr = VAddr::from(0x80000000: usize);
    let rinit_stack_size = 4;
    let rinit_buffer_vaddr = VAddr::from(0x90001000: usize);
    let rinit_vga_vaddr = VAddr::from(0x90002000: usize);
    let mut rinit_entry: u64 = 0x0;

    let mut rinit_pml4 = TopPageTableCap::retype_from(untyped.write().deref_mut());
    cpool.read().downgrade_free(&rinit_pml4);

    let slice_object = unsafe { MemoryObject::<u8>::slice(archinfo.rinit_region().start_paddr(),
                                                          archinfo.rinit_region().length()) };
    let bin_raw = unsafe { slice::from_raw_parts(*slice_object,
                                                 archinfo.rinit_region().length()) };
    let bin = ElfBinary::new("rinit", bin_raw).unwrap();

    log!("fheader = {:?}", bin.file_header());
    log!("entry = 0x{:x}", bin.file_header().entry);
    rinit_entry = bin.file_header().entry;

    for p in bin.program_headers() {
        use elf::{PT_LOAD};

        if p.progtype == PT_LOAD {
            log!("pheader = {}", p);
            assert!(p.filesz == p.memsz);

            let mut next_page_vaddr = VAddr::from(p.vaddr);
            let mut offset = 0x0;
            let end_vaddr = VAddr::from(p.vaddr + p.memsz as usize);

            while next_page_vaddr <= end_vaddr {
                use core::cmp::{min};
                log!("mapping from: 0x{:x}", next_page_vaddr);

                let page_cap = RawPageCap::retype_from(untyped.write().deref_mut());
                cpool.read().downgrade_free(&page_cap);
                rinit_pml4.map(next_page_vaddr, &page_cap,
                               untyped.write().deref_mut(),
                               cpool.write().deref_mut());

                let mut page = page_cap.write();
                let page_length = page.length();
                let mut page_raw = page.write();

                for i in 0..min(page_length, (p.memsz as usize) - offset) {
                    page_raw.0[i] = bin_raw[(p.offset as usize) + offset + i];
                }

                offset += page_length;
                next_page_vaddr += page_length;
            }
        }
    }

    log!("mapping the rinit stack ...");
    for i in 0..rinit_stack_size {
        let mut rinit_stack_page = RawPageCap::retype_from(untyped.write().deref_mut());
        cpool.read().downgrade_free(&rinit_stack_page);
        rinit_pml4.map(rinit_stack_vaddr + i * PAGE_LENGTH, &rinit_stack_page,
                       untyped.write().deref_mut(),
                       cpool.write().deref_mut());
    }

    log!("mapping the rinit task buffer ...");
    let mut rinit_buffer_page = TaskBufferPageCap::retype_from(untyped.write().deref_mut());
    cpool.read().downgrade_free(&rinit_buffer_page);
    rinit_pml4.map(rinit_buffer_vaddr, &rinit_buffer_page,
                   untyped.write().deref_mut(),
                   cpool.write().deref_mut());

    log!("mapping the rinit vga buffer ...");
    let mut rinit_vga_page = unsafe { RawPageCap::bootstrap(PAddr::from(0xb8000: usize), untyped.write().deref_mut()) };
    cpool.read().downgrade_free(&rinit_vga_page);
    rinit_pml4.map(rinit_vga_vaddr, &rinit_vga_page,
                   untyped.write().deref_mut(),
                   cpool.write().deref_mut());

    (rinit_pml4, rinit_buffer_page, VAddr::from(rinit_entry), rinit_stack_vaddr + (PAGE_LENGTH * rinit_stack_size - 4))
}

fn handle_system_call(call: &mut SystemCall, task: &mut TaskDescriptor, cpool: &CPoolDescriptor) {
    match call {
        &mut SystemCall::Print {
            request: ref request
        } => {
            use core::str;
            let buffer = request.0.clone();
            let slice = &buffer[0..request.1];
            let s = str::from_utf8(slice).unwrap();
            log!("Userspace print: {}", s);
        },
        &mut SystemCall::CPoolListDebug => {
            for i in 0..256 {
                let arc = cpool.upgrade_any(i);
                if arc.is_some() {
                    let arc = arc.unwrap();
                    if arc.is::<CPoolCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): CPoolCap);
                    } else if arc.is::<UntypedCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): UntypedCap);
                    } else if arc.is::<TaskCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): TaskCap);
                    } else if arc.is::<RawPageCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): RawPageCap);
                    } else if arc.is::<TaskBufferPageCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): TaskBufferPageCap);
                    } else if arc.is::<TopPageTableCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): TopPageTableCap);
                    } else if arc.is::<ChannelCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): ChannelCap);
                    } else {
                        log!("CPool index {} (arch specific) => {:?}", i, arc);
                        cap::drop_any(arc);
                    }
                }
            }
        },
        &mut SystemCall::RetypeCPool {
            request: ref request,
        } => {
            let source: Option<UntypedCap> = cpool.upgrade(request.0);
            if source.is_some() {
                let source = source.unwrap();
                let target = CPoolCap::retype_from(source.write().deref_mut());
                let result = cpool.downgrade_at(&target, request.1);
            }
        },
        &mut SystemCall::ChannelTake {
            request: ref request,
            response: ref mut response,
        } => {
            let mut chan_option: Option<ChannelCap> = cpool.upgrade(*request);
            if let Some(chan) = chan_option {
                task.set_status(TaskStatus::ChannelWait(chan))
            }
        },
        &mut SystemCall::ChannelPut {
            request: ref request,
        } => {
            let chan_option: Option<ChannelCap> = cpool.upgrade(request.0);
            if let Some(chan) = chan_option {
                chan.write().put(request.1);
            }
        }
    }
}

#[no_mangle]
pub fn kmain(archinfo: InitInfo)
{
    log!("archinfo: {:?}", &archinfo);
    let mut region_iter = archinfo.free_regions();

    let (mut cpool, mut untyped) = {
        let cpool_target_region = region_iter.next().unwrap();

        let untyped = unsafe { UntypedCap::bootstrap(cpool_target_region.start_paddr(),
                                                     cpool_target_region.length()) };
        let cpool = CPoolCap::retype_from(untyped.write().deref_mut());

        cpool.read().downgrade_at(&cpool, 0);
        cpool.read().downgrade_free(&untyped);

        let mut untyped_target = untyped;

        for region in region_iter {
            let untyped = unsafe { UntypedCap::bootstrap(region.start_paddr(),
                                                         region.length()) };
            cpool.read().downgrade_free(&untyped);

            if untyped.read().length() > untyped_target.read().length() {
                untyped_target = untyped;
            }
        }

        (cpool, untyped_target)
    };

    log!("CPool: {:?}", cpool);
    log!("Untyped: {:?}", untyped);

    log!("type_id: {:?}", TypeId::of::<CPoolCap>());
    {
        use util::{RwLock};
        use util::managed_arc::{ManagedArc};
        use cap::{CPoolDescriptor};
        log!("type_id: {:?}", TypeId::of::<ManagedArc<RwLock<CPoolDescriptor>>>());
    }

    {
        let (rinit_pml4, rinit_buffer_page, rinit_entry, rinit_stack) =
            bootstrap_rinit_paging(&archinfo, &mut cpool, &mut untyped);
        let rinit_task_cap = TaskCap::retype_from(untyped.write().deref_mut());
        let mut rinit_task = rinit_task_cap.write();
        rinit_task.set_instruction_pointer(rinit_entry);
        rinit_task.set_stack_pointer(rinit_stack);
        rinit_task.downgrade_cpool(&cpool);
        rinit_task.downgrade_top_page_table(&rinit_pml4);
        rinit_task.downgrade_buffer(&rinit_buffer_page);
    }

    let mut keyboard_cap = ChannelCap::retype_from(untyped.write().deref_mut());
    cpool.read().downgrade_at(&keyboard_cap, 254);

    log!("hello, world!");
    // arch::enable_timer();
    while true {
        let mut idle = true;

        for task_cap in cap::task_iter() {
            let mut task = task_cap.write();
            let exception = match task.status() {
                TaskStatus::Active => {
                    idle = false;
                    Some(task.switch_to())
                },
                TaskStatus::ChannelWait(ref chan) => {
                    let value = chan.write().take();
                    if let Some(value) = value {
                        let buffer = task.upgrade_buffer();
                        let mut buffer_desc = buffer.as_ref().unwrap().write().write();
                        let system_call = buffer_desc.deref_mut().call.as_mut().unwrap();
                        match system_call {
                            &mut SystemCall::ChannelTake {
                                request: ref request,
                                response: ref mut response,
                            } => {
                                idle = false;
                                *response = Some(value);
                                task.set_status(TaskStatus::Active);
                                Some(task.switch_to())
                            }
                            _ => panic!(),
                        }
                    } else {
                        None
                    }
                }
            };
            match exception {
                Some(Exception::SystemCall) => {
                    let cpool = task.upgrade_cpool();
                    let buffer = task.upgrade_buffer();
                    handle_system_call(buffer.as_ref().unwrap().write().write().deref_mut().call.as_mut().unwrap(),
                                       task.deref_mut(),
                                       cpool.as_ref().unwrap().read().deref());
                },
                Some(Exception::Keyboard) => {
                    keyboard_cap.write().put(unsafe { arch::inportb(0x60) } as u64);
                },
                _ => (),
            }
        }

        if idle {
            let exception = cap::idle();
            match exception {
                Exception::Keyboard => {
                    keyboard_cap.write().put(unsafe { arch::inportb(0x60) } as u64);
                },
                _ => (),
            }
        }
    }

    loop {}
}

fn divide_by_zero() {
    unsafe {
        asm!("mov dx, 0; div dx" ::: "ax", "dx" : "volatile", "intel")
    }
}
<commit_msg>Enable timer<commit_after>#![feature(lang_items)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(naked_functions)]
#![feature(associated_consts)]
#![feature(type_ascription)]
#![feature(core_intrinsics)]
#![feature(optin_builtin_traits)]
#![feature(drop_types_in_const)]
#![feature(thread_local)]
#![feature(nonzero)]
#![feature(unsize)]
#![feature(coerce_unsized)]
#![feature(core_slice_ext)]
#![feature(reflect_marker)]
#![feature(relaxed_adts)]
#![no_std]

extern crate x86;
extern crate spin;
extern crate rlibc;
extern crate abi;

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate bitflags;

/// Macros, need to be loaded before everything else due to how rust parses
#[macro_use]
mod macros;

/// Achitecture-specific modules
#[cfg(target_arch="x86_64")] #[path="arch/x86_64/mod.rs"]
pub mod arch;

/// Exception handling (panic)
pub mod unwind;

/// Logging code
mod logging;

#[macro_use]
mod util;
mod common;
mod elf;
mod cap;

use core::mem;
use core::slice;
use common::*;
use arch::{InitInfo, inportb, outportb, Exception};
use cap::{UntypedCap, CPoolCap, CPoolDescriptor, RawPageCap, TaskBufferPageCap, TopPageTableCap, TaskCap, TaskDescriptor, TaskStatus, ChannelCap, ChannelDescriptor, PAGE_LENGTH};
use core::ops::{Deref, DerefMut};
use abi::{SystemCall, TaskBuffer};
use util::{MemoryObject};
use core::any::{Any, TypeId};

fn bootstrap_rinit_paging(archinfo: &InitInfo, cpool: &mut CPoolCap, untyped: &mut UntypedCap) -> (TopPageTableCap, TaskBufferPageCap, VAddr, VAddr) {
    use elf::{ElfBinary};

    let rinit_stack_vaddr = VAddr::from(0x80000000: usize);
    let rinit_stack_size = 4;
    let rinit_buffer_vaddr = VAddr::from(0x90001000: usize);
    let rinit_vga_vaddr = VAddr::from(0x90002000: usize);
    let mut rinit_entry: u64 = 0x0;

    let mut rinit_pml4 = TopPageTableCap::retype_from(untyped.write().deref_mut());
    cpool.read().downgrade_free(&rinit_pml4);

    let slice_object = unsafe { MemoryObject::<u8>::slice(archinfo.rinit_region().start_paddr(),
                                                          archinfo.rinit_region().length()) };
    let bin_raw = unsafe { slice::from_raw_parts(*slice_object,
                                                 archinfo.rinit_region().length()) };
    let bin = ElfBinary::new("rinit", bin_raw).unwrap();

    log!("fheader = {:?}", bin.file_header());
    log!("entry = 0x{:x}", bin.file_header().entry);
    rinit_entry = bin.file_header().entry;

    for p in bin.program_headers() {
        use elf::{PT_LOAD};

        if p.progtype == PT_LOAD {
            log!("pheader = {}", p);
            assert!(p.filesz == p.memsz);

            let mut next_page_vaddr = VAddr::from(p.vaddr);
            let mut offset = 0x0;
            let end_vaddr = VAddr::from(p.vaddr + p.memsz as usize);

            while next_page_vaddr <= end_vaddr {
                use core::cmp::{min};
                log!("mapping from: 0x{:x}", next_page_vaddr);

                let page_cap = RawPageCap::retype_from(untyped.write().deref_mut());
                cpool.read().downgrade_free(&page_cap);
                rinit_pml4.map(next_page_vaddr, &page_cap,
                               untyped.write().deref_mut(),
                               cpool.write().deref_mut());

                let mut page = page_cap.write();
                let page_length = page.length();
                let mut page_raw = page.write();

                for i in 0..min(page_length, (p.memsz as usize) - offset) {
                    page_raw.0[i] = bin_raw[(p.offset as usize) + offset + i];
                }

                offset += page_length;
                next_page_vaddr += page_length;
            }
        }
    }

    log!("mapping the rinit stack ...");
    for i in 0..rinit_stack_size {
        let mut rinit_stack_page = RawPageCap::retype_from(untyped.write().deref_mut());
        cpool.read().downgrade_free(&rinit_stack_page);
        rinit_pml4.map(rinit_stack_vaddr + i * PAGE_LENGTH, &rinit_stack_page,
                       untyped.write().deref_mut(),
                       cpool.write().deref_mut());
    }

    log!("mapping the rinit task buffer ...");
    let mut rinit_buffer_page = TaskBufferPageCap::retype_from(untyped.write().deref_mut());
    cpool.read().downgrade_free(&rinit_buffer_page);
    rinit_pml4.map(rinit_buffer_vaddr, &rinit_buffer_page,
                   untyped.write().deref_mut(),
                   cpool.write().deref_mut());

    log!("mapping the rinit vga buffer ...");
    let mut rinit_vga_page = unsafe { RawPageCap::bootstrap(PAddr::from(0xb8000: usize), untyped.write().deref_mut()) };
    cpool.read().downgrade_free(&rinit_vga_page);
    rinit_pml4.map(rinit_vga_vaddr, &rinit_vga_page,
                   untyped.write().deref_mut(),
                   cpool.write().deref_mut());

    (rinit_pml4, rinit_buffer_page, VAddr::from(rinit_entry), rinit_stack_vaddr + (PAGE_LENGTH * rinit_stack_size - 4))
}

fn handle_system_call(call: &mut SystemCall, task: &mut TaskDescriptor, cpool: &CPoolDescriptor) {
    match call {
        &mut SystemCall::Print {
            request: ref request
        } => {
            use core::str;
            let buffer = request.0.clone();
            let slice = &buffer[0..request.1];
            let s = str::from_utf8(slice).unwrap();
            log!("Userspace print: {}", s);
        },
        &mut SystemCall::CPoolListDebug => {
            for i in 0..256 {
                let arc = cpool.upgrade_any(i);
                if arc.is_some() {
                    let arc = arc.unwrap();
                    if arc.is::<CPoolCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): CPoolCap);
                    } else if arc.is::<UntypedCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): UntypedCap);
                    } else if arc.is::<TaskCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): TaskCap);
                    } else if arc.is::<RawPageCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): RawPageCap);
                    } else if arc.is::<TaskBufferPageCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): TaskBufferPageCap);
                    } else if arc.is::<TopPageTableCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): TopPageTableCap);
                    } else if arc.is::<ChannelCap>() {
                        log!("CPool index {} => {:?}", i, arc.into(): ChannelCap);
                    } else {
                        log!("CPool index {} (arch specific) => {:?}", i, arc);
                        cap::drop_any(arc);
                    }
                }
            }
        },
        &mut SystemCall::RetypeCPool {
            request: ref request,
        } => {
            let source: Option<UntypedCap> = cpool.upgrade(request.0);
            if source.is_some() {
                let source = source.unwrap();
                let target = CPoolCap::retype_from(source.write().deref_mut());
                let result = cpool.downgrade_at(&target, request.1);
            }
        },
        &mut SystemCall::ChannelTake {
            request: ref request,
            response: ref mut response,
        } => {
            let mut chan_option: Option<ChannelCap> = cpool.upgrade(*request);
            if let Some(chan) = chan_option {
                task.set_status(TaskStatus::ChannelWait(chan))
            }
        },
        &mut SystemCall::ChannelPut {
            request: ref request,
        } => {
            let chan_option: Option<ChannelCap> = cpool.upgrade(request.0);
            if let Some(chan) = chan_option {
                chan.write().put(request.1);
            }
        }
    }
}

#[no_mangle]
pub fn kmain(archinfo: InitInfo)
{
    log!("archinfo: {:?}", &archinfo);
    let mut region_iter = archinfo.free_regions();

    let (mut cpool, mut untyped) = {
        let cpool_target_region = region_iter.next().unwrap();

        let untyped = unsafe { UntypedCap::bootstrap(cpool_target_region.start_paddr(),
                                                     cpool_target_region.length()) };
        let cpool = CPoolCap::retype_from(untyped.write().deref_mut());

        cpool.read().downgrade_at(&cpool, 0);
        cpool.read().downgrade_free(&untyped);

        let mut untyped_target = untyped;

        for region in region_iter {
            let untyped = unsafe { UntypedCap::bootstrap(region.start_paddr(),
                                                         region.length()) };
            cpool.read().downgrade_free(&untyped);

            if untyped.read().length() > untyped_target.read().length() {
                untyped_target = untyped;
            }
        }

        (cpool, untyped_target)
    };

    log!("CPool: {:?}", cpool);
    log!("Untyped: {:?}", untyped);

    log!("type_id: {:?}", TypeId::of::<CPoolCap>());
    {
        use util::{RwLock};
        use util::managed_arc::{ManagedArc};
        use cap::{CPoolDescriptor};
        log!("type_id: {:?}", TypeId::of::<ManagedArc<RwLock<CPoolDescriptor>>>());
    }

    {
        let (rinit_pml4, rinit_buffer_page, rinit_entry, rinit_stack) =
            bootstrap_rinit_paging(&archinfo, &mut cpool, &mut untyped);
        let rinit_task_cap = TaskCap::retype_from(untyped.write().deref_mut());
        let mut rinit_task = rinit_task_cap.write();
        rinit_task.set_instruction_pointer(rinit_entry);
        rinit_task.set_stack_pointer(rinit_stack);
        rinit_task.downgrade_cpool(&cpool);
        rinit_task.downgrade_top_page_table(&rinit_pml4);
        rinit_task.downgrade_buffer(&rinit_buffer_page);
    }

    let mut keyboard_cap = ChannelCap::retype_from(untyped.write().deref_mut());
    cpool.read().downgrade_at(&keyboard_cap, 254);

    log!("hello, world!");
    arch::enable_timer();
    while true {
        let mut idle = true;

        for task_cap in cap::task_iter() {
            let mut task = task_cap.write();
            let exception = match task.status() {
                TaskStatus::Active => {
                    idle = false;
                    Some(task.switch_to())
                },
                TaskStatus::ChannelWait(ref chan) => {
                    let value = chan.write().take();
                    if let Some(value) = value {
                        let buffer = task.upgrade_buffer();
                        let mut buffer_desc = buffer.as_ref().unwrap().write().write();
                        let system_call = buffer_desc.deref_mut().call.as_mut().unwrap();
                        match system_call {
                            &mut SystemCall::ChannelTake {
                                request: ref request,
                                response: ref mut response,
                            } => {
                                idle = false;
                                *response = Some(value);
                                task.set_status(TaskStatus::Active);
                                Some(task.switch_to())
                            }
                            _ => panic!(),
                        }
                    } else {
                        None
                    }
                }
            };
            match exception {
                Some(Exception::SystemCall) => {
                    let cpool = task.upgrade_cpool();
                    let buffer = task.upgrade_buffer();
                    handle_system_call(buffer.as_ref().unwrap().write().write().deref_mut().call.as_mut().unwrap(),
                                       task.deref_mut(),
                                       cpool.as_ref().unwrap().read().deref());
                },
                Some(Exception::Keyboard) => {
                    keyboard_cap.write().put(unsafe { arch::inportb(0x60) } as u64);
                },
                _ => (),
            }
        }

        if idle {
            let exception = cap::idle();
            match exception {
                Exception::Keyboard => {
                    keyboard_cap.write().put(unsafe { arch::inportb(0x60) } as u64);
                },
                _ => (),
            }
        }
    }

    loop {}
}

fn divide_by_zero() {
    unsafe {
        asm!("mov dx, 0; div dx" ::: "ax", "dx" : "volatile", "intel")
    }
}
<|endoftext|>


<commit_before>// Aldaron's Device Interface / Screen
// Copyright (c) 2017 Plop Grizzly, Jeron Lau <jeron.lau@plopgrizzly.com>
// Licensed under the MIT LICENSE
//
// src/gui/text.rs

use rusttype;
use rusttype::FontCollection;

use Texture;
use Sprite;
use Model;
use TexCoords;
use SpriteList;
use Window;
use window::WindowFunctions;
use Transform;

/// A font that's built into the library.
pub const DEFAULT_FONT: &'static [u8] =
	include_bytes!("res/font/SourceCodePro-Regular.ttf");

/// Text on the screen.
pub struct Text(Option<(Texture, Sprite)>, (f32, f32), (f32, f32));

impl Text {
	/// Add an empty text box to the screen.
	pub fn new(_: &mut Window, pos: (f32,f32), wh: (f32,f32)) -> Text {
		Text(None, pos, wh)
	}

	/// Update the texture.
	pub fn update(&mut self, window: &mut Window, text: &str, font: &[u8]) {
		let win_size = window.wh();
		let w = ((win_size.0 as f32 * self.2 .0) as u32) * (text.len() as u32) / 2;
		let h = (win_size.0 as f32 * self.2 .1) as u32;
		let mut texture = Texture::empty(window, w, h);
		let model = Model::new(window,
			(&[0, 1, 2, 1, 0, 3],
			&[
				0.0,  0.0, 0.0, 1.0,
				self.2 .0 * 0.5 * (text.len() as f32), self.2 .1, 0.0, 1.0,
				self.2 .0 * 0.5 * (text.len() as f32), 0.0, 0.0, 1.0,
				0.0,  self.2 .1, 0.0, 1.0,
			])
		);
		let tc = TexCoords::new(window, &[
			0.0, 0.0, 1.0, 1.0,
			1.0, 1.0, 1.0, 1.0,
			1.0, 0.0, 1.0, 1.0,
			0.0, 1.0, 1.0, 1.0,
		]);
		let sprite = SpriteList::new(model)
			.transform(Transform::new().translate(self.1 .0, self.1 .1, 0.0))
			.gui()
			.blend()
			.texture(window, texture, tc)
			.only();

		//

		let font = Font::new(font);
		let mut buf = vec![0; (texture.w() * texture.h()) as usize];

		font.render(w as usize, h as f32, buf.as_mut_slice(),
			(255, 255, 255, 255), text);
		texture.set(window, buf.as_slice());

		self.0 = Some((texture, sprite));
	}

	/// Set the position for the text.
	fn position(&mut self, x: f32, y: f32) {

	}
}

/// A font.
pub struct Font<'a>(&'a [u8], rusttype::Font<'a>);

impl<'a> Font<'a> {
	pub fn new(font_data: &'a [u8]) -> Font<'a> {
		Font(font_data, FontCollection::from_bytes(font_data).into_font().unwrap())
	}

	pub(crate) fn render(&self, width: usize, height: f32, buffer: &mut [u32],
		color: (u8, u8, u8, u8), text: &str) -> ()
	{
		let pixel_height = height.ceil() as usize;
		let scale = rusttype::Scale { x: height, y: height };
		let v_metrics = self.1.v_metrics(scale);
		let offset = rusttype::point(0.0, v_metrics.ascent);

		let glyphs: Vec<rusttype::PositionedGlyph> = self.1
			.layout(text, scale, offset)
			.collect();

		for g in glyphs {
			if let Some(bb) = g.pixel_bounding_box() {
				g.draw(|x, y, v| {
					let c = unsafe { ::std::mem::transmute([
						(color.0 as f32 * v) as u8,
						(color.1 as f32 * v) as u8,
						(color.2 as f32 * v) as u8,
						(color.3 as f32 * v) as u8
					]) };

					let x = x as i32 + bb.min.x;
					let y = y as i32 + bb.min.y;
					// There's still a possibility that the glyph clips the boundaries of the bitmap
					if x >= 0 && x < width as i32 && y >= 0 && y < pixel_height as i32 {
						let x = x as usize;
						let y = y as usize;
						buffer[(x + y * width)] = c;
					}
				});
			}
		}
	}
}
<commit_msg>Position function now works for text.<commit_after>// Aldaron's Device Interface / Screen
// Copyright (c) 2017 Plop Grizzly, Jeron Lau <jeron.lau@plopgrizzly.com>
// Licensed under the MIT LICENSE
//
// src/gui/text.rs

use rusttype;
use rusttype::FontCollection;

use Texture;
use Sprite;
use Model;
use TexCoords;
use SpriteList;
use Window;
use window::WindowFunctions;
use Transform;

/// A font that's built into the library.
pub const DEFAULT_FONT: &'static [u8] =
	include_bytes!("res/font/SourceCodePro-Regular.ttf");

/// Text on the screen.
pub struct Text(Option<(Texture, Sprite)>, (f32, f32), (f32, f32));

impl Text {
	/// Add an empty text box to the screen.
	pub fn new(_: &mut Window, pos: (f32,f32), wh: (f32,f32)) -> Text {
		Text(None, pos, wh)
	}

	/// Update the texture.
	pub fn update(&mut self, window: &mut Window, text: &str, font: &[u8]) {
		let win_size = window.wh();
		let w = ((win_size.0 as f32 * self.2 .0) as u32) * (text.len() as u32) / 2;
		let h = (win_size.0 as f32 * self.2 .1) as u32;
		let mut texture = Texture::empty(window, w, h);
		let model = Model::new(window,
			(&[0, 1, 2, 1, 0, 3],
			&[
				0.0,  0.0, 0.0, 1.0,
				self.2 .0 * 0.5 * (text.len() as f32), self.2 .1, 0.0, 1.0,
				self.2 .0 * 0.5 * (text.len() as f32), 0.0, 0.0, 1.0,
				0.0,  self.2 .1, 0.0, 1.0,
			])
		);
		let tc = TexCoords::new(window, &[
			0.0, 0.0, 1.0, 1.0,
			1.0, 1.0, 1.0, 1.0,
			1.0, 0.0, 1.0, 1.0,
			0.0, 1.0, 1.0, 1.0,
		]);
		let sprite = SpriteList::new(model)
			.transform(Transform::new().translate(self.1 .0, self.1 .1, 0.0))
			.gui()
			.blend()
			.texture(window, texture, tc)
			.only();

		//

		let font = Font::new(font);
		let mut buf = vec![0; (texture.w() * texture.h()) as usize];

		font.render(w as usize, h as f32, buf.as_mut_slice(),
			(255, 255, 255, 255), text);
		texture.set(window, buf.as_slice());

		self.0 = Some((texture, sprite));
	}

	/// Set the position for the text.
	pub fn position(&mut self, x: f32, y: f32) {
		self.1 = (x, y);
	}
}

/// A font.
pub struct Font<'a>(&'a [u8], rusttype::Font<'a>);

impl<'a> Font<'a> {
	pub fn new(font_data: &'a [u8]) -> Font<'a> {
		Font(font_data, FontCollection::from_bytes(font_data).into_font().unwrap())
	}

	pub(crate) fn render(&self, width: usize, height: f32, buffer: &mut [u32],
		color: (u8, u8, u8, u8), text: &str) -> ()
	{
		let pixel_height = height.ceil() as usize;
		let scale = rusttype::Scale { x: height, y: height };
		let v_metrics = self.1.v_metrics(scale);
		let offset = rusttype::point(0.0, v_metrics.ascent);

		let glyphs: Vec<rusttype::PositionedGlyph> = self.1
			.layout(text, scale, offset)
			.collect();

		for g in glyphs {
			if let Some(bb) = g.pixel_bounding_box() {
				g.draw(|x, y, v| {
					let c = unsafe { ::std::mem::transmute([
						(color.0 as f32 * v) as u8,
						(color.1 as f32 * v) as u8,
						(color.2 as f32 * v) as u8,
						(color.3 as f32 * v) as u8
					]) };

					let x = x as i32 + bb.min.x;
					let y = y as i32 + bb.min.y;
					// There's still a possibility that the glyph clips the boundaries of the bitmap
					if x >= 0 && x < width as i32 && y >= 0 && y < pixel_height as i32 {
						let x = x as usize;
						let y = y as usize;
						buffer[(x + y * width)] = c;
					}
				});
			}
		}
	}
}
<|endoftext|>


<commit_before>macro_rules! expand_align {
    () => {
        s! {
            #[allow(missing_debug_implementations)]
            #[repr(align(4))]
            pub struct pthread_mutex_t {
                size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T],
            }

            #[repr(align(4))]
            pub struct pthread_rwlock_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T],
            }

            #[repr(align(4))]
            pub struct pthread_mutexattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_rwlockattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_condattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T],
            }
        }

        s_no_extra_traits! {
            #[cfg_attr(target_pointer_width = "32",
                       repr(align(4)))]
            #[cfg_attr(target_pointer_width = "64",
                       repr(align(8)))]
            pub struct pthread_cond_t {
                size: [u8; ::__SIZEOF_PTHREAD_COND_T],
            }

            #[allow(missing_debug_implementations)]
            #[repr(align(8))]
            pub struct max_align_t {
                priv_: [f64; 2]
            }

        }

        cfg_if! {
            if #[cfg(feature = "extra_traits")] {
                impl PartialEq for pthread_cond_t {
                    fn eq(&self, other: &pthread_cond_t) -> bool {
                        self.size
                            .iter()
                            .zip(other.size.iter())
                            .all(|(a,b)| a == b)
                    }
                }
                impl Eq for pthread_cond_t {}
                impl ::fmt::Debug for pthread_cond_t {
                    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                        f.debug_struct("pthread_cond_t")
                            // FIXME: .field("size", &self.size)
                            .finish()
                    }
                }
                impl ::hash::Hash for pthread_cond_t {
                    fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                        self.size.hash(state);
                    }
                }
            }
        }
    };
}
<commit_msg>Fix `max_align_t` size and align<commit_after>macro_rules! expand_align {
    () => {
        s! {
            #[allow(missing_debug_implementations)]
            #[repr(align(4))]
            pub struct pthread_mutex_t {
                size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T],
            }

            #[repr(align(4))]
            pub struct pthread_rwlock_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T],
            }

            #[repr(align(4))]
            pub struct pthread_mutexattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_rwlockattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_condattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T],
            }
        }

        s_no_extra_traits! {
            #[cfg_attr(target_pointer_width = "32",
                       repr(align(4)))]
            #[cfg_attr(target_pointer_width = "64",
                       repr(align(8)))]
            pub struct pthread_cond_t {
                size: [u8; ::__SIZEOF_PTHREAD_COND_T],
            }

            #[allow(missing_debug_implementations)]
            #[repr(align(16))]
            pub struct max_align_t {
                priv_: [f64; 4]
            }

        }

        cfg_if! {
            if #[cfg(feature = "extra_traits")] {
                impl PartialEq for pthread_cond_t {
                    fn eq(&self, other: &pthread_cond_t) -> bool {
                        self.size
                            .iter()
                            .zip(other.size.iter())
                            .all(|(a,b)| a == b)
                    }
                }
                impl Eq for pthread_cond_t {}
                impl ::fmt::Debug for pthread_cond_t {
                    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                        f.debug_struct("pthread_cond_t")
                            // FIXME: .field("size", &self.size)
                            .finish()
                    }
                }
                impl ::hash::Hash for pthread_cond_t {
                    fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                        self.size.hash(state);
                    }
                }
            }
        }
    };
}
<|endoftext|>


<commit_before>//! Solve symmetric linear problem using the Bunch-Kaufman diagonal pivoting method.
//!
//! See also [the manual of dsytrf](http://www.netlib.org/lapack/lapack-3.1.1/html/dsytrf.f.html)

use super::*;
use crate::{error::*, layout::MatrixLayout};
use cauchy::*;

pub trait Solveh_: Sized {
    /// Bunch-Kaufman: wrapper of `*sytrf` and `*hetrf`
    unsafe fn bk(l: MatrixLayout, uplo: UPLO, a: &mut [Self]) -> Result<Pivot>;
    /// Wrapper of `*sytri` and `*hetri`
    unsafe fn invh(l: MatrixLayout, uplo: UPLO, a: &mut [Self], ipiv: &Pivot) -> Result<()>;
    /// Wrapper of `*sytrs` and `*hetrs`
    unsafe fn solveh(
        l: MatrixLayout,
        uplo: UPLO,
        a: &[Self],
        ipiv: &Pivot,
        b: &mut [Self],
    ) -> Result<()>;
}

macro_rules! impl_solveh {
    ($scalar:ty, $trf:path, $tri:path, $trs:path) => {
        impl Solveh_ for $scalar {
            unsafe fn bk(l: MatrixLayout, uplo: UPLO, a: &mut [Self]) -> Result<Pivot> {
                let (n, _) = l.size();
                let mut ipiv = vec![0; n as usize];
                if n == 0 {
                    // Work around bug in LAPACKE functions.
                    Ok(ipiv)
                } else {
                    $trf(l.lapacke_layout(), uplo as u8, n, a, l.lda(), &mut ipiv)
                        .as_lapack_result()?;
                    Ok(ipiv)
                }
            }

            unsafe fn invh(
                l: MatrixLayout,
                uplo: UPLO,
                a: &mut [Self],
                ipiv: &Pivot,
            ) -> Result<()> {
                let (n, _) = l.size();
                $tri(l.lapacke_layout(), uplo as u8, n, a, l.lda(), ipiv).as_lapack_result()?;
                Ok(())
            }

            unsafe fn solveh(
                l: MatrixLayout,
                uplo: UPLO,
                a: &[Self],
                ipiv: &Pivot,
                b: &mut [Self],
            ) -> Result<()> {
                let (n, _) = l.size();
                let nrhs = 1;
                let ldb = match l {
                    MatrixLayout::C { .. } => 1,
                    MatrixLayout::F { .. } => n,
                };
                $trs(
                    l.lapacke_layout(),
                    uplo as u8,
                    n,
                    nrhs,
                    a,
                    l.lda(),
                    ipiv,
                    b,
                    ldb,
                )
                .as_lapack_result()?;
                Ok(())
            }
        }
    };
} // impl_solveh!

impl_solveh!(f64, lapacke::dsytrf, lapacke::dsytri, lapacke::dsytrs);
impl_solveh!(f32, lapacke::ssytrf, lapacke::ssytri, lapacke::ssytrs);
impl_solveh!(c64, lapacke::zhetrf, lapacke::zhetri, lapacke::zhetrs);
impl_solveh!(c32, lapacke::chetrf, lapacke::chetri, lapacke::chetrs);
<commit_msg>Impl bk, solveh, and invh using LAPACK<commit_after>//! Solve symmetric linear problem using the Bunch-Kaufman diagonal pivoting method.
//!
//! See also [the manual of dsytrf](http://www.netlib.org/lapack/lapack-3.1.1/html/dsytrf.f.html)

use super::*;
use crate::{error::*, layout::MatrixLayout};
use cauchy::*;
use num_traits::{ToPrimitive, Zero};

pub trait Solveh_: Sized {
    /// Bunch-Kaufman: wrapper of `*sytrf` and `*hetrf`
    unsafe fn bk(l: MatrixLayout, uplo: UPLO, a: &mut [Self]) -> Result<Pivot>;
    /// Wrapper of `*sytri` and `*hetri`
    unsafe fn invh(l: MatrixLayout, uplo: UPLO, a: &mut [Self], ipiv: &Pivot) -> Result<()>;
    /// Wrapper of `*sytrs` and `*hetrs`
    unsafe fn solveh(
        l: MatrixLayout,
        uplo: UPLO,
        a: &[Self],
        ipiv: &Pivot,
        b: &mut [Self],
    ) -> Result<()>;
}

macro_rules! impl_solveh {
    ($scalar:ty, $trf:path, $tri:path, $trs:path) => {
        impl Solveh_ for $scalar {
            unsafe fn bk(l: MatrixLayout, uplo: UPLO, a: &mut [Self]) -> Result<Pivot> {
                let (n, _) = l.size();
                let mut ipiv = vec![0; n as usize];
                if n == 0 {
                    return Ok(Vec::new());
                }

                // calc work size
                let mut info = 0;
                let mut work_size = [Self::zero()];
                $trf(
                    uplo as u8,
                    n,
                    a,
                    l.lda(),
                    &mut ipiv,
                    &mut work_size,
                    -1,
                    &mut info,
                );
                info.as_lapack_result()?;

                // actual
                let lwork = work_size[0].to_usize().unwrap();
                let mut work = vec![Self::zero(); lwork];
                $trf(
                    uplo as u8,
                    n,
                    a,
                    l.lda(),
                    &mut ipiv,
                    &mut work,
                    lwork as i32,
                    &mut info,
                );
                info.as_lapack_result()?;
                Ok(ipiv)
            }

            unsafe fn invh(
                l: MatrixLayout,
                uplo: UPLO,
                a: &mut [Self],
                ipiv: &Pivot,
            ) -> Result<()> {
                let (n, _) = l.size();
                let mut info = 0;
                let mut work = vec![Self::zero(); n as usize];
                $tri(uplo as u8, n, a, l.lda(), ipiv, &mut work, &mut info);
                info.as_lapack_result()?;
                Ok(())
            }

            unsafe fn solveh(
                l: MatrixLayout,
                uplo: UPLO,
                a: &[Self],
                ipiv: &Pivot,
                b: &mut [Self],
            ) -> Result<()> {
                let (n, _) = l.size();
                let mut info = 0;
                $trs(uplo as u8, n, 1, a, l.lda(), ipiv, b, n, &mut info);
                info.as_lapack_result()?;
                Ok(())
            }
        }
    };
} // impl_solveh!

impl_solveh!(f64, lapack::dsytrf, lapack::dsytri, lapack::dsytrs);
impl_solveh!(f32, lapack::ssytrf, lapack::ssytri, lapack::ssytrs);
impl_solveh!(c64, lapack::zhetrf, lapack::zhetri, lapack::zhetrs);
impl_solveh!(c32, lapack::chetrf, lapack::chetri, lapack::chetrs);
<|endoftext|>


<commit_before>extern crate libc;
extern crate std;
use self::std::prelude::*;
use self::std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable,
                    MapNonStandardFlags};

extern "C" {
  #[link_name = "lwt_stack_register"]
  fn stack_register(start: *const u8, end: *const u8) -> libc::c_uint;
  #[link_name = "lwt_stack_deregister"]
  fn stack_deregister(id: libc::c_uint);
}

pub struct Stack {
  buf: MemoryMap,
  valgrind_id: libc::c_uint
}

const STACK_FLAGS: libc::c_int = libc::MAP_STACK
                               | libc::MAP_PRIVATE
                               | libc::MAP_ANON;

impl Stack {
  pub fn new(size: uint) -> Stack {
    let buf = match MemoryMap::new(size, &[MapReadable, MapWritable,
                                   MapNonStandardFlags(STACK_FLAGS)]) {
      Ok(map) => map,
      Err(e) => panic!("mmap for stack of size {} failed: {}", size, e)
    };

    if !protect_last_page(&buf) {
      panic!("Could not memory-protect guard page. stack={}, errno={}",
             buf.data(), errno());
    }

    let valgrind_id = unsafe {
      stack_register(buf.data().offset(buf.len() as int) as *const _,
                     buf.data() as *const _)
    };

    Stack {
      buf: buf,
      valgrind_id: valgrind_id
    }
  }
}

fn protect_last_page(stack: &MemoryMap) -> bool {
  unsafe {
    let last_page = stack.data() as *mut libc::c_void;
    libc::mprotect(last_page, page_size() as libc::size_t,
                   libc::PROT_NONE) != -1
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      stack_deregister(self.valgrind_id);
    }
  }
}

impl Stack {
  pub fn top(&mut self) -> *mut u8 {
    unsafe {
      self.buf.data().offset(self.buf.len() as int)
    }
  }

  pub fn limit(&self) -> *const u8 {
    unsafe {
      self.buf.data().offset(page_size() as int) as *const _
    }
  }
}
<commit_msg>Rust updates (MapOption fixes)<commit_after>extern crate libc;
extern crate std;
use self::std::prelude::*;
use self::std::os::{errno, page_size, MemoryMap};
use self::std::os::MapOption::{MapReadable, MapWritable, MapNonStandardFlags};

extern "C" {
  #[link_name = "lwt_stack_register"]
  fn stack_register(start: *const u8, end: *const u8) -> libc::c_uint;
  #[link_name = "lwt_stack_deregister"]
  fn stack_deregister(id: libc::c_uint);
}

pub struct Stack {
  buf: MemoryMap,
  valgrind_id: libc::c_uint
}

const STACK_FLAGS: libc::c_int = libc::MAP_STACK
                               | libc::MAP_PRIVATE
                               | libc::MAP_ANON;

impl Stack {
  pub fn new(size: uint) -> Stack {
    let buf = match MemoryMap::new(size, &[MapReadable, MapWritable,
                                   MapNonStandardFlags(STACK_FLAGS)]) {
      Ok(map) => map,
      Err(e) => panic!("mmap for stack of size {} failed: {}", size, e)
    };

    if !protect_last_page(&buf) {
      panic!("Could not memory-protect guard page. stack={}, errno={}",
             buf.data(), errno());
    }

    let valgrind_id = unsafe {
      stack_register(buf.data().offset(buf.len() as int) as *const _,
                     buf.data() as *const _)
    };

    Stack {
      buf: buf,
      valgrind_id: valgrind_id
    }
  }
}

fn protect_last_page(stack: &MemoryMap) -> bool {
  unsafe {
    let last_page = stack.data() as *mut libc::c_void;
    libc::mprotect(last_page, page_size() as libc::size_t,
                   libc::PROT_NONE) != -1
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      stack_deregister(self.valgrind_id);
    }
  }
}

impl Stack {
  pub fn top(&mut self) -> *mut u8 {
    unsafe {
      self.buf.data().offset(self.buf.len() as int)
    }
  }

  pub fn limit(&self) -> *const u8 {
    unsafe {
      self.buf.data().offset(page_size() as int) as *const _
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::errors::*;
use clap::{error::ErrorKind, IntoApp, Parser};
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use which::which_in;

#[derive(clap::ArgEnum, Debug, Clone)]
pub enum StatsFormat {
    Text,
    Json,
}

impl Default for StatsFormat {
    fn default() -> Self {
        Self::Text
    }
}

/// A specific command to run.
pub enum Command {
    /// Show cache statistics and exit.
    ShowStats(StatsFormat),
    /// Run background server.
    InternalStartServer,
    /// Start background server as a subprocess.
    StartServer,
    /// Stop background server.
    StopServer,
    /// Zero cache statistics and exit.
    ZeroStats,
    /// Show the status of the distributed client.
    DistStatus,
    /// Perform a login to authenticate for distributed compilation.
    DistAuth,
    /// Package a toolchain for distributed compilation (executable, out)
    PackageToolchain(PathBuf, PathBuf),
    /// Run a compiler command.
    Compile {
        /// The binary to execute.
        exe: OsString,
        /// The commandline arguments to pass to `exe`.
        cmdline: Vec<OsString>,
        /// The directory in which to execute the command.
        cwd: PathBuf,
        /// The environment variables to use for execution.
        env_vars: Vec<(OsString, OsString)>,
    },
}

#[derive(Parser)]
#[clap(version)]
#[clap(trailing_var_arg = true)]
#[clap(after_help = concat!(
        "Enabled features:\n",
        "    S3:        ", cfg!(feature = "s3"), "\n",
        "    Redis:     ", cfg!(feature = "redis"), "\n",
        "    Memcached: ", cfg!(feature = "memcached"), "\n",
        "    GCS:       ", cfg!(feature = "gcs"), "\n",
        "    Azure:     ", cfg!(feature = "azure"), "\n")
)]
struct Opts {
    /// authenticate for distributed compilation
    #[clap(long)]
    dist_auth: bool,
    /// show status of the distributed client
    #[clap(long)]
    dist_status: bool,
    /// show cache statistics
    #[clap(short, long)]
    show_stats: bool,
    /// start background server
    #[clap(long)]
    start_server: bool,
    /// stop background server
    #[clap(long)]
    stop_server: bool,
    /// zero statistic counters
    #[clap(short, long)]
    zero_stats: bool,

    /// package toolchain for distributed compilation
    #[clap(long, number_of_values = 2)]
    package_toolchain: Vec<PathBuf>,
    /// set output format of statistics
    #[clap(long, arg_enum, default_value_t = StatsFormat::default())]
    stats_format: StatsFormat,

    cmd: Vec<OsString>,
}

/// Parse the commandline into a `Command` to execute.
pub fn parse() -> Command {
    match try_parse() {
        Ok(cmd) => cmd,
        Err(e) => {
            println!("sccache: {e}");
            for e in e.chain().skip(1) {
                println!("sccache: caused by: {e}");
            }
            let mut clap_command = Opts::command();
            clap_command.print_help().unwrap();
            std::process::exit(1);
        }
    }
}

fn try_parse() -> Result<Command> {
    trace!("parse");
    let cwd =
        env::current_dir().context("sccache: Couldn't determine current working directory")?;
    // The internal start server command is passed in the environment.
    let internal_start_server = match env::var("SCCACHE_START_SERVER") {
        Ok(val) => val == "1",
        Err(_) => false,
    };
    let mut args: Vec<_> = env::args_os().collect();
    if !internal_start_server {
        if let Ok(exe) = env::current_exe() {
            match exe
                .file_stem()
                .and_then(|s| s.to_str())
                .map(|s| s.to_lowercase())
            {
                // If the executable has its standard name, do nothing.
                Some(ref e) if e == env!("CARGO_PKG_NAME") => {}
                // Otherwise, if it was copied/hardlinked under a different $name, act
                // as if it were invoked with `sccache $name`, but avoid $name resolving
                // to ourselves again if it's in the PATH.
                _ => {
                    if let (Some(path), Some(exe_filename)) = (env::var_os("PATH"), exe.file_name())
                    {
                        match which_in(exe_filename, Some(&path), &cwd) {
                            Ok(ref full_path)
                                if full_path.canonicalize()? == exe.canonicalize()? =>
                            {
                                if let Some(dir) = full_path.parent() {
                                    let path = env::join_paths(
                                        env::split_paths(&path).filter(|p| p != dir),
                                    )
                                    .ok();
                                    if let Ok(full_path) = which_in(exe_filename, path, &cwd) {
                                        args[0] = full_path.into();
                                    }
                                }
                            }
                            Ok(full_path) => args[0] = full_path.into(),
                            Err(_) => {}
                        }
                        args.insert(0, env!("CARGO_PKG_NAME").into());
                    }
                }
            }
        }
    }

    let Opts {
        dist_auth,
        dist_status,
        show_stats,
        start_server,
        stop_server,
        zero_stats,
        package_toolchain,
        stats_format,
        cmd,
    } = Opts::parse_from(args);

    // Ensure that we've only received one command to run.
    if [
        dist_auth,
        dist_status,
        internal_start_server,
        show_stats,
        start_server,
        stop_server,
        zero_stats,
        !cmd.is_empty(),
        !package_toolchain.is_empty(),
    ]
    .iter()
    .filter(|&&x| x)
    .count()
        > 1
    {
        let mut clap_command = Opts::command();
        clap_command
            .error(ErrorKind::ArgumentConflict, "Only one command can be run")
            .exit();
    }

    if internal_start_server {
        Ok(Command::InternalStartServer)
    } else if show_stats {
        Ok(Command::ShowStats(stats_format))
    } else if start_server {
        Ok(Command::StartServer)
    } else if stop_server {
        Ok(Command::StopServer)
    } else if zero_stats {
        Ok(Command::ZeroStats)
    } else if dist_auth {
        Ok(Command::DistAuth)
    } else if dist_status {
        Ok(Command::DistStatus)
    } else if let [executable, out] = package_toolchain.as_slice() {
        Ok(Command::PackageToolchain(executable.into(), out.into()))
    } else if let [exe, cmdline @ ..] = cmd.as_slice() {
        let mut env_vars: Vec<_> = env::vars_os().collect();

        // If we're running under rr, avoid the `LD_PRELOAD` bits, as it will
        // almost surely do the wrong thing, as the compiler gets executed
        // in a different process tree.
        //
        // FIXME: Maybe we should strip out `LD_PRELOAD` always?
        if env::var_os("RUNNING_UNDER_RR").is_some() {
            env_vars.retain(|(k, _v)| k != "LD_PRELOAD" && k != "RUNNING_UNDER_RR");
        }

        Ok(Command::Compile {
            exe: exe.to_owned(),
            cmdline: cmdline.to_owned(),
            cwd,
            env_vars,
        })
    } else {
        let mut clap_command = Opts::command();
        clap_command
            .error(ErrorKind::ArgumentConflict, "No command specified")
            .exit();
    }
}
<commit_msg>Cleanup sccache cli parsing<commit_after>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::errors::*;
use clap::{ArgGroup, IntoApp, Parser};
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use which::which_in;

const ENV_VAR_SCCACHE_START_SERVER: &str = "SCCACHE_START_SERVER";

#[derive(clap::ArgEnum, Debug, Clone)]
pub enum StatsFormat {
    Text,
    Json,
}

impl Default for StatsFormat {
    fn default() -> Self {
        Self::Text
    }
}

/// A specific command to run.
pub enum Command {
    /// Show cache statistics and exit.
    ShowStats(StatsFormat),
    /// Run background server.
    InternalStartServer,
    /// Start background server as a subprocess.
    StartServer,
    /// Stop background server.
    StopServer,
    /// Zero cache statistics and exit.
    ZeroStats,
    /// Show the status of the distributed client.
    DistStatus,
    /// Perform a login to authenticate for distributed compilation.
    DistAuth,
    /// Package a toolchain for distributed compilation (executable, out)
    PackageToolchain(PathBuf, PathBuf),
    /// Run a compiler command.
    Compile {
        /// The binary to execute.
        exe: OsString,
        /// The commandline arguments to pass to `exe`.
        cmdline: Vec<OsString>,
        /// The directory in which to execute the command.
        cwd: PathBuf,
        /// The environment variables to use for execution.
        env_vars: Vec<(OsString, OsString)>,
    },
}

#[derive(Parser)]
#[clap(version)]
#[clap(trailing_var_arg = true)]
#[clap(after_help = concat!(
    "Enabled features:\n",
    "    S3:        ", cfg!(feature = "s3"), "\n",
    "    Redis:     ", cfg!(feature = "redis"), "\n",
    "    Memcached: ", cfg!(feature = "memcached"), "\n",
    "    GCS:       ", cfg!(feature = "gcs"), "\n",
    "    Azure:     ", cfg!(feature = "azure"), "\n")
)]
#[clap(group(
    ArgGroup::new("one_and_only_one")
        .args(&[
            "dist-auth",
            "dist-status",
            "show-stats",
            "start-server",
            "stop-server",
            "zero-stats",
            "package-toolchain",
            "cmd",
        ])
        .required(true)
))]
struct Opts {
    /// authenticate for distributed compilation
    #[clap(long)]
    dist_auth: bool,
    /// show status of the distributed client
    #[clap(long)]
    dist_status: bool,
    /// show cache statistics
    #[clap(short, long)]
    show_stats: bool,
    /// start background server
    #[clap(long, env = ENV_VAR_SCCACHE_START_SERVER, hide_env = true)]
    start_server: bool,
    /// stop background server
    #[clap(long)]
    stop_server: bool,
    /// zero statistic counters
    #[clap(short, long)]
    zero_stats: bool,

    /// package toolchain for distributed compilation
    #[clap(long, number_of_values = 2, value_names = &["EXECUTABLE", "OUT"])]
    package_toolchain: Vec<PathBuf>,
    /// set output format of statistics
    #[clap(long, arg_enum, value_name = "FORMAT", default_value_t = StatsFormat::default())]
    stats_format: StatsFormat,

    cmd: Vec<OsString>,
}

/// Parse the commandline into a `Command` to execute.
pub fn parse() -> Command {
    match try_parse() {
        Ok(cmd) => cmd,
        Err(e) => {
            println!("sccache: {e}");
            for e in e.chain().skip(1) {
                println!("sccache: caused by: {e}");
            }
            let mut clap_command = Opts::command();
            clap_command.print_help().unwrap();
            std::process::exit(1);
        }
    }
}

fn try_parse() -> Result<Command> {
    trace!("parse");
    let cwd =
        env::current_dir().context("sccache: Couldn't determine current working directory")?;
    let internal_start_server = env::var(ENV_VAR_SCCACHE_START_SERVER).as_deref() == Ok("1");

    let mut args: Vec<_> = env::args_os().collect();
    if !internal_start_server {
        // Internal start server is passed in the env, but we only care about it being `1`, unset it
        // otherwise so that the `ArgGroup` is enforced correctly
        env::remove_var(ENV_VAR_SCCACHE_START_SERVER);

        if let Ok(exe) = env::current_exe() {
            match exe
                .file_stem()
                .and_then(|s| s.to_str())
                .map(|s| s.to_lowercase())
            {
                // If the executable has its standard name, do nothing.
                Some(ref e) if e == env!("CARGO_PKG_NAME") => {}
                // Otherwise, if it was copied/hardlinked under a different $name, act
                // as if it were invoked with `sccache $name`, but avoid $name resolving
                // to ourselves again if it's in the PATH.
                _ => {
                    if let (Some(path), Some(exe_filename)) = (env::var_os("PATH"), exe.file_name())
                    {
                        match which_in(exe_filename, Some(&path), &cwd) {
                            Ok(ref full_path)
                                if full_path.canonicalize()? == exe.canonicalize()? =>
                            {
                                if let Some(dir) = full_path.parent() {
                                    let path = env::join_paths(
                                        env::split_paths(&path).filter(|p| p != dir),
                                    )
                                    .ok();
                                    if let Ok(full_path) = which_in(exe_filename, path, &cwd) {
                                        args[0] = full_path.into();
                                    }
                                }
                            }
                            Ok(full_path) => args[0] = full_path.into(),
                            Err(_) => {}
                        }
                        args.insert(0, env!("CARGO_PKG_NAME").into());
                    }
                }
            }
        }
    }

    let Opts {
        dist_auth,
        dist_status,
        show_stats,
        mut start_server,
        stop_server,
        zero_stats,
        package_toolchain,
        stats_format,
        cmd,
    } = Opts::parse_from(args);

    // `start_server` is used to smuggle `SCCACHE_START_SERVER` into the group since env var only
    // args aren't supported in `clap`
    if internal_start_server {
        start_server = false;
    }

    if internal_start_server {
        Ok(Command::InternalStartServer)
    } else if show_stats {
        Ok(Command::ShowStats(stats_format))
    } else if start_server {
        Ok(Command::StartServer)
    } else if stop_server {
        Ok(Command::StopServer)
    } else if zero_stats {
        Ok(Command::ZeroStats)
    } else if dist_auth {
        Ok(Command::DistAuth)
    } else if dist_status {
        Ok(Command::DistStatus)
    } else if let [executable, out] = package_toolchain.as_slice() {
        Ok(Command::PackageToolchain(executable.into(), out.into()))
    } else if let [exe, cmdline @ ..] = cmd.as_slice() {
        let mut env_vars: Vec<_> = env::vars_os().collect();

        // If we're running under rr, avoid the `LD_PRELOAD` bits, as it will
        // almost surely do the wrong thing, as the compiler gets executed
        // in a different process tree.
        //
        // FIXME: Maybe we should strip out `LD_PRELOAD` always?
        if env::var_os("RUNNING_UNDER_RR").is_some() {
            env_vars.retain(|(k, _v)| k != "LD_PRELOAD" && k != "RUNNING_UNDER_RR");
        }

        Ok(Command::Compile {
            exe: exe.to_owned(),
            cmdline: cmdline.to_owned(),
            cwd,
            env_vars,
        })
    } else {
        unreachable!("`ArgGroup` should enforce a single command to be run");
    }
}

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

    #[test]
    fn cli_debug_asserts() {
        Opts::command().debug_assert();
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Macros and wrapper functions for dealing with ioctls.

use std::os::raw::*;
use std::os::unix::io::AsRawFd;

/// Raw macro to declare the expression that calculates an ioctl number
#[macro_export]
macro_rules! ioctl_expr {
    ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
        (($dir << $crate::ioctl::_IOC_DIRSHIFT)
            | ($ty << $crate::ioctl::_IOC_TYPESHIFT)
            | ($nr << $crate::ioctl::_IOC_NRSHIFT)
            | ($size << $crate::ioctl::_IOC_SIZESHIFT)) as ::std::os::raw::c_ulong
    };
}

/// Raw macro to declare a function that returns an ioctl number.
#[macro_export]
macro_rules! ioctl_ioc_nr {
    ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
        #[allow(non_snake_case)]
        pub fn $name() -> ::std::os::raw::c_ulong {
            $crate::ioctl_expr!($dir, $ty, $nr, $size)
        }
    };
    ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
        #[allow(non_snake_case)]
        pub fn $name($($v: ::std::os::raw::c_uint),+) -> ::std::os::raw::c_ulong {
            $crate::ioctl_expr!($dir, $ty, $nr, $size)
        }
    };
}

/// Declare an ioctl that transfers no data.
#[macro_export]
macro_rules! ioctl_io_nr {
    ($name:ident, $ty:expr, $nr:expr) => {
        $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0);
    };
    ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
        $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
    };
}

/// Declare an ioctl that reads data.
#[macro_export]
macro_rules! ioctl_ior_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32,
            $($v),+
        );
    };
}

/// Declare an ioctl that writes data.
#[macro_export]
macro_rules! ioctl_iow_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32,
            $($v),+
        );
    };
}

/// Declare an ioctl that reads and writes data.
#[macro_export]
macro_rules! ioctl_iowr_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32,
            $($v),+
        );
    };
}

pub const _IOC_NRBITS: c_uint = 8;
pub const _IOC_TYPEBITS: c_uint = 8;
pub const _IOC_SIZEBITS: c_uint = 14;
pub const _IOC_DIRBITS: c_uint = 2;
pub const _IOC_NRMASK: c_uint = 255;
pub const _IOC_TYPEMASK: c_uint = 255;
pub const _IOC_SIZEMASK: c_uint = 16383;
pub const _IOC_DIRMASK: c_uint = 3;
pub const _IOC_NRSHIFT: c_uint = 0;
pub const _IOC_TYPESHIFT: c_uint = 8;
pub const _IOC_SIZESHIFT: c_uint = 16;
pub const _IOC_DIRSHIFT: c_uint = 30;
pub const _IOC_NONE: c_uint = 0;
pub const _IOC_WRITE: c_uint = 1;
pub const _IOC_READ: c_uint = 2;
pub const IOC_IN: c_uint = 1_073_741_824;
pub const IOC_OUT: c_uint = 2_147_483_648;
pub const IOC_INOUT: c_uint = 3_221_225_472;
pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
pub const IOCSIZE_SHIFT: c_uint = 16;

/// Run an ioctl with no arguments.
pub unsafe fn ioctl<F: AsRawFd>(fd: &F, nr: c_ulong) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, 0)
}

/// Run an ioctl with a single value argument.
pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, nr: c_ulong, arg: c_ulong) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg)
}

/// Run an ioctl with an immutable reference.
pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg as *const T as *const c_void)
}

/// Run an ioctl with a mutable reference.
pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &mut T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg as *mut T as *mut c_void)
}

/// Run an ioctl with a raw pointer.
pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *const T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg as *const c_void)
}

/// Run an ioctl with a mutable raw pointer.
pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *mut T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg as *mut c_void)
}

#[cfg(test)]
mod tests {
    const TUNTAP: ::std::os::raw::c_uint = 0x54;
    const VHOST: ::std::os::raw::c_uint = 0xaf;
    const EVDEV: ::std::os::raw::c_uint = 0x45;

    ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
    ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
    ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
    ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);

    ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
    ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);

    #[test]
    fn ioctl_macros() {
        assert_eq!(0x0000af01, VHOST_SET_OWNER());
        assert_eq!(0x800454cf, TUNGETFEATURES());
        assert_eq!(0x400454d9, TUNSETQUEUE());
        assert_eq!(0xc004af12, VHOST_GET_VRING_BASE());

        assert_eq!(0x80804522, EVIOCGBIT(2));
        assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
    }
}
<commit_msg>sys_util: Make ioctl number method a const fn<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Macros and wrapper functions for dealing with ioctls.

use std::os::raw::*;
use std::os::unix::io::AsRawFd;

/// Raw macro to declare the expression that calculates an ioctl number
#[macro_export]
macro_rules! ioctl_expr {
    ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
        (($dir << $crate::ioctl::_IOC_DIRSHIFT)
            | ($ty << $crate::ioctl::_IOC_TYPESHIFT)
            | ($nr << $crate::ioctl::_IOC_NRSHIFT)
            | ($size << $crate::ioctl::_IOC_SIZESHIFT)) as ::std::os::raw::c_ulong
    };
}

/// Raw macro to declare a function that returns an ioctl number.
#[macro_export]
macro_rules! ioctl_ioc_nr {
    ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
        #[allow(non_snake_case)]
        pub const fn $name() -> ::std::os::raw::c_ulong {
            $crate::ioctl_expr!($dir, $ty, $nr, $size)
        }
    };
    ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
        #[allow(non_snake_case)]
        pub const fn $name($($v: ::std::os::raw::c_uint),+) -> ::std::os::raw::c_ulong {
            $crate::ioctl_expr!($dir, $ty, $nr, $size)
        }
    };
}

/// Declare an ioctl that transfers no data.
#[macro_export]
macro_rules! ioctl_io_nr {
    ($name:ident, $ty:expr, $nr:expr) => {
        $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0);
    };
    ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
        $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
    };
}

/// Declare an ioctl that reads data.
#[macro_export]
macro_rules! ioctl_ior_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32,
            $($v),+
        );
    };
}

/// Declare an ioctl that writes data.
#[macro_export]
macro_rules! ioctl_iow_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32,
            $($v),+
        );
    };
}

/// Declare an ioctl that reads and writes data.
#[macro_export]
macro_rules! ioctl_iowr_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
        $crate::ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32,
            $($v),+
        );
    };
}

pub const _IOC_NRBITS: c_uint = 8;
pub const _IOC_TYPEBITS: c_uint = 8;
pub const _IOC_SIZEBITS: c_uint = 14;
pub const _IOC_DIRBITS: c_uint = 2;
pub const _IOC_NRMASK: c_uint = 255;
pub const _IOC_TYPEMASK: c_uint = 255;
pub const _IOC_SIZEMASK: c_uint = 16383;
pub const _IOC_DIRMASK: c_uint = 3;
pub const _IOC_NRSHIFT: c_uint = 0;
pub const _IOC_TYPESHIFT: c_uint = 8;
pub const _IOC_SIZESHIFT: c_uint = 16;
pub const _IOC_DIRSHIFT: c_uint = 30;
pub const _IOC_NONE: c_uint = 0;
pub const _IOC_WRITE: c_uint = 1;
pub const _IOC_READ: c_uint = 2;
pub const IOC_IN: c_uint = 1_073_741_824;
pub const IOC_OUT: c_uint = 2_147_483_648;
pub const IOC_INOUT: c_uint = 3_221_225_472;
pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
pub const IOCSIZE_SHIFT: c_uint = 16;

/// Run an ioctl with no arguments.
pub unsafe fn ioctl<F: AsRawFd>(fd: &F, nr: c_ulong) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, 0)
}

/// Run an ioctl with a single value argument.
pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, nr: c_ulong, arg: c_ulong) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg)
}

/// Run an ioctl with an immutable reference.
pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg as *const T as *const c_void)
}

/// Run an ioctl with a mutable reference.
pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &mut T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg as *mut T as *mut c_void)
}

/// Run an ioctl with a raw pointer.
pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *const T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg as *const c_void)
}

/// Run an ioctl with a mutable raw pointer.
pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *mut T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), nr, arg as *mut c_void)
}

#[cfg(test)]
mod tests {
    const TUNTAP: ::std::os::raw::c_uint = 0x54;
    const VHOST: ::std::os::raw::c_uint = 0xaf;
    const EVDEV: ::std::os::raw::c_uint = 0x45;

    ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
    ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
    ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
    ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);

    ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
    ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);

    #[test]
    fn ioctl_macros() {
        assert_eq!(0x0000af01, VHOST_SET_OWNER());
        assert_eq!(0x800454cf, TUNGETFEATURES());
        assert_eq!(0x400454d9, TUNSETQUEUE());
        assert_eq!(0xc004af12, VHOST_GET_VRING_BASE());

        assert_eq!(0x80804522, EVIOCGBIT(2));
        assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
    }
}
<|endoftext|>


<commit_before>/*
 * Simple web server in Rust.
 * For now, the pool_size argument is not used: there is at most only
 * one client at a time.
 */
extern mod std;
use std::getopts::*;
use std::net::tcp;
use std::net::ip;
use std::task;
use std::uv;
//use pipes::{stream, Port, Chan};

use StatusCodes::StatusCode;
mod StatusCodes {
   // HTTP Status code
   pub struct StatusCode(int);
   impl StatusCode {
      fn shortmsg(&self) -> &'static str {
        match **self {
            401 => "Not authorized",
            404 => "Not found",
            505 => "HTTP Version Not Supported",
            _   => {fail!(fmt!("shortmsg not implemented for error code %?", self));}
         }
      }
      fn longmsg(&self) -> &'static str {
         match **self {
            400 => "The request is not well-formatted",
            401 => "The file cannot be accessed",
            404 => "The requested resource could not be found",
            505 => "The server does not support the HTTP protocol version used in the request",
            _   => {fail!(fmt!("longmsg not implemented for error code %?", self));}
         }
      }
   }
}

// TODO: investigate core::unstable::Exclusive
type ConnectMsg = (tcp::TcpNewConnection, core::unstable::Exclusive<core::comm::Chan<Option<tcp::TcpErrData>>>);

fn print_usage(program: ~str) {
   fail!(fmt!("Usage: %s -p port -s pool_size -d web_dir", program));
}

// Another version to parse the arguments, which uses getopts
fn parse_arguments_with_getopts(args: ~[~str]) -> (uint, uint, ~str) {
   let opts = ~[
      optopt("p"),
      optopt("s"),
      optopt("d")
   ];
   let matches = match getopts(vec::tail(args), opts) {
      result::Ok(m) => { m }
      result::Err(f) => {fail!(fail_str(f));}
   };
   let port = uint::from_str(opt_str(&matches, "p")).get();
   let pool_size = uint::from_str(opt_str(&matches, "s")).get();
   let web_dir = opt_str(&matches, "d");

   if port == -1 || pool_size == -1 || web_dir == ~"" {
      io::println("Bad arguments values: ");
      print_usage(copy args[0]);
   }

   (port, pool_size, web_dir)
}

/* read the file path */
fn read_file(path: ~str) -> (~[u8], int) {
   let res = io::read_whole_file(&Path(path));
   if result::is_err(&res) {
      // XXX how to make the difference between file not found and not authorized?
      // In both cases res = Err(~"error opening file")
      (~[], 404)
   } else {
      (res.get(), 200)
   }
}

/*
 * Read an HTTP request and return a couple (line, code).
 * Block until a line has been read, in which case line is
 * the line that has been read and code=0, or return the line
 * that has been read so far and code=1 in case of error.
 */
fn read_request(socket: &tcp::TcpSocket) -> (~str, uint) {
   let mut req: ~str = ~"";
   loop {
      let result = socket.read(0u);
      if result.is_err() {
         return (req, 1);
      }

      let req2 = req + str::from_bytes(result.get());
      let req = req2;
      if str::contains(req, "\n") {
         return (req, 0);
      }
   }
}

fn clienterror(socket: &tcp::TcpSocket, cause: &str, errorcode: StatusCodes::StatusCode) {
   let errnum = errorcode.to_str();
   let shortmsg = errorcode.shortmsg();
   let longmsg = errorcode.longmsg();
   io::println(fmt!("Client error: %s -> %s %s %s", cause, errnum, shortmsg, longmsg));

   let body = ~"<title>Simple Web Server Error</title>\r\n"
      + fmt!("%s: %s\r\n", errnum, shortmsg)
      + fmt!("
%s: %s
\r\n", longmsg, cause)
      + ~"
The Simple Web Server\r\n";
   let header = fmt!("HTTP/1.0 %s %s\r\n", errnum, shortmsg) + ~"Content-type: text/html\r\n" + fmt!("Content-length: %u\r\n\r\n", body.len());

   socket.write(str::to_bytes(header));
   socket.write(str::to_bytes(body));
}

fn get_file_type(filename: &str) -> ~str {
   if str::ends_with(filename, ~".html") {
      ~"text/html"
   } else if str::ends_with(filename, ~".gif") {
      ~"image/gif"
   } else if str::ends_with(filename, ~".jpg") {
      ~"image/jpeg"
   } else {
      ~"text/plain"
   }
}

fn clientsuccess(socket: &tcp::TcpSocket, filename: &str, content: ~[u8]) {
   let filetype = get_file_type(filename);

   let header = ~"HTTP/1.0 200 OK\r\nServer: Simple Web Server\r\n"
      +fmt!("Content-length: %u\r\n", content.len())
      +fmt!("Content-type: %s\r\n\r\n", filetype);

   socket.write(str::to_bytes(header));
   socket.write(content);
}

fn handle_connection(port_endpoint: ~Port<ConnectMsg>, web_dir: ~str) {
   // this is the task which accepts new connections
   do task::spawn{
      loop {
         let (conn, kill_ch) = port_endpoint.recv();
         io::println("Going to accept a new connection");
         match tcp::accept(conn) {
            result::Err(err) => {
               io::println(fmt!("Connection error: %?", err));
               kill_ch.send(Some(err));
            },
            result::Ok(socket) => {
               let peer_addr: ~str = ip::format_addr(&socket.get_peer_addr());
               io::println(fmt!("Connection accepted from %s", peer_addr));

               let (request, code) = read_request(&socket);
               if code == 0 {
                  // FIXME: hacky
                  let mut words = ~[];
                  for str::each_word(request) |word| { words.push(word) }

                  if words.len() < 3 {
                     clienterror(&socket, request, StatusCode(400));
                  } else if words[0] != ~"GET" {
                     clienterror(&socket, request, StatusCode(501));
                  } else if words[2] != ~"HTTP/1.1" {
                     clienterror(&socket, request, StatusCode(505));
                  } else {
                     let (content, code) = read_file(web_dir + words[1]);
                     match code {
                        200 => {clientsuccess(&socket, copy words[1], content);},
                        404 => {clienterror(&socket, copy words[1], StatusCode(404));},
                        401 => {clienterror(&socket, copy words[1], StatusCode(401));},
                        _   => {fail!(fmt!("Unknown error code: %d", code));}
                     }
                  }
               }
            }
         }
      }
   }
}

fn main()  {
   let args : ~[~str] = os::args();
   if (args.len() != 7) {
      io::print("Bad length: ");
      print_usage(copy args[0]);
   }

   let (port, pool_size, web_dir) = parse_arguments_with_getopts(args);

   //to play with string concatenation
   io::println(~"Port: " + uint::to_str(port));
   io::println(~"Pool size: " + uint::to_str(pool_size));
   io::println(~"Web dir: " + web_dir);

   //Connection information will be transmitted using this Port and Chan
   let (port_endpoint, chan_endpoint): (Port<ConnectMsg>, Chan<ConnectMsg>) = stream();

   handle_connection(~port_endpoint, web_dir);

   let result = tcp::listen(ip::v4::parse_addr("127.0.0.1"), port, 100,
         &uv::global_loop::get(),
         |_|{
            io::println("Server is now listening!");
         },
         |conn, kill_chan| {
            // The connection must be accepted from another task or the server will block.
            chan_endpoint.send((conn, kill_chan));
         }
   );

   if result.is_err() {
      fail!(fmt!("Failed listen: %?", result.get_err()));
   }
}

<commit_msg>Call methods as methods instead of functions<commit_after>/*
 * Simple web server in Rust.
 * For now, the pool_size argument is not used: there is at most only
 * one client at a time.
 */
extern mod std;
use std::getopts::*;
use std::net::tcp;
use std::net::ip;
use std::task;
use std::uv;
//use pipes::{stream, Port, Chan};

use StatusCodes::StatusCode;
mod StatusCodes {
   // HTTP Status code
   pub struct StatusCode(int);
   impl StatusCode {
      fn shortmsg(&self) -> &'static str {
        match **self {
            401 => "Not authorized",
            404 => "Not found",
            505 => "HTTP Version Not Supported",
            _   => {fail!(fmt!("shortmsg not implemented for error code %?", self));}
         }
      }
      fn longmsg(&self) -> &'static str {
         match **self {
            400 => "The request is not well-formatted",
            401 => "The file cannot be accessed",
            404 => "The requested resource could not be found",
            505 => "The server does not support the HTTP protocol version used in the request",
            _   => {fail!(fmt!("longmsg not implemented for error code %?", self));}
         }
      }
   }
}

// TODO: investigate core::unstable::Exclusive
type ConnectMsg = (tcp::TcpNewConnection, core::unstable::Exclusive<core::comm::Chan<Option<tcp::TcpErrData>>>);

fn print_usage(program: ~str) {
   fail!(fmt!("Usage: %s -p port -s pool_size -d web_dir", program));
}

// Another version to parse the arguments, which uses getopts
fn parse_arguments_with_getopts(args: ~[~str]) -> (uint, uint, ~str) {
   let opts = ~[
      optopt("p"),
      optopt("s"),
      optopt("d")
   ];
   let matches = match getopts(vec::tail(args), opts) {
      result::Ok(m) => { m }
      result::Err(f) => {fail!(fail_str(f));}
   };
   let port = uint::from_str(opt_str(&matches, "p")).get();
   let pool_size = uint::from_str(opt_str(&matches, "s")).get();
   let web_dir = opt_str(&matches, "d");

   if port == -1 || pool_size == -1 || web_dir == ~"" {
      io::println("Bad arguments values: ");
      print_usage(copy args[0]);
   }

   (port, pool_size, web_dir)
}

/* read the file path */
fn read_file(path: ~str) -> (~[u8], int) {
   let res = io::read_whole_file(&Path(path));
   if result::is_err(&res) {
      // XXX how to make the difference between file not found and not authorized?
      // In both cases res = Err(~"error opening file")
      (~[], 404)
   } else {
      (res.get(), 200)
   }
}

/*
 * Read an HTTP request and return a couple (line, code).
 * Block until a line has been read, in which case line is
 * the line that has been read and code=0, or return the line
 * that has been read so far and code=1 in case of error.
 */
fn read_request(socket: &tcp::TcpSocket) -> (~str, uint) {
   let mut req: ~str = ~"";
   loop {
      let result = socket.read(0u);
      if result.is_err() {
         return (req, 1);
      }

      let req2 = req + str::from_bytes(result.get());
      let req = req2;
      if str::contains(req, "\n") {
         return (req, 0);
      }
   }
}

fn clienterror(socket: &tcp::TcpSocket, cause: &str, errorcode: StatusCodes::StatusCode) {
   let errnum = errorcode.to_str();
   let shortmsg = errorcode.shortmsg();
   let longmsg = errorcode.longmsg();
   io::println(fmt!("Client error: %s -> %s %s %s", cause, errnum, shortmsg, longmsg));

   let body = ~"<title>Simple Web Server Error</title>\r\n"
      + fmt!("%s: %s\r\n", errnum, shortmsg)
      + fmt!("
%s: %s
\r\n", longmsg, cause)
      + ~"
The Simple Web Server\r\n";
   let header = fmt!("HTTP/1.0 %s %s\r\n", errnum, shortmsg) + ~"Content-type: text/html\r\n" + fmt!("Content-length: %u\r\n\r\n", body.len());

   socket.write(header.to_bytes());
   socket.write(body.to_bytes());
}

fn get_file_type(filename: &str) -> ~str {
   if filename.ends_with(~".html") {
      ~"text/html"
   } else if filename.ends_with(~".gif") {
      ~"image/gif"
   } else if filename.ends_with(~".jpg") {
      ~"image/jpeg"
   } else {
      ~"text/plain"
   }
}

fn clientsuccess(socket: &tcp::TcpSocket, filename: &str, content: ~[u8]) {
   let filetype = get_file_type(filename);

   let header = ~"HTTP/1.0 200 OK\r\nServer: Simple Web Server\r\n"
      +fmt!("Content-length: %u\r\n", content.len())
      +fmt!("Content-type: %s\r\n\r\n", filetype);

   socket.write(header.to_bytes());
   socket.write(content);
}

fn handle_connection(port_endpoint: ~Port<ConnectMsg>, web_dir: ~str) {
   // this is the task which accepts new connections
   do task::spawn{
      loop {
         let (conn, kill_ch) = port_endpoint.recv();
         io::println("Going to accept a new connection");
         match tcp::accept(conn) {
            result::Err(err) => {
               io::println(fmt!("Connection error: %?", err));
               kill_ch.send(Some(err));
            },
            result::Ok(socket) => {
               let peer_addr: ~str = ip::format_addr(&socket.get_peer_addr());
               io::println(fmt!("Connection accepted from %s", peer_addr));

               let (request, code) = read_request(&socket);
               if code == 0 {
                  // FIXME: hacky
                  let mut words = ~[];
                  for str::each_word(request) |word| { words.push(word) }

                  if words.len() < 3 {
                     clienterror(&socket, request, StatusCode(400));
                  } else if words[0] != ~"GET" {
                     clienterror(&socket, request, StatusCode(501));
                  } else if words[2] != ~"HTTP/1.1" {
                     clienterror(&socket, request, StatusCode(505));
                  } else {
                     let (content, code) = read_file(web_dir + words[1]);
                     match code {
                        200 => {clientsuccess(&socket, copy words[1], content);},
                        404 => {clienterror(&socket, copy words[1], StatusCode(404));},
                        401 => {clienterror(&socket, copy words[1], StatusCode(401));},
                        _   => {fail!(fmt!("Unknown error code: %d", code));}
                     }
                  }
               }
            }
         }
      }
   }
}

fn main()  {
   let args : ~[~str] = os::args();
   if (args.len() != 7) {
      io::print("Bad length: ");
      print_usage(copy args[0]);
   }

   let (port, pool_size, web_dir) = parse_arguments_with_getopts(args);

   //to play with string concatenation
   io::println(~"Port: " + port.to_str());
   io::println(~"Pool size: " + pool_size.to_str());
   io::println(~"Web dir: " + web_dir);

   //Connection information will be transmitted using this Port and Chan
   let (port_endpoint, chan_endpoint): (Port<ConnectMsg>, Chan<ConnectMsg>) = stream();

   handle_connection(~port_endpoint, web_dir);

   let result = tcp::listen(ip::v4::parse_addr("127.0.0.1"), port, 100,
         &uv::global_loop::get(),
         |_|{
            io::println("Server is now listening!");
         },
         |conn, kill_chan| {
            // The connection must be accepted from another task or the server will block.
            chan_endpoint.send((conn, kill_chan));
         }
   );

   if result.is_err() {
      fail!(fmt!("Failed listen: %?", result.get_err()));
   }
}

<|endoftext|>


<commit_before>use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

static NTHREADS: i32 = 3;

fn main () {
    let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
    let mut children = Vec::new();
    for id in 0..NTHREADS {
        let thread_tx = tx.clone();

        let child = thread::spawn( move || {
            thread_tx.send(id).unwrap();
            println!("thread {} finished ", id);
        });
        children.push(child);
    }

    let mut ids = Vec::with_capacity(NTHREADS as usize);
    for _ in 0..NTHREADS {
        ids.push(rx.recv());
    }

    for child in children {
        child.join().expect("oop!, the childern thread panicked");
    }
    println!("{:?}", ids);
}
<commit_msg>added changes in channel<commit_after>use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

static NTHREADS: i32 = 3;

pub struct Hello;
impl Hello {
    pub fn hello_world (self) {
        println!("hello world");
    }
}
fn main () {
    let hello = Hello{};
    thread::spawn(hello.hello_world());

    let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
    let mut children = Vec::new();
    for id in 0..NTHREADS {
        let thread_tx = tx.clone();

        let child = thread::spawn( move || {
            thread_tx.send(id).unwrap();
            println!("thread {} finished ", id);
        });
        children.push(child);
    }

    let mut ids = Vec::with_capacity(NTHREADS as usize);
    for _ in 0..NTHREADS {
        ids.push(rx.recv());
    }

    for child in children {
        child.join().expect("oop!, the childern thread panicked");
    }
    println!("{:?}", ids);
}
<|endoftext|>