<commit_before>#![deny(missing_docs)]
#![feature(unsafe_destructor)]
#![feature(associated_types)]
#![unstable]

//! A library for setting current values for stack scope,
//! such as application structure.

use std::cell::RefCell;
use std::intrinsics::TypeId;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::ops::{ Deref, DerefMut };

// Stores the current pointers for concrete types.
thread_local!(static KEY_CURRENT: RefCell<HashMap<TypeId, uint>>
    = RefCell::new(HashMap::new()));

/// Puts back the previous current pointer.
#[unstable]
pub struct CurrentGuard<'a, T: 'a> {
    _val: &'a mut T,
    old_ptr: Option<uint>
}

#[unstable]
impl<'a, T: 'static> CurrentGuard<'a, T> {
    /// Creates a new current guard.
    #[unstable]
    pub fn new(val: &mut T) -> CurrentGuard<T> {
        let id = TypeId::of::<T>();
        let ptr = val as *mut T as uint;
        let old_ptr = KEY_CURRENT.with(|current| {
            match current.borrow_mut().entry(&id) {
                Occupied(mut entry) => Some(entry.insert(ptr)),
                Vacant(entry) => {
                    entry.insert(ptr);
                    None
                }
            }
        });
        CurrentGuard { old_ptr: old_ptr, _val: val }
    }
}

#[unsafe_destructor]
impl<'a, T: 'static> Drop for CurrentGuard<'a, T> {
    fn drop(&mut self) {
        let id = TypeId::of::<T>();
        match self.old_ptr {
            None => {
                KEY_CURRENT.with(|current| {
                    current.borrow_mut().remove(&id);
                });
                return;
            }
            Some(old_ptr) => {
                KEY_CURRENT.with(|current| {
                    match current.borrow_mut().entry(&id) {
                        Occupied(mut entry) => { entry.insert(old_ptr); }
                        Vacant(entry) => { entry.insert(old_ptr); }
                    };
                });
            }
        };
    }
}

/// The current value of a type.
#[unstable]
pub struct Current<T>(());

#[unstable]
impl<T: 'static> Current<T> {
    /// Creates a new current object
    #[unstable]
    pub unsafe fn new() -> Current<T> { Current(()) }

    /// Gets mutable reference to current object.
    /// Requires mutable reference to prevent access to globals in safe code,
    /// and to prevent mutable borrows of same value in scope.
    /// Is unsafe because returned reference inherits lifetime from argument.
    #[unstable]
    pub unsafe fn current(&mut self) -> Option<&mut T> {
        use std::mem::transmute;
        let id = TypeId::of::<T>();
        let ptr: Option<uint> = KEY_CURRENT.with(|current| {
                current.borrow().get(&id).map(|id| *id)
            });
        let ptr = match ptr { None => { return None; } Some(x) => x };
        Some(transmute(ptr as *mut T))
    }

    /// Unwraps mutable reference to current object,
    /// but with nicer error message.
    #[unstable]
    pub unsafe fn current_unwrap(&mut self) -> &mut T {
        match self.current() {
            None => {
                use std::intrinsics::get_tydesc;
                let name = (*get_tydesc::<T>()).name;
                panic!("No current `{}` is set", name);
            }
            Some(x) => x
        }
    }
}

impl<T: 'static> Deref for Current<T> {
    type Target = T;

    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        use std::mem::transmute;
        unsafe {
            // Current does not contain anything,
            // so it is safe to transmute to mutable.
            transmute::<_, &'a mut Current<T>>(self).current_unwrap()
        }
    }
}

impl<T: 'static> DerefMut for Current<T> {
    #[inline(always)]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { self.current_unwrap() }
    }
}
<commit_msg>Upgraded to latest Rust<commit_after>#![deny(missing_docs)]
#![feature(unsafe_destructor)]
#![unstable]

//! A library for setting current values for stack scope,
//! such as application structure.

use std::cell::RefCell;
use std::intrinsics::TypeId;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::ops::{ Deref, DerefMut };

// Stores the current pointers for concrete types.
thread_local!(static KEY_CURRENT: RefCell<HashMap<TypeId, uint>>
    = RefCell::new(HashMap::new()));

/// Puts back the previous current pointer.
#[unstable]
pub struct CurrentGuard<'a, T: 'a> {
    _val: &'a mut T,
    old_ptr: Option<uint>
}

#[unstable]
impl<'a, T: 'static> CurrentGuard<'a, T> {
    /// Creates a new current guard.
    #[unstable]
    pub fn new(val: &mut T) -> CurrentGuard<T> {
        let id = TypeId::of::<T>();
        let ptr = val as *mut T as uint;
        let old_ptr = KEY_CURRENT.with(|current| {
            match current.borrow_mut().entry(&id) {
                Occupied(mut entry) => Some(entry.insert(ptr)),
                Vacant(entry) => {
                    entry.insert(ptr);
                    None
                }
            }
        });
        CurrentGuard { old_ptr: old_ptr, _val: val }
    }
}

#[unsafe_destructor]
impl<'a, T: 'static> Drop for CurrentGuard<'a, T> {
    fn drop(&mut self) {
        let id = TypeId::of::<T>();
        match self.old_ptr {
            None => {
                KEY_CURRENT.with(|current| {
                    current.borrow_mut().remove(&id);
                });
                return;
            }
            Some(old_ptr) => {
                KEY_CURRENT.with(|current| {
                    match current.borrow_mut().entry(&id) {
                        Occupied(mut entry) => { entry.insert(old_ptr); }
                        Vacant(entry) => { entry.insert(old_ptr); }
                    };
                });
            }
        };
    }
}

/// The current value of a type.
#[unstable]
pub struct Current<T>(());

#[unstable]
impl<T: 'static> Current<T> {
    /// Creates a new current object
    #[unstable]
    pub unsafe fn new() -> Current<T> { Current(()) }

    /// Gets mutable reference to current object.
    /// Requires mutable reference to prevent access to globals in safe code,
    /// and to prevent mutable borrows of same value in scope.
    /// Is unsafe because returned reference inherits lifetime from argument.
    #[unstable]
    pub unsafe fn current(&mut self) -> Option<&mut T> {
        use std::mem::transmute;
        let id = TypeId::of::<T>();
        let ptr: Option<uint> = KEY_CURRENT.with(|current| {
                current.borrow().get(&id).map(|id| *id)
            });
        let ptr = match ptr { None => { return None; } Some(x) => x };
        Some(transmute(ptr as *mut T))
    }

    /// Unwraps mutable reference to current object,
    /// but with nicer error message.
    #[unstable]
    pub unsafe fn current_unwrap(&mut self) -> &mut T {
        match self.current() {
            None => {
                use std::intrinsics::get_tydesc;
                let name = (*get_tydesc::<T>()).name;
                panic!("No current `{}` is set", name);
            }
            Some(x) => x
        }
    }
}

impl<T: 'static> Deref for Current<T> {
    type Target = T;

    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        use std::mem::transmute;
        unsafe {
            // Current does not contain anything,
            // so it is safe to transmute to mutable.
            transmute::<_, &'a mut Current<T>>(self).current_unwrap()
        }
    }
}

impl<T: 'static> DerefMut for Current<T> {
    #[inline(always)]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { self.current_unwrap() }
    }
}
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(custom_attribute)]
#![feature(box_syntax)]
#![feature(box_patterns)]
#![feature(asm)]
#![feature(step_by)]
#![feature(alloc)]
#![feature(associated_type_defaults)]
#![feature(drop_types_in_const)]
#![no_std]

#[macro_use]
extern crate bitflags;
extern crate rlibc;
extern crate spin;
extern crate x86;
extern crate alloc;

#[macro_use]
mod vga_buffer;
mod multiboot2;
mod common;
mod cap;
mod utils;

use common::*;
use cap::{MemoryBlock, UntypedCapability,
          FrameCapability, GuardedCapability,
          CapabilityPool, CapabilityMove,
          PageTableCapability
};

use core::mem;
use x86::{controlregs, tlb};

#[no_mangle]
pub extern fn rust_main(multiboot_information_address: usize) {
    enable_nxe_bit();
    enable_write_protect_bit();

    vga_buffer::clear_screen();

    let mut cap_pool = CapabilityPool::new();

    let boot_info = unsafe { multiboot2::load(multiboot_information_address) };
    let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required");
    let elf_sections_tag = boot_info.elf_sections_tag().expect("Elf-sections tag required");

    println!("Memory areas:");
    for area in memory_map_tag.memory_areas() {
        println!("    start: 0x{:x}, length: 0x{:x}", area.base_addr, area.length);
        cap_pool.put(unsafe { UntypedCapability::bootstrap(area.base_addr as PhysicalAddress, area.length as usize) });
    }

    let kernel_start = elf_sections_tag.sections().map(|s| s.addr).min().unwrap() as usize;
    let kernel_end = elf_sections_tag.sections().map(|s| s.addr + s.size - 1).max().unwrap() as usize;

    let multiboot_start = multiboot_information_address as usize;
    let multiboot_end = multiboot_start + (boot_info.total_size as usize) - 1;

    println!("Kernel start: 0x{:x}, end: 0x{:x}", kernel_start, kernel_end);
    println!("Multiboot start: 0x{:x}, end: 0x{:x}", multiboot_start, multiboot_end);

    let mut page_untyped = cap_pool.select(|x: &UntypedCapability| {
        x.block().start_addr() <= kernel_start &&
            x.block().end_addr() >= kernel_end &&
            x.block().start_addr() <= multiboot_start &&
            x.block().end_addr() >= multiboot_end
    }).expect("Unexcepted multiboot memory allocation.");

    let mut kernel_untyped = {
        let target_block_start_addr = page_untyped.block().physical_start_addr();
        UntypedCapability::from_untyped(&mut page_untyped, multiboot_end - target_block_start_addr + 1)
    };

    println!("Page untyped start address: 0x{:x}.", page_untyped.block().start_addr());

    let mut kernel_page_table = PageTableCapability::from_untyped(&mut page_untyped, 0x7e0000000, 512);
    println!("Inactive page table capability address: 0x{:x}.", kernel_page_table.p4_block().start_addr());

    let cr3 = unsafe { controlregs::cr3() as usize };

    println!("Kernel sections:");
    for section in elf_sections_tag.sections() {
        use multiboot2::ELF_SECTION_ALLOCATED;

        println!("    addr: 0x{:x}, size: 0x{:x}, flags: 0x{:x}",
                 section.addr, section.size, section.flags);

        let section_size = section.size as usize;
        let section_addr = section.addr as usize;
        let untyped_start_addr = kernel_untyped.block().start_addr();

        assert!(untyped_start_addr <= section_addr);

        if !section.flags().contains(ELF_SECTION_ALLOCATED) {
            // section is not loaded to memory

            let reserved = GuardedCapability::from_untyped_fixed(&mut kernel_untyped,
                                                                 section_addr, section_size);
            cap_pool.put(reserved);
        } else {
            // section loaded to memory

            assert!(section_addr % PAGE_SIZE == 0);
            let flags = EntryFlags::from_elf_section_flags(&section);

            let reserved = if cr3 >= section_addr && cr3 < section_addr + section_size {
                assert!(cr3 == section_addr);

                // There will be one guarded page directly on the old P4 table.
                let guarded = GuardedCapability::from_untyped_fixed(&mut kernel_untyped, cr3, PAGE_SIZE);
                cap_pool.put(guarded);

                println!("    (Stack guarded page initialized at: 0x{:x}.)", cr3);

                FrameCapability::from_untyped_fixed(&mut kernel_untyped, cr3 + PAGE_SIZE,
                                                    utils::necessary_page_count(section_size - PAGE_SIZE),
                                                    flags)
            } else {
                FrameCapability::from_untyped_fixed(&mut kernel_untyped, section_addr,
                                                    utils::necessary_page_count(section_size), flags)
            };

            // println!("    (Identity mapping ...)");
            let frame_start_addr = reserved.block().start_addr();
            let frame_count = reserved.count();

            kernel_page_table.create_tables_and_identity_map(reserved, &mut page_untyped);
        }
    }

    unsafe {
        kernel_page_table.create_tables_and_map_vga_buffer(&mut page_untyped);
        kernel_page_table.switch_on();
    }

    println!("Available slots in kernel's capability pool: {}.", cap_pool.available_count());
    println!("Yeah, the kernel did not crash!");

    let test_page_table = PageTableCapability::from_untyped(&mut page_untyped, 0x7e0000000, 512);

    println!("Test page table created successfullly.");

    cap_pool.put(page_untyped);
    cap_pool.put(kernel_untyped);

    loop{}
}

fn stack_overflow(i: usize) {
    stack_overflow(i+1)
}

fn enable_nxe_bit() {
    use x86::msr::{IA32_EFER, rdmsr, wrmsr};

    let nxe_bit = 1 << 11;
    unsafe {
        let efer = rdmsr(IA32_EFER);
        wrmsr(IA32_EFER, efer | nxe_bit);
    }
}

fn enable_write_protect_bit() {
    use x86::controlregs::{cr0, cr0_write};

    let wp_bit = 1 << 16;
    unsafe { cr0_write(cr0() | wp_bit) };
}

#[lang = "eh_personality"] extern fn eh_personality() { }
#[lang = "panic_fmt"]
extern fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! {
    println!("\n\nPANIC in {} at line {}:", file, line);
    println!("    {}", fmt);
    loop{}
}
<commit_msg>WIP: switch to user mode<commit_after>#![feature(lang_items)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(custom_attribute)]
#![feature(box_syntax)]
#![feature(box_patterns)]
#![feature(asm)]
#![feature(step_by)]
#![feature(alloc)]
#![feature(associated_type_defaults)]
#![feature(drop_types_in_const)]
#![no_std]

#[macro_use]
extern crate bitflags;
extern crate rlibc;
extern crate spin;
extern crate x86;
extern crate alloc;

#[macro_use]
mod vga_buffer;
mod multiboot2;
mod common;
mod cap;
mod utils;

use common::*;
use cap::{MemoryBlock, UntypedCapability,
          FrameCapability, GuardedCapability,
          CapabilityPool, CapabilityMove,
          PageTableCapability
};

use core::mem;
use x86::{controlregs, tlb};

#[no_mangle]
pub extern fn rust_main(multiboot_information_address: usize) {
    enable_nxe_bit();
    enable_write_protect_bit();

    vga_buffer::clear_screen();

    let mut cap_pool = CapabilityPool::new();

    let boot_info = unsafe { multiboot2::load(multiboot_information_address) };
    let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required");
    let elf_sections_tag = boot_info.elf_sections_tag().expect("Elf-sections tag required");

    println!("Memory areas:");
    for area in memory_map_tag.memory_areas() {
        println!("    start: 0x{:x}, length: 0x{:x}", area.base_addr, area.length);
        cap_pool.put(unsafe { UntypedCapability::bootstrap(area.base_addr as PhysicalAddress, area.length as usize) });
    }

    let kernel_start = elf_sections_tag.sections().map(|s| s.addr).min().unwrap() as usize;
    let kernel_end = elf_sections_tag.sections().map(|s| s.addr + s.size - 1).max().unwrap() as usize;

    let multiboot_start = multiboot_information_address as usize;
    let multiboot_end = multiboot_start + (boot_info.total_size as usize) - 1;

    println!("Kernel start: 0x{:x}, end: 0x{:x}", kernel_start, kernel_end);
    println!("Multiboot start: 0x{:x}, end: 0x{:x}", multiboot_start, multiboot_end);

    let mut page_untyped = cap_pool.select(|x: &UntypedCapability| {
        x.block().start_addr() <= kernel_start &&
            x.block().end_addr() >= kernel_end &&
            x.block().start_addr() <= multiboot_start &&
            x.block().end_addr() >= multiboot_end
    }).expect("Unexcepted multiboot memory allocation.");

    let mut kernel_untyped = {
        let target_block_start_addr = page_untyped.block().physical_start_addr();
        UntypedCapability::from_untyped(&mut page_untyped, multiboot_end - target_block_start_addr + 1)
    };

    println!("Page untyped start address: 0x{:x}.", page_untyped.block().start_addr());

    let mut kernel_page_table = PageTableCapability::from_untyped(&mut page_untyped, 0x7e0000000, 512);
    println!("Inactive page table capability address: 0x{:x}.", kernel_page_table.p4_block().start_addr());

    let cr3 = unsafe { controlregs::cr3() as usize };

    println!("Kernel sections:");
    for section in elf_sections_tag.sections() {
        use multiboot2::ELF_SECTION_ALLOCATED;

        println!("    addr: 0x{:x}, size: 0x{:x}, flags: 0x{:x}",
                 section.addr, section.size, section.flags);

        let section_size = section.size as usize;
        let section_addr = section.addr as usize;
        let untyped_start_addr = kernel_untyped.block().start_addr();

        assert!(untyped_start_addr <= section_addr);

        if !section.flags().contains(ELF_SECTION_ALLOCATED) {
            // section is not loaded to memory

            let reserved = GuardedCapability::from_untyped_fixed(&mut kernel_untyped,
                                                                 section_addr, section_size);
            cap_pool.put(reserved);
        } else {
            // section loaded to memory

            assert!(section_addr % PAGE_SIZE == 0);
            let flags = EntryFlags::from_elf_section_flags(&section);

            let reserved = if cr3 >= section_addr && cr3 < section_addr + section_size {
                assert!(cr3 == section_addr);

                // There will be one guarded page directly on the old P4 table.
                let guarded = GuardedCapability::from_untyped_fixed(&mut kernel_untyped, cr3, PAGE_SIZE);
                cap_pool.put(guarded);

                println!("    (Stack guarded page initialized at: 0x{:x}.)", cr3);

                FrameCapability::from_untyped_fixed(&mut kernel_untyped, cr3 + PAGE_SIZE,
                                                    utils::necessary_page_count(section_size - PAGE_SIZE),
                                                    flags)
            } else {
                FrameCapability::from_untyped_fixed(&mut kernel_untyped, section_addr,
                                                    utils::necessary_page_count(section_size), flags)
            };

            // println!("    (Identity mapping ...)");
            let frame_start_addr = reserved.block().start_addr();
            let frame_count = reserved.count();

            kernel_page_table.create_tables_and_identity_map(reserved, &mut page_untyped);
        }
    }

    unsafe {
        kernel_page_table.create_tables_and_map_vga_buffer(&mut page_untyped);
        kernel_page_table.switch_on();
    }

    println!("Available slots in kernel's capability pool: {}.", cap_pool.available_count());
    println!("Yeah, the kernel did not crash!");

    let test_page_table = PageTableCapability::from_untyped(&mut page_untyped, 0x7e0000000, 512);

    println!("Test page table created successfullly.");

    cap_pool.put(page_untyped);
    cap_pool.put(kernel_untyped);

    unsafe {
        asm!("mov rax, [esp + 32]
              mov ds, rax
              mov es, rax
              mov fs, rax
              mov gs, rax
              iretq" : : : "memory" : "intel", "volatile");
    }

    loop{}
}

fn stack_overflow(i: usize) {
    stack_overflow(i+1)
}

fn enable_nxe_bit() {
    use x86::msr::{IA32_EFER, rdmsr, wrmsr};

    let nxe_bit = 1 << 11;
    unsafe {
        let efer = rdmsr(IA32_EFER);
        wrmsr(IA32_EFER, efer | nxe_bit);
    }
}

fn enable_write_protect_bit() {
    use x86::controlregs::{cr0, cr0_write};

    let wp_bit = 1 << 16;
    unsafe { cr0_write(cr0() | wp_bit) };
}

#[lang = "eh_personality"] extern fn eh_personality() { }
#[lang = "panic_fmt"]
extern fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! {
    println!("\n\nPANIC in {} at line {}:", file, line);
    println!("    {}", fmt);
    loop{}
}
<|endoftext|>


<commit_before>#![experimental]

extern crate hyper;
extern crate url;

use hyper::Url;
use hyper::client::Request;
use hyper::method::{Get, Post, Delete, Put, Patch};

use std::fmt::{mod, Show};
use std::io::IoError;
use url::ParseError;
use hyper::HttpError;
use hyper::header::common::ContentLength;
use hyper::header::common::ContentType;

pub struct RestClient;

impl RestClient {
    // TODO: add cookies

    pub fn get(url_str:&str) -> Result<Response, RestError> {
        RestClient::new(Get, url_str, None, None, None)
    }

    pub fn get_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::new(Get, url_str, Some(params), None, None)
    }

    pub fn post_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::pstar_with_params( Post, url_str, params )
    }

    pub fn post(url_str:&str, body:&str, content_type:&str) -> Result<Response, RestError> {
        RestClient::pstar( Post, url_str, body, content_type )
    }

    pub fn patch_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::pstar_with_params( Patch, url_str, params )
    }

    pub fn patch(url_str:&str, body:&str, content_type:&str) -> Result<Response, RestError> {
        RestClient::pstar( Patch, url_str, body, content_type )
    }

    pub fn put_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::pstar_with_params( Put, url_str, params )
    }

    pub fn put(url_str:&str, body:&str, content_type:&str) -> Result<Response, RestError> {
        RestClient::pstar( Put, url_str, body, content_type )
    }

    pub fn delete(url_str:&str) -> Result<Response, RestError> {
        RestClient::new(Delete, url_str, None, None, None)
    }

    pub fn delete_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::new(Delete, url_str, Some(params), None, None)
    }

    fn pstar_with_params( method:hyper::method::Method, url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        let mut params_vec = Vec::new();
        for param in params.iter() {
            params_vec.push(*param);
        }

        let post_body = url::form_urlencoded::serialize(params_vec.into_iter(), None);

        RestClient::pstar( method, url_str, post_body.as_slice(), "application/x-www-form-urlencoded" )
    }

    fn pstar(method:hyper::method::Method, url_str:&str, body:&str, content_type:&str) -> Result<Response, RestError> {
        RestClient::new( method, url_str, None, Some(body), Some(content_type) )
    }

    pub fn new(method:hyper::method::Method, url_str:&str, url_params:Option<&[(&str, &str)]>, body:Option<&str>, content_type:Option<&str>) -> Result<Response, RestError> {
        let mut url = match Url::parse(url_str) {
            Ok(url) => url,
            Err(err) => return Err(UrlParseError(err))
        };

        match url_params {
            Some(params) => {
                let mut params_vec = Vec::new();
                for param in params.iter() {
                    params_vec.push(*param);
                }

                // TODO: write article talking about iter() vs into_iter()
                url.set_query_from_pairs(params_vec.into_iter());
            },
            None => ()
        };

        let mut req = match Request::new(method, url) {
            Ok(req) => req,
            Err(err) => return Err(HttpRequestError(err))
        };

        match body {
            Some(body) =>
                req.headers_mut().set(ContentLength(body.len())),
            None =>
                // needed so that hyper doesn't try to send Transfer-Encoding:
                // Chunked, which causes some servers (e.g. www.reddit.co) to
                // hang. is this a bug in the hyper client? why would it send
                // T-E: Ch as a header in a GET request?
                req.headers_mut().set(ContentLength(0))
        };

        match content_type {
            Some(content_type) =>
                req.headers_mut().set(ContentType(from_str(content_type).unwrap())),
            None => ()
        };

        let mut req_started = match req.start() {
            Ok(req) => req,
            Err(err) => return Err(HttpRequestError(err))
        };

        match body {
            Some(body) =>
                match req_started.write(body.as_bytes()) {
                    Ok(()) => (),
                    Err(err) => return Err(HttpIoError(err))
                },
            None => ()
        };

        let mut resp = match req_started.send() {
            Ok(resp) => resp,
            Err(err) => return Err(HttpRequestError(err))
        };

        let body = match resp.read_to_string() {
            Ok(body) => body,
            Err(err) => return Err(HttpIoError(err))
        };

        let rest_response = Response {
            code: resp.status as i32,
            status: resp.status,
            headers: resp.headers,
            body: body,
        };

        return Ok(rest_response);
    }
}

pub struct Response {
    pub code: i32,
    pub status: hyper::status::StatusCode,
    pub headers: hyper::header::Headers,
    pub body: String,
}

impl Show for Response {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.body.fmt(fmt)
    }
}

#[deriving(Show, PartialEq, Clone)]
pub enum RestError {
    UrlParseError(ParseError),
    HttpRequestError(HttpError),
    HttpIoError(IoError)
}

#[test]
fn it_works() {
}
<commit_msg>Using 'to_vec()' instead of manually building my own vector of params. Still need to do it in order to translate to the required "into" iterator type.<commit_after>#![experimental]

extern crate hyper;
extern crate url;

use hyper::Url;
use hyper::client::Request;
use hyper::method::{Get, Post, Delete, Put, Patch};

use std::fmt::{mod, Show};
use std::io::IoError;
use url::ParseError;
use hyper::HttpError;
use hyper::header::common::ContentLength;
use hyper::header::common::ContentType;

pub struct RestClient;

impl RestClient {
    // TODO: add cookies

    pub fn get(url_str:&str) -> Result<Response, RestError> {
        RestClient::new(Get, url_str, None, None, None)
    }

    pub fn get_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::new(Get, url_str, Some(params), None, None)
    }

    pub fn post_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::pstar_with_params( Post, url_str, params )
    }

    pub fn post(url_str:&str, body:&str, content_type:&str) -> Result<Response, RestError> {
        RestClient::pstar( Post, url_str, body, content_type )
    }

    pub fn patch_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::pstar_with_params( Patch, url_str, params )
    }

    pub fn patch(url_str:&str, body:&str, content_type:&str) -> Result<Response, RestError> {
        RestClient::pstar( Patch, url_str, body, content_type )
    }

    pub fn put_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::pstar_with_params( Put, url_str, params )
    }

    pub fn put(url_str:&str, body:&str, content_type:&str) -> Result<Response, RestError> {
        RestClient::pstar( Put, url_str, body, content_type )
    }

    pub fn delete(url_str:&str) -> Result<Response, RestError> {
        RestClient::new(Delete, url_str, None, None, None)
    }

    pub fn delete_with_params(url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        RestClient::new(Delete, url_str, Some(params), None, None)
    }

    fn pstar_with_params( method:hyper::method::Method, url_str:&str, params:&[(&str, &str)]) -> Result<Response, RestError> {
        let post_body = url::form_urlencoded::serialize(params.to_vec().into_iter(), None);

        RestClient::pstar( method, url_str, post_body.as_slice(), "application/x-www-form-urlencoded" )
    }

    fn pstar(method:hyper::method::Method, url_str:&str, body:&str, content_type:&str) -> Result<Response, RestError> {
        RestClient::new( method, url_str, None, Some(body), Some(content_type) )
    }

    pub fn new(method:hyper::method::Method, url_str:&str, url_params:Option<&[(&str, &str)]>, body:Option<&str>, content_type:Option<&str>) -> Result<Response, RestError> {
        let mut url = match Url::parse(url_str) {
            Ok(url) => url,
            Err(err) => return Err(UrlParseError(err))
        };

        match url_params {
            Some(params) => {
                // TODO: write article talking about iter() vs into_iter()
                url.set_query_from_pairs(params.to_vec().into_iter());
            },
            None => ()
        };

        let mut req = match Request::new(method, url) {
            Ok(req) => req,
            Err(err) => return Err(HttpRequestError(err))
        };

        match body {
            Some(body) =>
                req.headers_mut().set(ContentLength(body.len())),
            None =>
                // needed so that hyper doesn't try to send Transfer-Encoding:
                // Chunked, which causes some servers (e.g. www.reddit.co) to
                // hang. is this a bug in the hyper client? why would it send
                // T-E: Ch as a header in a GET request?
                req.headers_mut().set(ContentLength(0))
        };

        match content_type {
            Some(content_type) =>
                req.headers_mut().set(ContentType(from_str(content_type).unwrap())),
            None => ()
        };

        let mut req_started = match req.start() {
            Ok(req) => req,
            Err(err) => return Err(HttpRequestError(err))
        };

        match body {
            Some(body) =>
                match req_started.write(body.as_bytes()) {
                    Ok(()) => (),
                    Err(err) => return Err(HttpIoError(err))
                },
            None => ()
        };

        let mut resp = match req_started.send() {
            Ok(resp) => resp,
            Err(err) => return Err(HttpRequestError(err))
        };

        let body = match resp.read_to_string() {
            Ok(body) => body,
            Err(err) => return Err(HttpIoError(err))
        };

        let rest_response = Response {
            code: resp.status as i32,
            status: resp.status,
            headers: resp.headers,
            body: body,
        };

        return Ok(rest_response);
    }
}

pub struct Response {
    pub code: i32,
    pub status: hyper::status::StatusCode,
    pub headers: hyper::header::Headers,
    pub body: String,
}

impl Show for Response {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.body.fmt(fmt)
    }
}

#[deriving(Show, PartialEq, Clone)]
pub enum RestError {
    UrlParseError(ParseError),
    HttpRequestError(HttpError),
    HttpIoError(IoError)
}

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>//! [![ggez logo](docs/ggez-logo-maroon-full.svg)](http://ggez.rs/)
//!
//! # What is this?
//!
//! ![Build status](https://github.com/ggez/ggez/workflows/CI/badge.svg)
//! [![Docs Status](https://docs.rs/ggez/badge.svg)](https://docs.rs/ggez)
//! [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ggez/ggez/blob/master/LICENSE)
//! [![Crates.io](https://img.shields.io/crates/v/ggez.svg)](https://crates.io/crates/ggez)
//! [![Crates.io](https://img.shields.io/crates/d/ggez.svg)](https://crates.io/crates/ggez)
//!
//! ggez is a Rust library to create a Good Game Easily.
//!
//! More specifically, ggez is a lightweight cross-platform game framework
//! for making 2D games with minimum friction.  It aims to implement an
//! API based on (a Rustified version of) the [LÖVE](https://love2d.org/)
//! game framework.  This means it contains basic and portable 2D
//! drawing, sound, resource loading and event handling, but finer details
//! and performance characteristics may be different than LÖVE.
//!
//! ggez is not meant to be everything to everyone, but rather a good
//! base upon which to build.  Thus it takes a fairly
//! batteries-included approach without needing a million additions
//! and plugins for everything imaginable, but also does not dictate
//! higher-level functionality such as physics engine or entity
//! component system.  Instead the goal is to allow you to use
//! whichever libraries you want to provide these functions, or build
//! your own libraries atop ggez.
//!
//! ## Features
//!
//! * Filesystem abstraction that lets you load resources from folders or zip files
//! * Hardware-accelerated 2D rendering built on the `gfx-rs` graphics engine
//! * Loading and playing .ogg, .wav and .flac files via the `rodio` crate
//! * TTF font rendering with `rusttype` and `glyph_brush`.
//! * Interface for handling keyboard and mouse events easily through callbacks
//! * Config file for defining engine and game settings
//! * Easy timing and FPS measurement functions.
//! * Math library integration with `mint`.
//! * Some more advanced graphics options: shaders, sprite batches and render targets
//!
//! ## Supported platforms
//!
//!  * Fully supported: Windows, Linux
//!  * Not officially supported but might work anyway: Mac, iOS
//!  * Work in progress: WebAssembly
//!  * Not officially supported yet (but maybe you can help!): Android
//!
//! For details, see [docs/BuildingForEveryPlatform.md](docs/BuildingForEveryPlatform.md)
//!
//! ## Who's using ggez?
//!
//! Check out the [projects list!](docs/Projects.md)
//!
//! ## Usage
//!
//! ggez requires rustc >= 1.40 and is distributed on
//! crates.io. To include it in your project, just add the dependency
//! line to your `Cargo.toml` file:
//!
//! ```text
//! ggez = "0.6"
//! ```
//!
//! ggez consists of three main parts: A `Context` object which
//! contains all the state required to interface with the computer's
//! hardware, an `EventHandler` trait that the user implements to
//! register callbacks for events, and various sub-modules such as
//! `graphics` and `audio` that provide the functionality to actually
//! get stuff done.  The general pattern is to create a struct holding
//! your game's data which implements the `EventHandler` trait.
//! Create a new `Context` object with default objects from a `ContextBuilder`
//! or `Conf` object, and then call `event::run()` with
//! the `Context` and an instance of your `EventHandler` to run your game's
//! main loop.
//!
//! See the [API docs](https://docs.rs/ggez/) for full documentation, or the [examples](/examples) directory for a number of commented examples of varying complexity.  Most examples show off
//! a single feature of ggez, while `astroblasto` and `snake` are small but complete games.
//!
//! ## Getting started
//!
//! For a quick tutorial on ggez, see the [Hello ggez](https://github.com/ggez/ggez/blob/master/docs/guides/HelloGgez.md) guide in the `docs/` directory.
//!
//! ## Examples
//!
//! See the `examples/` directory in the source.  Most examples show off
//! a single feature of ggez, while `astroblasto` is a small  but
//! complete Asteroids-like game.
//!
//! To run the examples, just check out the source and execute `cargo run --example`
//! in the root directory:
//!
//! ```text
//! git clone https://github.com/ggez/ggez.git
//! cd ggez
//! cargo run --example 05_astroblasto
//! ```
//!
//! If this doesn't work, see the
//! [FAQ](https://github.com/ggez/ggez/blob/master/docs/FAQ.md) for solutions
//! to common problems.
//!
//! ### Basic Project Template
//!
//! ```rust,no_run
//! use ggez::{Context, ContextBuilder, GameResult};
//! use ggez::graphics::{self, Color};
//! use ggez::event::{self, EventHandler};
//!
//! fn main() {
//!     // Make a Context.
//!     let (mut ctx, event_loop) = ContextBuilder::new("my_game", "Cool Game Author")
//!         .build()
//!         .expect("aieee, could not create ggez context!");
//!
//!     // Create an instance of your event handler.
//!     // Usually, you should provide it with the Context object to
//!     // use when setting your game up.
//!     let my_game = MyGame::new(&mut ctx);
//!
//!     // Run!
//!     event::run(ctx, event_loop, my_game);
//! }
//!
//! struct MyGame {
//!     // Your state here...
//! }
//!
//! impl MyGame {
//!     pub fn new(_ctx: &mut Context) -> MyGame {
//!         // Load/create resources such as images here.
//!         MyGame {
//!             // ...
//!         }
//!     }
//! }
//!
//! impl EventHandler for MyGame {
//!     fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
//!         // Update code here...
//!         Ok(())
//!     }
//!
//!     fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
//!         graphics::clear(ctx, Color::WHITE);
//!         // Draw code here...
//!         graphics::present(ctx)
//!     }
//! }
//! ```
//!
//! ## Implementation details
//!
//! ggez is built upon `winit` for windowing and events, `rodio` for
//! sound, and a 2D drawing engine implemented in `gfx` using the OpenGL
//! backend (which currently defaults to use OpenGL 3.2).  It is entirely
//! thread-safe (though platform constraints mean the event-handling loop
//! and drawing must be done in the main thread), and portable to Windows
//! and Linux.
//!
//! ggez is pure Rust™.
//!
//! ## Help!
//!
//! Sources of information:
//!
//!  * The [FAQ](https://github.com/ggez/ggez/blob/master/docs/FAQ.md) has answers to common questions and problems.
//!  * The [API docs](https://docs.rs/ggez/), a lot of design stuff is explained there.
//!  * Check out the [examples](https://github.com/ggez/ggez/tree/master/examples).
//!
//!  If you still have problems or questions, feel free to ask!  Easiest ways are:
//!
//!  * Open an issue on [the Github issue tracker](https://github.com/ggez/ggez/issues)
//!  * Say hi on the [unofficial Rust Discord server](http://bit.ly/rust-community) or the [Rust Gamedev server](https://discord.gg/yNtPTb2)

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(unused_results)]
// This is not as strong a constraint as `#![forbid(unsafe_code)]` but is good enough.
// It means the only place we use unsafe is then in the modules noted as allowing it.
#![deny(unsafe_code)]
#![warn(bare_trait_objects)]
#![warn(missing_copy_implementations)]
#![allow(clippy::needless_doctest_main)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate gfx;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate smart_default;

pub extern crate mint;

pub mod audio;
pub mod conf;
mod context;
pub mod error;
pub mod event;
pub mod filesystem;
pub mod graphics;
pub mod input;
pub mod timer;
mod vfs;

#[cfg(test)]
pub mod tests;

pub use crate::context::{Context, ContextBuilder};
pub use crate::error::*;
<commit_msg>Update lib.rs<commit_after>//! [![ggez logo](docs/ggez-logo-maroon-full.svg)](http://ggez.rs/)
//!
//! # What is this?
//!
//! ![Build status](https://github.com/ggez/ggez/workflows/CI/badge.svg)
//! [![Docs Status](https://docs.rs/ggez/badge.svg)](https://docs.rs/ggez)
//! [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ggez/ggez/blob/master/LICENSE)
//! [![Crates.io](https://img.shields.io/crates/v/ggez.svg)](https://crates.io/crates/ggez)
//! [![Crates.io](https://img.shields.io/crates/d/ggez.svg)](https://crates.io/crates/ggez)
//!
//! ggez is a Rust library to create a Good Game Easily.
//!
//! More specifically, ggez is a lightweight cross-platform game framework
//! for making 2D games with minimum friction.  It aims to implement an
//! API based on (a Rustified version of) the [LÖVE](https://love2d.org/)
//! game framework.  This means it contains basic and portable 2D
//! drawing, sound, resource loading and event handling, but finer details
//! and performance characteristics may be different than LÖVE.
//!
//! ggez is not meant to be everything to everyone, but rather a good
//! base upon which to build.  Thus it takes a fairly
//! batteries-included approach without needing a million additions
//! and plugins for everything imaginable, but also does not dictate
//! higher-level functionality such as physics engine or entity
//! component system.  Instead the goal is to allow you to use
//! whichever libraries you want to provide these functions, or build
//! your own libraries atop ggez.
//!
//! ## Features
//!
//! * Filesystem abstraction that lets you load resources from folders or zip files
//! * Hardware-accelerated 2D rendering built on the `gfx-rs` graphics engine
//! * Loading and playing .ogg, .wav and .flac files via the `rodio` crate
//! * TTF font rendering with `rusttype` and `glyph_brush`.
//! * Interface for handling keyboard and mouse events easily through callbacks
//! * Config file for defining engine and game settings
//! * Easy timing and FPS measurement functions.
//! * Math library integration with `mint`.
//! * Some more advanced graphics options: shaders, sprite batches and render targets
//!
//! ## Supported platforms
//!
//!  * Fully supported: Windows, Linux
//!  * Not officially supported but might work anyway: Mac, iOS
//!  * Work in progress: WebAssembly
//!  * Not officially supported yet (but maybe you can help!): Android
//!
//! For details, see [docs/BuildingForEveryPlatform.md](docs/BuildingForEveryPlatform.md)
//!
//! ## Who's using ggez?
//!
//! Check out the [projects list!](docs/Projects.md)
//!
//! ## Usage
//!
//! ggez requires rustc >= 1.40 and is distributed on
//! crates.io. To include it in your project, just add the dependency
//! line to your `Cargo.toml` file:
//!
//! ```text
//! ggez = "0.6"
//! ```
//!
//! ggez consists of three main parts: A `Context` object which
//! contains all the state required to interface with the computer's
//! hardware, an `EventHandler` trait that the user implements to
//! register callbacks for events, and various sub-modules such as
//! `graphics` and `audio` that provide the functionality to actually
//! get stuff done.  The general pattern is to create a struct holding
//! your game's data which implements the `EventHandler` trait.
//! Create a new `Context` object with default objects from a `ContextBuilder`
//! or `Conf` object, and then call `event::run()` with
//! the `Context` and an instance of your `EventHandler` to run your game's
//! main loop.
//!
//! See the [API docs](https://docs.rs/ggez/) for full documentation, or the [examples](/examples) directory for a number of commented examples of varying complexity.  Most examples show off
//! a single feature of ggez, while `astroblasto` and `snake` are small but complete games.
//!
//! ## Getting started
//!
//! For a quick tutorial on ggez, see the [Hello ggez](https://github.com/ggez/ggez/blob/master/docs/guides/HelloGgez.md) guide in the `docs/` directory.
//!
//! ## Examples
//!
//! See the `examples/` directory in the source.  Most examples show off
//! a single feature of ggez, while `astroblasto` is a small  but
//! complete Asteroids-like game.
//!
//! To run the examples, just check out the source and execute `cargo run --example`
//! in the root directory:
//!
//! ```text
//! git clone https://github.com/ggez/ggez.git
//! cd ggez
//! cargo run --example 05_astroblasto
//! ```
//!
//! If this doesn't work, see the
//! [FAQ](https://github.com/ggez/ggez/blob/master/docs/FAQ.md) for solutions
//! to common problems.
//!
//! ### Basic Project Template
//!
//! ```rust,no_run
//! use ggez::{Context, ContextBuilder, GameResult};
//! use ggez::graphics::{self, Color};
//! use ggez::event::{self, EventHandler};
//!
//! fn main() {
//!     // Make a Context.
//!     let (mut ctx, event_loop) = ContextBuilder::new("my_game", "Cool Game Author")
//!         .build()
//!         .expect("aieee, could not create ggez context!");
//!
//!     // Create an instance of your event handler.
//!     // Usually, you should provide it with the Context object to
//!     // use when setting your game up.
//!     let my_game = MyGame::new(&mut ctx);
//!
//!     // Run!
//!     event::run(ctx, event_loop, my_game);
//! }
//!
//! struct MyGame {
//!     // Your state here...
//! }
//!
//! impl MyGame {
//!     pub fn new(_ctx: &mut Context) -> MyGame {
//!         // Load/create resources such as images here.
//!         MyGame {
//!             // ...
//!         }
//!     }
//! }
//!
//! impl EventHandler for MyGame {
//!     fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
//!         // Update code here...
//!         Ok(())
//!     }
//!
//!     fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
//!         graphics::clear(ctx, Color::WHITE);
//!         // Draw code here...
//!         graphics::present(ctx)
//!     }
//! }
//! ```
//!
//! ## Implementation details
//!
//! ggez is built upon `winit` for windowing and events, `rodio` for
//! sound, and a 2D drawing engine implemented in `gfx` using the OpenGL
//! backend (which currently defaults to use OpenGL 3.2).  It is entirely
//! thread-safe (though platform constraints mean the event-handling loop
//! and drawing must be done in the main thread), and portable to Windows
//! and Linux.
//!
//! ggez is pure Rust™.
//!
//! ## Help!
//!
//! Sources of information:
//!
//!  * The [FAQ](https://github.com/ggez/ggez/blob/master/docs/FAQ.md) has answers to common questions and problems.
//!  * The [API docs](https://docs.rs/ggez/), a lot of design stuff is explained there.
//!  * Check out the [examples](https://github.com/ggez/ggez/tree/master/examples).
//!
//!  If you still have problems or questions, feel free to ask!  Easiest ways are:
//!
//!  * Open an issue on [the Github issue tracker](https://github.com/ggez/ggez/issues)
//!  * Say hi on the [unofficial Rust Discord server](http://bit.ly/rust-community) or the [Rust Gamedev server](https://discord.gg/yNtPTb2)

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(unused_results)]
// This is not as strong a constraint as `#![forbid(unsafe_code)]` but is good enough.
// It means the only place we use unsafe is then in the modules noted as allowing it.
#![deny(unsafe_code)]
#![warn(bare_trait_objects)]
#![warn(missing_copy_implementations)]
#![allow(clippy::needless_doctest_main)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate gfx;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate smart_default;

pub extern crate mint;

pub mod audio;
pub mod conf;
mod context;
pub mod error;
pub mod event;
pub mod filesystem;
pub mod graphics;
pub mod input;
pub mod timer;
mod vfs;

#[cfg(test)]
pub mod tests;

pub use crate::context::{Context, ContextBuilder, winit};
pub use crate::error::*;
<|endoftext|>


<commit_before>// (c) 2015 Joost Yervante Damad <joost@damad.be>

// loosely based on https://github.com/cgaebel/sexp

use std::fmt;
use std::str::FromStr;

use std::fs::File;
use std::io::prelude::*;

pub enum Atom {
  S(String),
  Q(String),
  I(i64),
  F(f64),
}

pub enum Sexp {
  Atom(Atom),
  List(Vec<Sexp>),
}

impl fmt::Display for Atom {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      Atom::S(ref s) => write!(f, "{}", s),
      Atom::Q(ref s) => write!(f, "\"{}\"", s),
      Atom::I(i)     => write!(f, "{}", i),
      Atom::F(d)     => write!(f, "{}", d),
    }
  }
}

impl fmt::Display for Sexp {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      Sexp::Atom(ref a) => write!(f, "{}", a),
      Sexp::List(ref xs) => {
        try!(write!(f, "("));
        for (i, x) in xs.iter().enumerate() {
          let s = if i == 0 { "" } else { " " };
          try!(write!(f, "{}{}", s, x));
        }
        write!(f, ")")
      },
    }
  }
}

fn parse_list(vec: &Vec<char>, mut pos: usize) -> (usize, Sexp) {
    println!("list");
    pos += 1;
    let mut l: Vec<Sexp> = Vec::new();
    loop {
        pos = match vec[pos] {
            ')' => {
                break;
            }
            _ => {
                let (pos, s) = parse_sexp(vec, pos);
                l.push(s);
                pos
            }
        }
    }
    println!("Found list");
    (pos+1, Sexp::List(l))
}

fn parse_quoted_string(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("qstring");
    pos += 1;
    let mut s = String::new();
    loop {
        match vec[pos] {
            '"' => break,
            x => s.push(x)
        }
        pos += 1;
    }
    println!("Found quoted string {}", s);
    (pos+1, Atom::Q(s))
}

fn parse_string(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("string");
    let mut s = String::new();
    loop {
        match vec[pos] {
            ' ' | '\t' | '\r' | '\n' | ')' => break,
            '"' => panic!("quote in unquoted string {}", s),
            x => s.push(x)
        }
        pos += 1;
    }
    println!("Found string {}", s);
    (pos, Atom::S(s))
}

fn parse_number(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("number");
    let mut s = String::new();
    loop {
        match vec[pos] {
            ' ' | '\r' | '\n' | '\t' | ')' => break,
            '0' ... '9' | '.' | '-' => s.push(vec[pos]),
            _ => panic!("unexpected char in number"),
        }
        pos += 1;
    }
    println!("Found number {}", s);
    let s2: &str = &s[..];
    if s.contains('.') {
        (pos, Atom::F(f64::from_str(s2).unwrap()))
    } else {
        (pos, Atom::I(i64::from_str(s2).unwrap()))
    }
}

fn parse_atom(vec: &Vec<char>, pos: usize) -> (usize, Sexp) {
    println!("atom");
    let (pos, a) = match vec[pos] {
        '"' => {
            parse_quoted_string(vec, pos)
        }
        '0' ... '9' | '.' | '-' => {
            parse_number(vec, pos)
        }
        _ => {
            parse_string(vec, pos)
        }
    };
    (pos, Sexp::Atom(a))
}

fn parse_sexp(vec: &Vec<char>, pos: usize) -> (usize, Sexp) {
    let mut pos = pos;
    loop {
        match vec[pos] {
            '(' => {
                return parse_list(vec, pos)
            }
            ' ' | '\r' | '\t' | '\n' => {
                pos += 1;
            }
            _ => {
                return parse_atom(vec, pos)
            }
        }
    }
}

fn parse(data: &str) -> Sexp {
    let vec: Vec<char> = data.chars().collect();
    let (_, res) = parse_sexp(&vec, 0);
    res
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Sexp {
    parse(s)
}

pub fn parse_file(name: &str) -> Sexp {
    let s = read_file(name).unwrap();
    parse(&s[..])
}
<commit_msg>add sample unit test<commit_after>// (c) 2015 Joost Yervante Damad <joost@damad.be>

// loosely based on https://github.com/cgaebel/sexp

use std::fmt;
use std::str::FromStr;

use std::fs::File;
use std::io::prelude::*;

pub enum Atom {
  S(String),
  Q(String),
  I(i64),
  F(f64),
}

pub enum Sexp {
  Atom(Atom),
  List(Vec<Sexp>),
}

impl fmt::Display for Atom {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      Atom::S(ref s) => write!(f, "{}", s),
      Atom::Q(ref s) => write!(f, "\"{}\"", s),
      Atom::I(i)     => write!(f, "{}", i),
      Atom::F(d)     => write!(f, "{}", d),
    }
  }
}

impl fmt::Display for Sexp {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      Sexp::Atom(ref a) => write!(f, "{}", a),
      Sexp::List(ref xs) => {
        try!(write!(f, "("));
        for (i, x) in xs.iter().enumerate() {
          let s = if i == 0 { "" } else { " " };
          try!(write!(f, "{}{}", s, x));
        }
        write!(f, ")")
      },
    }
  }
}

fn parse_list(vec: &Vec<char>, mut pos: usize) -> (usize, Sexp) {
    println!("list");
    pos += 1;
    let mut l: Vec<Sexp> = Vec::new();
    loop {
        pos = match vec[pos] {
            ')' => {
                break;
            }
            _ => {
                let (pos, s) = parse_sexp(vec, pos);
                l.push(s);
                pos
            }
        }
    }
    println!("Found list");
    (pos+1, Sexp::List(l))
}

fn parse_quoted_string(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("qstring");
    pos += 1;
    let mut s = String::new();
    loop {
        match vec[pos] {
            '"' => break,
            x => s.push(x)
        }
        pos += 1;
    }
    println!("Found quoted string {}", s);
    (pos+1, Atom::Q(s))
}

fn parse_string(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("string");
    let mut s = String::new();
    loop {
        match vec[pos] {
            ' ' | '\t' | '\r' | '\n' | ')' => break,
            '"' => panic!("quote in unquoted string {}", s),
            x => s.push(x)
        }
        pos += 1;
    }
    println!("Found string {}", s);
    (pos, Atom::S(s))
}

fn parse_number(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("number");
    let mut s = String::new();
    loop {
        match vec[pos] {
            ' ' | '\r' | '\n' | '\t' | ')' => break,
            '0' ... '9' | '.' | '-' => s.push(vec[pos]),
            _ => panic!("unexpected char in number"),
        }
        pos += 1;
    }
    println!("Found number {}", s);
    let s2: &str = &s[..];
    if s.contains('.') {
        (pos, Atom::F(f64::from_str(s2).unwrap()))
    } else {
        (pos, Atom::I(i64::from_str(s2).unwrap()))
    }
}

fn parse_atom(vec: &Vec<char>, pos: usize) -> (usize, Sexp) {
    println!("atom");
    let (pos, a) = match vec[pos] {
        '"' => {
            parse_quoted_string(vec, pos)
        }
        '0' ... '9' | '.' | '-' => {
            parse_number(vec, pos)
        }
        _ => {
            parse_string(vec, pos)
        }
    };
    (pos, Sexp::Atom(a))
}

fn parse_sexp(vec: &Vec<char>, pos: usize) -> (usize, Sexp) {
    let mut pos = pos;
    loop {
        match vec[pos] {
            '(' => {
                return parse_list(vec, pos)
            }
            ' ' | '\r' | '\t' | '\n' => {
                pos += 1;
            }
            _ => {
                return parse_atom(vec, pos)
            }
        }
    }
}

fn parse(data: &str) -> Sexp {
    let vec: Vec<char> = data.chars().collect();
    let (_, res) = parse_sexp(&vec, 0);
    res
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Sexp {
    parse(s)
}

pub fn parse_file(name: &str) -> Sexp {
    let s = read_file(name).unwrap();
    parse(&s[..])
}

#[allow(dead_code)]
fn check_parse(s: &str) {
    let e = parse_str(s);
    let t = format!("{}", e);
    assert_eq!(s, t);
}

#[test]
fn test1() { check_parse("()") }
<|endoftext|>


<commit_before>extern crate libc;
extern crate time;
#[cfg(target_os = "macos")]
extern crate rand;

mod sys;
mod errno;
pub use sys::{
    Semaphore,
    SemaphoreGuard,
};

#[cfg(test)]
mod tests {
    use std::sync::Arc;
    use super::Semaphore;
    use std::sync::mpsc::channel;
    use std::thread;

    #[test]
    fn test_sem_acquire_post() {
        let s = Semaphore::new(1);
        s.wait();
        s.post();
        s.wait();
    }

    #[test]
    fn test_sem_basic() {
        let s = Semaphore::new(1);
        let _g = s.take();
    }

    #[test]
    fn test_sem_as_mutex() {
        let s = Arc::new(Semaphore::new(1));
        let s2 = s.clone();
        let _t = thread::spawn(move|| {
            let _g = s2.take();
        });
        let _g = s.take();
    }

    #[test]
    fn test_sem_as_cvar() {
        /* Child waits and parent signals */
        let (tx, rx) = channel();
        let s = Arc::new(Semaphore::new(0));
        let s2 = s.clone();
        let _t = thread::spawn(move|| {
            s2.wait();
            tx.send(()).unwrap();
        });
        s.post();
        let _ = rx.recv();

        /* Parent waits and child signals */
        let (tx, rx) = channel();
        let s = Arc::new(Semaphore::new(0));
        let s2 = s.clone();
        let _t = thread::spawn(move|| {
            s2.post();
            let _ = rx.recv();
        });
        s.wait();
        tx.send(()).unwrap();
    }

    #[test]
    fn test_sem_multi_resource() {
        // Parent and child both get in the critical section at the same
        // time, and shake hands.
        let s = Arc::new(Semaphore::new(2));
        let s2 = s.clone();
        let (tx1, rx1) = channel();
        let (tx2, rx2) = channel();
        let _t = thread::spawn(move|| {
            let _g = s2.take();
            let _ = rx2.recv();
            tx1.send(()).unwrap();
        });
        let _g = s.take();
        tx2.send(()).unwrap();
        rx1.recv().unwrap();
    }

    #[test]
    fn test_sem_runtime_friendly_blocking() {
        let s = Arc::new(Semaphore::new(1));
        let s2 = s.clone();
        let (tx, rx) = channel();
        {
            let _g = s.take();
            thread::spawn(move|| {
                tx.send(()).unwrap();
                drop(s2.take());
                tx.send(()).unwrap();
            });
            rx.recv().unwrap(); // wait for child to come alive
        }
        rx.recv().unwrap(); // wait for child to be done
    }
}
<commit_msg>remove tests<commit_after>extern crate libc;
extern crate time;
extern crate rand;

mod sys;
mod errno;
pub use sys::{
    Semaphore,
    SemaphoreGuard,
};

<|endoftext|>


<commit_before>extern crate libc;

use std::net::{SocketAddrV4, SocketAddrV6};
use std::ffi::CString;
use libc::*;

const IW_AUTH_WPA_VERSION_DISABLED: u8 = 0x00000001;
const IW_AUTH_WPA_VERSION_WPA: u8 = 0x00000002;
const IW_AUTH_WPA_VERSION_WPA2: u8 = 0x00000004;
const IW_MAX_BITRATES: usize = 32;
const IW_MAX_ENCODING_SIZES: usize = 8;
const IW_MAX_FREQUENCIES: usize = 32;
const IW_MAX_TXPOWER: usize = 8;

pub enum WirelessMode {
    Auto, /* Let the driver decide */
    AdHoc, /* Single cell network */
    Infra, /* Multi cell network, roaming, ... */
    Master, /* Synchronisation master or Access Point */
    Repeat, /* Wireless Repeater (forwarder) */
    Second, /* Secondary master/repeater (backup) */
    Monitor, /* Passive monitor (listen only) */
}

pub struct IwQuality {
    quality: u8,
    level: u8,
    noise: u8,
}

pub struct IwStats {
    status: uint16_t,
    quality: IwQuality,
}

pub struct WirelessKey<'a> {
    key: &'a [u8],
    size: u32,
    flags: i32,
}

pub struct WirelessNetwork<'a> {
    ap_addr4: Option<SocketAddrV4>,
    ap_addr6: Option<SocketAddrV6>,
    stats: Option<IwStats>,
    maxbitrate: Option<i32>,
    name: String,
    freq: Option<f64>,
    key: Option<WirelessKey<'a>>,
    essid: Option<String>,
    mode: Option<WirelessMode>,
}

struct priv_iw_quality {
    qual: uint8_t,
    level: uint8_t,
    noise: uint8_t,
    updated: uint8_t,
}

struct priv_iw_freq {
    m: int32_t,
    e: int16_t,
    i: uint8_t,
    flags: uint8_t,
}

#[repr(C)]
struct iw_range {
    /* Informative stuff (to choose between different interface) */
    throughput: uint32_t, /* To give an idea... */
    /* In theory this value should be the maximum benchmarked
     * TCP/IP throughput, because with most of these devices the
     * bit rate is meaningless (overhead an co) to estimate how
     * fast the connection will go and pick the fastest one.
     * I suggest people to play with Netperf or any benchmark...
     */

    /* NWID (or domain id) */
    min_nwid: uint32_t, /* Minimal NWID we are able to set */
    max_nwid: uint32_t, /* Maximal NWID we are able to set */

    /* Old Frequency (backward compat - moved lower ) */
    old_num_channels: uint16_t,
    old_num_frequency: uint8_t,

    /* Wireless event capability bitmasks */
    event_capa: [uint32_t; 6],

    /* signal level threshold range */
    sensitivity: int32_t,

    /* Quality of link & SNR stuff */
    /* Quality range (link, level, noise)
     * If the quality is absolute, it will be in the range [0 , max_qual],
     * if the quality is dBm, it will be in the range [max_qual , 0].
     * Don't forget that we use 8 bit arithmetics... */
    max_qual: priv_iw_quality, /* Quality of the link */
    /* This should contain the average/typical values of the quality
     * indicator. This should be the threshold between a "good" and
     * a "bad" link (example : monitor going from green to orange).
     * Currently, user space apps like quality monitors don't have any
     * way to calibrate the measurement. With this, they can split
     * the range between 0 and max_qual in different quality level
     * (using a geometric subdivision centered on the average).
     * I expect that people doing the user space apps will feedback
     * us on which value we need to put in each driver... */
    avg_qual: priv_iw_quality, /* Quality of the link */

    /* Rates */
    num_bitrates: uint8_t, /* Number of entries in the list */
    bitrate: [int32_t; IW_MAX_BITRATES], /* list, in bps */

    /* RTS threshold */
    min_rts: int32_t, /* Minimal RTS threshold */
    max_rts: int32_t, /* Maximal RTS threshold */

    /* Frag threshold */
    min_frag: int32_t, /* Minimal frag threshold */
    max_frag: int32_t, /* Maximal frag threshold */

    /* Power Management duration & timeout */
    min_pmp: int32_t, /* Minimal PM period */
    max_pmp: int32_t, /* Maximal PM period */
    min_pmt: int32_t, /* Minimal PM timeout */
    max_pmt: int32_t, /* Maximal PM timeout */
    pmp_flags: uint16_t, /* How to decode max/min PM period */
    pmt_flags: uint16_t, /* How to decode max/min PM timeout */
    pm_capa: uint16_t, /* What PM options are supported */

    /* Encoder stuff */
    encoding_size: [uint16_t; IW_MAX_ENCODING_SIZES], /* Different token sizes */
    num_encoding_sizes: uint8_t, /* Number of entry in the list */
    max_encoding_tokens: uint8_t, /* Max number of tokens */
    /* For drivers that need a "login/passwd" form */
    encoding_login_index: uint8_t, /* token index for login token */

    /* Transmit power */
    txpower_capa: uint16_t, /* What options are supported */
    num_txpower: uint8_t, /* Number of entries in the list */
    txpower: [int32_t; IW_MAX_TXPOWER], /* list, in bps */

    /* Wireless Extension version info */
    we_version_compiled: uint8_t, /* Must be WIRELESS_EXT */
    we_version_source: uint8_t, /* Last update of source */

    /* Retry limits and lifetime */
    retry_capa: uint16_t, /* What retry options are supported */
    retry_flags: uint16_t, /* How to decode max/min retry limit */
    r_time_flags: uint16_t, /* How to decode max/min retry life */
    min_retry: int32_t, /* Minimal number of retries */
    max_retry: int32_t, /* Maximal number of retries */
    min_r_time: int32_t, /* Minimal retry lifetime */
    max_r_time: int32_t, /* Maximal retry lifetime */

    /* Frequency */
    num_channels: uint16_t, /* Number of channels [0, num - 1] */
    num_frequency: uint8_t, /* Number of entry in the list */
    freq: [priv_iw_freq; IW_MAX_FREQUENCIES], /* list */
    /* Note : this frequency list doesn't need to fit channel numbers,
     * because each entry contain its channel index */
    enc_capa: uint32_t, /* IW_ENC_CAPA_* bit field */

    /* More power management stuff */
    min_pms: int32_t, /* Minimal PM saving */
    max_pms: int32_t, /* Maximal PM saving */
    pms_flags: int16_t, /* How to decode max/min PM saving */

    /* All available modulations for driver (hw may support less) */
    modul_capa: uint32_t, /* IW_MODUL_* bit field */

    /* More bitrate stuff */
    bitrate_capa: uint32_t, /* Types of bitrates supported */
}

#[link(name="iwlib")]
extern {
    fn iw_socket_open() -> c_int;
    fn iw_get_range_info(socket: c_int,
                         interface: CString,
                         range: &iw_range) -> c_int;
    fn iw_scan(socket: c_int,
               interface: CString,
               version: c_int,
               head: &wireless_scan_head) -> c_int;
}

pub struct WifiScan<'a> {
    networks: Vec<WirelessNetwork<'a>>,
}

impl<'a> WifiScan<'a> {
    pub fn scan(interface: String) -> Result<WifiScan<'a>, WifiScanError> {
        // Scan things here
        unsafe { // TODO: Slim down unsafe blocks.
            // First get an iw socket.
            let sock = iw_socket_open();
            let interface_name = CString::new(interface).unwrap(); // TODO: Make the interface name configurable.
            let range: iw_range;
            let head: wireless_scan_head;
            if iw_get_range_info(sock, interface_name, &range) < 0 {
                // We have to make this call in order to get the version of the library on the computer
                Err("Got an error from the iw library")
            }
            if iw_scan(sock, interface_name, range.we_version_compiled, &head) <0 {
                // This is the actual scan call that fills in the `head` struct with information about the visible networks.
                Err("Got an error from the iw library")
            }
            let result = head.result;
            let mut list = Vec::new();
            while result != ptr::null {
                // The scan results are a linked list of structs with a bunch of information about each network
                // The type of encryption is encoded in a bitflag called `key_flags` which we check by doing
                // a bitwise and against the known bitflags.
                let answer = if result.b.key_flags & IW_AUTH_WPA_VERSION_DISABLED > 0 {
                    "None".to_string()
                } else if result.b.key_flags & IW_AUTH_WPA_VERSION_WPA > 0 {
                    "WPA".to_string()
                } else if result.b.key_flags & IW_AUTH_WPA_VERSION_WPA2 > 0 {
                    "WPA2".to_string()
                } ;
                list.push(WirelessNetwork {
                    SSID: result.b.essid.to_string(),
                    encryption: answer, // TODO Figure out how to get encryption type from `result`
                    strength: result.stats
                });
                result = result.next;
            }
        }
        Ok( WifiScan { networks: list });
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Add C representation to necessary structs<commit_after>extern crate libc;

use std::net::{SocketAddrV4, SocketAddrV6};
use std::ffi::CString;
use libc::*;

const IW_AUTH_WPA_VERSION_DISABLED: u8 = 0x00000001;
const IW_AUTH_WPA_VERSION_WPA: u8 = 0x00000002;
const IW_AUTH_WPA_VERSION_WPA2: u8 = 0x00000004;
const IW_MAX_BITRATES: usize = 32;
const IW_MAX_ENCODING_SIZES: usize = 8;
const IW_MAX_FREQUENCIES: usize = 32;
const IW_MAX_TXPOWER: usize = 8;

pub enum WirelessMode {
    Auto, /* Let the driver decide */
    AdHoc, /* Single cell network */
    Infra, /* Multi cell network, roaming, ... */
    Master, /* Synchronisation master or Access Point */
    Repeat, /* Wireless Repeater (forwarder) */
    Second, /* Secondary master/repeater (backup) */
    Monitor, /* Passive monitor (listen only) */
}

pub struct IwQuality {
    quality: u8,
    level: u8,
    noise: u8,
}

pub struct IwStats {
    status: uint16_t,
    quality: IwQuality,
}

pub struct WirelessKey<'a> {
    key: &'a [u8],
    size: u32,
    flags: i32,
}

pub struct WirelessNetwork<'a> {
    ap_addr4: Option<SocketAddrV4>,
    ap_addr6: Option<SocketAddrV6>,
    stats: Option<IwStats>,
    maxbitrate: Option<i32>,
    name: String,
    freq: Option<f64>,
    key: Option<WirelessKey<'a>>,
    essid: Option<String>,
    mode: Option<WirelessMode>,
}

#[repr(C)]
struct priv_iw_quality {
    qual: uint8_t,
    level: uint8_t,
    noise: uint8_t,
    updated: uint8_t,
}

#[repr(C)]
struct priv_iw_freq {
    m: int32_t,
    e: int16_t,
    i: uint8_t,
    flags: uint8_t,
}

#[repr(C)]
struct iw_range {
    /* Informative stuff (to choose between different interface) */
    throughput: uint32_t, /* To give an idea... */
    /* In theory this value should be the maximum benchmarked
     * TCP/IP throughput, because with most of these devices the
     * bit rate is meaningless (overhead an co) to estimate how
     * fast the connection will go and pick the fastest one.
     * I suggest people to play with Netperf or any benchmark...
     */

    /* NWID (or domain id) */
    min_nwid: uint32_t, /* Minimal NWID we are able to set */
    max_nwid: uint32_t, /* Maximal NWID we are able to set */

    /* Old Frequency (backward compat - moved lower ) */
    old_num_channels: uint16_t,
    old_num_frequency: uint8_t,

    /* Wireless event capability bitmasks */
    event_capa: [uint32_t; 6],

    /* signal level threshold range */
    sensitivity: int32_t,

    /* Quality of link & SNR stuff */
    /* Quality range (link, level, noise)
     * If the quality is absolute, it will be in the range [0 , max_qual],
     * if the quality is dBm, it will be in the range [max_qual , 0].
     * Don't forget that we use 8 bit arithmetics... */
    max_qual: priv_iw_quality, /* Quality of the link */
    /* This should contain the average/typical values of the quality
     * indicator. This should be the threshold between a "good" and
     * a "bad" link (example : monitor going from green to orange).
     * Currently, user space apps like quality monitors don't have any
     * way to calibrate the measurement. With this, they can split
     * the range between 0 and max_qual in different quality level
     * (using a geometric subdivision centered on the average).
     * I expect that people doing the user space apps will feedback
     * us on which value we need to put in each driver... */
    avg_qual: priv_iw_quality, /* Quality of the link */

    /* Rates */
    num_bitrates: uint8_t, /* Number of entries in the list */
    bitrate: [int32_t; IW_MAX_BITRATES], /* list, in bps */

    /* RTS threshold */
    min_rts: int32_t, /* Minimal RTS threshold */
    max_rts: int32_t, /* Maximal RTS threshold */

    /* Frag threshold */
    min_frag: int32_t, /* Minimal frag threshold */
    max_frag: int32_t, /* Maximal frag threshold */

    /* Power Management duration & timeout */
    min_pmp: int32_t, /* Minimal PM period */
    max_pmp: int32_t, /* Maximal PM period */
    min_pmt: int32_t, /* Minimal PM timeout */
    max_pmt: int32_t, /* Maximal PM timeout */
    pmp_flags: uint16_t, /* How to decode max/min PM period */
    pmt_flags: uint16_t, /* How to decode max/min PM timeout */
    pm_capa: uint16_t, /* What PM options are supported */

    /* Encoder stuff */
    encoding_size: [uint16_t; IW_MAX_ENCODING_SIZES], /* Different token sizes */
    num_encoding_sizes: uint8_t, /* Number of entry in the list */
    max_encoding_tokens: uint8_t, /* Max number of tokens */
    /* For drivers that need a "login/passwd" form */
    encoding_login_index: uint8_t, /* token index for login token */

    /* Transmit power */
    txpower_capa: uint16_t, /* What options are supported */
    num_txpower: uint8_t, /* Number of entries in the list */
    txpower: [int32_t; IW_MAX_TXPOWER], /* list, in bps */

    /* Wireless Extension version info */
    we_version_compiled: uint8_t, /* Must be WIRELESS_EXT */
    we_version_source: uint8_t, /* Last update of source */

    /* Retry limits and lifetime */
    retry_capa: uint16_t, /* What retry options are supported */
    retry_flags: uint16_t, /* How to decode max/min retry limit */
    r_time_flags: uint16_t, /* How to decode max/min retry life */
    min_retry: int32_t, /* Minimal number of retries */
    max_retry: int32_t, /* Maximal number of retries */
    min_r_time: int32_t, /* Minimal retry lifetime */
    max_r_time: int32_t, /* Maximal retry lifetime */

    /* Frequency */
    num_channels: uint16_t, /* Number of channels [0, num - 1] */
    num_frequency: uint8_t, /* Number of entry in the list */
    freq: [priv_iw_freq; IW_MAX_FREQUENCIES], /* list */
    /* Note : this frequency list doesn't need to fit channel numbers,
     * because each entry contain its channel index */
    enc_capa: uint32_t, /* IW_ENC_CAPA_* bit field */

    /* More power management stuff */
    min_pms: int32_t, /* Minimal PM saving */
    max_pms: int32_t, /* Maximal PM saving */
    pms_flags: int16_t, /* How to decode max/min PM saving */

    /* All available modulations for driver (hw may support less) */
    modul_capa: uint32_t, /* IW_MODUL_* bit field */

    /* More bitrate stuff */
    bitrate_capa: uint32_t, /* Types of bitrates supported */
}

#[link(name="iwlib")]
extern {
    fn iw_socket_open() -> c_int;
    fn iw_get_range_info(socket: c_int,
                         interface: CString,
                         range: &iw_range) -> c_int;
    fn iw_scan(socket: c_int,
               interface: CString,
               version: c_int,
               head: &wireless_scan_head) -> c_int;
}

pub struct WifiScan<'a> {
    networks: Vec<WirelessNetwork<'a>>,
}

impl<'a> WifiScan<'a> {
    pub fn scan(interface: String) -> Result<WifiScan<'a>, WifiScanError> {
        // Scan things here
        unsafe { // TODO: Slim down unsafe blocks.
            // First get an iw socket.
            let sock = iw_socket_open();
            let interface_name = CString::new(interface).unwrap(); // TODO: Make the interface name configurable.
            let range: iw_range;
            let head: wireless_scan_head;
            if iw_get_range_info(sock, interface_name, &range) < 0 {
                // We have to make this call in order to get the version of the library on the computer
                Err("Got an error from the iw library")
            }
            if iw_scan(sock, interface_name, range.we_version_compiled, &head) <0 {
                // This is the actual scan call that fills in the `head` struct with information about the visible networks.
                Err("Got an error from the iw library")
            }
            let result = head.result;
            let mut list = Vec::new();
            while result != ptr::null {
                // The scan results are a linked list of structs with a bunch of information about each network
                // The type of encryption is encoded in a bitflag called `key_flags` which we check by doing
                // a bitwise and against the known bitflags.
                let answer = if result.b.key_flags & IW_AUTH_WPA_VERSION_DISABLED > 0 {
                    "None".to_string()
                } else if result.b.key_flags & IW_AUTH_WPA_VERSION_WPA > 0 {
                    "WPA".to_string()
                } else if result.b.key_flags & IW_AUTH_WPA_VERSION_WPA2 > 0 {
                    "WPA2".to_string()
                } ;
                list.push(WirelessNetwork {
                    SSID: result.b.essid.to_string(),
                    encryption: answer, // TODO Figure out how to get encryption type from `result`
                    strength: result.stats
                });
                result = result.next;
            }
        }
        Ok( WifiScan { networks: list });
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>#![feature(associated_type_defaults)]
#![feature(clone_from_slice)]
#![feature(fn_traits)]
#![feature(unboxed_closures)]

extern crate gtk;
extern crate cairo;

pub mod console_ui;
pub mod gtk_ui;

pub mod actions;
pub mod board;
pub mod game;
<commit_msg>First major skeleton of game search DAG.<commit_after>#![feature(associated_type_defaults)]
#![feature(clone_from_slice)]
#![feature(fn_traits)]
#![feature(unboxed_closures)]

extern crate gtk;
extern crate cairo;

pub mod actions;
pub mod board;
pub mod game;
pub mod search_graph;

pub mod console_ui;
pub mod gtk_ui;
<|endoftext|>