<commit_before>extern crate capsize;
extern crate termsize;

use capsize::Capacity;
use std::io::{self, Read, Write};
use std::iter;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::default::Default;

static FORMAT: &'static str = "[=>_]";

/// Unit of display for progress counter
pub enum Units {
    /// No units
    None,
    /// formats units in humanized byte sizes
    Bytes
}

impl Default for Units {
    fn default() -> Units {
        Units::None
    }
}

/// Preference for reporting progress
pub enum Reporter {
    StdOut,
    StdErr,
    Callback(fn(String) -> ())
}

impl Default for Reporter {
    fn default() -> Reporter {
        Reporter::StdErr
    }
}

/// IO progress. Implementations for Read and Write are provided
pub struct IO<T> {
    inner: T,
    bar: Bar
}

impl <R: Read> IO<R> {
    pub fn new(read: R, bar: Bar) -> IO<R> {
        IO {
            inner: read,
            bar: bar
        }
    }
}

impl <R: Read> Read for IO<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let n = try!(self.inner.read(buf));
        self.bar.add(n);
        Ok(n)
    }
}

impl <W: Write> IO<W> {
    pub fn new(write: W, bar: Bar) -> IO<W> {
        IO {
            inner: write,
            bar: bar
        }
    }
}

impl <W: Write> Write for IO<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = buf.len();
        self.bar.add(n);
        Ok(n)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

/// A bar of progress information
#[derive(Default)]
pub struct Bar {
    total: usize,
    /// show progress percent, defaults to true
    pub show_percent: bool,
    /// show progress counter. Defaults to true
    pub show_counter: bool,
    /// show main progress bar UI. Defaults to true
    pub show_bar: bool,
    /// an arbitrary string label to prefix display with
    pub prefix: String,
    /// preference for reporting progress
    pub reporter: Reporter,
    current: AtomicUsize,
    units: Units,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_empty: String,
    bar_end: String
}

impl Bar {
    /// creates a new bar with a target total size of `total`
    pub fn new(total: usize) -> Bar {
        let mut bar = Bar {
            total: total,
            show_percent: true,
            show_counter: true,
            show_bar: true,
            ..Default::default()
        };
        bar.format(FORMAT);
        bar
    }

    /// sets a custom format for display
    /// Example: bar.format("[=>_]")
    pub fn format(&mut self, spec: &str) {
        if spec.len() == 5 {
            let parts = spec.split("").collect::<Vec<&str>>();
            self.bar_start = parts[1].to_owned();
            self.bar_current = parts[2].to_owned();
            self.bar_current_n = parts[3].to_owned();
            self.bar_empty = parts[4].to_owned();
            self.bar_end = parts[5].to_owned();
        }
    }

    /// increment bar count by one
    pub fn incr(&self) -> usize {
        self.add(1)
    }

    /// add 1 to the bar count
    pub fn add(&self, delta: usize) -> usize {
        let prev = self.current.fetch_add(delta, Ordering::Relaxed);
        self.update();
        prev
    }

    /// sets the bar count to specified value
    pub fn set(&self, value: usize) {
        self.current.store(value, Ordering::Relaxed);
        self.update()
    }

    pub fn update(&self) {
        let current = self.current.load(Ordering::Relaxed);
        if current <= self.total {
            self.write(current)
        }
    }

    pub fn finish_print(&self, msg: &str) {
        println!("");
        println!("{}", msg)
    }

    fn width(&self) -> usize {
        termsize::get().map(|s|s.cols as usize).unwrap_or(80)
    }

    fn write(&self, current: usize) {
        fn repeat(what: &str, n: usize) -> String {
            iter::repeat(what).take(n).collect::<String>()
        }

        fn unit(value: usize, units: &Units) -> String {
            match *units {
                Units::None => value.to_string(),
                Units::Bytes => (value as i64).capacity()
            }
        }

        let width = self.width();

        let mut prefix = self.prefix.clone();
        let mut mid = String::new();
        let mut suffix = String::new();

        // counter
        if self.show_counter {
            prefix = prefix + &format!(
                "{} / {} ", unit(current, &self.units), unit(self.total, &self.units)
            );
        }

        // percent complete
        if self.show_percent {
            let percent = current as f64 / (self.total as f64 / 100_f64);
            suffix = suffix + &format!(
                " {:.*} %", 2, percent
            );
        }

        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let cur_count = (
                    (current as f64 / self.total as f64) * size as f64
                ).ceil() as usize;
                let empt_count = size - cur_count;
                mid = self.bar_start.clone();
                if empt_count > 0 {
                    mid = mid + &repeat(self.bar_current.as_ref(), (cur_count - 1) as usize) +  &self.bar_current_n;
                } else {
                    mid = mid + &repeat(self.bar_current.as_ref(), cur_count as usize);
                }
                mid = mid + &repeat(self.bar_empty.as_ref(), (empt_count) as usize) + &self.bar_end
            }
        }
        let mut display = prefix + &mid + &suffix;
        if display.len() < width {
            let remaining = width - display.len();
            display = display + &repeat(" ", remaining);
        }

        match self.reporter {
            Reporter::StdErr => {
                let _ = write!(&mut std::io::stderr(), "\r{}", display);
            },
            Reporter::StdOut => {
                let _ = write!(&mut std::io::stderr(), "\r{}", display);
            },
            Reporter::Callback(cb) => {
                cb(display);
            }
        }
    }
}

#[test]
fn it_works() {
}
<commit_msg>rustdocs for reporter options<commit_after>extern crate capsize;
extern crate termsize;

use capsize::Capacity;
use std::io::{self, Read, Write};
use std::iter;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::default::Default;

static FORMAT: &'static str = "[=>_]";

/// Unit of display for progress counter
pub enum Units {
    /// No units
    None,
    /// formats units in humanized byte sizes
    Bytes
}

impl Default for Units {
    fn default() -> Units {
        Units::None
    }
}

/// Preference for reporting progress
pub enum Reporter {
    /// Report progress to stdout
    StdOut,
    /// Report progress to stderr
    StdErr,
    /// Report progress to a callback
    Callback(fn(String) -> ())
}

impl Default for Reporter {
    fn default() -> Reporter {
        Reporter::StdErr
    }
}

/// IO progress. Implementations for Read and Write are provided
pub struct IO<T> {
    inner: T,
    bar: Bar
}

impl <R: Read> IO<R> {
    pub fn new(read: R, bar: Bar) -> IO<R> {
        IO {
            inner: read,
            bar: bar
        }
    }
}

impl <R: Read> Read for IO<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let n = try!(self.inner.read(buf));
        self.bar.add(n);
        Ok(n)
    }
}

impl <W: Write> IO<W> {
    pub fn new(write: W, bar: Bar) -> IO<W> {
        IO {
            inner: write,
            bar: bar
        }
    }
}

impl <W: Write> Write for IO<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = buf.len();
        self.bar.add(n);
        Ok(n)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

/// A bar of progress information
#[derive(Default)]
pub struct Bar {
    total: usize,
    /// show progress percent, defaults to true
    pub show_percent: bool,
    /// show progress counter. Defaults to true
    pub show_counter: bool,
    /// show main progress bar UI. Defaults to true
    pub show_bar: bool,
    /// an arbitrary string label to prefix display with
    pub prefix: String,
    /// preference for reporting progress
    pub reporter: Reporter,
    current: AtomicUsize,
    units: Units,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_empty: String,
    bar_end: String
}

impl Bar {
    /// creates a new bar with a target total size of `total`
    pub fn new(total: usize) -> Bar {
        let mut bar = Bar {
            total: total,
            show_percent: true,
            show_counter: true,
            show_bar: true,
            ..Default::default()
        };
        bar.format(FORMAT);
        bar
    }

    /// sets a custom format for display
    /// Example: bar.format("[=>_]")
    pub fn format(&mut self, spec: &str) {
        if spec.len() == 5 {
            let parts = spec.split("").collect::<Vec<&str>>();
            self.bar_start = parts[1].to_owned();
            self.bar_current = parts[2].to_owned();
            self.bar_current_n = parts[3].to_owned();
            self.bar_empty = parts[4].to_owned();
            self.bar_end = parts[5].to_owned();
        }
    }

    /// increment bar count by one
    pub fn incr(&self) -> usize {
        self.add(1)
    }

    /// add 1 to the bar count
    pub fn add(&self, delta: usize) -> usize {
        let prev = self.current.fetch_add(delta, Ordering::Relaxed);
        self.update();
        prev
    }

    /// sets the bar count to specified value
    pub fn set(&self, value: usize) {
        self.current.store(value, Ordering::Relaxed);
        self.update()
    }

    pub fn update(&self) {
        let current = self.current.load(Ordering::Relaxed);
        if current <= self.total {
            self.write(current)
        }
    }

    pub fn finish_print(&self, msg: &str) {
        println!("");
        println!("{}", msg)
    }

    fn width(&self) -> usize {
        termsize::get().map(|s|s.cols as usize).unwrap_or(80)
    }

    fn write(&self, current: usize) {
        fn repeat(what: &str, n: usize) -> String {
            iter::repeat(what).take(n).collect::<String>()
        }

        fn unit(value: usize, units: &Units) -> String {
            match *units {
                Units::None => value.to_string(),
                Units::Bytes => (value as i64).capacity()
            }
        }

        let width = self.width();

        let mut prefix = self.prefix.clone();
        let mut mid = String::new();
        let mut suffix = String::new();

        // counter
        if self.show_counter {
            prefix = prefix + &format!(
                "{} / {} ", unit(current, &self.units), unit(self.total, &self.units)
            );
        }

        // percent complete
        if self.show_percent {
            let percent = current as f64 / (self.total as f64 / 100_f64);
            suffix = suffix + &format!(
                " {:.*} %", 2, percent
            );
        }

        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let cur_count = (
                    (current as f64 / self.total as f64) * size as f64
                ).ceil() as usize;
                let empt_count = size - cur_count;
                mid = self.bar_start.clone();
                if empt_count > 0 {
                    mid = mid + &repeat(self.bar_current.as_ref(), (cur_count - 1) as usize) +  &self.bar_current_n;
                } else {
                    mid = mid + &repeat(self.bar_current.as_ref(), cur_count as usize);
                }
                mid = mid + &repeat(self.bar_empty.as_ref(), (empt_count) as usize) + &self.bar_end
            }
        }
        let mut display = prefix + &mid + &suffix;
        if display.len() < width {
            let remaining = width - display.len();
            display = display + &repeat(" ", remaining);
        }

        match self.reporter {
            Reporter::StdErr => {
                let _ = write!(&mut std::io::stderr(), "\r{}", display);
            },
            Reporter::StdOut => {
                let _ = write!(&mut std::io::stderr(), "\r{}", display);
            },
            Reporter::Callback(cb) => {
                cb(display);
            }
        }
    }
}

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


<commit_before>#![allow(trivial_casts)]
#![cfg_attr(test, deny(warnings))]

extern crate conduit;
extern crate conduit_mime_types as mime;
extern crate time;
extern crate filetime;
#[cfg(test)] extern crate tempdir;

use std::collections::HashMap;
use std::error::Error;
use std::io;
use std::io::prelude::*;
use std::path::{PathBuf, Path};
use std::fs::File;
use conduit::{Request, Response, Handler};
use filetime::FileTime;

pub struct Static {
    path: PathBuf,
    types: mime::Types
}

impl Static {
    pub fn new<P: AsRef<Path>>(path: P) -> Static {
        Static {
            path: path.as_ref().to_path_buf(),
            types: mime::Types::new()
                .ok().expect("Couldn't load mime-types")
        }
    }
}

impl Handler for Static {
    #[allow(deprecated)]
    fn call(&self, request: &mut Request) -> Result<Response, Box<Error+Send>> {
        let request_path = &request.path()[1..];
        if request_path.contains("..") { return Ok(not_found()) }

        let path = self.path.join(request_path);
        let mime = self.types.mime_for_path(&path);
        let file = match File::open(&path) {
            Ok(f) => f,
            Err(..) => return Ok(not_found()),
        };
        let data = try!(file.metadata().map_err(|e| Box::new(e) as Box<Error+Send>));
        if data.is_dir() {
            return Ok(not_found())
        }
        let mtime = FileTime::from_last_modification_time(&data);
        let ts = time::Timespec {
            sec: (mtime.seconds_relative_to_1970() as i64) / 1000,
            nsec: (((mtime.nanoseconds() as u32) % 1000) as i32) * 1000000
        };
        let tm = time::at(ts).to_utc();

        let mut headers = HashMap::new();
        headers.insert("Content-Type".to_string(), vec![mime.to_string()]);
        headers.insert("Content-Length".to_string(),
                       vec![data.len().to_string()]);
        headers.insert("Last-Modified".to_string(),
                       vec![tm.strftime("%a, %d %b %Y %T GMT").unwrap()
                              .to_string()]);

        Ok(Response {
            status: (200, "OK"),
            headers: headers,
            body: Box::new(file),
        })
    }
}

fn not_found() -> Response {
    Response {
        status: (404, "Not Found"),
        headers: HashMap::new(),
        body: Box::new(io::empty()),
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test as test;

    use std::fs::{self, File};
    use std::io::prelude::*;
    use tempdir::TempDir;

    use conduit::{Handler, Method};
    use Static;

    #[test]
    fn test_static() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        let handler = Static::new(root.clone());
        File::create(&root.join("Cargo.toml")).unwrap()
             .write_all(b"[package]").unwrap();
        let mut req = test::MockRequest::new(Method::Get, "/Cargo.toml");
        let mut res = handler.call(&mut req).ok().expect("No response");
        let mut body = String::new();
        res.body.read_to_string(&mut body).unwrap();
        assert_eq!(body, "[package]");
        assert_eq!(res.headers.get("Content-Type"),
                   Some(&vec!("text/plain".to_string())));
        assert_eq!(res.headers.get("Content-Length"),
                   Some(&vec!["9".to_string()]));
    }

    #[test]
    fn test_mime_types() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        fs::create_dir(&root.join("src")).unwrap();
        File::create(&root.join("src/fixture.css")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/src/fixture.css");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.headers.get("Content-Type"),
                   Some(&vec!("text/css".to_string())));
        assert_eq!(res.headers.get("Content-Length"),
                   Some(&vec!["0".to_string()]));
    }

    #[test]
    fn test_missing() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/nope");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 404);
    }

    #[test]
    fn test_dir() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        fs::create_dir(&root.join("foo")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/foo");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 404);
    }

    #[test]
    fn last_modified() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        File::create(&root.join("test")).unwrap();
        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/test");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 200);
        assert!(res.headers.get("Last-Modified").is_some());
    }
}
<commit_msg>Remove unused import<commit_after>#![allow(trivial_casts)]
#![cfg_attr(test, deny(warnings))]

extern crate conduit;
extern crate conduit_mime_types as mime;
extern crate time;
extern crate filetime;
#[cfg(test)] extern crate tempdir;

use std::collections::HashMap;
use std::error::Error;
use std::io;
use std::path::{PathBuf, Path};
use std::fs::File;
use conduit::{Request, Response, Handler};
use filetime::FileTime;

pub struct Static {
    path: PathBuf,
    types: mime::Types
}

impl Static {
    pub fn new<P: AsRef<Path>>(path: P) -> Static {
        Static {
            path: path.as_ref().to_path_buf(),
            types: mime::Types::new()
                .ok().expect("Couldn't load mime-types")
        }
    }
}

impl Handler for Static {
    #[allow(deprecated)]
    fn call(&self, request: &mut Request) -> Result<Response, Box<Error+Send>> {
        let request_path = &request.path()[1..];
        if request_path.contains("..") { return Ok(not_found()) }

        let path = self.path.join(request_path);
        let mime = self.types.mime_for_path(&path);
        let file = match File::open(&path) {
            Ok(f) => f,
            Err(..) => return Ok(not_found()),
        };
        let data = try!(file.metadata().map_err(|e| Box::new(e) as Box<Error+Send>));
        if data.is_dir() {
            return Ok(not_found())
        }
        let mtime = FileTime::from_last_modification_time(&data);
        let ts = time::Timespec {
            sec: (mtime.seconds_relative_to_1970() as i64) / 1000,
            nsec: (((mtime.nanoseconds() as u32) % 1000) as i32) * 1000000
        };
        let tm = time::at(ts).to_utc();

        let mut headers = HashMap::new();
        headers.insert("Content-Type".to_string(), vec![mime.to_string()]);
        headers.insert("Content-Length".to_string(),
                       vec![data.len().to_string()]);
        headers.insert("Last-Modified".to_string(),
                       vec![tm.strftime("%a, %d %b %Y %T GMT").unwrap()
                              .to_string()]);

        Ok(Response {
            status: (200, "OK"),
            headers: headers,
            body: Box::new(file),
        })
    }
}

fn not_found() -> Response {
    Response {
        status: (404, "Not Found"),
        headers: HashMap::new(),
        body: Box::new(io::empty()),
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test as test;

    use std::fs::{self, File};
    use std::io::prelude::*;
    use tempdir::TempDir;

    use conduit::{Handler, Method};
    use Static;

    #[test]
    fn test_static() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        let handler = Static::new(root.clone());
        File::create(&root.join("Cargo.toml")).unwrap()
             .write_all(b"[package]").unwrap();
        let mut req = test::MockRequest::new(Method::Get, "/Cargo.toml");
        let mut res = handler.call(&mut req).ok().expect("No response");
        let mut body = String::new();
        res.body.read_to_string(&mut body).unwrap();
        assert_eq!(body, "[package]");
        assert_eq!(res.headers.get("Content-Type"),
                   Some(&vec!("text/plain".to_string())));
        assert_eq!(res.headers.get("Content-Length"),
                   Some(&vec!["9".to_string()]));
    }

    #[test]
    fn test_mime_types() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        fs::create_dir(&root.join("src")).unwrap();
        File::create(&root.join("src/fixture.css")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/src/fixture.css");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.headers.get("Content-Type"),
                   Some(&vec!("text/css".to_string())));
        assert_eq!(res.headers.get("Content-Length"),
                   Some(&vec!["0".to_string()]));
    }

    #[test]
    fn test_missing() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/nope");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 404);
    }

    #[test]
    fn test_dir() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        fs::create_dir(&root.join("foo")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/foo");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 404);
    }

    #[test]
    fn last_modified() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        File::create(&root.join("test")).unwrap();
        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/test");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 200);
        assert!(res.headers.get("Last-Modified").is_some());
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS: the Stupid Operating System
//!
//! SOS is a simple, tiny toy OS implemented in Rust.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel //! hacking, so don't expect anything new or exciting out of this project.

#![crate_name = "sos_kernel"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(no_std, lang_items)]
#![feature(const_fn, unique, core_str_ext, core_slice_ext)]
#![feature(slice_patterns)]
#![feature(iter_cmp)]
#![no_std]

extern crate rlibc;
extern crate spin;

pub mod arch;
#[macro_use]
pub mod io;
pub mod util;
pub mod panic;
pub mod multiboot;
pub mod memory;

use arch::cpu;
use memory::{Allocator, AreaAllocator};

/// Kernel main loop
///
/// The kernel main loop expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern fn kernel_main(multiboot_addr: usize) {
    io::term::CONSOLE.lock().clear();

    println!("Hello from the kernel!");

    // Unpack multiboot tag
    let boot_info = unsafe { multiboot::Info::from(multiboot_addr) };
    let mmap_tag // Extract the memory map tag from the multiboot info
        = boot_info.mem_map()
                   .expect("Memory map tag required!");

    println!("Detected memory areas:");
    for a in mmap_tag.areas() {
        println!("     start: {:#08x}, end: {:#08x}"
                , a.base, a.length );
    }

    let elf_sections_tag // Extract ELF sections tag from the multiboot info
        = boot_info.elf64_sections()
                   .expect("Elf-sections tag required!");

    println!("Detected kernel sections:");
    for section in elf_sections_tag.sections() {
    println!( "     address: {:#08x}, size: {:#08x}, flags: {:#08x}"
            , section.address
            , section.length
            , section.flags );
    }

    let kernel_begin
        = elf_sections_tag.sections()
                          .map(|s| s.address).min()
                          .expect("Could not find kernel start section!\
                                   \nSomething is deeply wrong.");
    let kernel_end
        = elf_sections_tag.sections()
                        .map(|s| s.address).max()
                        .expect("Could not find kernel end section!\
                                \nSomething is deeply wrong.");

    println!( "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as usize;

    println!( "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let mut alloc
        = AreaAllocator::new( kernel_begin as usize, kernel_end as usize
                            , multiboot_addr, multiboot_end
                            , mmap_tag.areas());

    println!( "Created initial allocator." );

    for i in 0.. {
        if let None = alloc.allocate() {
            println!("Allocated {} frames", i);
            break;
        }
    }
    // println!("Intializing interrupts...");
    // cpu::interrupts::initialize();

    loop { }
}
<commit_msg>Initial boot logging made prettier<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS: the Stupid Operating System
//!
//! SOS is a simple, tiny toy OS implemented in Rust.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel //! hacking, so don't expect anything new or exciting out of this project.

#![crate_name = "sos_kernel"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(no_std, lang_items)]
#![feature(const_fn, unique, core_str_ext, core_slice_ext)]
#![feature(slice_patterns)]
#![feature(iter_cmp)]
#![no_std]

extern crate rlibc;
extern crate spin;

pub mod arch;
#[macro_use]
pub mod io;
pub mod util;
pub mod panic;
pub mod multiboot;
pub mod memory;

use arch::cpu;
use memory::{Allocator, AreaAllocator};

/// Kernel main loop
///
/// The kernel main loop expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern fn kernel_main(multiboot_addr: usize) {
    io::term::CONSOLE.lock().clear();

    println!("Hello from the kernel!");

    // Unpack multiboot tag
    let boot_info = unsafe { multiboot::Info::from(multiboot_addr) };
    let mmap_tag // Extract the memory map tag from the multiboot info
        = boot_info.mem_map()
                   .expect("Memory map tag required!");

    println!("Detected memory areas:");
    for a in mmap_tag.areas() {
        println!("     start: {:#08x}, end: {:#08x}"
                , a.base, a.length );
    }

    let elf_sections_tag // Extract ELF sections tag from the multiboot info
        = boot_info.elf64_sections()
                   .expect("ELF sections tag required!");

    println!("Detecting kernel ELF sections:");
    // for section in elf_sections_tag.sections() {
    //
    // }

    let kernel_begin
        = elf_sections_tag.sections()
            .map(|s| {
                println!("     address: {:#08x}, size: {:#08x}, flags: {:#08x}"
                        , s.address
                        , s.length
                        , s.flags );
                s.address })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1;
                     s.address })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    println!( "Detected {} kernel ELF sections.", n_elf_sections);
    println!( "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as usize;

    println!( "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let mut alloc
        = AreaAllocator::new( kernel_begin as usize, kernel_end as usize
                            , multiboot_addr, multiboot_end
                            , mmap_tag.areas());

    println!( "Created initial allocator." );

    // for i in 0.. {
    //     if let None = alloc.allocate() {
    //         println!("Allocated {} frames", i);
    //         break;
    //     }
    // }
    // println!("Intializing interrupts...");
    // cpu::interrupts::initialize();

    loop { }
}
<|endoftext|>


<commit_before>
//! A semi-safe, semi-stateless wrapper around OpenGL 3.3 Core. This library provides various
//! utilities to make using OpenGL 3.3 safer. It uses rust's type system to encode some information
//! which helps prevent common errors. This library is primarily intended to be used for games,
//! but you can also use it to create other graphics applications.
//!
//! Some points to get started:
//!
//!  - Use [`gondola::run`] to launch your game.
//!  - Use a [`VertexBuffer`] to do basic drawing.
//!  - Use [`GameState::gen_input_manager`] to get access to keyboard/mouse state.
//!
//! [`GameState::gen_input_manager`]: struct.GameState.html#method.gen_input_manager
//! [`VertexBuffer`]:                 buffer/struct.VertexBuffer.html
//! [`gondola::run`]:                 fn.run.html

extern crate gl;
extern crate glutin;
extern crate png;
extern crate cable_math;
extern crate rusttype;
#[macro_use]
extern crate bitflags;

mod color;
mod matrix_stack;
mod input;

pub mod texture;
#[macro_use]
pub mod shader;
pub mod buffer;
pub mod util;
pub mod framebuffer;
pub mod font;
pub mod ui;

pub use color::*;
pub use input::*;
pub use matrix_stack::*;
pub use util::graphics;

use cable_math::Vec2;
use std::time::{Instant, Duration};
use std::sync::mpsc;

/// The most generic result type possible. Used in top-level
pub type GameResult<T> = Result<T, Box<std::error::Error>>;

/// Creates a new window and runs the given game in this window. This function does
/// not return until the game exits.
///
/// # Example
/// ```rust,no_run
/// extern crate gondola;
///
/// use gondola::{Game, GameResult, GameState, MatrixStack};
///
/// fn main() {
///     gondola::run::<Pong>();
/// }
///
/// struct Pong {
///     // All data neded for game is defined here
/// }
///
/// impl Game for Pong {
///     fn setup(state: &mut GameState) -> GameResult<Pong> {
///         Ok(Pong {})
///     }
///
///     fn update(&mut self, delta: u32, state: &mut GameState) {
///         // All logic goes here.
///     }
///
///     fn draw(&mut self, state: &GameState, mut mat_stack: &mut MatrixStack) {
///         // All rendering goes here
///     }
/// }
/// ```
pub fn run<T: Game + Sized>() {
    // Create window
    let window = glutin::Window::new().unwrap();
    unsafe {
        window.make_current().unwrap();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    }
    window.set_title(T::name());

    // Set up game state
    let mut state = GameState::new();
    state.win_size = {
        let (width, height) = window.get_inner_size_pixels().unwrap();
        Vec2::new(width, height)
    };
    graphics::viewport(0, 0, state.win_size.x, state.win_size.y);

    let mut mat_stack = MatrixStack::new();

    // Set up game
    let mut game = match T::setup(&mut state) {
        Err(err) => {
            println!("Failed to launch game:\n{}", err);
            panic!();
        },
        Ok(game) => game,
    };

    let mut delta: u64 = 16;

    'main_loop:
    loop {
        let start_time = Instant::now();

        // Events
        for event in window.poll_events() {
            match event {
                glutin::Event::Closed => break 'main_loop,
                glutin::Event::Resized(..) => {
                    let (width, height) = window.get_inner_size_pixels().unwrap();
                    if width != 0 && height != 0 {
                        state.win_size = Vec2::new(width, height);
                        graphics::viewport(0, 0, state.win_size.x, state.win_size.y);
                        game.on_resize(&state);
                    }
                }
                other => {
                    // Send events to receivers, and remove those which are unable to receive.
                    state.event_sinks.retain(|sink| {
                        sink.send(other.clone()).is_ok()
                    });
                },
            }
        }

        // Logic and rendering
        game.update(delta as u32, &mut state);
        game.draw(&state, &mut mat_stack);
        window.swap_buffers().unwrap();
        graphics::print_errors();

        if state.exit {
            break 'main_loop;
        }

        // Timing
        let elapsed = start_time.elapsed();
        let target_delta = Duration::from_millis(state.target_delta as u64);
        if state.target_delta > 0 && elapsed < target_delta {
            std::thread::sleep(target_delta - elapsed); // This is not very precice :/
        }
        let delta_dur = start_time.elapsed();
        delta = delta_dur.as_secs()*1000 + (delta_dur.subsec_nanos() as u64)/1000000;
    }

    game.close();
}

/// General info about the currently running game. Passed as a parameter to
/// most [`Game`](trait.Game.html) methods.
pub struct GameState {
    /// The size of the window in which this game is running, in pixels.
    pub win_size: Vec2<u32>,
    /// If set to true the game will exit after rendering.
    pub exit: bool,
    /// The number of milliseconds per frame this game should aim to run at. Set to 16
    /// for 60 fps. If the main loop takes less time than this amount the game will
    /// sleep until a total of `target_delta` has ellapsed. If set to `0` the game will
    /// never sleep.
    pub target_delta: u32,

    event_sinks: Vec<mpsc::Sender<glutin::Event>>,
}

/// Used with [`gondola::run`](fn.run.html)
pub trait Game: Sized {
    /// Called before the main loop. Resources and initial state should be set up here.
    fn setup(state: &mut GameState) -> GameResult<Self>;
    /// Called once every frame, before drawing.
    fn update(&mut self, delta: u32, state: &mut GameState);
    /// Called once every frame, after updating.
    fn draw(&mut self, state: &GameState, mat_stack: &mut MatrixStack);

    /// Called whenever the game window is resized
    fn on_resize(&mut self, _state: &GameState) {}
    /// Called after the main game loop exists. This method is not called if the main
    /// loop `panic!`s.
    fn close(&mut self) {} // Most simple games dont need any special logic here

    fn name() -> &'static str { "Unnamed game (Override Game::name to change title)" }
}

impl GameState {
    fn new() -> GameState {
        GameState {
            win_size: Vec2::zero(),
            exit: false,
            target_delta: 15,

            event_sinks: Vec::new(),
        }
    }

    /// Generates a new receiver for glutin events. All events not consumed by the
    /// game itself will be received by this receiver. Note that all receiver receive
    /// all events, there is no notion of event consumption.
    pub fn gen_event_receiver(&mut self) -> mpsc::Receiver<glutin::Event> {
        let (sender, receiver) = mpsc::channel();
        self.event_sinks.push(sender);
        receiver
    }

    /// Creates a new input manager which can be used to access the state of input devices.
    pub fn gen_input_manager(&mut self) -> InputManager {
        let receiver = self.gen_event_receiver();
        InputManager::new(receiver)
    }
}

<commit_msg>Now calculates average framerate<commit_after>
//! A semi-safe, semi-stateless wrapper around OpenGL 3.3 Core. This library provides various
//! utilities to make using OpenGL 3.3 safer. It uses rust's type system to encode some information
//! which helps prevent common errors. This library is primarily intended to be used for games,
//! but you can also use it to create other graphics applications.
//!
//! Some points to get started:
//!
//!  - Use [`gondola::run`] to launch your game.
//!  - Use a [`VertexBuffer`] to do basic drawing.
//!  - Use [`GameState::gen_input_manager`] to get access to keyboard/mouse state.
//!
//! [`GameState::gen_input_manager`]: struct.GameState.html#method.gen_input_manager
//! [`VertexBuffer`]:                 buffer/struct.VertexBuffer.html
//! [`gondola::run`]:                 fn.run.html

extern crate gl;
extern crate glutin;
extern crate png;
extern crate cable_math;
extern crate rusttype;
#[macro_use]
extern crate bitflags;

mod color;
mod matrix_stack;
mod input;

pub mod texture;
#[macro_use]
pub mod shader;
pub mod buffer;
pub mod util;
pub mod framebuffer;
pub mod font;
pub mod ui;

pub use color::*;
pub use input::*;
pub use matrix_stack::*;
pub use util::graphics;

use cable_math::Vec2;
use std::time::{Instant, Duration};
use std::sync::mpsc;

/// The most generic result type possible. Used in top-level
pub type GameResult<T> = Result<T, Box<std::error::Error>>;

/// Creates a new window and runs the given game in this window. This function does
/// not return until the game exits.
///
/// # Example
/// ```rust,no_run
/// extern crate gondola;
///
/// use gondola::{Game, GameResult, GameState, MatrixStack};
///
/// fn main() {
///     gondola::run::<Pong>();
/// }
///
/// struct Pong {
///     // All data neded for game is defined here
/// }
///
/// impl Game for Pong {
///     fn setup(state: &mut GameState) -> GameResult<Pong> {
///         Ok(Pong {})
///     }
///
///     fn update(&mut self, delta: u32, state: &mut GameState) {
///         // All logic goes here.
///     }
///
///     fn draw(&mut self, state: &GameState, mut mat_stack: &mut MatrixStack) {
///         // All rendering goes here
///     }
/// }
/// ```
pub fn run<T: Game + Sized>() {
    // Create window
    let window = glutin::Window::new().unwrap();
    unsafe {
        window.make_current().unwrap();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    }
    window.set_title(T::name());

    // Set up game state
    let mut state = GameState::new();
    state.win_size = {
        let (width, height) = window.get_inner_size_pixels().unwrap();
        Vec2::new(width, height)
    };
    graphics::viewport(0, 0, state.win_size.x, state.win_size.y);

    let mut mat_stack = MatrixStack::new();

    // Set up game
    let mut game = match T::setup(&mut state) {
        Err(err) => {
            println!("Failed to launch game:\n{}", err);
            panic!();
        },
        Ok(game) => game,
    };

    let mut delta: u64 = 16;

    'main_loop:
    loop {
        let start_time = Instant::now();

        // Events
        for event in window.poll_events() {
            match event {
                glutin::Event::Closed => break 'main_loop,
                glutin::Event::Resized(..) => {
                    let (width, height) = window.get_inner_size_pixels().unwrap();
                    if width != 0 && height != 0 {
                        state.win_size = Vec2::new(width, height);
                        graphics::viewport(0, 0, state.win_size.x, state.win_size.y);
                        game.on_resize(&state);
                    }
                }
                other => {
                    // Send events to receivers, and remove those which are unable to receive.
                    state.event_sinks.retain(|sink| {
                        sink.send(other.clone()).is_ok()
                    });
                },
            }
        }

        // Logic and rendering
        game.update(delta as u32, &mut state);
        game.draw(&state, &mut mat_stack);
        window.swap_buffers().unwrap();
        graphics::print_errors();

        if state.exit {
            break 'main_loop;
        }

        // Timing
        if let Some(target_delta) = state.target_delta {
            let target_delta = Duration::from_millis(target_delta as u64);
            let elapsed = start_time.elapsed();
            if elapsed < target_delta {
                std::thread::sleep(target_delta - elapsed); // This is not very precice :/
            }
        }
        let delta_dur = start_time.elapsed();
        delta = delta_dur.as_secs()*1000 + (delta_dur.subsec_nanos() as u64)/1000000;

        // Calculate average framerate
        state.frame_accumulator += 1;
        state.delta_accumulator += delta as u32;
        if state.delta_accumulator > 500 { // Update every half second
            let frames = state.frame_accumulator as f32;
            let time = (state.delta_accumulator as f32) * 0.001;

            state.average_framerate = frames / time;

            state.frame_accumulator = 0;
            state.delta_accumulator = 0;
        }
    }

    game.close();
}

/// General info about the currently running game. Passed as a parameter to
/// most [`Game`](trait.Game.html) methods.
pub struct GameState {
    /// The size of the window in which this game is running, in pixels.
    pub win_size: Vec2<u32>,
    /// If set to true the game will exit after rendering.
    pub exit: bool,
    /// The number of milliseconds per frame this game should aim to run at. Set to 16
    /// for 60 fps. If the main loop takes less time than this amount the game will
    /// sleep until a total of `target_delta` has ellapsed. If set to `None` the game will
    /// never sleep, and run as fast as possible.
    pub target_delta: Option<u32>,
    /// The number of frames that where displayed in the last second. This number is updated every
    /// half second. Note that this is only an average; it does not reflect rapid fluctuations of
    /// delta times.
    pub average_framerate: f32,

    // Used to calculate framerate
    frame_accumulator: u32,
    delta_accumulator: u32,

    event_sinks: Vec<mpsc::Sender<glutin::Event>>,
}

/// Used with [`gondola::run`](fn.run.html)
pub trait Game: Sized {
    /// Called before the main loop. Resources and initial state should be set up here.
    fn setup(state: &mut GameState) -> GameResult<Self>;
    /// Called once every frame, before drawing.
    fn update(&mut self, delta: u32, state: &mut GameState);
    /// Called once every frame, after updating.
    fn draw(&mut self, state: &GameState, mat_stack: &mut MatrixStack);

    /// Called whenever the game window is resized
    fn on_resize(&mut self, _state: &GameState) {}
    /// Called after the main game loop exists. This method is not called if the main
    /// loop `panic!`s.
    fn close(&mut self) {} // Most simple games dont need any special logic here

    fn name() -> &'static str { "Unnamed game (Override Game::name to change title)" }
}

impl GameState {
    fn new() -> GameState {
        GameState {
            win_size: Vec2::zero(),
            exit: false,
            target_delta: Some(15),

            average_framerate: -1.0,
            frame_accumulator: 0,
            delta_accumulator: 0,

            event_sinks: Vec::new(),
        }
    }

    /// Generates a new receiver for glutin events. All events not consumed by the
    /// game itself will be received by this receiver. Note that all receiver receive
    /// all events, there is no notion of event consumption.
    pub fn gen_event_receiver(&mut self) -> mpsc::Receiver<glutin::Event> {
        let (sender, receiver) = mpsc::channel();
        self.event_sinks.push(sender);
        receiver
    }

    /// Creates a new input manager which can be used to access the state of input devices.
    pub fn gen_input_manager(&mut self) -> InputManager {
        let receiver = self.gen_event_receiver();
        InputManager::new(receiver)
    }
}

<|endoftext|>


<commit_before>//! bitbit provides functions to read and write streams one bit at a time.
//!
//! # Reading
//!
//! ```rust,ignore
//! let r = try!(File::open("somefile"));
//! let mut br = BitReader::new(r);
//!
//! let is_one = try!(br.read_bit());
//!
//! let byte = try!(br.read_byte());
//!
//! let num = try!(br.read_bits(5));
//! ```
//!
//! # Writing
//!
//! ```rust,ignore
//! let w = try!(File::create("somefile"));
//! let mut bw = BitWriter::new(w);
//!
//! try!(br.write_bit(true));
//!
//! try!(br.write_byte(0x55));
//!
//! try!(br.write_bits(0x15, 5));
//! ```

pub mod reader;
pub use reader::BitReader;

pub mod writer;
pub use writer::BitWriter;
<commit_msg>Export Bit enums<commit_after>//! bitbit provides functions to read and write streams one bit at a time.
//!
//! # Reading
//!
//! ```rust,ignore
//! let r = try!(File::open("somefile"));
//! let mut br = BitReader::new(r);
//!
//! let is_one = try!(br.read_bit());
//!
//! let byte = try!(br.read_byte());
//!
//! let num = try!(br.read_bits(5));
//! ```
//!
//! # Writing
//!
//! ```rust,ignore
//! let w = try!(File::create("somefile"));
//! let mut bw = BitWriter::new(w);
//!
//! try!(br.write_bit(true));
//!
//! try!(br.write_byte(0x55));
//!
//! try!(br.write_bits(0x15, 5));
//! ```

pub mod reader;
pub use reader::{BitReader,MSB,LSB};

pub mod writer;
pub use writer::BitWriter;
<|endoftext|>


<commit_before>//! Open URLs in the web browsers available on a platform
//!
//! Inspired by the [webbrowser](https://docs.python.org/2/library/webbrowser.html) python library
//!
//! #Examples
//!
//! ```
//! use webbrowser;
//!
//! if webbrowser::open("http://github.com").is_ok() {
//!     // ...
//! }
//! ```
//!
//! Currently state of platform support is:
//!
//! * macos => default, as well as browsers listed under [Browser](enum.Browser.html)
//! * windows => default browser only
//! * linux => default browser only (uses $BROWSER env var, failing back to xdg-open, gvfs-open and
//! gnome-open, in that order)
//! * android => not supported right now
//! * ios => not supported right now
//!
//! Important note:
//!
//! * This library requires availability of browsers and a graphical environment during runtime
//! * `cargo test` will actually open the browser locally

use std::process::{Command, Output};
use std::io::{Result, Error, ErrorKind};
use std::env;

#[derive(Debug)]
/// Browser types available
pub enum Browser {
    Default,
    Firefox,
    InternetExplorer,
    Chrome,
    Opera,
    Safari
}

/// Opens the URL on the default browser of this platform
///
/// Returns Ok(..) so long as the browser invocation was successful. An Err(..) is returned only if
/// there was an error in running the command, or if the browser was not found
///
/// # Examples
/// ```
/// use webbrowser;
///
/// if webbrowser::open("http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open(url: &str) -> Result<Output> {
    open_browser(Browser::Default, url)
}

/// Opens the specified URL on the specific browser (if available) requested. Return semantics are
/// the same as for [open](fn.open.html)
///
/// # Examples
/// ```
/// use webbrowser::{open_browser, Browser};
///
/// if open_browser(Browser::Firefox, "http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    let os = std::env::consts::OS;
    match os {
        "macos" => open_on_macos(browser, url),
        "windows" => open_on_windows(browser, url),
        "linux" => open_on_linux(browser, url),
        _ => Err(Error::new(ErrorKind::NotFound, format!("Platform {} not yet supported by this library", os)))
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
fn open_on_macos(browser: Browser, url: &str) -> Result<Output> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).output(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).output(),
                None => Err(Error::new(ErrorKind::NotFound, format!("Unsupported browser {:?}", browser)))
            }
        }
    }
}

/// Deal with opening of browsers on Windows, using `start link` command
fn open_on_windows(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => Command::new("start").arg("link").arg(url).output(),
        _ => Err(Error::new(
                ErrorKind::NotFound,
                "Only the default browser is supported on this platform right now"
            ))
    }
}

/// Deal with opening of browsers on Linux - currently supports only the default browser
///
/// The mechanism of opening the default browser is as follows:
/// 1. Attempt to use $BROWSER env var if available
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, respectively, whichever works
///    first
fn open_on_linux(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => open_on_linux_using_browser_env(url)
            .or_else(|_| -> Result<Output> {Command::new("xdg-open").arg(url).output()})
            .or_else(|_| -> Result<Output> {Command::new("gvfs-open").arg(url).output()})
            .or_else(|_| -> Result<Output> {Command::new("gnome-open").arg(url).output()}),
        _ => Err(Error::new(
                ErrorKind::NotFound,
                "Only the default browser is supported on this platform right now"
            ))
    }
}

/// Open on Linux using the $BROWSER env var
fn open_on_linux_using_browser_env(url: &str) -> Result<Output> {
    let browsers = try!(env::var("BROWSER").map_err(|_| -> Error {Error::new(ErrorKind::NotFound, format!("BROWSER env not set"))}));
    for browser in browsers.split(':') { // $BROWSER can contain ':' delimited options, each representing a potential browser command line
        if !browser.is_empty() {
            // each browser command can have %s to represent URL, while %c needs to be replaced
            // with ':' and %% with '%'
            let cmdline = browser.replace("%s", url).replace("%c", ":").replace("%%", "%");
            let cmdarr: Vec<&str> = cmdline.split_whitespace().collect();
            let mut cmd = Command::new(&cmdarr[0]);
            if cmdarr.len() > 1 {
                cmd.args(&cmdarr[1..cmdarr.len()]);
            }
            if !browser.contains("%s") {
                // append the url as an argument only if it was not already set via %s
                cmd.arg(url);
            }
            if let Ok(output) = cmd.output() {
                return Ok(output);
            }
        }
    }
    return Err(Error::new(ErrorKind::NotFound, "No valid command in $BROWSER"));
}

#[test]
fn test_open_default() {
    assert!(open("http://github.com").is_ok());
}

#[test]
#[cfg(target_os = "macos")]
fn test_open_browser() {
    assert!(open_browser(Browser::Firefox, "http://github.com").is_ok());
}
<commit_msg>Fix the command in open_on_windows<commit_after>//! Open URLs in the web browsers available on a platform
//!
//! Inspired by the [webbrowser](https://docs.python.org/2/library/webbrowser.html) python library
//!
//! #Examples
//!
//! ```
//! use webbrowser;
//!
//! if webbrowser::open("http://github.com").is_ok() {
//!     // ...
//! }
//! ```
//!
//! Currently state of platform support is:
//!
//! * macos => default, as well as browsers listed under [Browser](enum.Browser.html)
//! * windows => default browser only
//! * linux => default browser only (uses $BROWSER env var, failing back to xdg-open, gvfs-open and
//! gnome-open, in that order)
//! * android => not supported right now
//! * ios => not supported right now
//!
//! Important note:
//!
//! * This library requires availability of browsers and a graphical environment during runtime
//! * `cargo test` will actually open the browser locally

use std::process::{Command, Output};
use std::io::{Result, Error, ErrorKind};
use std::env;

#[derive(Debug)]
/// Browser types available
pub enum Browser {
    Default,
    Firefox,
    InternetExplorer,
    Chrome,
    Opera,
    Safari
}

/// Opens the URL on the default browser of this platform
///
/// Returns Ok(..) so long as the browser invocation was successful. An Err(..) is returned only if
/// there was an error in running the command, or if the browser was not found
///
/// # Examples
/// ```
/// use webbrowser;
///
/// if webbrowser::open("http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open(url: &str) -> Result<Output> {
    open_browser(Browser::Default, url)
}

/// Opens the specified URL on the specific browser (if available) requested. Return semantics are
/// the same as for [open](fn.open.html)
///
/// # Examples
/// ```
/// use webbrowser::{open_browser, Browser};
///
/// if open_browser(Browser::Firefox, "http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    let os = std::env::consts::OS;
    match os {
        "macos" => open_on_macos(browser, url),
        "windows" => open_on_windows(browser, url),
        "linux" => open_on_linux(browser, url),
        _ => Err(Error::new(ErrorKind::NotFound, format!("Platform {} not yet supported by this library", os)))
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
fn open_on_macos(browser: Browser, url: &str) -> Result<Output> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).output(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).output(),
                None => Err(Error::new(ErrorKind::NotFound, format!("Unsupported browser {:?}", browser)))
            }
        }
    }
}

/// Deal with opening of browsers on Windows, using `start` command
fn open_on_windows(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => Command::new("cmd").arg("/C").arg("start").arg(url).output(),
        _ => Err(Error::new(
                ErrorKind::NotFound,
                "Only the default browser is supported on this platform right now"
            ))
    }
}

/// Deal with opening of browsers on Linux - currently supports only the default browser
///
/// The mechanism of opening the default browser is as follows:
/// 1. Attempt to use $BROWSER env var if available
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, respectively, whichever works
///    first
fn open_on_linux(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => open_on_linux_using_browser_env(url)
            .or_else(|_| -> Result<Output> {Command::new("xdg-open").arg(url).output()})
            .or_else(|_| -> Result<Output> {Command::new("gvfs-open").arg(url).output()})
            .or_else(|_| -> Result<Output> {Command::new("gnome-open").arg(url).output()}),
        _ => Err(Error::new(
                ErrorKind::NotFound,
                "Only the default browser is supported on this platform right now"
            ))
    }
}

/// Open on Linux using the $BROWSER env var
fn open_on_linux_using_browser_env(url: &str) -> Result<Output> {
    let browsers = try!(env::var("BROWSER").map_err(|_| -> Error {Error::new(ErrorKind::NotFound, format!("BROWSER env not set"))}));
    for browser in browsers.split(':') { // $BROWSER can contain ':' delimited options, each representing a potential browser command line
        if !browser.is_empty() {
            // each browser command can have %s to represent URL, while %c needs to be replaced
            // with ':' and %% with '%'
            let cmdline = browser.replace("%s", url).replace("%c", ":").replace("%%", "%");
            let cmdarr: Vec<&str> = cmdline.split_whitespace().collect();
            let mut cmd = Command::new(&cmdarr[0]);
            if cmdarr.len() > 1 {
                cmd.args(&cmdarr[1..cmdarr.len()]);
            }
            if !browser.contains("%s") {
                // append the url as an argument only if it was not already set via %s
                cmd.arg(url);
            }
            if let Ok(output) = cmd.output() {
                return Ok(output);
            }
        }
    }
    return Err(Error::new(ErrorKind::NotFound, "No valid command in $BROWSER"));
}

#[test]
fn test_open_default() {
    assert!(open("http://github.com").is_ok());
}

#[test]
#[cfg(target_os = "macos")]
fn test_open_browser() {
    assert!(open_browser(Browser::Firefox, "http://github.com").is_ok());
}
<|endoftext|>


<commit_before>//! Body Parser middleware for Iron
//!
//! This middleware focuses on parsing incoming data from client requests.
#![crate_id = "bodyparser"]
#![license = "MIT"]

extern crate iron;
extern crate serialize;

use iron::{Request, Response, Middleware, Alloy};
use iron::middleware::{Status, Continue, Unwind};

use serialize::json;
use serialize::json::Json;

/// The Parsed type holds the Json object that is parsed from incoming data.
#[deriving(Clone)]
pub struct Parsed(pub Json);

#[deriving(Clone)]
pub struct BodyParser;

/// Using `pub fn new() -> BodyParser` will create a new instance of BodyParser,
/// which can then be `link`ed to a `Chain`.
impl BodyParser {
    pub fn new() -> BodyParser {
        BodyParser
    }
}

impl Middleware for BodyParser {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        if !req.body.is_empty() {
            match json::from_str(req.body.as_slice()) {
                Ok(parsed) => {
                    alloy.insert::<Parsed>(Parsed(parsed));
                },
                Err(_) => {
                    return Continue;
                }
            }
        }
        Continue
    }
}
<commit_msg>(doc) Minor style cleanup and details of failure handling<commit_after>//! Body Parser middleware for Iron
//!
//! This middleware parses incoming JSON data from client requests. On an empy
//! request, or on malformed data, the chain is not unwound, but rather
//! nothing is inserted into the `Alloy`. Middleware further down the chain
//! must take care to handle this robustly.
#![crate_id = "bodyparser"]
#![license = "MIT"]

extern crate iron;
extern crate serialize;

use iron::{Request, Response, Middleware, Alloy};
use iron::middleware::{Status, Continue, Unwind};

use serialize::json;
use serialize::json::Json;

/// The Parsed type holds the Json object that was parsed from incoming data.
#[deriving(Clone)]
pub struct Parsed(pub Json);

#[deriving(Clone)]
pub struct BodyParser;

impl BodyParser {
    /// Create a new `BodyParse`, for linking into a `Chain`
    pub fn new() -> BodyParser {
        BodyParser
    }
}

impl Middleware for BodyParser {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        if !req.body.is_empty() {
            match json::from_str(req.body.as_slice()) {
                Ok(parsed) => {
                    alloy.insert::<Parsed>(Parsed(parsed));
                },
                Err(_) => {
                    return Continue;
                }
            }
        }
        Continue
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate helix;
extern crate csv;

use std::error::Error;
use std::io::Read;
use helix::sys;
use helix::sys::{ID, VALUE};
use helix::{FromRuby, CheckResult, ToRuby};
use helix::libc::c_int;

#[cfg_attr(windows, link(name = "helix-runtime"))]
extern "C" {
    pub fn rb_block_given_p() -> c_int;
    pub fn rb_yield(value: VALUE);
    pub fn rb_funcall(value: VALUE, name: ID, nargs: c_int, ...) -> VALUE;
}

fn generate_lines(rows: &[Vec<String>]) -> Result<String, Box<Error>> {
    let mut wtr = csv::WriterBuilder::new().from_writer(vec![]);
    for row in rows {
        wtr.write_record(row)?;
    }

    Ok(String::from_utf8(wtr.into_inner()?)?)
}

fn record_to_ruby(record: &csv::ByteRecord) -> VALUE {
    let inner_array = unsafe { sys::rb_ary_new_capa(record.len() as isize) };
    for column in record.iter() {
        unsafe {
            let column_value =
                sys::rb_utf8_str_new(column.as_ptr() as *const i8, column.len() as i64);
            sys::rb_ary_push(inner_array, column_value);
        }
    }
    inner_array
}

struct Enumerator {
    value: VALUE,
}

impl FromRuby for Enumerator {
    type Checked = Enumerator;

    fn from_ruby(value: VALUE) -> CheckResult<Enumerator> {
        // TODO: validate this?
        Ok(Enumerator { value })
    }

    fn from_checked(checked: Enumerator) -> Enumerator {
        checked
    }
}

struct EnumeratorRead {
    value: VALUE,
    next: Option<Vec<u8>>,
}

impl EnumeratorRead {
    fn new(value: VALUE) -> EnumeratorRead {
        EnumeratorRead {
            value,
            next: None,
        }
    }

    fn read_and_store_overflow(&mut self, buf: &mut [u8], value: &[u8]) -> std::io::Result<usize> {
        if value.len() > buf.len() {
            match value.split_at(buf.len()) {
                (current, next) => {
                    for (index, c) in current.iter().enumerate() {
                        buf[index] = *c;
                    }
                    self.next = Some(next.to_vec());
                    Ok(current.len())
                }
            }

        } else {
            for (index, value) in value.iter().enumerate() {
                buf[index] = *value;
            }
            self.next = None;
            Ok(value.len() as usize)
        }
    }

    fn read_from_external(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let next = unsafe {
            rb_funcall(
                self.value,
                sys::rb_intern("next\0".as_ptr() as *const i8),
                0,
            )
        };

        let string = String::from_ruby_unwrap(next);

        self.read_and_store_overflow(buf, string.as_bytes())
    }
}

impl Read for EnumeratorRead {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        match self.next.clone() {
            Some(ref inner) => self.read_and_store_overflow(buf, inner),
            None => self.read_from_external(buf),
        }
    }
}

fn csv_reader<R: Read>(reader: R) -> csv::Reader<R> {
    csv::ReaderBuilder::new()
        .buffer_capacity(16 * 1024)
        .has_headers(false)
        .from_reader(reader)
}

fn yield_csv(data: &Enumerator) -> Result<(), csv::Error> {
    let mut reader = csv_reader(EnumeratorRead::new(data.value));
    let mut record = csv::ByteRecord::new();

    while reader.read_byte_record(&mut record)? {
        let inner_array = record_to_ruby(&record);
        unsafe {
            rb_yield(inner_array);
        }
    }

    Ok(())
}

fn parse_csv(data: &str) -> Result<Vec<Vec<VALUE>>, csv::Error> {
    csv_reader(data.as_bytes())
        .records()
        .map(|r| r.map(|v| record_to_vec(&v)))
        .collect()
}

fn record_to_vec(record: &csv::StringRecord) -> Vec<VALUE> {
    record.iter().map(|s| s.to_ruby().unwrap()).collect()
}

ruby! {
    class RscsvReader {
        def each_internal(data: Enumerator) -> Result<(), &'static str> {
            yield_csv(&data).map_err(|_| "Error parsing CSV")
        }

        def parse(data: String) -> Result<Vec<Vec<VALUE>>, &'static str> {
            parse_csv(&data).map_err(|_| "Error parsing CSV")
        }
    }

    class RscsvWriter {
        def generate_line(row: Vec<String>) -> Result<String, &'static str> {
            let mut wtr = csv::WriterBuilder::new().from_writer(vec![]);

            wtr.write_record(&row)
                .map(|_| String::from_utf8(wtr.into_inner().unwrap()).unwrap())
                .map_err(|_| "Error generating csv")
        }

        def generate_lines(rows: Vec<Vec<String>>) -> Result<String, &'static str> {
            generate_lines(&rows).map_err(|_| "Error generating csv")
        }
    }
}
<commit_msg>Use .take() instead of .clone()<commit_after>#[macro_use]
extern crate helix;
extern crate csv;

use std::error::Error;
use std::io::Read;
use helix::sys;
use helix::sys::{ID, VALUE};
use helix::{FromRuby, CheckResult, ToRuby};
use helix::libc::c_int;

#[cfg_attr(windows, link(name = "helix-runtime"))]
extern "C" {
    pub fn rb_block_given_p() -> c_int;
    pub fn rb_yield(value: VALUE);
    pub fn rb_funcall(value: VALUE, name: ID, nargs: c_int, ...) -> VALUE;
}

fn generate_lines(rows: &[Vec<String>]) -> Result<String, Box<Error>> {
    let mut wtr = csv::WriterBuilder::new().from_writer(vec![]);
    for row in rows {
        wtr.write_record(row)?;
    }

    Ok(String::from_utf8(wtr.into_inner()?)?)
}

fn record_to_ruby(record: &csv::ByteRecord) -> VALUE {
    let inner_array = unsafe { sys::rb_ary_new_capa(record.len() as isize) };
    for column in record.iter() {
        unsafe {
            let column_value =
                sys::rb_utf8_str_new(column.as_ptr() as *const i8, column.len() as i64);
            sys::rb_ary_push(inner_array, column_value);
        }
    }
    inner_array
}

struct Enumerator {
    value: VALUE,
}

impl FromRuby for Enumerator {
    type Checked = Enumerator;

    fn from_ruby(value: VALUE) -> CheckResult<Enumerator> {
        // TODO: validate this?
        Ok(Enumerator { value })
    }

    fn from_checked(checked: Enumerator) -> Enumerator {
        checked
    }
}

struct EnumeratorRead {
    value: VALUE,
    next: Option<Vec<u8>>,
}

impl EnumeratorRead {
    fn new(value: VALUE) -> EnumeratorRead {
        EnumeratorRead {
            value,
            next: None,
        }
    }

    fn read_and_store_overflow(&mut self, buf: &mut [u8], value: &[u8]) -> std::io::Result<usize> {
        if value.len() > buf.len() {
            match value.split_at(buf.len()) {
                (current, next) => {
                    for (index, c) in current.iter().enumerate() {
                        buf[index] = *c;
                    }
                    self.next = Some(next.to_vec());
                    Ok(current.len())
                }
            }

        } else {
            for (index, value) in value.iter().enumerate() {
                buf[index] = *value;
            }
            self.next = None;
            Ok(value.len() as usize)
        }
    }

    fn read_from_external(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let next = unsafe {
            rb_funcall(
                self.value,
                sys::rb_intern("next\0".as_ptr() as *const i8),
                0,
            )
        };

        let string = String::from_ruby_unwrap(next);

        self.read_and_store_overflow(buf, string.as_bytes())
    }
}

impl Read for EnumeratorRead {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        match self.next.take() {
            Some(ref inner) => self.read_and_store_overflow(buf, inner),
            None => self.read_from_external(buf),
        }
    }
}

fn csv_reader<R: Read>(reader: R) -> csv::Reader<R> {
    csv::ReaderBuilder::new()
        .buffer_capacity(16 * 1024)
        .has_headers(false)
        .from_reader(reader)
}

fn yield_csv(data: &Enumerator) -> Result<(), csv::Error> {
    let mut reader = csv_reader(EnumeratorRead::new(data.value));
    let mut record = csv::ByteRecord::new();

    while reader.read_byte_record(&mut record)? {
        let inner_array = record_to_ruby(&record);
        unsafe {
            rb_yield(inner_array);
        }
    }

    Ok(())
}

fn parse_csv(data: &str) -> Result<Vec<Vec<VALUE>>, csv::Error> {
    csv_reader(data.as_bytes())
        .records()
        .map(|r| r.map(|v| record_to_vec(&v)))
        .collect()
}

fn record_to_vec(record: &csv::StringRecord) -> Vec<VALUE> {
    record.iter().map(|s| s.to_ruby().unwrap()).collect()
}

ruby! {
    class RscsvReader {
        def each_internal(data: Enumerator) -> Result<(), &'static str> {
            yield_csv(&data).map_err(|_| "Error parsing CSV")
        }

        def parse(data: String) -> Result<Vec<Vec<VALUE>>, &'static str> {
            parse_csv(&data).map_err(|_| "Error parsing CSV")
        }
    }

    class RscsvWriter {
        def generate_line(row: Vec<String>) -> Result<String, &'static str> {
            let mut wtr = csv::WriterBuilder::new().from_writer(vec![]);

            wtr.write_record(&row)
                .map(|_| String::from_utf8(wtr.into_inner().unwrap()).unwrap())
                .map_err(|_| "Error generating csv")
        }

        def generate_lines(rows: Vec<Vec<String>>) -> Result<String, &'static str> {
            generate_lines(&rows).map_err(|_| "Error generating csv")
        }
    }
}
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(stmt_expr_attributes)]

#![no_std]

extern crate rlibc;
extern crate libc;

#[macro_use]
pub mod fmt;
#[macro_use]
pub mod interrupts;

pub mod serial;
pub mod error_handling;
pub mod ioports;
pub mod vga;
pub mod utility;

use fmt::Write;

#[no_mangle]
pub unsafe extern fn main() {
    #[cfg(gdb)] gdb_start();
    #[cfg(os_test)] test_all();
    println!("Hello, World");
    ini();

    end();
}

#[cfg(os_test)]
fn test_all() {
    fmt::tests::all();
}

#[cfg(gdb)]
fn gdb_start() {
    let mut gdb_wait = true;
    while unsafe { core::ptr::read_volatile(&gdb_wait) } {  }
}

unsafe fn ini() {
    interrupts::init_default();
}

fn end() {
    const OK_MESSAGE: &'static str = "[^_^]";

    println!("{}", OK_MESSAGE);
    vga::print(OK_MESSAGE.as_bytes());
    loop{}
}
<commit_msg>interrupt! added to main<commit_after>#![feature(lang_items)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(stmt_expr_attributes)]

#![no_std]

extern crate rlibc;
extern crate libc;

#[macro_use]
pub mod fmt;
#[macro_use]
pub mod interrupts;

pub mod serial;
pub mod error_handling;
pub mod ioports;
pub mod vga;
pub mod utility;

use fmt::Write;

#[no_mangle]
pub unsafe extern fn main() {
    #[cfg(gdb)] gdb_start();
    #[cfg(os_test)] test_all();
    println!("Hello, World");
    ini();

    interrupt!(55);

    end();
}

#[cfg(os_test)]
fn test_all() {
    fmt::tests::all();
}

#[cfg(gdb)]
fn gdb_start() {
    let mut gdb_wait = true;
    while unsafe { core::ptr::read_volatile(&gdb_wait) } {  }
}

unsafe fn ini() {
    interrupts::init_default();
}

fn end() {
    const OK_MESSAGE: &'static str = "[^_^]";

    println!("{}", OK_MESSAGE);
    vga::print(OK_MESSAGE.as_bytes());
    loop{}
}
<|endoftext|>


<commit_before>//! A TOML-parsing library
//!
//! This library is an implementation in Rust of a parser for TOML configuration
//! files [1]. It is focused around high quality errors including specific spans
//! and detailed error messages when things go wrong.
//!
//! This implementation currently passes the language agnostic [test suite][2].
//!
//! # Example
//!
//! ```
//! let toml = r#"
//!     [test]
//!     foo = "bar"
//! "#;
//!
//! let value = toml::Parser::new(toml).parse().unwrap();
//! println!("{}", value);
//! ```
//!
//! # Conversions
//!
//! This library also supports using the standard `Encodable` and `Decodable`
//! traits with TOML values. This library provides the following conversion
//! capabilities:
//!
//! * `String` => `toml::Value` - via `Parser`
//! * `toml::Value` => `String` - via `Show`
//! * `toml::Value` => rust object - via `Decoder`
//! * rust object => `toml::Value` - via `Encoder`
//!
//! Convenience functions for performing multiple conversions at a time are also
//! provided.
//!
//! [1]: https://github.com/mojombo/toml
//! [2]: https://github.com/BurntSushi/toml-test
//!

#![crate_name = "toml"]
#![crate_type = "lib"]
#![feature(macro_rules)]
#![deny(missing_docs)]

extern crate serialize;

use std::collections::TreeMap;
use std::from_str::FromStr;
use std::string;

pub use parser::{Parser, ParserError};
pub use serialization::{Encoder, encode, encode_str};
pub use serialization::{Decoder, decode, decode_str};
pub use serialization::{Error, NeedsKey, NoValue};
pub use serialization::{InvalidMapKeyLocation, InvalidMapKeyType};
pub use serialization::{DecodeError, ApplicationError, ExpectedField};
pub use serialization::{ExpectedMapElement, ExpectedMapKey, NoEnumVariants};
pub use serialization::{ExpectedType, NilTooLong};

mod parser;
mod show;
mod serialization;
#[cfg(test)]mod test;
/// Representation of a TOML value.
#[deriving(PartialEq, Clone)]
#[allow(missing_docs)]
pub enum Value {
    String(string::String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(string::String),
    Array(TomlArray),
    Table(TomlTable),
}

pub type TomlArray = Vec<Value>;
pub type TomlTable = TreeMap<string::String, Value>;

impl Value {
    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        match (self, other) {
            (&String(..), &String(..)) |
            (&Integer(..), &Integer(..)) |
            (&Float(..), &Float(..)) |
            (&Boolean(..), &Boolean(..)) |
            (&Datetime(..), &Datetime(..)) |
            (&Array(..), &Array(..)) |
            (&Table(..), &Table(..)) => true,

            _ => false,
        }
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            String(..) => "string",
            Integer(..) => "integer",
            Float(..) => "float",
            Boolean(..) => "boolean",
            Datetime(..) => "datetime",
            Array(..) => "array",
            Table(..) => "table",
        }
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
        match *self { String(ref s) => Some(s.as_slice()), _ => None }
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self { Integer(i) => Some(i), _ => None }
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self { Float(f) => Some(f), _ => None }
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self { Boolean(b) => Some(b), _ => None }
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime<'a>(&'a self) -> Option<&'a str> {
        match *self { Datetime(ref s) => Some(s.as_slice()), _ => None }
    }

    /// Extracts the array value if it is an array.
    pub fn as_slice<'a>(&'a self) -> Option<&'a [Value]> {
        match *self { Array(ref s) => Some(s.as_slice()), _ => None }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table<'a>(&'a self) -> Option<&'a TomlTable> {
        match *self { Table(ref s) => Some(s), _ => None }
    }

    /// Lookups for value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// ```
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let value: toml::Value = from_str(toml).unwrap();
    ///
    /// let foo = value.lookup("test.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "bar");
    ///
    /// let foo = value.lookup("values.1.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "qux");
    ///
    /// let no_bar = value.lookup("test.bar");
    /// assert_eq!(no_bar.is_none(), true);
    /// ```
    pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
        let mut cur_value = self;
        for key in path.split('.') {
            match cur_value {
                &Table(ref hm) => {
                    match hm.find_with(|k| key.cmp(k.as_slice())) {
                        Some(v) => cur_value = v,
                        _ => return None
                    }
                },
                &Array(ref v) => {
                    let idx: Option<uint> = FromStr::from_str(key);
                    match idx {
                        Some(idx) if idx < v.len() => cur_value = &v[idx],
                        _ => return None
                    }
                },
                _ => return None
            }
        };

        Some(cur_value)
    }
}

impl FromStr for Value {
    fn from_str(s: &str) -> Option<Value> {
        Parser::new(s).parse().map(Table)
    }
}

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

    #[test]
    fn lookup_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let value: Value = from_str(toml).unwrap();

        let test_foo = value.lookup("test.foo").unwrap();
        assert_eq!(test_foo.as_str().unwrap(), "bar");

        let foo1 = value.lookup("values.1.foo").unwrap();
        assert_eq!(foo1.as_str().unwrap(), "qux");

        let no_bar = value.lookup("test.bar");
        assert!(no_bar.is_none());
    }

    #[test]
    fn lookup_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let value: Value = from_str(toml).unwrap();

        let foo = value.lookup("test.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.100.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.str.foo");
        assert!(foo.is_none());
    }
}
<commit_msg>FromStr fixes<commit_after>//! A TOML-parsing library
//!
//! This library is an implementation in Rust of a parser for TOML configuration
//! files [1]. It is focused around high quality errors including specific spans
//! and detailed error messages when things go wrong.
//!
//! This implementation currently passes the language agnostic [test suite][2].
//!
//! # Example
//!
//! ```
//! let toml = r#"
//!     [test]
//!     foo = "bar"
//! "#;
//!
//! let value = toml::Parser::new(toml).parse().unwrap();
//! println!("{}", value);
//! ```
//!
//! # Conversions
//!
//! This library also supports using the standard `Encodable` and `Decodable`
//! traits with TOML values. This library provides the following conversion
//! capabilities:
//!
//! * `String` => `toml::Value` - via `Parser`
//! * `toml::Value` => `String` - via `Show`
//! * `toml::Value` => rust object - via `Decoder`
//! * rust object => `toml::Value` - via `Encoder`
//!
//! Convenience functions for performing multiple conversions at a time are also
//! provided.
//!
//! [1]: https://github.com/mojombo/toml
//! [2]: https://github.com/BurntSushi/toml-test
//!

#![crate_name = "toml"]
#![crate_type = "lib"]
#![feature(macro_rules)]
#![deny(missing_docs)]

extern crate serialize;

use std::collections::TreeMap;
use std::str::FromStr;
use std::string;

pub use parser::{Parser, ParserError};
pub use serialization::{Encoder, encode, encode_str};
pub use serialization::{Decoder, decode, decode_str};
pub use serialization::{Error, NeedsKey, NoValue};
pub use serialization::{InvalidMapKeyLocation, InvalidMapKeyType};
pub use serialization::{DecodeError, ApplicationError, ExpectedField};
pub use serialization::{ExpectedMapElement, ExpectedMapKey, NoEnumVariants};
pub use serialization::{ExpectedType, NilTooLong};

mod parser;
mod show;
mod serialization;
#[cfg(test)]mod test;
/// Representation of a TOML value.
#[deriving(PartialEq, Clone)]
#[allow(missing_docs)]
pub enum Value {
    String(string::String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(string::String),
    Array(TomlArray),
    Table(TomlTable),
}

pub type TomlArray = Vec<Value>;
pub type TomlTable = TreeMap<string::String, Value>;

impl Value {
    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        match (self, other) {
            (&String(..), &String(..)) |
            (&Integer(..), &Integer(..)) |
            (&Float(..), &Float(..)) |
            (&Boolean(..), &Boolean(..)) |
            (&Datetime(..), &Datetime(..)) |
            (&Array(..), &Array(..)) |
            (&Table(..), &Table(..)) => true,

            _ => false,
        }
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            String(..) => "string",
            Integer(..) => "integer",
            Float(..) => "float",
            Boolean(..) => "boolean",
            Datetime(..) => "datetime",
            Array(..) => "array",
            Table(..) => "table",
        }
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
        match *self { String(ref s) => Some(s.as_slice()), _ => None }
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self { Integer(i) => Some(i), _ => None }
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self { Float(f) => Some(f), _ => None }
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self { Boolean(b) => Some(b), _ => None }
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime<'a>(&'a self) -> Option<&'a str> {
        match *self { Datetime(ref s) => Some(s.as_slice()), _ => None }
    }

    /// Extracts the array value if it is an array.
    pub fn as_slice<'a>(&'a self) -> Option<&'a [Value]> {
        match *self { Array(ref s) => Some(s.as_slice()), _ => None }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table<'a>(&'a self) -> Option<&'a TomlTable> {
        match *self { Table(ref s) => Some(s), _ => None }
    }

    /// Lookups for value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// ```
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let value: toml::Value = from_str(toml).unwrap();
    ///
    /// let foo = value.lookup("test.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "bar");
    ///
    /// let foo = value.lookup("values.1.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "qux");
    ///
    /// let no_bar = value.lookup("test.bar");
    /// assert_eq!(no_bar.is_none(), true);
    /// ```
    pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
        let mut cur_value = self;
        for key in path.split('.') {
            match cur_value {
                &Table(ref hm) => {
                    match hm.find_with(|k| key.cmp(k.as_slice())) {
                        Some(v) => cur_value = v,
                        _ => return None
                    }
                },
                &Array(ref v) => {
                    let idx: Option<uint> = FromStr::from_str(key);
                    match idx {
                        Some(idx) if idx < v.len() => cur_value = &v[idx],
                        _ => return None
                    }
                },
                _ => return None
            }
        };

        Some(cur_value)
    }
}

impl FromStr for Value {
    fn from_str(s: &str) -> Option<Value> {
        Parser::new(s).parse().map(Table)
    }
}

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

    #[test]
    fn lookup_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let value: Value = from_str(toml).unwrap();

        let test_foo = value.lookup("test.foo").unwrap();
        assert_eq!(test_foo.as_str().unwrap(), "bar");

        let foo1 = value.lookup("values.1.foo").unwrap();
        assert_eq!(foo1.as_str().unwrap(), "qux");

        let no_bar = value.lookup("test.bar");
        assert!(no_bar.is_none());
    }

    #[test]
    fn lookup_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let value: Value = from_str(toml).unwrap();

        let foo = value.lookup("test.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.100.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.str.foo");
        assert!(foo.is_none());
    }
}
<|endoftext|>