<commit_before>/* diosix hypervisor main entry code
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* let the compiler know we're on our own here in bare-metal world */
#![no_std]
#![no_main]
#![feature(asm)]

#![allow(dead_code)]
#![allow(unused_unsafe)]
#![allow(improper_ctypes)]
#![feature(type_ascription)]

/* provide a framework for unit testing */
#![feature(custom_test_frameworks)]
#![test_runner(crate::run_tests)]
#![reexport_test_harness_main = "hvtests"] /* entry point for tests */

/* plug our custom heap allocator into the Rust language: Box, etc */
#![feature(alloc_error_handler)]
#![feature(box_syntax)]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;

/* needed to convert raw dtb pointer into a slice */
use core::slice;

/* needed for fast lookup tables of stuff */
extern crate hashbrown;

/* needed for elf parsing */
extern crate xmas_elf;

/* needed for device tree parsing and manipulation */
extern crate devicetree;

/* needed for parsing diosix manifest file-system (DMFS) images bundled with the hypervisor */
extern crate dmfs;

/* pass the feature qemudebug to be able to write direct to the emulator's stdout
via the macro qemuprint::println!() */
#[cfg(feature = "qemudebug")]
extern crate qemuprint;

/* needed for lazyily-allocated static variables */
#[macro_use]
extern crate lazy_static;

/* this will bring in all the hardware-specific code */
extern crate platform;

/* and now for all our non-hw specific code */
#[macro_use]
mod debug;      /* get us some kind of debug output, typically to a serial port */
#[macro_use]
mod capsule;    /* manage capsules */
#[macro_use]
mod heap;       /* per-CPU private heap management */
#[macro_use]
mod physmem;    /* manage host physical memory */
mod hardware;   /* parse device trees into hardware objects */
mod panic;      /* implement panic() handlers */
mod irq;        /* handle hw interrupts and sw exceptions, collectively known as IRQs */
mod virtmem;    /* manage capsule virtual memory */
mod pcore;      /* manage CPU cores */
mod vcore;      /* virtual CPU core management... */
mod scheduler;  /* ...and scheduling */
mod loader;     /* parse and load supervisor binaries */
mod message;    /* send messages between physical cores */
mod service;    /* allow capsules to register services */
mod manifest;   /* manage capsules loaded with the hypervisor */

/* needed for exclusive locks */
mod lock;
use lock::Mutex;

/* list of error codes */
mod error;
use error::Cause;

use pcore::{PhysicalCoreID, BOOT_PCORE_ID};

/* tell Rust to use our HVallocator to allocate and free heap memory.
although we'll keep track of physical memory, we'll let Rust perform essential
tasks, such as dropping objects when it's no longer needed, borrow checking, etc */
#[global_allocator]
static HV_HEAP: heap::HVallocator = heap::HVallocator;

/* set to true to allow physical CPU cores to start running supervisor code */
lazy_static!
{
    static ref INIT_DONE: Mutex<bool> = Mutex::new("system bring-up", false);
}

/* a physical CPU core obtaining this lock when it is false must walk the DMFS, create
capsules required to run at boot time, and set the flag to true. any other core
obtaining it as true must release the lock and move on */
lazy_static!
{
    static ref MANIFEST_UNPACKED: Mutex<bool> = Mutex::new("dmfs unpacked", false);
}

/* set to true if individual cores can sound off their presence and capabilities */
lazy_static!
{
    static ref ROLL_CALL: Mutex<bool> = Mutex::new("CPU roll call", false);
}

/* pointer sizes: do not assume this is a 32-bit or 64-bit system. it could be either.
in future, we may support 16- or 128-bit, too. stick to usize as much as possible */

/* hventry
   This is the official entry point of the Rust-level hypervisor.
   Call hvmain, which is where all the real work happens, and catch any errors.
   => cpu_nr = this boot-assigned CPU ID number
      dtb_ptr = pointer to start of device tree blob structure
      dtb_len = 32-bit big-endian length of the device tree blob
   <= return to infinite loop, awaiting interrupts */
#[no_mangle]
pub extern "C" fn hventry(cpu_nr: PhysicalCoreID, dtb_ptr: *const u8, dtb_len: u32)
{
    /* carry out tests if that's what we're here for */
    #[cfg(test)]
    hvtests();

    /* if not performing tests, start the system as normal */
    match hvmain(cpu_nr, dtb_ptr, dtb_len)
    {
        Err(e) =>
        {
            hvalert!("Hypervisor failed to start. Reason: {:?}", e);
            debughousekeeper!(); /* attempt to flush queued debug to output */
        },
        _ => () /* continue waiting for an IRQ to come in */
    }
}

/* hvmain
   This code runs at the hypervisor level, with full physical memory access.
   Its job is to initialize physical CPU cores and other resources so that capsules can be
   created in which supervisors run that manage their own user spaces, in which
   applications run. The hypervisor ensures capsules are kept apart using
   hardware protections.

   Assumes all physical CPU cores enter this function during startup.
   The boot CPU is chosen to initialize the system in pre-SMP mode.
   If we're on a single CPU core then everything should still run OK.
   Assumes hardware and exception interrupts are enabled and handlers
   installed.

   Also assumes all CPU cores are compatible ISA-wise. There is provision
   for marking some cores as more powerful than others for systems with
   a mix of performance and efficiency CPU cores.

   => cpu_nr = arbitrary CPU core ID number assigned by boot code,
               separate from hardware ID number.
               BOOT_PCORE_ID = boot CPU core.
      dtb_ptr = pointer to device tree in memory from bootlaoder
      dtb_len = 32-bit big endian size of the device tree
   <= return to infinite loop, waiting for interrupts
*/
fn hvmain(cpu_nr: PhysicalCoreID, dtb_ptr: *const u8, dtb_len: u32) -> Result<(), Cause>
{
    /* set up each physical processor core with its own private heap pool and any other resources.
    each private pool uses physical memory assigned by the pre-hvmain boot code. init() should be called
    first thing to set up each processor core, including the boot CPU, which then sets up the global
    resources. all non-boot CPUs should wait until global resources are ready. */
    pcore::PhysicalCore::init(cpu_nr);

    /* note that pre-physmem::init(), CPU cores rely on their pre-hventry()-assigned
    heap space. after physmem::init(), CPU cores can extend their heaps using physical memory.
    the hypervisor will become stuck pre-physmem::init() if it goes beyond its assigned heap space. */

    match cpu_nr
    {
        /* delegate to boot CPU the welcome banner and set up global resources.
        note: the platform code should ensure whichever CPU core is assigned
        BOOT_PCORE_ID as its cpu_nr can initialize the hypervisor */
        BOOT_PCORE_ID =>
        {
            /* convert the dtb pointer into a rust byte slice. assumes dtb_len is valid */
            let dtb = unsafe { slice::from_raw_parts(dtb_ptr, u32::from_be(dtb_len) as usize) };

            /* process device tree to create data structures representing system hardware,
            allowing these peripherals to be accessed by subsequent routines. this should
            also initialize any found hardware */
            hardware::parse_and_init(dtb)?;

            /* register all the available physical RAM */
            physmem::init()?;
            describe_system();

            /* allow other cores to continue */
            *(INIT_DONE.lock()) = true;
        },

        /* non-boot cores must wait here for early initialization to complete */
        _ => while *(INIT_DONE.lock()) != true {}
    }

    /* we're now ready to start creating capsules to run from the bundled DMFS image.
    the hypervisor can't make any assumptions about the underlying hardware.
    the device tree for these early capsules is derived from the host's device tree,
    modified to virtualize the peripherals. the virtual CPU cores that will run the
    capsule are based on the physical CPU core that creates it. ensure a suitable
    physical CPU core creates the boot-time capsules. this is more straightforward
    than the hypervisor trying to specify a hypothetical CPU core */
    if pcore::PhysicalCore::smode_supported() == true
    {
        let mut flag = MANIFEST_UNPACKED.lock();

        if *flag == false
        {
            /* process the manifest and mark it as handled */
            process_manifest()?;
            *flag = true;

            /* allow all working cores to join the roll call */
            *(ROLL_CALL.lock()) = true;
        }
    }

    /* once ROLL_CALL is set to true, acknowledge we're alive and well, and report CPU core features */
    while *(ROLL_CALL.lock()) != true {}
    hvdebug!("Physical CPU core {:?} ready to roll", pcore::PhysicalCore::describe());

    /* enable timer on this physical CPU core to start scheduling and running virtual cores */
    scheduler::start()?;

    /* initialization complete. fall through to infinite loop waiting for a timer interrupt
    to come in. when it does fire, this stack will be flattened, a virtual CPU loaded up to run,
    and this boot thread will disappear. thus, the call to start() should be the last thing
    this boot thread does */
    Ok(())
}

fn process_manifest() -> Result<(), Cause>
{
    /* process the contents of the DMFS image, including
    printing to the debug port any messages and creating
    capsules to run system services and supplied guests */
    manifest::unpack_at_boot()?;
    Ok(())
}

/* dump system information to the user */
fn describe_system()
{
    const KILOBYTE: usize = 1024;
    const MEGABYTE: usize = KILOBYTE * KILOBYTE;
    const GIGABYTE: usize = KILOBYTE * MEGABYTE;

    /* say hello via the debug port with some information */
    hvdebug!("Diosix {} :: Debug enabled. {} and {} RAM found",

        /* build version number */
        env!("CARGO_PKG_VERSION"),

        /* report number of CPU cores found */
        match hardware::get_nr_cpu_cores()
        {
            None | Some(0) => format!("no CPU cores"),
            Some(1) => format!("1 CPU core"),
            Some(c) => format!("{} CPU cores", c)
        },

        /* count up total system RAM using GiB / MiB / KiB */
        match hardware::get_phys_ram_total()
        {
            Some(t) => if t >= GIGABYTE
            {
                format!("{} GiB", t / GIGABYTE)
            }
            else if t >= MEGABYTE
            {
                format!("{} MiB", t / MEGABYTE)
            }
            else
            {
                format!("{} KiB", t / KILOBYTE)
            },

            None => format!("no")
    });
}

/* mandatory error handler for memory allocations */
#[alloc_error_handler]
fn hvalloc_error(attempt: core::alloc::Layout) -> !
{
    let heap = &(*<pcore::PhysicalCore>::this()).heap;
    hvalert!("hvalloc_error: Failed to allocate/free {} bytes. Heap: {:?}", attempt.size(), heap);
    debughousekeeper!();
    loop {} /* it would be nice to be able to not die here :( */
}

/* perform all unit tests required */
#[cfg(test)]
fn run_tests(unit_tests: &[&dyn Fn()])
{
    /* run each test one by one */
    for test in unit_tests
    {
        test();
    }

    /* exit cleanly once tests are complete */
    platform::test::end(Ok(0));
}

#[test_case]
fn test_assertion()
{
    assert_eq!(42, 42);
}<commit_msg>Remove reference to qemuprint * This is no longer needed, and implemented as a cargo feature instead<commit_after>/* diosix hypervisor main entry code
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* let the compiler know we're on our own here in bare-metal world */
#![no_std]
#![no_main]
#![feature(asm)]

#![allow(dead_code)]
#![allow(unused_unsafe)]
#![allow(improper_ctypes)]
#![feature(type_ascription)]

/* provide a framework for unit testing */
#![feature(custom_test_frameworks)]
#![test_runner(crate::run_tests)]
#![reexport_test_harness_main = "hvtests"] /* entry point for tests */

/* plug our custom heap allocator into the Rust language: Box, etc */
#![feature(alloc_error_handler)]
#![feature(box_syntax)]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;

/* needed to convert raw dtb pointer into a slice */
use core::slice;

/* needed for fast lookup tables of stuff */
extern crate hashbrown;

/* needed for elf parsing */
extern crate xmas_elf;

/* needed for device tree parsing and manipulation */
extern crate devicetree;

/* needed for parsing diosix manifest file-system (DMFS) images bundled with the hypervisor */
extern crate dmfs;

/* needed for lazyily-allocated static variables */
#[macro_use]
extern crate lazy_static;

/* this will bring in all the hardware-specific code */
extern crate platform;

/* and now for all our non-hw specific code */
#[macro_use]
mod debug;      /* get us some kind of debug output, typically to a serial port */
#[macro_use]
mod capsule;    /* manage capsules */
#[macro_use]
mod heap;       /* per-CPU private heap management */
#[macro_use]
mod physmem;    /* manage host physical memory */
mod hardware;   /* parse device trees into hardware objects */
mod panic;      /* implement panic() handlers */
mod irq;        /* handle hw interrupts and sw exceptions, collectively known as IRQs */
mod virtmem;    /* manage capsule virtual memory */
mod pcore;      /* manage CPU cores */
mod vcore;      /* virtual CPU core management... */
mod scheduler;  /* ...and scheduling */
mod loader;     /* parse and load supervisor binaries */
mod message;    /* send messages between physical cores */
mod service;    /* allow capsules to register services */
mod manifest;   /* manage capsules loaded with the hypervisor */

/* needed for exclusive locks */
mod lock;
use lock::Mutex;

/* list of error codes */
mod error;
use error::Cause;

use pcore::{PhysicalCoreID, BOOT_PCORE_ID};

/* tell Rust to use our HVallocator to allocate and free heap memory.
although we'll keep track of physical memory, we'll let Rust perform essential
tasks, such as dropping objects when it's no longer needed, borrow checking, etc */
#[global_allocator]
static HV_HEAP: heap::HVallocator = heap::HVallocator;

/* set to true to allow physical CPU cores to start running supervisor code */
lazy_static!
{
    static ref INIT_DONE: Mutex<bool> = Mutex::new("system bring-up", false);
}

/* a physical CPU core obtaining this lock when it is false must walk the DMFS, create
capsules required to run at boot time, and set the flag to true. any other core
obtaining it as true must release the lock and move on */
lazy_static!
{
    static ref MANIFEST_UNPACKED: Mutex<bool> = Mutex::new("dmfs unpacked", false);
}

/* set to true if individual cores can sound off their presence and capabilities */
lazy_static!
{
    static ref ROLL_CALL: Mutex<bool> = Mutex::new("CPU roll call", false);
}

/* pointer sizes: do not assume this is a 32-bit or 64-bit system. it could be either.
in future, we may support 16- or 128-bit, too. stick to usize as much as possible */

/* hventry
   This is the official entry point of the Rust-level hypervisor.
   Call hvmain, which is where all the real work happens, and catch any errors.
   => cpu_nr = this boot-assigned CPU ID number
      dtb_ptr = pointer to start of device tree blob structure
      dtb_len = 32-bit big-endian length of the device tree blob
   <= return to infinite loop, awaiting interrupts */
#[no_mangle]
pub extern "C" fn hventry(cpu_nr: PhysicalCoreID, dtb_ptr: *const u8, dtb_len: u32)
{
    /* carry out tests if that's what we're here for */
    #[cfg(test)]
    hvtests();

    /* if not performing tests, start the system as normal */
    match hvmain(cpu_nr, dtb_ptr, dtb_len)
    {
        Err(e) =>
        {
            hvalert!("Hypervisor failed to start. Reason: {:?}", e);
            debughousekeeper!(); /* attempt to flush queued debug to output */
        },
        _ => () /* continue waiting for an IRQ to come in */
    }
}

/* hvmain
   This code runs at the hypervisor level, with full physical memory access.
   Its job is to initialize physical CPU cores and other resources so that capsules can be
   created in which supervisors run that manage their own user spaces, in which
   applications run. The hypervisor ensures capsules are kept apart using
   hardware protections.

   Assumes all physical CPU cores enter this function during startup.
   The boot CPU is chosen to initialize the system in pre-SMP mode.
   If we're on a single CPU core then everything should still run OK.
   Assumes hardware and exception interrupts are enabled and handlers
   installed.

   Also assumes all CPU cores are compatible ISA-wise. There is provision
   for marking some cores as more powerful than others for systems with
   a mix of performance and efficiency CPU cores.

   => cpu_nr = arbitrary CPU core ID number assigned by boot code,
               separate from hardware ID number.
               BOOT_PCORE_ID = boot CPU core.
      dtb_ptr = pointer to device tree in memory from bootlaoder
      dtb_len = 32-bit big endian size of the device tree
   <= return to infinite loop, waiting for interrupts
*/
fn hvmain(cpu_nr: PhysicalCoreID, dtb_ptr: *const u8, dtb_len: u32) -> Result<(), Cause>
{
    /* set up each physical processor core with its own private heap pool and any other resources.
    each private pool uses physical memory assigned by the pre-hvmain boot code. init() should be called
    first thing to set up each processor core, including the boot CPU, which then sets up the global
    resources. all non-boot CPUs should wait until global resources are ready. */
    pcore::PhysicalCore::init(cpu_nr);

    /* note that pre-physmem::init(), CPU cores rely on their pre-hventry()-assigned
    heap space. after physmem::init(), CPU cores can extend their heaps using physical memory.
    the hypervisor will become stuck pre-physmem::init() if it goes beyond its assigned heap space. */

    match cpu_nr
    {
        /* delegate to boot CPU the welcome banner and set up global resources.
        note: the platform code should ensure whichever CPU core is assigned
        BOOT_PCORE_ID as its cpu_nr can initialize the hypervisor */
        BOOT_PCORE_ID =>
        {
            /* convert the dtb pointer into a rust byte slice. assumes dtb_len is valid */
            let dtb = unsafe { slice::from_raw_parts(dtb_ptr, u32::from_be(dtb_len) as usize) };

            /* process device tree to create data structures representing system hardware,
            allowing these peripherals to be accessed by subsequent routines. this should
            also initialize any found hardware */
            hardware::parse_and_init(dtb)?;

            /* register all the available physical RAM */
            physmem::init()?;
            describe_system();

            /* allow other cores to continue */
            *(INIT_DONE.lock()) = true;
        },

        /* non-boot cores must wait here for early initialization to complete */
        _ => while *(INIT_DONE.lock()) != true {}
    }

    /* we're now ready to start creating capsules to run from the bundled DMFS image.
    the hypervisor can't make any assumptions about the underlying hardware.
    the device tree for these early capsules is derived from the host's device tree,
    modified to virtualize the peripherals. the virtual CPU cores that will run the
    capsule are based on the physical CPU core that creates it. ensure a suitable
    physical CPU core creates the boot-time capsules. this is more straightforward
    than the hypervisor trying to specify a hypothetical CPU core */
    if pcore::PhysicalCore::smode_supported() == true
    {
        let mut flag = MANIFEST_UNPACKED.lock();

        if *flag == false
        {
            /* process the manifest and mark it as handled */
            process_manifest()?;
            *flag = true;

            /* allow all working cores to join the roll call */
            *(ROLL_CALL.lock()) = true;
        }
    }

    /* once ROLL_CALL is set to true, acknowledge we're alive and well, and report CPU core features */
    while *(ROLL_CALL.lock()) != true {}
    hvdebug!("Physical CPU core {:?} ready to roll", pcore::PhysicalCore::describe());

    /* enable timer on this physical CPU core to start scheduling and running virtual cores */
    scheduler::start()?;

    /* initialization complete. fall through to infinite loop waiting for a timer interrupt
    to come in. when it does fire, this stack will be flattened, a virtual CPU loaded up to run,
    and this boot thread will disappear. thus, the call to start() should be the last thing
    this boot thread does */
    Ok(())
}

fn process_manifest() -> Result<(), Cause>
{
    /* process the contents of the DMFS image, including
    printing to the debug port any messages and creating
    capsules to run system services and supplied guests */
    manifest::unpack_at_boot()?;
    Ok(())
}

/* dump system information to the user */
fn describe_system()
{
    const KILOBYTE: usize = 1024;
    const MEGABYTE: usize = KILOBYTE * KILOBYTE;
    const GIGABYTE: usize = KILOBYTE * MEGABYTE;

    /* say hello via the debug port with some information */
    hvdebug!("Diosix {} :: Debug enabled. {} and {} RAM found",

        /* build version number */
        env!("CARGO_PKG_VERSION"),

        /* report number of CPU cores found */
        match hardware::get_nr_cpu_cores()
        {
            None | Some(0) => format!("no CPU cores"),
            Some(1) => format!("1 CPU core"),
            Some(c) => format!("{} CPU cores", c)
        },

        /* count up total system RAM using GiB / MiB / KiB */
        match hardware::get_phys_ram_total()
        {
            Some(t) => if t >= GIGABYTE
            {
                format!("{} GiB", t / GIGABYTE)
            }
            else if t >= MEGABYTE
            {
                format!("{} MiB", t / MEGABYTE)
            }
            else
            {
                format!("{} KiB", t / KILOBYTE)
            },

            None => format!("no")
    });
}

/* mandatory error handler for memory allocations */
#[alloc_error_handler]
fn hvalloc_error(attempt: core::alloc::Layout) -> !
{
    let heap = &(*<pcore::PhysicalCore>::this()).heap;
    hvalert!("hvalloc_error: Failed to allocate/free {} bytes. Heap: {:?}", attempt.size(), heap);
    debughousekeeper!();
    loop {} /* it would be nice to be able to not die here :( */
}

/* perform all unit tests required */
#[cfg(test)]
fn run_tests(unit_tests: &[&dyn Fn()])
{
    /* run each test one by one */
    for test in unit_tests
    {
        test();
    }

    /* exit cleanly once tests are complete */
    platform::test::end(Ok(0));
}

#[test_case]
fn test_assertion()
{
    assert_eq!(42, 42);
}<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate redis;
extern crate rustc_serialize;
extern crate hyper;
extern crate url;

use std::path::Path;
use std::io::Read;
use std::env;

use rustc_serialize::json::Json;

use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::status;
use iron::Url as iUrl;

use url::Url;

use hyper::Client;
use hyper::header;

use staticfile::Static;
use router::Router;

use redis::Commands;

fn main() {

    let router = router!(
        get "/github/:user/:repo/:branch/badge.svg" => github_handler,
        get "/github/:user/:repo/badge.svg" => github_handler,
        get "/" => Static::new(Path::new("static"))
    );

    println!("Check out 8080");
    Iron::new(router).http("0.0.0.0:8080").unwrap();

    fn github_handler(req: &mut Request) -> IronResult<Response> {

        let ref router = req.extensions.get::<Router>().unwrap();
        let user = router.find("user").unwrap();
        let repo = router.find("repo").unwrap();
        let branch = router.find("branch").unwrap_or("master");
        let ext = router.find("ext").unwrap_or("svg");
        let key = format!("{}/{}:{} ", user, repo, branch);

        let redis: redis::Connection = setup_redis();
        // Create a client.

        if let Some(url) = get_redis_redir(&redis, &key){
            return redir(&url);
        }

        let hyper_client: Client = Client::new();

        let github_url = format!("https://api.github.com/repos/{0}/{1}/git/refs/heads/{2}", user, repo, branch);
        if let Some(body) = fetch(&hyper_client, &github_url) {
            if let Ok(json) = Json::from_str(&body) {
                if let Some(sha) = json.find_path(&["object", "sha"]) {
                    let sha_key = format!("{}/{}:{} ", user, repo, sha);

                    if let Some(url) = get_redis_redir(&redis, &sha_key) {
                        set_redis_cache(&redis, &key, &url.clone().serialize());
                        return redir(&url);
                    }

                    let linting_url = format!("https://img.shields.io/badge/clippy-linting-blue.{}", &ext);

                    set_redis_cache(&redis, &sha_key, &linting_url);
                    set_redis_cache(&redis, &key, &linting_url);

                    // we are building. sent the appropriate

                    // let resp = format!("There shall be content here for {}", key);
                    return redir(&Url::parse(&linting_url).unwrap());
                } else {
                   return Ok(Response::with((status::InternalServerError,
                                             format!("SHA not found in JSON: {}", &json))))
               }
            } else {
               return Ok(Response::with((status::InternalServerError,
                                         format!("Couldn't parse Githubs JSON response: {}", &body))))
            }
        } else {
           return Ok(Response::with((status::InternalServerError,
                                     format!("Couldn't find on github {}", &github_url))))
            // return Ok(Response::with(status::NotFound))
        }

        Ok(Response::with(status::InternalServerError))
    }
}

fn set_redis_cache(redis: &redis::Connection, key: &str, value: &str) {
    redis::pipe()
        .cmd("SET").arg(key.clone()).arg(value).ignore()
        .cmd("EXPIRE").arg(key.clone()).arg(5 * 60).ignore() // we expire in 5min
        .execute(redis);
}

fn redir(url: &Url) -> IronResult<Response> {
    match iUrl::from_generic_url(url.clone()) {
        Ok(redir_url) => Ok(Response::with((status::TemporaryRedirect, Redirect(redir_url)))),
        Err(err) => Ok(Response::with((status::InternalServerError, err)))
    }
}

fn get_redis_redir(redis: &redis::Connection, key: &str) -> Option<Url> {
    let result : Option<String> = get_redis_value(redis, key);
    if result.is_some(){
        if let Ok(url) = Url::parse(&result.unwrap()){
            return Some(url);
        }
    }
    return None;
}

fn get_redis_value(redis: &redis::Connection, key: &str) -> Option<String> {

    let cached_result = redis.get(key);

    if cached_result.is_ok(){
        let cached_value : Option<String>  = cached_result.unwrap();
        if cached_value.is_some(){
            return cached_value;
        }
    }

    return None;
}

fn fetch(client: &Client, url: &str) -> Option<String> {
    let res = client.get(url)
                    .header(header::UserAgent("Clippy".to_owned()))
                    .header(header::Connection::close());
    if  let Ok(mut res) = res.send() {
        let mut body = String::new();
        if res.read_to_string(&mut body).is_ok(){
            return Some(body);
        }
    }

    return None;
}

fn setup_redis() -> redis::Connection<> {
    let url = redis::parse_redis_url(
            &env::var("REDIS_URL").unwrap_or("redis://redis/".to_string())
        ).unwrap();
    redis::Client::open(url
            ).unwrap(
            ).get_connection(
            ).unwrap()
}
<commit_msg>Also copy all parameters forward to shields.io<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate redis;
extern crate rustc_serialize;
extern crate hyper;
extern crate url;

use std::path::Path;
use std::io::Read;
use std::env;

use rustc_serialize::json::Json;

use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::status;
use iron::Url as iUrl;

use url::Url;

use hyper::Client;
use hyper::header;

use staticfile::Static;
use router::Router;

use redis::Commands;

fn main() {

    let router = router!(
        get "/github/:user/:repo/:branch/badge.svg" => github_handler,
        get "/github/:user/:repo/badge.svg" => github_handler,
        get "/" => Static::new(Path::new("static"))
    );

    println!("Check out 8080");
    Iron::new(router).http("0.0.0.0:8080").unwrap();

    fn github_handler(req: &mut Request) -> IronResult<Response> {

        let ref router = req.extensions.get::<Router>().unwrap();
        let user = router.find("user").unwrap();
        let repo = router.find("repo").unwrap();
        let branch = router.find("branch").unwrap_or("master");
        let ext = router.find("ext").unwrap_or("svg");
        let key = format!("{}/{}:{} ", user, repo, branch);

        let redis: redis::Connection = setup_redis();
        // Create a client.

        if let Some(url) = get_redis_redir(&redis, &key){
            return redir(&url, &req.url);
        }

        let hyper_client: Client = Client::new();

        let github_url = format!("https://api.github.com/repos/{0}/{1}/git/refs/heads/{2}", user, repo, branch);
        if let Some(body) = fetch(&hyper_client, &github_url) {
            if let Ok(json) = Json::from_str(&body) {
                if let Some(sha) = json.find_path(&["object", "sha"]) {
                    let sha_key = format!("{}/{}:{} ", user, repo, sha);

                    if let Some(url) = get_redis_redir(&redis, &sha_key) {
                        set_redis_cache(&redis, &key, &url.clone().serialize());
                        return redir(&url, &req.url);
                    }

                    let linting_url = format!("https://img.shields.io/badge/clippy-linting-blue.{}?", &ext);

                    set_redis_cache(&redis, &sha_key, &linting_url);
                    set_redis_cache(&redis, &key, &linting_url);

                    // let resp = format!("There shall be content here for {}", key);
                    return redir(&Url::parse(&linting_url).unwrap(), &req.url);
                } else {
                   return Ok(Response::with((status::InternalServerError,
                                             format!("SHA not found in JSON: {}", &json))))
               }
            } else {
               return Ok(Response::with((status::InternalServerError,
                                         format!("Couldn't parse Githubs JSON response: {}", &body))))
            }
        } else {
           return Ok(Response::with((status::InternalServerError,
                                     format!("Couldn't find on github {}", &github_url))))
            // return Ok(Response::with(status::NotFound))
        }

        Ok(Response::with(status::InternalServerError))
    }
}

fn set_redis_cache(redis: &redis::Connection, key: &str, value: &str) {
    redis::pipe()
        .cmd("SET").arg(key.clone()).arg(value).ignore()
        .cmd("EXPIRE").arg(key.clone()).arg(5 * 60).ignore() // we expire in 5min
        .execute(redis);
}

fn redir(url: &Url, source_url: &iUrl) -> IronResult<Response> {
    match iUrl::from_generic_url(url.clone()) {
        Ok(mut redir_url) => {
            if let Some(ref query) = source_url.query {
                redir_url.query = Some(query.clone());
            }
            Ok(Response::with((status::TemporaryRedirect,
                               Redirect(redir_url))))
        },
        Err(err) => Ok(Response::with((status::InternalServerError, err)))
    }
}

fn get_redis_redir(redis: &redis::Connection, key: &str) -> Option<Url> {
    let result : Option<String> = get_redis_value(redis, key);
    if result.is_some(){
        if let Ok(url) = Url::parse(&result.unwrap()){
            return Some(url);
        }
    }
    return None;
}

fn get_redis_value(redis: &redis::Connection, key: &str) -> Option<String> {

    let cached_result = redis.get(key);

    if cached_result.is_ok(){
        let cached_value : Option<String>  = cached_result.unwrap();
        if cached_value.is_some(){
            return cached_value;
        }
    }

    return None;
}

fn fetch(client: &Client, url: &str) -> Option<String> {
    let res = client.get(url)
                    .header(header::UserAgent("Clippy".to_owned()))
                    .header(header::Connection::close());
    if  let Ok(mut res) = res.send() {
        let mut body = String::new();
        if res.read_to_string(&mut body).is_ok(){
            return Some(body);
        }
    }

    return None;
}

fn setup_redis() -> redis::Connection<> {
    let url = redis::parse_redis_url(
            &env::var("REDIS_URL").unwrap_or("redis://redis/".to_string())
        ).unwrap();
    redis::Client::open(url
            ).unwrap(
            ).get_connection(
            ).unwrap()
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::HashMap;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_after(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                // We only check servers that existed in the clock
                // Because we can't tell sequences from missing servers
                if ac > bc {return true;}
            }
        }
        return false;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_after(clock_b) {
            return Relation::After;
        }
        if clock_b.happened_after(self) {
            return Relation::Before;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_after(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.happened_after(clock_b)
    }
    pub fn equals(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &VectorClock<u64>) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> VectorClock<u64> {
        let clock = self.clock.read();
        clock.clone()
    }
}
<commit_msg>ues happened before instead of after<commit_after>use std::hash::Hash;
use std::collections::HashMap;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                // We only check servers that existed in the clock
                // Because we can't tell sequences from missing servers
                if ac < bc {return true;}
            }
        }
        return false;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &VectorClock<u64>) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> VectorClock<u64> {
        let clock = self.clock.read();
        clock.clone()
    }
}
<|endoftext|>


<commit_before>use constants;

use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

// TODO: Eliminate hardcoded strings and ints
fn find_package(name: &str) -> String
{
    let mut list = match File::open(constants::PACKAGE_LIST) {
        Err(why) => panic!("An error occured. \n{}", why),
        Ok(file) => file,
    };

    let mut reader = BufReader::new(list);
    let mut buffer = String::new();

    for line in reader.lines() {
        let x = line.unwrap();
        let tokens: Vec<&str> = x.split(' ').collect();

        if tokens.len() < 2 {
            buffer.push_str("NOT FOUND");
        }
        else {
            if tokens[0] == name {
                buffer.push_str(tokens[1]);
            }
            else {
                buffer.push_str("NOT FOUND"); // this is only temporary!
            }
        }
    }

    buffer
}

fn retrieve_package(url: &str) // -> Path
{
    /*
      This function retrieves the package, and
      puts them in a temporary folder.
    */
}

fn verify_package(package: &File, provided: &str) -> bool
{
    /*
      This function verifies the package(CRC32 IEEE)
      retrieved by retrieve_package, and returns boolean indicating
      that the file is not corrupted.
    */
    true
}

fn copy_package()
{
    /*
      This function retrieves the package, and put them
      to specified locations accordingly.
    */
}

fn process_package()
{
    /*
      This function finalises the installation of
      the package, such as setting PATH and such.
    */
}

fn install()
{

}<commit_msg>Package verification completed<commit_after>use constants;
use wiz::verification;

use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

// TODO: Eliminate hardcoded strings and ints
fn find_package(name: &str) -> String
{
    let mut list = match File::open(constants::PACKAGE_LIST) {
        Err(why) => panic!("An error occured. \n{}", why),
        Ok(file) => file,
    };

    let mut reader = BufReader::new(list);
    let mut buffer = String::new();

    for line in reader.lines() {
        let x = line.unwrap();
        let tokens: Vec<&str> = x.split(' ').collect();

        if tokens.len() < 2 {
            buffer.push_str("NOT FOUND");
        }
        else {
            if tokens[0] == name {
                buffer.push_str(tokens[1]);
            }
            else {
                buffer.push_str("NOT FOUND"); // this is only temporary!
            }
        }
    }

    buffer
}

fn retrieve_package(url: &str) // -> Path
{
    /*
      This function retrieves the package, and
      puts them in a temporary folder.
    */
}

fn verify_package(package: &File, provided: u32) -> bool
{
    let checksum = verification::get_crc32(package);
    checksum == provided
}

fn copy_package()
{
    /*
      This function retrieves the package, and put them
      to specified locations accordingly.
    */
}

fn process_package()
{
    /*
      This function finalises the installation of
      the package, such as setting PATH and such.
    */
}

fn install()
{

}<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashSet};

use config::{Config};
use config::command::{MainCommand, SuperviseInfo};
use config::containers::Container;

#[derive(PartialEq, Eq, Hash)]
struct CommandOption<'a> {
    names: &'a [&'a str],
    has_args: bool,
    single: bool,
}

struct BuiltinCommand<'a> {
    name: &'a str,
    accept_container: bool,
    options: &'a [&'a CommandOption<'a>],
}

#[derive(Clone)]
struct SuperviseCommand<'a> {
    name: &'a str,
    info: &'a SuperviseInfo,
    options: &'a [&'a CommandOption<'a>],
}

struct SuperviseOption<'a> {
    cmd: SuperviseCommand<'a>,
    option: &'a CommandOption<'a>,
}

/**

Transition table:
             _______________________                 ______________
 +——————————|                       |——————————————>|              |
 |  +———————| GlobalOptionOrCommand |               | SuperviseArg |
 |  |  +————|_______________________|<———+   +——————|______________|<—————+
 |  |  |                                 |   |                            |
 |  |  |        _________________        |   |    ____________________    |
 |  |  |       |                 |       |   |   |                    |   |
 |  |  +——————>| GlobalOptionArg |———————+   +——>| SuperviseOptionArg |———+
 |  |          |_________________|               |____________________|
 |  |
 |  |       __________________________
 |  +—————>|                          |
 |  +——————| CommandOptionOrContainer |<——+
 |  |  +———|__________________________|   |
 |  |  |                                  |
 |  |  |        __________________        |
 |  |  |       |                  |       |
 |  |  +——————>| CommandOptionArg |———————+
 |  |          |__________________|
 |  |
 |  |             ____________
 |  +———————————>|            |
 |               | CommandArg |
 +——————————————>|____________|

*/
enum States<'a> {
    GlobalOptionOrCommand,
    GlobalOptionArg(&'a CommandOption<'a>),
    CommandOptionOrContainer(&'a BuiltinCommand<'a>),
    CommandOptionArg(&'a BuiltinCommand<'a>, &'a CommandOption<'a>),
    CommandArg,
    SuperviseArg(SuperviseCommand<'a>),
    SuperviseOptionArg(SuperviseOption<'a>),
}

struct Completion<'a> {
    commands: &'a BTreeMap<String, MainCommand>,
    containers: &'a BTreeMap<String, Container>,
    state: States<'a>,
    single_global_options: HashSet<&'a CommandOption<'a>>,
    single_command_options: HashSet<&'a CommandOption<'a>>,
    supervise_chosen_children: HashSet<&'a str>,
}

impl<'a> Completion<'a> {
    pub fn new(
        commands: &'a BTreeMap<String, MainCommand>,
        containers: &'a BTreeMap<String, Container>
    ) -> Completion<'a> {

        Completion {
            commands: commands,
            containers: containers,
            state: States::GlobalOptionOrCommand,
            single_global_options: HashSet::new(),
            single_command_options: HashSet::new(),
            supervise_chosen_children: HashSet::new(),
        }
    }

    pub fn trans(&mut self, arg: &'a str) {
        let mut next_state: Option<States> = None;
        match self.state {
            States::GlobalOptionOrCommand => {
                for cmd in BUILTIN_COMMANDS {
                    if cmd.name == arg {
                        self.state = States::CommandOptionOrContainer(cmd);
                        return;
                    }
                }
                for opt in GLOBAL_OPTIONS {
                    for &opt_name in opt.names {
                        if arg == opt_name {
                            if opt.has_args {
                                self.state = States::GlobalOptionArg(opt);
                            }
                            if opt.single {
                                self.single_global_options.insert(opt);
                            }
                            return;
                        }
                    }
                }
                for (cmd_name, user_cmd) in self.commands.iter() {
                    if arg != cmd_name {
                        continue;
                    }
                    match *user_cmd {
                        MainCommand::Command(_) => {
                            self.state = States::CommandArg;
                            return;
                        },
                        MainCommand::Supervise(ref supervise_info) => {
                            let supervise_cmd = SuperviseCommand {
                                name: cmd_name,
                                info: supervise_info,
                                options: SUPERVISE_OPTIONS,
                            };
                            self.state = States::SuperviseArg(supervise_cmd);
                            return;
                        },
                    }
                }
                self.state = States::CommandArg;
            },
            States::GlobalOptionArg(_) => {
                self.state = States::GlobalOptionOrCommand;
            },
            States::CommandOptionOrContainer(cmd) => {
                for cmd_opt in cmd.options {
                    for &opt_name in cmd_opt.names {
                        if arg == opt_name {
                            if cmd_opt.has_args {
                                self.state = States::CommandOptionArg(cmd, cmd_opt);
                            }
                            if cmd_opt.single {
                                self.single_command_options.insert(cmd_opt);
                            }
                            return;
                        }
                    }
                }
                self.state = States::CommandArg;
            },
            States::CommandOptionArg(cmd, _) => {
                self.state = States::CommandOptionOrContainer(cmd);
            },
            States::CommandArg => {},
            States::SuperviseArg(ref cmd) => {
                'options_label: for cmd_opt in cmd.options {
                    for &opt_name in cmd_opt.names {
                        if arg == opt_name {
                            let supervise_option = SuperviseOption {
                                cmd: cmd.clone(),
                                option: cmd_opt,
                            };
                            next_state = Some(States::SuperviseOptionArg(supervise_option));
                            break 'options_label;
                        }
                    }
                }
            },
            States::SuperviseOptionArg(ref opt) => {
                if opt.cmd.info.children.contains_key(arg) {
                    self.supervise_chosen_children.insert(arg);
                } else {
                    next_state = Some(States::SuperviseArg(opt.cmd.clone()));
                }
            },
        }

        if let Some(next_state) = next_state {
            self.state = next_state;
        }
    }

    pub fn complete(&self, cur: &str) -> Vec<&str> {
        let mut completions: Vec<&str> = Vec::new();
        match self.state {
            States::GlobalOptionOrCommand => {
                completions.extend(self.commands.keys().map(|c| &c[..]));
                if cur.starts_with("_") {
                    completions.extend(BUILTIN_COMMANDS.iter().map(|c| c.name));
                }
                if cur.starts_with("-") {
                    for opt in GLOBAL_OPTIONS {
                        if !self.single_global_options.contains(opt) {
                            completions.extend(opt.names);
                        }
                    }
                }
            },
            States::CommandOptionOrContainer(cmd) => {
                if cmd.accept_container {
                    completions.extend(self.containers.keys().map(|c| &c[..]));
                }
                if cur.starts_with("-") {
                    for opt in cmd.options {
                        if !self.single_command_options.contains(opt) {
                            completions.extend(opt.names);
                        }
                    }
                }
            },
            States::SuperviseArg(ref supervise_cmd) => {
                for opt in supervise_cmd.options {
                    completions.extend(opt.names);
                }
            },
            States::SuperviseOptionArg(ref supervise_opt) => {
                // TODO: specify which supervise options can accept child as argument
                for child in supervise_opt.cmd.info.children.keys() {
                    let child_name = &child[..];
                    if !self.supervise_chosen_children.contains(child_name) {
                        completions.push(child_name);
                    }
                }
            },
            _ => {},
        }
        completions.retain(|c| c.starts_with(cur));
        return completions;
    }
}

const BUILTIN_COMMANDS: &'static [&'static BuiltinCommand<'static>] = &[
    &BuiltinCommand {
        name: "_build",
        accept_container: true,
        options: &[
            &CommandOption { names: &["--force"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_build_shell",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_clean",
        accept_container: false,
        options: &[
            &CommandOption { names: &["--tmp", "--tmp-folders"], has_args: false, single: true },
            &CommandOption { names: &["--old", "--old-containers"], has_args: false, single: true },
            &CommandOption { names: &["--unused"], has_args: false, single: true },
            &CommandOption { names: &["--transient"], has_args: false, single: true },
            &CommandOption { names: &["--global"], has_args: false, single: true },
            &CommandOption { names: &["-n", "--dry-run"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_create_netns",
        accept_container: false,
        options: &[
            &CommandOption { names: &["--dry-run"], has_args: false, single: true },
            &CommandOption { names: &["--no-iptables"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_destroy_netns",
        accept_container: false,
        options: &[
            &CommandOption { names: &["--dry-run"], has_args: false, single: true },
            &CommandOption { names: &["--no-iptables"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_init_storage_dir",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_list",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_pack_image",
        accept_container: true,
        options: &[
            &CommandOption { names: &["-f", "--file"], has_args: true, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_run",
        accept_container: true,
        options: &[
            &CommandOption { names: &["-W", "--writable"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_run_in_netns",
        accept_container: true,
        options: &[
            &CommandOption { names: &["--pid"], has_args: true, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_version_hash",
        accept_container: true,
        options: &[
            &CommandOption { names: &["-s", "--short"], has_args: false, single: true },
            &CommandOption { names: &["-fd3"], has_args: false, single: true },
        ]
    },
];

const GLOBAL_OPTIONS: &'static [&'static CommandOption<'static>] = &[
    &CommandOption { names: &["-E", "--env", "--environ"], has_args: true, single: false },
    &CommandOption { names: &["-e", "--use-env"], has_args: true, single: false },
    &CommandOption { names: &["--ignore-owner-check"], has_args: false, single: true },
    &CommandOption { names: &["--no-build"], has_args: false, single: true },
    &CommandOption { names: &["--no-version-check"], has_args: false, single: true },
];

const SUPERVISE_OPTIONS: &'static [&'static CommandOption<'static>] = &[
    &CommandOption { names: &["--only"], has_args: true, single: false },
    &CommandOption { names: &["--exclude"], has_args: true, single: false },
];

pub fn generate_completions(config: &Config, args: Vec<String>) -> Result<i32, String> {
    let default_cur_arg = "".to_string();
    let mut splitted_args = args.splitn(2, |a| a == "--");
    let full_args = match splitted_args.next() {
        Some(a) => a.iter().collect::<Vec<_>>(),
        None => vec!(),
    };
    let cur_arg = match splitted_args.next() {
        Some(a) => a.get(0).unwrap_or(&default_cur_arg),
        None => &default_cur_arg,
    };

    let mut state = Completion::new(&config.commands, &config.containers);
    for arg in full_args {
        state.trans(arg);
    }
    for comp in state.complete(cur_arg) {
        println!("{}", comp);
    }

    Ok(0)
}
<commit_msg>Completion states refactoring<commit_after>use std::collections::{BTreeMap, HashSet};

use config::{Config};
use config::command::{MainCommand, SuperviseInfo};
use config::containers::Container;

#[derive(PartialEq, Eq, Hash)]
struct CommandOption<'a> {
    names: &'a [&'a str],
    has_args: bool,
    single: bool,
}

struct BuiltinCommand<'a> {
    name: &'a str,
    accept_container: bool,
    options: &'a [&'a CommandOption<'a>],
}

#[derive(Clone)]
struct SuperviseCommand<'a> {
    name: &'a str,
    info: &'a SuperviseInfo,
    options: &'a [&'a SuperviseOption<'a>],
}

struct SuperviseOption<'a> {
    names: &'a [&'a str],
    has_args: bool,
    single: bool,
    accept_children: bool,
}

/**

Transition table:
               ________                     ______________
 +————————————|        |——————————————————>|              |
 |  +—————————| Global |                   | SuperviseCmd |
 |  |  +——————|________|<————————+   +—————|______________|<————+
 |  |  |                         |   |                          |
 |  |  |    ______________       |   |     _________________    |?
 |  |  |   |              |      |   +———>|                 |———+
 |  |  +——>| GlobalOption |——————+        | SuperviseOption |
 |  |      |______________|          +————|_________________|<————+
 |  |                                |                            |
 |  |         _________              |    ____________________    |
 |  +———————>|         |             |   |                    |   |
 |  +————————| Command |<——————+     +——>| SuperviseOptionArg |<——+
 |  |  +—————|_________|       |         |____________________|
 |  |  |                       |
 |  |  |    _______________    |
 |  |  |   |               |   |
 |  |  +——>| CommandOption |———+
 |  |      |_______________|
 |  |
 |  |        _____________
 |  +——————>|             |
 |          | CommandArgs |
 +—————————>|_____________|

*/
enum States<'a> {
    Global,
    GlobalOption(&'a CommandOption<'a>),
    Command(&'a BuiltinCommand<'a>),
    CommandOption(&'a BuiltinCommand<'a>, &'a CommandOption<'a>),
    CommandArgs,
    SuperviseCmd(SuperviseCommand<'a>),
    SuperviseOption(SuperviseCommand<'a>, &'a SuperviseOption<'a>),
    SuperviseOptionArg(SuperviseCommand<'a>, &'a SuperviseOption<'a>),
}

struct CompletionState<'a> {
    commands: &'a BTreeMap<String, MainCommand>,
    containers: &'a BTreeMap<String, Container>,
    state: States<'a>,
    single_global_options: HashSet<&'a CommandOption<'a>>,
    single_command_options: HashSet<&'a CommandOption<'a>>,
    supervise_chosen_children: HashSet<&'a str>,
}

impl<'a> CompletionState<'a> {
    pub fn new(
        commands: &'a BTreeMap<String, MainCommand>,
        containers: &'a BTreeMap<String, Container>
    ) -> CompletionState<'a> {

        CompletionState {
            commands: commands,
            containers: containers,
            state: States::Global,
            single_global_options: HashSet::new(),
            single_command_options: HashSet::new(),
            supervise_chosen_children: HashSet::new(),
        }
    }

    pub fn trans(&mut self, arg: &'a str) {
        let mut next_state: Option<States> = None;
        match self.state {
            States::Global => {
                for cmd in BUILTIN_COMMANDS {
                    if cmd.name == arg {
                        self.state = States::Command(cmd);
                        return;
                    }
                }
                for opt in GLOBAL_OPTIONS {
                    for &opt_name in opt.names {
                        if arg == opt_name {
                            if opt.has_args {
                                self.state = States::GlobalOption(opt);
                            }
                            if opt.single {
                                self.single_global_options.insert(opt);
                            }
                            return;
                        }
                    }
                }
                for (cmd_name, user_cmd) in self.commands.iter() {
                    if arg != cmd_name {
                        continue;
                    }
                    match *user_cmd {
                        MainCommand::Command(_) => {
                            self.state = States::CommandArgs;
                            return;
                        },
                        MainCommand::Supervise(ref supervise_info) => {
                            let supervise_cmd = SuperviseCommand {
                                name: cmd_name,
                                info: supervise_info,
                                options: SUPERVISE_OPTIONS,
                            };
                            self.state = States::SuperviseCmd(supervise_cmd);
                            return;
                        },
                    }
                }
                self.state = States::CommandArgs;
            },
            States::GlobalOption(_) => {
                self.state = States::Global;
            },
            States::Command(cmd) => {
                for cmd_opt in cmd.options {
                    for &opt_name in cmd_opt.names {
                        if arg == opt_name {
                            if cmd_opt.has_args {
                                self.state = States::CommandOption(cmd, cmd_opt);
                            }
                            if cmd_opt.single {
                                self.single_command_options.insert(cmd_opt);
                            }
                            return;
                        }
                    }
                }
                self.state = States::CommandArgs;
            },
            States::CommandOption(cmd, _) => {
                self.state = States::Command(cmd);
            },
            States::CommandArgs => {},
            States::SuperviseCmd(ref cmd) => {
                'options_label: for cmd_opt in cmd.options {
                    for &opt_name in cmd_opt.names {
                        if arg == opt_name {
                            next_state = Some(States::SuperviseOption(cmd.clone(), cmd_opt));
                            break 'options_label;
                        }
                    }
                }
            },
            States::SuperviseOption(ref cmd, opt) => {
                if cmd.info.children.contains_key(arg) {
                    self.supervise_chosen_children.insert(arg);
                } else {
                    next_state = Some(States::SuperviseCmd(cmd.clone()));
                }
            },
            States::SuperviseOptionArg(ref cmd, opt) => {
            },
        }

        if let Some(next_state) = next_state {
            self.state = next_state;
        }
    }

    pub fn complete(&self, cur: &str) -> Vec<&str> {
        let mut completions: Vec<&str> = Vec::new();
        match self.state {
            States::Global => {
                completions.extend(self.commands.keys().map(|c| &c[..]));
                if cur.starts_with("_") {
                    completions.extend(BUILTIN_COMMANDS.iter().map(|c| c.name));
                }
                if cur.starts_with("-") {
                    for opt in GLOBAL_OPTIONS {
                        if !self.single_global_options.contains(opt) {
                            completions.extend(opt.names);
                        }
                    }
                }
            },
            States::Command(cmd) => {
                if cmd.accept_container {
                    completions.extend(self.containers.keys().map(|c| &c[..]));
                }
                if cur.starts_with("-") {
                    for opt in cmd.options {
                        if !self.single_command_options.contains(opt) {
                            completions.extend(opt.names);
                        }
                    }
                }
            },
            States::SuperviseCmd(ref supervise_cmd) => {
                for opt in supervise_cmd.options {
                    completions.extend(opt.names);
                }
            },
            States::SuperviseOption(ref supervise_cmd, supervise_opt) => {
                // TODO: specify which supervise options can accept child as argument
                for child in supervise_cmd.info.children.keys() {
                    let child_name = &child[..];
                    if !self.supervise_chosen_children.contains(child_name) {
                        completions.push(child_name);
                    }
                }
            },
            _ => {},
        }
        completions.retain(|c| c.starts_with(cur));
        return completions;
    }
}

const BUILTIN_COMMANDS: &'static [&'static BuiltinCommand<'static>] = &[
    &BuiltinCommand {
        name: "_build",
        accept_container: true,
        options: &[
            &CommandOption { names: &["--force"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_build_shell",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_clean",
        accept_container: false,
        options: &[
            &CommandOption { names: &["--tmp", "--tmp-folders"], has_args: false, single: true },
            &CommandOption { names: &["--old", "--old-containers"], has_args: false, single: true },
            &CommandOption { names: &["--unused"], has_args: false, single: true },
            &CommandOption { names: &["--transient"], has_args: false, single: true },
            &CommandOption { names: &["--global"], has_args: false, single: true },
            &CommandOption { names: &["-n", "--dry-run"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_create_netns",
        accept_container: false,
        options: &[
            &CommandOption { names: &["--dry-run"], has_args: false, single: true },
            &CommandOption { names: &["--no-iptables"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_destroy_netns",
        accept_container: false,
        options: &[
            &CommandOption { names: &["--dry-run"], has_args: false, single: true },
            &CommandOption { names: &["--no-iptables"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_init_storage_dir",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_list",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_pack_image",
        accept_container: true,
        options: &[
            &CommandOption { names: &["-f", "--file"], has_args: true, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_run",
        accept_container: true,
        options: &[
            &CommandOption { names: &["-W", "--writable"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_run_in_netns",
        accept_container: true,
        options: &[
            &CommandOption { names: &["--pid"], has_args: true, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_version_hash",
        accept_container: true,
        options: &[
            &CommandOption { names: &["-s", "--short"], has_args: false, single: true },
            &CommandOption { names: &["-fd3"], has_args: false, single: true },
        ]
    },
];

const GLOBAL_OPTIONS: &'static [&'static CommandOption<'static>] = &[
    &CommandOption { names: &["-E", "--env", "--environ"], has_args: true, single: false },
    &CommandOption { names: &["-e", "--use-env"], has_args: true, single: false },
    &CommandOption { names: &["--ignore-owner-check"], has_args: false, single: true },
    &CommandOption { names: &["--no-build"], has_args: false, single: true },
    &CommandOption { names: &["--no-version-check"], has_args: false, single: true },
];

const SUPERVISE_OPTIONS: &'static [&'static SuperviseOption<'static>] = &[
    &SuperviseOption { names: &["--only"], has_args: true, single: false, accept_children: true },
    &SuperviseOption { names: &["--exclude"], has_args: true, single: false, accept_children: true },
];

pub fn generate_completions(config: &Config, args: Vec<String>) -> Result<i32, String> {
    let default_cur_arg = "".to_string();
    let mut splitted_args = args.splitn(2, |a| a == "--");
    let full_args = match splitted_args.next() {
        Some(a) => a.iter().collect::<Vec<_>>(),
        None => vec!(),
    };
    let cur_arg = match splitted_args.next() {
        Some(a) => a.get(0).unwrap_or(&default_cur_arg),
        None => &default_cur_arg,
    };

    let mut state = CompletionState::new(&config.commands, &config.containers);
    for arg in full_args {
        state.trans(arg);
    }
    for comp in state.complete(cur_arg) {
        println!("{}", comp);
    }

    Ok(0)
}
<|endoftext|>


<commit_before>#[doc = "The main parser interface"];

export parse_sess;
export next_node_id;
export new_parser_from_file;
export new_parser_from_source_str;
export parse_crate_from_file;
export parse_crate_from_crate_file;
export parse_crate_from_source_str;
export parse_expr_from_source_str;
export parse_from_source_str;

import parser::parser;
import ast::node_id;
import util::interner;
import lexer::reader;

type parse_sess = @{
    cm: codemap::codemap,
    mut next_id: node_id,
    span_diagnostic: diagnostic::span_handler,
    // these two must be kept up to date
    mut chpos: uint,
    mut byte_pos: uint
};

fn parse_crate_from_file(input: str, cfg: ast::crate_cfg, sess: parse_sess) ->
   @ast::crate {
    if str::ends_with(input, ".rc") {
        parse_crate_from_crate_file(input, cfg, sess)
    } else if str::ends_with(input, ".rs") {
        parse_crate_from_source_file(input, cfg, sess)
    } else {
        sess.span_diagnostic.handler().fatal("unknown input file type: " +
                                             input)
    }
}

fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_file(sess, cfg, input, parser::CRATE_FILE);
    let lo = p.span.lo;
    let prefix = path::dirname(p.reader.filemap.name);
    let leading_attrs = attr::parse_inner_attrs_and_next(p);
    let crate_attrs = leading_attrs.inner;
    let first_cdir_attr = leading_attrs.next;
    let cdirs = parser::parse_crate_directives(
        p, token::EOF, first_cdir_attr);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    let cx =
        @{p: p,
          sess: sess,
          cfg: p.cfg};
    let (companionmod, _) = path::splitext(path::basename(input));
    let (m, attrs) = eval::eval_crate_directives_to_mod(
        cx, cdirs, prefix, option::some(companionmod));
    let mut hi = p.span.hi;
    parser::expect(p, token::EOF);
    ret @ast_util::respan(ast_util::mk_sp(lo, hi),
                          {directives: cdirs,
                           module: m,
                           attrs: crate_attrs + attrs,
                           config: p.cfg});
}

fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,
                                sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_file(sess, cfg, input, parser::SOURCE_FILE);
    let r = parser::parse_crate_mod(p, cfg);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = parser::parse_crate_mod(p, cfg);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                              sess: parse_sess) -> @ast::expr {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = parser::parse_expr(p);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_from_source_str<T>(f: fn (p: parser) -> T,
                            name: str, ss: codemap::file_substr,
                            source: @str, cfg: ast::crate_cfg,
                            sess: parse_sess)
    -> T
{
    let p = new_parser_from_source_str(sess, cfg, name, ss, source);
    let r = f(p);
    if !p.reader.is_eof() {
        p.reader.fatal("expected end-of-string");
    }
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn next_node_id(sess: parse_sess) -> node_id {
    let rv = sess.next_id;
    sess.next_id += 1;
    // ID 0 is reserved for the crate and doesn't actually exist in the AST
    assert rv != 0;
    ret rv;
}

fn new_parser(sess: parse_sess, cfg: ast::crate_cfg, rdr: lexer::reader,
              ftype: parser::file_type) -> parser {
    let tok0 = lexer::next_token(rdr);
    let span0 = ast_util::mk_sp(tok0.chpos, rdr.chpos);
    @{sess: sess,
      cfg: cfg,
      file_type: ftype,
      mut token: tok0.tok,
      mut span: span0,
      mut last_span: span0,
      mut buffer: [],
      mut restriction: parser::UNRESTRICTED,
      reader: rdr,
      keywords: token::keyword_table(),
      restricted_keywords: token::restricted_keyword_table()}
}

fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
                              name: str, ss: codemap::file_substr,
                              source: @str) -> parser {
    let ftype = parser::SOURCE_FILE;
    let filemap = codemap::new_filemap_w_substr
        (name, ss, source, sess.chpos, sess.byte_pos);
    sess.cm.files += [filemap];
    let itr = @interner::mk(str::hash, str::eq);
    let rdr = lexer::new_reader(sess.span_diagnostic,
                                filemap, itr);
    ret new_parser(sess, cfg, rdr, ftype);
}

fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, path: str,
                        ftype: parser::file_type) ->
   parser {
    let src = alt io::read_whole_file_str(path) {
      result::ok(src) {
        // FIXME: This copy is unfortunate
        @src
      }
      result::err(e) {
        sess.span_diagnostic.handler().fatal(e)
      }
    };
    let filemap = codemap::new_filemap(path, src,
                                       sess.chpos, sess.byte_pos);
    sess.cm.files += [filemap];
    let itr = @interner::mk(str::hash, str::eq);
    let rdr = lexer::new_reader(sess.span_diagnostic, filemap, itr);
    ret new_parser(sess, cfg, rdr, ftype);
}
<commit_msg>Annotate FIXME (comment only)<commit_after>#[doc = "The main parser interface"];

export parse_sess;
export next_node_id;
export new_parser_from_file;
export new_parser_from_source_str;
export parse_crate_from_file;
export parse_crate_from_crate_file;
export parse_crate_from_source_str;
export parse_expr_from_source_str;
export parse_from_source_str;

import parser::parser;
import ast::node_id;
import util::interner;
import lexer::reader;

type parse_sess = @{
    cm: codemap::codemap,
    mut next_id: node_id,
    span_diagnostic: diagnostic::span_handler,
    // these two must be kept up to date
    mut chpos: uint,
    mut byte_pos: uint
};

fn parse_crate_from_file(input: str, cfg: ast::crate_cfg, sess: parse_sess) ->
   @ast::crate {
    if str::ends_with(input, ".rc") {
        parse_crate_from_crate_file(input, cfg, sess)
    } else if str::ends_with(input, ".rs") {
        parse_crate_from_source_file(input, cfg, sess)
    } else {
        sess.span_diagnostic.handler().fatal("unknown input file type: " +
                                             input)
    }
}

fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_file(sess, cfg, input, parser::CRATE_FILE);
    let lo = p.span.lo;
    let prefix = path::dirname(p.reader.filemap.name);
    let leading_attrs = attr::parse_inner_attrs_and_next(p);
    let crate_attrs = leading_attrs.inner;
    let first_cdir_attr = leading_attrs.next;
    let cdirs = parser::parse_crate_directives(
        p, token::EOF, first_cdir_attr);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    let cx =
        @{p: p,
          sess: sess,
          cfg: p.cfg};
    let (companionmod, _) = path::splitext(path::basename(input));
    let (m, attrs) = eval::eval_crate_directives_to_mod(
        cx, cdirs, prefix, option::some(companionmod));
    let mut hi = p.span.hi;
    parser::expect(p, token::EOF);
    ret @ast_util::respan(ast_util::mk_sp(lo, hi),
                          {directives: cdirs,
                           module: m,
                           attrs: crate_attrs + attrs,
                           config: p.cfg});
}

fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,
                                sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_file(sess, cfg, input, parser::SOURCE_FILE);
    let r = parser::parse_crate_mod(p, cfg);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = parser::parse_crate_mod(p, cfg);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                              sess: parse_sess) -> @ast::expr {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = parser::parse_expr(p);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_from_source_str<T>(f: fn (p: parser) -> T,
                            name: str, ss: codemap::file_substr,
                            source: @str, cfg: ast::crate_cfg,
                            sess: parse_sess)
    -> T
{
    let p = new_parser_from_source_str(sess, cfg, name, ss, source);
    let r = f(p);
    if !p.reader.is_eof() {
        p.reader.fatal("expected end-of-string");
    }
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn next_node_id(sess: parse_sess) -> node_id {
    let rv = sess.next_id;
    sess.next_id += 1;
    // ID 0 is reserved for the crate and doesn't actually exist in the AST
    assert rv != 0;
    ret rv;
}

fn new_parser(sess: parse_sess, cfg: ast::crate_cfg, rdr: lexer::reader,
              ftype: parser::file_type) -> parser {
    let tok0 = lexer::next_token(rdr);
    let span0 = ast_util::mk_sp(tok0.chpos, rdr.chpos);
    @{sess: sess,
      cfg: cfg,
      file_type: ftype,
      mut token: tok0.tok,
      mut span: span0,
      mut last_span: span0,
      mut buffer: [],
      mut restriction: parser::UNRESTRICTED,
      reader: rdr,
      keywords: token::keyword_table(),
      restricted_keywords: token::restricted_keyword_table()}
}

fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
                              name: str, ss: codemap::file_substr,
                              source: @str) -> parser {
    let ftype = parser::SOURCE_FILE;
    let filemap = codemap::new_filemap_w_substr
        (name, ss, source, sess.chpos, sess.byte_pos);
    sess.cm.files += [filemap];
    let itr = @interner::mk(str::hash, str::eq);
    let rdr = lexer::new_reader(sess.span_diagnostic,
                                filemap, itr);
    ret new_parser(sess, cfg, rdr, ftype);
}

fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, path: str,
                        ftype: parser::file_type) ->
   parser {
    let src = alt io::read_whole_file_str(path) {
      result::ok(src) {
        // FIXME: This copy is unfortunate (#2319)
        @src
      }
      result::err(e) {
        sess.span_diagnostic.handler().fatal(e)
      }
    };
    let filemap = codemap::new_filemap(path, src,
                                       sess.chpos, sess.byte_pos);
    sess.cm.files += [filemap];
    let itr = @interner::mk(str::hash, str::eq);
    let rdr = lexer::new_reader(sess.span_diagnostic, filemap, itr);
    ret new_parser(sess, cfg, rdr, ftype);
}
<|endoftext|>


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

use std::cmp::{Eq, TotalEq, eq};

pub enum IpAddr {
    Ipv4(u8, u8, u8, u8, u16),
    Ipv6
}

impl Eq for IpAddr {
    fn eq(&self, other: &IpAddr) -> bool {
        match (*self, *other) {
            (Ipv4(a,b,c,d,e), Ipv4(f,g,h,i,j)) => a == f && b == g && c == h && d == i && e == j,
            (Ipv6, Ipv6) => fail!(),
            _ => false
        }
    }
    fn ne(&self, other: &IpAddr) -> bool {
        !eq(self, other)
    }
}

impl TotalEq for IpAddr {
    fn equals(&self, other: &IpAddr) -> bool {
        *self == *other
    }
}
<commit_msg>Wrote the Eq instance of IpAddr in a slightly different way.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cmp::{Eq, TotalEq};

pub enum IpAddr {
    Ipv4(u8, u8, u8, u8, u16),
    Ipv6
}

impl Eq for IpAddr {
    fn eq(&self, other: &IpAddr) -> bool {
        match (*self, *other) {
            (Ipv4(a,b,c,d,e), Ipv4(f,g,h,i,j)) => (a,b,c,d,e) == (f,g,h,i,j),
            (Ipv6, Ipv6) => fail!(),
            _ => false
        }
    }
    fn ne(&self, other: &IpAddr) -> bool {
        !(self == other)
    }
}

impl TotalEq for IpAddr {
    fn equals(&self, other: &IpAddr) -> bool {
        *self == *other
    }
}
<|endoftext|>


<commit_before>#![no_std]
/**
 * This example shows a repeated timer combined with reading and displaying the current time in
 * clock ticks.
 **/
use core::fmt::Write;
use libtock::console::Console;
use libtock::result::TockResult;
use libtock::timer;
use libtock::timer::Duration;

#[libtock::main]
async fn main() -> TockResult<()> {
    const DELAY_MS: usize = 500;

    let mut console = Console::new();
    let mut previous_ticks = None;

    for i in 0.. {
        let mut timer_with_callback = timer::with_callback(|_, _| {});
        let timer = timer_with_callback.init()?;
        let current_clock = timer.get_current_clock()?;
        let ticks = current_clock.num_ticks();
        let frequency = timer.clock_frequency().hz();
        writeln!(
            console,
            "[{}] Waited roughly {:?}. Now is {:?} = {:#010x} ticks ({:?} ticks since last time at {} Hz)",
            i,
            PrettyTime::from_ms(i * DELAY_MS),
            PrettyTime::from_ms(current_clock.ms_f64() as usize),
            ticks,
            previous_ticks.map(|previous| ticks - previous),
            frequency
        )?;
        previous_ticks = Some(ticks);
        timer::sleep(Duration::from_ms(DELAY_MS as isize)).await?;
    }

    Ok(())
}

struct PrettyTime {
    mins: usize,
    secs: usize,
    ms: usize,
}

impl PrettyTime {
    fn from_ms(ms: usize) -> PrettyTime {
        PrettyTime {
            ms: ms % 1000,
            secs: (ms / 1000) % 60,
            mins: ms / (60 * 1000),
        }
    }
}

impl core::fmt::Debug for PrettyTime {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        if self.mins != 0 {
            write!(f, "{}m", self.mins)?
        }
        write!(f, "{}.{:03}s", self.secs, self.ms)
    }
}
<commit_msg>Move print_now to a standalone function, to make sure the timer driver is dropped before being used again.<commit_after>#![no_std]
/**
 * This example shows a repeated timer combined with reading and displaying the current time in
 * clock ticks.
 **/
use core::fmt::Write;
use libtock::console::Console;
use libtock::result::TockResult;
use libtock::timer;
use libtock::timer::Duration;

const DELAY_MS: usize = 500;

#[libtock::main]
async fn main() -> TockResult<()> {
    let mut console = Console::new();
    let mut previous_ticks = None;

    for i in 0.. {
        print_now(&mut console, &mut previous_ticks, i)?;
        timer::sleep(Duration::from_ms(DELAY_MS as isize)).await?;
    }

    Ok(())
}

fn print_now(
    console: &mut Console,
    previous_ticks: &mut Option<isize>,
    i: usize,
) -> TockResult<()> {
    let mut timer_with_callback = timer::with_callback(|_, _| {});
    let timer = timer_with_callback.init()?;
    let current_clock = timer.get_current_clock()?;
    let ticks = current_clock.num_ticks();
    let frequency = timer.clock_frequency().hz();
    writeln!(
            console,
            "[{}] Waited roughly {:?}. Now is {:?} = {:#010x} ticks ({:?} ticks since last time at {} Hz)",
            i,
            PrettyTime::from_ms(i * DELAY_MS),
            PrettyTime::from_ms(current_clock.ms_f64() as usize),
            ticks,
            previous_ticks.map(|previous| ticks - previous),
            frequency
        )?;
    *previous_ticks = Some(ticks);
    Ok(())
}

struct PrettyTime {
    mins: usize,
    secs: usize,
    ms: usize,
}

impl PrettyTime {
    fn from_ms(ms: usize) -> PrettyTime {
        PrettyTime {
            ms: ms % 1000,
            secs: (ms / 1000) % 60,
            mins: ms / (60 * 1000),
        }
    }
}

impl core::fmt::Debug for PrettyTime {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        if self.mins != 0 {
            write!(f, "{}m", self.mins)?
        }
        write!(f, "{}.{:03}s", self.secs, self.ms)
    }
}
<|endoftext|>