<commit_before>use escargot::CargoBuild;
use failure::ResultExt;
use std::io;
use std::{thread, time};
use varlink::Connection;
use Result;

fn run_self_test(address: String) -> Result<()> {
    let client_address = address.clone();

    let child = thread::spawn(move || {
        if let Err(e) = ::run_server(&address, 4) {
            match e.kind() {
                ::varlink::ErrorKind::Timeout => {}
                _ => panic!("error: {}", e),
            }
        }
    });

    // give server time to start
    thread::sleep(time::Duration::from_secs(1));

    let ret = ::run_client(Connection::with_address(&client_address)?);
    if let Err(e) = ret {
        panic!("error: {:?}", e);
    }
    if let Err(e) = child.join() {
        Err(io::Error::new(io::ErrorKind::ConnectionRefused, format!("{:#?}", e)).into())
    } else {
        Ok(())
    }
}

#[test]
fn test_unix() -> ::Result<()> {
    run_self_test("unix:/tmp/org.varlink.certification".into())
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_unix_abstract() -> Result<()> {
    run_self_test("unix:@org.varlink.certification".into())
}

#[test]
fn test_tcp() -> Result<()> {
    run_self_test("tcp:0.0.0.0:23456".into())
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn get_exec() -> Result<String> {
    let runner = CargoBuild::new()
        .current_release()
        .run()
        .context(::ErrorKind::Io_Error(::std::io::ErrorKind::NotFound))?;
    Ok(runner.path().to_owned().to_string_lossy().to_string())
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_exec() -> Result<()> {
    ::run_client(Connection::with_activate(&format!(
        "{} --varlink=$VARLINK_ADDRESS",
        get_exec()?
    ))?)
}

#[test]
fn test_wrong_address_1() {
    assert!(::run_server("tcpd:0.0.0.0:12345".into(), 1).is_err());
}
<commit_msg>Revert "varlink-certification/src/test.rs: mark get_exec() linux only"<commit_after>use escargot::CargoBuild;
use failure::ResultExt;
use std::io;
use std::{thread, time};
use varlink::Connection;
use Result;

fn run_self_test(address: String) -> Result<()> {
    let client_address = address.clone();

    let child = thread::spawn(move || {
        if let Err(e) = ::run_server(&address, 4) {
            match e.kind() {
                ::varlink::ErrorKind::Timeout => {}
                _ => panic!("error: {}", e),
            }
        }
    });

    // give server time to start
    thread::sleep(time::Duration::from_secs(1));

    let ret = ::run_client(Connection::with_address(&client_address)?);
    if let Err(e) = ret {
        panic!("error: {:?}", e);
    }
    if let Err(e) = child.join() {
        Err(io::Error::new(io::ErrorKind::ConnectionRefused, format!("{:#?}", e)).into())
    } else {
        Ok(())
    }
}

#[test]
fn test_unix() -> ::Result<()> {
    run_self_test("unix:/tmp/org.varlink.certification".into())
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_unix_abstract() -> Result<()> {
    run_self_test("unix:@org.varlink.certification".into())
}

#[test]
fn test_tcp() -> Result<()> {
    run_self_test("tcp:0.0.0.0:23456".into())
}

fn get_exec() -> Result<String> {
    let runner = CargoBuild::new()
        .current_release()
        .run()
        .context(::ErrorKind::Io_Error(::std::io::ErrorKind::NotFound))?;
    Ok(runner.path().to_owned().to_string_lossy().to_string())
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_exec() -> Result<()> {
    ::run_client(Connection::with_activate(&format!(
        "{} --varlink=$VARLINK_ADDRESS",
        get_exec()?
    ))?)
}

#[test]
fn test_wrong_address_1() {
    assert!(::run_server("tcpd:0.0.0.0:12345".into(), 1).is_err());
}
<|endoftext|>


<commit_before>use std::env;

use clap;
use env_logger;
use log;

use cobalt;
use error::*;

pub fn get_config_args() -> Vec<clap::Arg<'static, 'static>> {
    [clap::Arg::with_name("config")
         .short("c")
         .long("config")
         .value_name("FILE")
         .help("Config file to use [default: .cobalt.yml]")
         .takes_value(true),
     clap::Arg::with_name("destination")
         .short("d")
         .long("destination")
         .value_name("DIR")
         .help("Destination folder [default: ./]")
         .takes_value(true),
     clap::Arg::with_name("drafts")
         .long("drafts")
         .help("Include drafts.")
         .takes_value(false),
     clap::Arg::with_name("dump")
         .long("dump")
         .possible_values(&cobalt::Dump::variants())
         .help("Dump the specified internal state")
         .multiple(true)
         .takes_value(true)]
        .to_vec()
}

pub fn get_config(matches: &clap::ArgMatches) -> Result<cobalt::ConfigBuilder> {
    let config_path = matches.value_of("config");

    // Fetch config information if available
    let mut config = if let Some(config_path) = config_path {
        cobalt::ConfigBuilder::from_file(config_path)
            .chain_err(|| format!("Error reading config file {:?}", config_path))?
    } else {
        let cwd = env::current_dir().expect("How does this fail?");
        cobalt::ConfigBuilder::from_cwd(cwd)?
    };

    config.abs_dest = matches.value_of("destination").map(str::to_string);

    config.include_drafts = matches.is_present("drafts");

    if matches.is_present("dump") {
        let mut dump = values_t!(matches, "dump", cobalt::Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }

    Ok(config)
}

pub fn get_logging_args() -> Vec<clap::Arg<'static, 'static>> {
    [clap::Arg::with_name("log-level")
         .short("L")
         .long("log-level")
         .possible_values(&["error", "warn", "info", "debug", "trace", "off"])
         .help("Log level [default: info]")
         .global(true)
         .takes_value(true),
     clap::Arg::with_name("trace")
         .long("trace")
         .help("Log ultra-verbose (trace level) information")
         .global(true)
         .takes_value(false),
     clap::Arg::with_name("silent")
         .long("silent")
         .help("Suppress all output")
         .global(true)
         .takes_value(false)]
        .to_vec()
}

pub fn get_logging(global_matches: &clap::ArgMatches,
                   matches: &clap::ArgMatches)
                   -> Result<env_logger::LogBuilder> {
    let format = |record: &log::LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format);

    match matches
              .value_of("log-level")
              .or_else(|| global_matches.value_of("log-level")) {
        Some("error") => builder.filter(None, log::LogLevelFilter::Error),
        Some("warn") => builder.filter(None, log::LogLevelFilter::Warn),
        Some("debug") => builder.filter(None, log::LogLevelFilter::Debug),
        Some("trace") => builder.filter(None, log::LogLevelFilter::Trace),
        Some("off") => builder.filter(None, log::LogLevelFilter::Off),
        Some("info") | _ => builder.filter(None, log::LogLevelFilter::Info),
    };

    if matches.is_present("trace") {
        builder.filter(None, log::LogLevelFilter::Trace);
    }

    if matches.is_present("silent") {
        builder.filter(None, log::LogLevelFilter::Off);
    }

    Ok(builder)
}
<commit_msg>fix(cli): Clarify role of --destination<commit_after>use std::env;

use clap;
use env_logger;
use log;

use cobalt;
use error::*;

pub fn get_config_args() -> Vec<clap::Arg<'static, 'static>> {
    [clap::Arg::with_name("config")
         .short("c")
         .long("config")
         .value_name("FILE")
         .help("Config file to use [default: .cobalt.yml]")
         .takes_value(true),
     clap::Arg::with_name("destination")
         .short("d")
         .long("destination")
         .value_name("DIR")
         .help("Site destination folder [default: ./]")
         .takes_value(true),
     clap::Arg::with_name("drafts")
         .long("drafts")
         .help("Include drafts.")
         .takes_value(false),
     clap::Arg::with_name("dump")
         .long("dump")
         .possible_values(&cobalt::Dump::variants())
         .help("Dump the specified internal state")
         .multiple(true)
         .takes_value(true)]
        .to_vec()
}

pub fn get_config(matches: &clap::ArgMatches) -> Result<cobalt::ConfigBuilder> {
    let config_path = matches.value_of("config");

    // Fetch config information if available
    let mut config = if let Some(config_path) = config_path {
        cobalt::ConfigBuilder::from_file(config_path)
            .chain_err(|| format!("Error reading config file {:?}", config_path))?
    } else {
        let cwd = env::current_dir().expect("How does this fail?");
        cobalt::ConfigBuilder::from_cwd(cwd)?
    };

    config.abs_dest = matches.value_of("destination").map(str::to_string);

    config.include_drafts = matches.is_present("drafts");

    if matches.is_present("dump") {
        let mut dump = values_t!(matches, "dump", cobalt::Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }

    Ok(config)
}

pub fn get_logging_args() -> Vec<clap::Arg<'static, 'static>> {
    [clap::Arg::with_name("log-level")
         .short("L")
         .long("log-level")
         .possible_values(&["error", "warn", "info", "debug", "trace", "off"])
         .help("Log level [default: info]")
         .global(true)
         .takes_value(true),
     clap::Arg::with_name("trace")
         .long("trace")
         .help("Log ultra-verbose (trace level) information")
         .global(true)
         .takes_value(false),
     clap::Arg::with_name("silent")
         .long("silent")
         .help("Suppress all output")
         .global(true)
         .takes_value(false)]
        .to_vec()
}

pub fn get_logging(global_matches: &clap::ArgMatches,
                   matches: &clap::ArgMatches)
                   -> Result<env_logger::LogBuilder> {
    let format = |record: &log::LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format);

    match matches
              .value_of("log-level")
              .or_else(|| global_matches.value_of("log-level")) {
        Some("error") => builder.filter(None, log::LogLevelFilter::Error),
        Some("warn") => builder.filter(None, log::LogLevelFilter::Warn),
        Some("debug") => builder.filter(None, log::LogLevelFilter::Debug),
        Some("trace") => builder.filter(None, log::LogLevelFilter::Trace),
        Some("off") => builder.filter(None, log::LogLevelFilter::Off),
        Some("info") | _ => builder.filter(None, log::LogLevelFilter::Info),
    };

    if matches.is_present("trace") {
        builder.filter(None, log::LogLevelFilter::Trace);
    }

    if matches.is_present("silent") {
        builder.filter(None, log::LogLevelFilter::Off);
    }

    Ok(builder)
}
<|endoftext|>


<commit_before>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]
#![allow(unstable)]

extern crate collections;

use std::cmp;
use std::f64;
use std::hash::{Hasher, SipHasher, Writer};
use std::num::Float;
use std::rand;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher; 2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::from_elem(bitmap_bits as usize, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * Float::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

/// Record the presence of an item.
    pub fn set<T>(& mut self, item: T) where T: AsSlice<u8> {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool where T: AsSlice<u8> {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T)
                               -> bool where T: AsSlice<u8> {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * Float::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: & mut [u64; 2],
                  item: &T, k_i: u32) -> u64 where T: AsSlice<u8> {
        if k_i < 2 {
            let mut sip = self.sips[k_i as usize].clone();
            sip.write(item.as_slice());
            let hash = sip.finish();
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::thread_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<commit_msg>Hash anything that can be hashed using SipHash<commit_after>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]
#![allow(unstable)]

extern crate collections;

use std::cmp;
use std::f64;
use std::hash::{Hash, Hasher, SipHasher};
use std::num::Float;
use std::rand;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher; 2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::from_elem(bitmap_bits as usize, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * Float::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

/// Record the presence of an item.
    pub fn set<T>(& mut self, item: T) where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T)
                               -> bool where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * Float::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: & mut [u64; 2],
                  item: &T, k_i: u32) -> u64 where T: Hash<SipHasher> {
        if k_i < 2 {
            let sip = &mut self.sips[k_i as usize].clone();
            item.hash(sip);
            let hash = sip.finish();
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::thread_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<|endoftext|>


<commit_before>use std::fmt::Display;
use json_display::JsonDisplay;

#[derive(Debug)]
pub struct CircularBuffer<T> {
    first: usize,
    last: usize,
    valid_items: usize,
    data: Vec<T>,
    max_items: usize,
}

impl<T: Display + JsonDisplay> CircularBuffer<T> {
    pub fn new(size: usize) -> CircularBuffer<T> {
        CircularBuffer {
            first: 0,
            last: 0,
            valid_items: 0,
            data: Vec::<T>::with_capacity(size),
            max_items: size,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.valid_items == 0
    }

    pub fn get_nb_items(&self) -> usize {
        self.valid_items
    }

    pub fn put_item(&mut self, item_value: T) -> bool {
        if self.valid_items >= self.max_items {
            println!("The queue is full\n");
            println!("You cannot add items\n");
            false
        } else {
            self.valid_items += 1;
            if self.last + 1 < self.data.len() {
                self.data[self.last as usize] = item_value;
            } else {
                self.data.push(item_value);
            }
            self.last = (self.last + 1) % self.max_items;
            true
        }
    }

    pub fn get_item(&mut self) -> Option<&T> {
        if self.is_empty() {
            println!("isempty\n");
            None
        } else {
            let index = self.first;
            self.first = (self.first + 1) % self.max_items;
            self.valid_items -= 1;
            Some(&self.data[index])
        }
    }

    pub fn peek_item(&self, index: usize) -> Option<&T> {
        if index < self.valid_items {
            let internal_index = (self.first + index) % self.max_items;
            Some(&self.data[internal_index]);
        }
        None
    }
}

// IntToIterator is fully functionnal
impl<'a, T:'a + Display + JsonDisplay> IntoIterator for &'a CircularBuffer<T> {
    type Item = &'a T;
    type IntoIter = CircularBufferIterator<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        CircularBufferIterator {
            circular_buffer : self,
            current_index : self.first,
            remaining_items : self.get_nb_items()
        }
    }
}

pub struct CircularBufferIterator<'a, T: 'a> {
    circular_buffer: &'a CircularBuffer<T>,
    current_index: usize,
    remaining_items: usize,
}

/* // This constructor is no more need, since inToIterator compile
impl<'a, T: 'a + Display> CircularBufferIterator<'a, T> {
    fn new(circular_buffer : &'a CircularBuffer<T>) -> CircularBufferIterator<T> {
         CircularBufferIterator {
            circular_buffer : circular_buffer,
            current_index : circular_buffer.first,
            remaining_items : circular_buffer.get_nb_items()
        }
    }
}
*/

impl<'a, T> Iterator for CircularBufferIterator<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        if self.remaining_items > 0 {
            let current_index_before_update = self.current_index;
            self.current_index = (self.current_index + 1) % self.circular_buffer.max_items;
            self.remaining_items -= 1;
            Some(&self.circular_buffer.data[current_index_before_update])
        }
        else {
            None
        }
    }
}
<commit_msg>Correction of peek_item (wrong return)<commit_after>use std::fmt::Display;
use json_display::JsonDisplay;

#[derive(Debug)]
pub struct CircularBuffer<T> {
    first: usize,
    last: usize,
    valid_items: usize,
    data: Vec<T>,
    max_items: usize,
}

impl<T: Display + JsonDisplay> CircularBuffer<T> {
    pub fn new(size: usize) -> CircularBuffer<T> {
        CircularBuffer {
            first: 0,
            last: 0,
            valid_items: 0,
            data: Vec::<T>::with_capacity(size),
            max_items: size,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.valid_items == 0
    }

    pub fn get_nb_items(&self) -> usize {
        self.valid_items
    }

    pub fn put_item(&mut self, item_value: T) -> bool {
        if self.valid_items >= self.max_items {
            println!("The queue is full\n");
            println!("You cannot add items\n");
            false
        } else {
            self.valid_items += 1;
            if self.last + 1 < self.data.len() {
                self.data[self.last as usize] = item_value;
            } else {
                self.data.push(item_value);
            }
            self.last = (self.last + 1) % self.max_items;
            true
        }
    }

    pub fn get_item(&mut self) -> Option<&T> {
        if self.is_empty() {
            println!("isempty\n");
            None
        } else {
            let index = self.first;
            self.first = (self.first + 1) % self.max_items;
            self.valid_items -= 1;
            Some(&self.data[index])
        }
    }

    pub fn peek_item(&self, index: usize) -> Option<&T> {
        if index < self.valid_items {
            let internal_index = (self.first + index) % self.max_items;
            Some(&self.data[internal_index]);
        }
        else {
            None
        }
    }
}

// IntToIterator is fully functionnal
impl<'a, T:'a + Display + JsonDisplay> IntoIterator for &'a CircularBuffer<T> {
    type Item = &'a T;
    type IntoIter = CircularBufferIterator<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        CircularBufferIterator {
            circular_buffer : self,
            current_index : self.first,
            remaining_items : self.get_nb_items()
        }
    }
}

pub struct CircularBufferIterator<'a, T: 'a> {
    circular_buffer: &'a CircularBuffer<T>,
    current_index: usize,
    remaining_items: usize,
}

/* // This constructor is no more need, since inToIterator compile
impl<'a, T: 'a + Display> CircularBufferIterator<'a, T> {
    fn new(circular_buffer : &'a CircularBuffer<T>) -> CircularBufferIterator<T> {
         CircularBufferIterator {
            circular_buffer : circular_buffer,
            current_index : circular_buffer.first,
            remaining_items : circular_buffer.get_nb_items()
        }
    }
}
*/

impl<'a, T> Iterator for CircularBufferIterator<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        if self.remaining_items > 0 {
            let current_index_before_update = self.current_index;
            self.current_index = (self.current_index + 1) % self.circular_buffer.max_items;
            self.remaining_items -= 1;
            Some(&self.circular_buffer.data[current_index_before_update])
        }
        else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use database::models::{AutoReply, NewAutoReply};
use filters::Filter;

use discord::model::{permissions, UserId, ChannelId, LiveServer};

use diesel;
use diesel::prelude::*;

use lalafell::error::*;
use lalafell::commands::prelude::*;
use lalafell::commands::ChannelOrId;

#[derive(Debug, Deserialize)]
pub struct DeleteParams {
  id: i32
}

fn list_all() -> Result<String> {
  let ars: Vec<AutoReply> = ::bot::CONNECTION.with(|c| {
    use database::schema::auto_replies::dsl;
    dsl::auto_replies.load(c).chain_err(|| "could not load auto_replies")
  })?;
  Ok(ars.iter()
    .map(|r| format!("{id}. Replying to messages in {channel}{filters} with a delay of {delay} second{plural}.\n```{message}```",
                     id = r.id,
                     channel = ChannelId(*r.channel_id).mention(),
                     filters = r.filters.as_ref().map(|f| format!(" with filters `{}`", f)).unwrap_or_default(),
                     delay = r.delay,
                     plural = if r.delay == 1 { "" } else { "s" },
                     message = r.message
    ))
    .collect::<Vec<_>>()
    .join("\n"))
}

pub fn auto_reply<'a>(author: UserId, server: &LiveServer, content: &str) -> CommandResult<'a> {
  if !server.permissions_for(server.id.main(), author).contains(permissions::MANAGE_MESSAGES) {
    return Err(ExternalCommandFailure::default()
      .message(|e: EmbedBuilder| e
        .title("Not enough permissions.")
        .description("You don't have enough permissions to use this command."))
      .wrap());
  }
  let args: Vec<&str> = content.split(|c| c == ' ' || c == '\t').filter(|x| !x.is_empty()).skip(3).collect();
  if args.is_empty() {
    return Ok(list_all()?.into());
  }
  let subcommand = &args[0];
  let args = &args[1..];
  match subcommand.to_lowercase().as_str() {
    "add" | "create" => {
      if args.len() < 4 {
        return Err("Invalid parameters.".into());
      }
      let channel = ChannelOrId::parse(args[0]).map_err(|_| into!(CommandFailure, "Invalid channel reference."))?;
      let on_join = match args[1].to_lowercase().as_str() {
        "true" | "yes" | "y" => true,
        "false" | "no" | "n" => false,
        _ => return Err("Invalid on-join parameter.".into())
      };
      let delay: u64 = match args[2].parse() {
        Ok(d) => d,
        Err(_) => return Err("Invalid delay.".into())
      };
      let args = &args[3..];
      let ars: Vec<AutoReply> = ::bot::CONNECTION.with(|c| {
        use database::schema::auto_replies::dsl;
        dsl::auto_replies
          .filter(dsl::channel_id.eq(channel.0.to_string())
            .and(dsl::server_id.eq(server.id.0.to_string())))
          .load(c)
          .chain_err(|| "could not load auto_replies")
      })?;
      if !ars.is_empty() {
        return Err("An auto-reply already exists for that channel.".into());
      }
      let joined_args = args.join(" ");
      let parts: Vec<&str> = joined_args.splitn(2, '\n').collect();
      let (filters, message) = if parts.len() == 1 {
        (None, &parts[0])
      } else {
        let filters: Option<Vec<Filter>> = parts[0].split(' ').map(Filter::parse).collect();
        let filters = match filters {
          Some(f) => f.into_iter().map(|x| x.to_string()).collect::<Vec<_>>().join(" "),
          None => return Err("Invalid filters.".into())
        };
        (Some(filters), &parts[1])
      };
      let nar = NewAutoReply {
        server_id: server.id.0.into(),
        channel_id: channel.0.into(),
        message: message.to_string(),
        on_join: on_join,
        delay: delay as i32,
        filters: filters
      };
      ::bot::CONNECTION.with(|c| {
        use database::schema::auto_replies;
        diesel::insert(&nar)
          .into(auto_replies::table)
          .execute(c)
          .chain_err(|| "could not insert new dam")
      })?;
      Ok(CommandSuccess::default())
    },
    "remove" | "delete" => {
      let params: DeleteParams = ::lalafell::commands::params::from_str(&args.join(" "))
        .map_err(|_| into!(CommandFailure, "Invalid parameters."))?;
      let affected = ::bot::CONNECTION.with(|c| {
        use database::schema::auto_replies::dsl;
        diesel::delete(dsl::auto_replies.filter(dsl::id.eq(params.id)))
          .execute(c)
          .chain_err(|| "could not delete auto_replies")
      })?;
      if affected > 0 {
        Ok(CommandSuccess::default())
      } else {
        Err("No delete all messages were deleted.".into())
      }
    },
    _ => Err("No such subcommand.".into())
  }
}
<commit_msg>fix: don't check for existing auto replies<commit_after>use database::models::{AutoReply, NewAutoReply};
use filters::Filter;

use discord::model::{permissions, UserId, ChannelId, LiveServer};

use diesel;
use diesel::prelude::*;

use lalafell::error::*;
use lalafell::commands::prelude::*;
use lalafell::commands::ChannelOrId;

#[derive(Debug, Deserialize)]
pub struct DeleteParams {
  id: i32
}

fn list_all() -> Result<String> {
  let ars: Vec<AutoReply> = ::bot::CONNECTION.with(|c| {
    use database::schema::auto_replies::dsl;
    dsl::auto_replies.load(c).chain_err(|| "could not load auto_replies")
  })?;
  Ok(ars.iter()
    .map(|r| format!("{id}. Replying to messages in {channel}{filters} with a delay of {delay} second{plural}.\n```{message}```",
                     id = r.id,
                     channel = ChannelId(*r.channel_id).mention(),
                     filters = r.filters.as_ref().map(|f| format!(" with filters `{}`", f)).unwrap_or_default(),
                     delay = r.delay,
                     plural = if r.delay == 1 { "" } else { "s" },
                     message = r.message
    ))
    .collect::<Vec<_>>()
    .join("\n"))
}

pub fn auto_reply<'a>(author: UserId, server: &LiveServer, content: &str) -> CommandResult<'a> {
  if !server.permissions_for(server.id.main(), author).contains(permissions::MANAGE_MESSAGES) {
    return Err(ExternalCommandFailure::default()
      .message(|e: EmbedBuilder| e
        .title("Not enough permissions.")
        .description("You don't have enough permissions to use this command."))
      .wrap());
  }
  let args: Vec<&str> = content.split(|c| c == ' ' || c == '\t').filter(|x| !x.is_empty()).skip(3).collect();
  if args.is_empty() {
    return Ok(list_all()?.into());
  }
  let subcommand = &args[0];
  let args = &args[1..];
  match subcommand.to_lowercase().as_str() {
    "add" | "create" => {
      if args.len() < 4 {
        return Err("Invalid parameters.".into());
      }
      let channel = ChannelOrId::parse(args[0]).map_err(|_| into!(CommandFailure, "Invalid channel reference."))?;
      let on_join = match args[1].to_lowercase().as_str() {
        "true" | "yes" | "y" => true,
        "false" | "no" | "n" => false,
        _ => return Err("Invalid on-join parameter.".into())
      };
      let delay: u64 = match args[2].parse() {
        Ok(d) => d,
        Err(_) => return Err("Invalid delay.".into())
      };
      let args = &args[3..];
      let joined_args = args.join(" ");
      let parts: Vec<&str> = joined_args.splitn(2, '\n').collect();
      let (filters, message) = if parts.len() == 1 {
        (None, &parts[0])
      } else {
        let filters: Option<Vec<Filter>> = parts[0].split(' ').map(Filter::parse).collect();
        let filters = match filters {
          Some(f) => f.into_iter().map(|x| x.to_string()).collect::<Vec<_>>().join(" "),
          None => return Err("Invalid filters.".into())
        };
        (Some(filters), &parts[1])
      };
      let nar = NewAutoReply {
        server_id: server.id.0.into(),
        channel_id: channel.0.into(),
        message: message.to_string(),
        on_join: on_join,
        delay: delay as i32,
        filters: filters
      };
      ::bot::CONNECTION.with(|c| {
        use database::schema::auto_replies;
        diesel::insert(&nar)
          .into(auto_replies::table)
          .execute(c)
          .chain_err(|| "could not insert new dam")
      })?;
      Ok(CommandSuccess::default())
    },
    "remove" | "delete" => {
      let params: DeleteParams = ::lalafell::commands::params::from_str(&args.join(" "))
        .map_err(|_| into!(CommandFailure, "Invalid parameters."))?;
      let affected = ::bot::CONNECTION.with(|c| {
        use database::schema::auto_replies::dsl;
        diesel::delete(dsl::auto_replies.filter(dsl::id.eq(params.id)))
          .execute(c)
          .chain_err(|| "could not delete auto_replies")
      })?;
      if affected > 0 {
        Ok(CommandSuccess::default())
      } else {
        Err("No delete all messages were deleted.".into())
      }
    },
    _ => Err("No such subcommand.".into())
  }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use super::{ElfResult, ElfWord, Section, section};
use super::ValidatesWord;
use core::{fmt, mem};

pub trait Header {
    type Word: ElfWord;

    /// Attempt to extract an ELF file header from a slice of bytes.
    /// TODO: should this be a From impl maybe?
    //          - eliza, 03/08/2017
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self>;

    /// Attempt to extract a section header from a slice of bytes.
    /// TODO: can/should the index be `usize`?
    //          - eliza, 03/08/2017
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>;

    // Field accessors -------------------------------------------
    fn ident(&self) -> Ident;
    fn get_type(&self) -> Type;
    fn machine(&self) -> Machine;
    /// Offset of the program entry point
    fn entry_point(&self) -> usize;
    /// Offset of the start of program headers
    fn ph_offset(&self) -> usize;
    /// Number of program headers.
    fn ph_count(&self) -> usize;
    /// Size of a program header.
    /// TODO: add function for using this and `ph_count` to make a memrange
    ///       representing the program header entries?
    //          - eliza, 03/08/2017
    fn ph_entry_size(&self) -> usize;
    /// Offset of the start of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_offset(&self) -> usize;
    /// Number of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_count(&self) -> usize;
    /// Size of a [section header].
    ///
    /// [section header]: ../section/struct.Header.html
    /// TODO: add function for using this and `sh_count` to make a memrange
    ///       representing the section header entries?
    //          - eliza, 03/08/2017
    fn sh_entry_size(&self) -> usize;
    /// TODO: can this return the flags type?
    //          - eliza, 03/08/2017
    fn flags(&self) -> u32;
    /// Index of the section header [string table].
    ///
    /// [string table]: ../section/struct.StrTable.html"]
    fn sh_str_idx(&self) -> usize;

}

/// FIXME(style): generate more stuff with macros/use `macro_attr` to derive
///               these...
//                  - eliza, 03/08/2017
macro_rules! impl_getters {
    ($(#[$attr:meta])* pub fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ($(#[$attr:meta])* fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ( $(#[$attr:meta])* pub fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
    };
    ( $(#[$attr:meta])* fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
    };
    () => {};
}

macro_rules! Header {
    (($($size:ty),+) $(pub)* enum $name:ident $($tail:tt)* ) => {
        Header! { @impl $name, $($size)+ }
    };
    (($($size:ty),+) $(pub)* struct $name:ident $($tail:tt)*) => {
        Header! { @impl $name, $($size)+ }
    };
    (@impl $name:ident, $($size:ty)+) => {
        $(impl Header for $name<$size> {
            type Word = $size;
            /// Attempt to extract an ELF file header from a slice of bytes.
            fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self> {
                if input.len() < mem::size_of::<Self>() {
                    Err("Input too short to extract ELF header")
                } else {
                    unsafe { Ok(&super::extract_from_slice::<Self>(input, 0, 1)[0]) }
                }
            }

            /// Attempt to extract a section header from a slice of bytes.
            fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                                    -> ElfResult<&'a Section>
            {
                if idx < section::SHN_LORESERVE {
                    Err("Cannot parse reserved section.")
                } else {
                    // use ValidatesWord to check if this section's Class field
                    // will let us interpret the section with the requested
                    // word length. this is a bit of a hack around the type
                    // system not letting me do this the way I wanted to to....
                    let validator: &ValidatesWord<Self::Word>
                        = &self.ident.class;
                    validator.check()?;

                    // start offset for section
                    let start = self.sh_offset() + idx as usize *
                                self.sh_entry_size();
                    // end offset for section
                    let end = start + self.sh_entry_size();
                    let raw = &input[start .. end];

                    match self.ident.class {
                        // Class::None is always invalid ----------------------
                        Class::None =>
                            Err("Invalid ELF class (ELFCLASSNONE).")
                        // Class and header types mismatch --------------------
                      , Class::Elf64 =>
                            Err("Cannot parse 64-bit section from 32-bit ELF.")
                        // class and header types match -----------------------
                      , Class::Elf32 => unsafe {
                            Ok(&*(raw as *const [u8] as *const u8 as *const Section))
                        }
                    }
                }
            }

            #[inline] fn get_type(&self) -> Type { self.elftype.as_type() }

            impl_getters! {
                #[doc = "Index for the start of [section header]s. \
                         [section header]: ../section/struct.Header.html"]
                fn sh_offset(&self) -> usize;
                fn sh_entry_size(&self) -> usize;
                fn sh_count(&self) -> usize;

                #[doc = "Index for the start of program headers"]
                fn ph_offset(&self) -> usize;
                fn ph_entry_size(&self) -> usize;
                fn ph_count(&self) -> usize;

                #[doc = "Index for the program entry point"]
                fn entry_point(&self) -> usize;
                #[doc = "Index of the section header [string table] \
                         [string table]: ../section/struct.StrTable.html"]
                fn sh_str_idx(&self) -> usize;
                fn flags(&self) -> u32;
                fn ident(&self) -> Ident;
                fn machine(&self) -> Machine;
            }
        })+
    }
}

macro_attr! {
    /// An ELF file header
    #[derive(Copy, Clone, Debug, Header!(u32, u64))]
    #[repr(C, packed)]
    pub struct HeaderRepr<W: ElfWord> {
        /// the ELF [file identifier](struct.Ident.html)
        pub ident: Ident
      , elftype: TypeRepr
      , pub machine: Machine
      , /// Program entry point
        /// TODO: getters for turning these into `usize`?
        //          - eliza, 03/08/2017
        entry_point: W
      , /// Offset for start of program headers
        ph_offset: W
      , /// Offset for start of [section header]s.
        /// [section header]: ../section/struct.Header.html
        sh_offset: W
      , pub flags: u32
      , pub header_size: u16
      , pub ph_entry_size: u16
      , pub ph_count: u16
      , pub sh_entry_size: u16
      , pub sh_count: u16
      , /// Index of the section header string table
        sh_str_idx: u16
    }
}

/// ELF header magic
pub const MAGIC: Magic = [0x7f, b'E', b'L', b'F'];

/// Type of header magic
pub type Magic = [u8; 4];

/// ELF identifier (`e_ident` in the ELF standard)
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct Ident {
    /// ELF magic numbers. Must be equal to the [ELF magic], `[0x7, E, L, F]`.
    ///
    /// [ELF magic]: constant.MAGIC.html
    pub magic: Magic
  , /// ELF [file class](enum.Class.html) (32- or 64-bit)
    pub class: Class
  , /// ELF [data encoding](enum.DataEncoding.html) (big- or little-endian)
    pub encoding: DataEncoding
  , /// ELF file [version](enum.Version.html)
    pub version: Version
  , /// What [operating system ABI] this file was compiled for.
    ///
    /// [operating system ABI]: enum.OsAbi.html
    pub abi: OsAbi
  , /// ABI version (often this is just padding)
    pub abi_version: u8
  , _padding: [u8; 7]
}

impl Ident {
    #[inline] pub fn check_magic(&self) -> bool { self.magic == MAGIC }

    /// Returns true if the identifier section identifies a valid ELF file.
    #[inline] pub fn is_valid(&self) -> bool {
        // the ELF magic number is correct
        self.check_magic() &&
        // the file class is either 32- or 64-bits
        self.class.is_valid() &&
        // the data encoding is either big- or little-endian
        self.encoding.is_valid()
    }
}

/// Identifies the class of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Class {
    /// Invalid ELF class file (`ELFCLASSNONE` in the standard)
    None  = 0
  , /// 32-bit ELF file (`ELFCLASS32` in the standard)
    Elf32 = 1
  , /// 64-bit ELF file (`ELFCLASS64` in the standard)
    Elf64 = 2
}

impl Class {
    /// Returns true if the class field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { Class::None => false
                    , _ => true
                    }
    }

}

impl ValidatesWord<u64> for Class {
    #[inline]
    fn check(&self) -> ElfResult<()> {
        use self::Class::*;
        match *self {
            None => Err("Invalid ELF type ELFCLASSNONE!")
          , Elf32 => Err("Cannot extract 64-bit section from 32-bit ELF")
          , Elf64 => Ok(())
        }
    }
}

impl ValidatesWord<u32> for Class {
    #[inline]
    fn check(&self) -> ElfResult<()> {
        use self::Class::*;
        match *self {
            None => Err("Invalid ELF type ELFCLASSNONE!")
          , Elf64 =>
                // TODO: is this actually true?
                //          - eliza, 03/08/2017
                Err("Cannot extract 32-bit section from 64-bit ELF")
          , Elf32 => Ok(())
        }
    }
}

/// Identifies the data encoding of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum DataEncoding {
    /// Invalid data encoding (`ELFDATANONE` in the standard)
    None  = 0
  , /// Twos-complement little-endian data encoding
    /// (`ELFDATA2LSB` in the standard)
    LittleEndian = 1
  , /// Twos-complement big-endian data encoding
    /// (`ELFDATA2MSB` in the standard)
    BigEndian = 2
}

impl DataEncoding {
    /// Returns true if the data encoding field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { DataEncoding::None => false
                    , _ => true
                    }
    }
}

/// Operating system ABI
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum OsAbi { /// Ox00 also represents "none"
                 SystemV = 0x00
               , HpUx    = 0x01
               , NetBsd  = 0x02
               , Linux   = 0x03
               , Solaris = 0x06
               , Aix     = 0x07
               , Irix    = 0x08
               , FreeBsd = 0x09
               , OpenBsd = 0x0C
               , OpenVms = 0x0D
               }

/// Identifies the version of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Version { None = 0, Current = 1 }

#[derive(Clone, Copy, PartialEq)]
struct TypeRepr(u16);

impl TypeRepr {
    pub fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::None
          , 1 => Type::Relocatable
          , 2 => Type::Executable
          , 3 => Type::SharedObject
          , 4 => Type::Core
          , anything => Type::Other(anything)
        }
    }
}

impl fmt::Debug for TypeRepr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_type().fmt(f)
    }
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Type { None
              , Relocatable
              , Executable
              , SharedObject
              , Core
              , Other(u16)
              }

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u16)]
pub enum Machine { None    = 0
                 , Sparc   = 0x02
                 , X86     = 0x03
                 , Mips    = 0x08
                 , PowerPc = 0x14
                 , Arm     = 0x28
                 , SuperH  = 0x2A
                 , Ia64    = 0x32
                 , X86_64  = 0x3E
                 , AArch64 = 0xB7
                 }
<commit_msg>style(elf): make some ugly code less ugly<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use super::{ElfResult, ElfWord, Section, section};
use super::ValidatesWord;
use core::{fmt, mem};

pub trait Header {
    type Word: ElfWord;

    /// Attempt to extract an ELF file header from a slice of bytes.
    /// TODO: should this be a From impl maybe?
    //          - eliza, 03/08/2017
    fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self>;

    /// Attempt to extract a section header from a slice of bytes.
    /// TODO: can/should the index be `usize`?
    //          - eliza, 03/08/2017
    fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                            -> ElfResult<&'a Section>;

    // Field accessors -------------------------------------------
    fn ident(&self) -> Ident;
    fn get_type(&self) -> Type;
    fn machine(&self) -> Machine;
    /// Offset of the program entry point
    fn entry_point(&self) -> usize;
    /// Offset of the start of program headers
    fn ph_offset(&self) -> usize;
    /// Number of program headers.
    fn ph_count(&self) -> usize;
    /// Size of a program header.
    /// TODO: add function for using this and `ph_count` to make a memrange
    ///       representing the program header entries?
    //          - eliza, 03/08/2017
    fn ph_entry_size(&self) -> usize;
    /// Offset of the start of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_offset(&self) -> usize;
    /// Number of [section header]s.
    ///
    /// [section header]: ../section/struct.Header.html
    fn sh_count(&self) -> usize;
    /// Size of a [section header].
    ///
    /// [section header]: ../section/struct.Header.html
    /// TODO: add function for using this and `sh_count` to make a memrange
    ///       representing the section header entries?
    //          - eliza, 03/08/2017
    fn sh_entry_size(&self) -> usize;
    /// TODO: can this return the flags type?
    //          - eliza, 03/08/2017
    fn flags(&self) -> u32;
    /// Index of the section header [string table].
    ///
    /// [string table]: ../section/struct.StrTable.html"]
    fn sh_str_idx(&self) -> usize;

}

/// FIXME(style): generate more stuff with macros/use `macro_attr` to derive
///               these...
//                  - eliza, 03/08/2017
macro_rules! impl_getters {
    ($(#[$attr:meta])* pub fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ($(#[$attr:meta])* fn $name:ident(&self) -> $ty:ident; $($rest:tt)*) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ( $(#[$attr:meta])* pub fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
    };
    ( $(#[$attr:meta])* fn $name: ident (&self)-> $ty: ident; ) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
    };
    () => {};
}

macro_rules! Header {
    (($($size:ty),+) $(pub)* enum $name:ident $($tail:tt)* ) => {
        Header! { @impl $name, $($size)+ }
    };
    (($($size:ty),+) $(pub)* struct $name:ident $($tail:tt)*) => {
        Header! { @impl $name, $($size)+ }
    };
    (@impl $name:ident, $($size:ty)+) => {
        $(impl Header for $name<$size> {
            type Word = $size;
            /// Attempt to extract an ELF file header from a slice of bytes.
            fn from_slice<'a>(input: &'a [u8]) -> ElfResult<&'a Self> {
                if input.len() < mem::size_of::<Self>() {
                    Err("Input too short to extract ELF header")
                } else {
                    unsafe { Ok(&super::extract_from_slice::<Self>(input, 0, 1)[0]) }
                }
            }

            /// Attempt to extract a section header from a slice of bytes.
            fn parse_section<'a>(&'a self, input: &'a [u8], idx: u16)
                                    -> ElfResult<&'a Section>
            {
                if idx < section::SHN_LORESERVE {
                    Err("Cannot parse reserved section.")
                } else {
                    // use ValidatesWord to check if this section's Class field
                    // will let us interpret the section with the requested
                    // word length. this is a bit of a hack around the type
                    // system not letting me do this the way I wanted to to....
                    let validator: &ValidatesWord<Self::Word>
                        = &self.ident.class;
                    validator.check()?;

                    // start offset for section
                    let start = self.sh_offset() + idx as usize *
                                self.sh_entry_size();
                    // end offset for section
                    let end = start + self.sh_entry_size();
                    let raw = &input[start .. end];

                    unsafe {
                        Ok(&*(raw as *const [u8]
                                  as *const _
                                  as *const Section))
                    }
                }
            }

            #[inline] fn get_type(&self) -> Type { self.elftype.as_type() }

            impl_getters! {
                #[doc = "Index for the start of [section header]s. \
                         [section header]: ../section/struct.Header.html"]
                fn sh_offset(&self) -> usize;
                fn sh_entry_size(&self) -> usize;
                fn sh_count(&self) -> usize;

                #[doc = "Index for the start of program headers"]
                fn ph_offset(&self) -> usize;
                fn ph_entry_size(&self) -> usize;
                fn ph_count(&self) -> usize;

                #[doc = "Index for the program entry point"]
                fn entry_point(&self) -> usize;
                #[doc = "Index of the section header [string table] \
                         [string table]: ../section/struct.StrTable.html"]
                fn sh_str_idx(&self) -> usize;
                fn flags(&self) -> u32;
                fn ident(&self) -> Ident;
                fn machine(&self) -> Machine;
            }
        })+
    }
}

macro_attr! {
    /// An ELF file header
    #[derive(Copy, Clone, Debug, Header!(u32, u64))]
    #[repr(C, packed)]
    pub struct HeaderRepr<W: ElfWord> {
        /// the ELF [file identifier](struct.Ident.html)
        pub ident: Ident
      , elftype: TypeRepr
      , pub machine: Machine
      , /// Program entry point
        entry_point: W
      , /// Offset for start of program headers
        ph_offset: W
      , /// Offset for start of [section header]s.
        /// [section header]: ../section/struct.Header.html
        sh_offset: W
      , pub flags: u32
      , pub header_size: u16
      , pub ph_entry_size: u16
      , pub ph_count: u16
      , pub sh_entry_size: u16
      , pub sh_count: u16
      , /// Index of the section header string table
        sh_str_idx: u16
    }
}

/// ELF header magic
pub const MAGIC: Magic = [0x7f, b'E', b'L', b'F'];

/// Type of header magic
pub type Magic = [u8; 4];

/// ELF identifier (`e_ident` in the ELF standard)
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct Ident {
    /// ELF magic numbers. Must be equal to the [ELF magic], `[0x7, E, L, F]`.
    ///
    /// [ELF magic]: constant.MAGIC.html
    pub magic: Magic
  , /// ELF [file class](enum.Class.html) (32- or 64-bit)
    pub class: Class
  , /// ELF [data encoding](enum.DataEncoding.html) (big- or little-endian)
    pub encoding: DataEncoding
  , /// ELF file [version](enum.Version.html)
    pub version: Version
  , /// What [operating system ABI] this file was compiled for.
    ///
    /// [operating system ABI]: enum.OsAbi.html
    pub abi: OsAbi
  , /// ABI version (often this is just padding)
    pub abi_version: u8
  , _padding: [u8; 7]
}

impl Ident {
    #[inline] pub fn check_magic(&self) -> bool { self.magic == MAGIC }

    /// Returns true if the identifier section identifies a valid ELF file.
    #[inline] pub fn is_valid(&self) -> bool {
        // the ELF magic number is correct
        self.check_magic() &&
        // the file class is either 32- or 64-bits
        self.class.is_valid() &&
        // the data encoding is either big- or little-endian
        self.encoding.is_valid()
    }
}

/// Identifies the class of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Class {
    /// Invalid ELF class file (`ELFCLASSNONE` in the standard)
    None  = 0
  , /// 32-bit ELF file (`ELFCLASS32` in the standard)
    Elf32 = 1
  , /// 64-bit ELF file (`ELFCLASS64` in the standard)
    Elf64 = 2
}

impl Class {
    /// Returns true if the class field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { Class::None => false
                    , _ => true
                    }
    }

}

impl ValidatesWord<u64> for Class {
    #[inline]
    fn check(&self) -> ElfResult<()> {
        use self::Class::*;
        match *self {
            None => Err("Invalid ELF type ELFCLASSNONE!")
          , Elf32 => Err("Cannot extract 64-bit section from 32-bit ELF")
          , Elf64 => Ok(())
        }
    }
}

impl ValidatesWord<u32> for Class {
    #[inline]
    fn check(&self) -> ElfResult<()> {
        use self::Class::*;
        match *self {
            None => Err("Invalid ELF type ELFCLASSNONE!")
          , Elf64 =>
                // TODO: is this actually true?
                //          - eliza, 03/08/2017
                Err("Cannot extract 32-bit section from 64-bit ELF")
          , Elf32 => Ok(())
        }
    }
}

/// Identifies the data encoding of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum DataEncoding {
    /// Invalid data encoding (`ELFDATANONE` in the standard)
    None  = 0
  , /// Twos-complement little-endian data encoding
    /// (`ELFDATA2LSB` in the standard)
    LittleEndian = 1
  , /// Twos-complement big-endian data encoding
    /// (`ELFDATA2MSB` in the standard)
    BigEndian = 2
}

impl DataEncoding {
    /// Returns true if the data encoding field for this file is valid.
    #[inline]
    pub fn is_valid(&self) -> bool {
        match *self { DataEncoding::None => false
                    , _ => true
                    }
    }
}

/// Operating system ABI
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum OsAbi { /// Ox00 also represents "none"
                 SystemV = 0x00
               , HpUx    = 0x01
               , NetBsd  = 0x02
               , Linux   = 0x03
               , Solaris = 0x06
               , Aix     = 0x07
               , Irix    = 0x08
               , FreeBsd = 0x09
               , OpenBsd = 0x0C
               , OpenVms = 0x0D
               }

/// Identifies the version of the ELF file
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Version { None = 0, Current = 1 }

#[derive(Clone, Copy, PartialEq)]
struct TypeRepr(u16);

impl TypeRepr {
    pub fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::None
          , 1 => Type::Relocatable
          , 2 => Type::Executable
          , 3 => Type::SharedObject
          , 4 => Type::Core
          , anything => Type::Other(anything)
        }
    }
}

impl fmt::Debug for TypeRepr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_type().fmt(f)
    }
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Type { None
              , Relocatable
              , Executable
              , SharedObject
              , Core
              , Other(u16)
              }

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u16)]
pub enum Machine { None    = 0
                 , Sparc   = 0x02
                 , X86     = 0x03
                 , Mips    = 0x08
                 , PowerPc = 0x14
                 , Arm     = 0x28
                 , SuperH  = 0x2A
                 , Ia64    = 0x32
                 , X86_64  = 0x3E
                 , AArch64 = 0xB7
                 }
<|endoftext|>


<commit_before>import std._vec;
import std._str;
import std.option;
import std.option.some;
import std.option.none;
import std.map.hashmap;

import driver.session;
import ast.ident;
import front.parser.parser;
import front.parser.spanned;
import front.parser.new_parser;
import front.parser.parse_mod_items;
import util.common;
import util.common.filename;
import util.common.append;
import util.common.span;
import util.common.new_str_hash;

// Simple dynamic-typed value type for eval_expr.
tag val {
    val_bool(bool);
    val_int(int);
    val_str(str);
}

type env = vec[tup(ident, val)];

fn mk_env() -> env {
    let env e = vec();
    ret e;
}

fn val_is_bool(val v) -> bool {
    alt (v) {
        case (val_bool(_)) { ret true; }
        case (_) { }
    }
    ret false;
}

fn val_is_int(val v) -> bool {
    alt (v) {
        case (val_bool(_)) { ret true; }
        case (_) { }
    }
    ret false;
}

fn val_is_str(val v) -> bool {
    alt (v) {
        case (val_str(_)) { ret true; }
        case (_) { }
    }
    ret false;
}

fn val_as_bool(val v) -> bool {
    alt (v) {
        case (val_bool(?b)) { ret b; }
        case (_) { }
    }
    fail;
}

fn val_as_int(val v) -> int {
    alt (v) {
        case (val_int(?i)) { ret i; }
        case (_) { }
    }
    fail;
}

fn val_as_str(val v) -> str {
    alt (v) {
        case (val_str(?s)) { ret s; }
        case (_) { }
    }
    fail;
}

fn lookup(session.session sess, env e, span sp, ident i) -> val {
    for (tup(ident, val) pair in e) {
        if (_str.eq(i, pair._0)) {
            ret pair._1;
        }
    }
    sess.span_err(sp, "unknown variable: " + i);
    fail;
}

fn eval_lit(session.session sess, env e, span sp, @ast.lit lit) -> val {
    alt (lit.node) {
        case (ast.lit_bool(?b)) { ret val_bool(b); }
        case (ast.lit_int(?i)) { ret val_int(i); }
        case (ast.lit_str(?s)) { ret val_str(s); }
        case (_) {
            sess.span_err(sp, "evaluating unsupported literal");
        }
    }
    fail;
}

fn eval_expr(session.session sess, env e, @ast.expr x) -> val {
    alt (x.node) {
        case (ast.expr_path(?pth, _, _)) {
            if (_vec.len[ident](pth.node.idents) == 1u &&
                _vec.len[@ast.ty](pth.node.types) == 0u) {
                ret lookup(sess, e, x.span, pth.node.idents.(0));
            }
            sess.span_err(x.span, "evaluating structured path-name");
        }

        case (ast.expr_lit(?lit, _)) {
            ret eval_lit(sess, e, x.span, lit);
        }

        case (ast.expr_unary(?op, ?a, _)) {
            auto av = eval_expr(sess, e, a);
            alt (op) {
                case (ast.not) {
                    if (val_is_bool(av)) {
                        ret val_bool(!val_as_bool(av));
                    }
                    sess.span_err(x.span, "bad types in '!' expression");
                }
                case (_) {
                    sess.span_err(x.span, "evaluating unsupported unop");
                }
            }
        }

        case (ast.expr_binary(?op, ?a, ?b, _)) {
            auto av = eval_expr(sess, e, a);
            auto bv = eval_expr(sess, e, b);
            alt (op) {
                case (ast.add) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) + val_as_int(bv));
                    }
                    if (val_is_str(av) && val_is_str(bv)) {
                        ret val_str(val_as_str(av) + val_as_str(bv));
                    }
                    sess.span_err(x.span, "bad types in '+' expression");
                }

                case (ast.sub) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) - val_as_int(bv));
                    }
                    sess.span_err(x.span, "bad types in '-' expression");
                }

                case (ast.mul) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) * val_as_int(bv));
                    }
                    sess.span_err(x.span, "bad types in '*' expression");
                }

                case (ast.div) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) / val_as_int(bv));
                    }
                    sess.span_err(x.span, "bad types in '/' expression");
                }

                case (ast.rem) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) % val_as_int(bv));
                    }
                    sess.span_err(x.span, "bad types in '%' expression");
                }

                case (ast.and) {
                    if (val_is_bool(av) && val_is_bool(bv)) {
                        ret val_bool(val_as_bool(av) && val_as_bool(bv));
                    }
                    sess.span_err(x.span, "bad types in '&&' expression");
                }

                case (ast.or) {
                    if (val_is_bool(av) && val_is_bool(bv)) {
                        ret val_bool(val_as_bool(av) || val_as_bool(bv));
                    }
                    sess.span_err(x.span, "bad types in '||' expression");
                }

                case (ast.eq) {
                    ret val_bool(val_eq(sess, x.span, av, bv));
                }

                case (ast.ne) {
                    ret val_bool(! val_eq(sess, x.span, av, bv));
                }

                case (_) {
                    sess.span_err(x.span, "evaluating unsupported binop");
                }
            }
        }
        case (_) {
            sess.span_err(x.span, "evaluating unsupported expression");
        }
    }
    fail;
}

fn val_eq(session.session sess, span sp, val av, val bv) -> bool {
    if (val_is_bool(av) && val_is_bool(bv)) {
        ret val_as_bool(av) == val_as_bool(bv);
    }
    if (val_is_int(av) && val_is_int(bv)) {
        ret val_as_int(av) == val_as_int(bv);
    }
    if (val_is_str(av) && val_is_str(bv)) {
        ret _str.eq(val_as_str(av),
                    val_as_str(bv));
    }
    sess.span_err(sp, "bad types in comparison");
    fail;
}

impure fn eval_crate_directives(parser p,
                                env e,
                                vec[@ast.crate_directive] cdirs,
                                str prefix,
                                &mutable vec[@ast.view_item] view_items,
                                &mutable vec[@ast.item] items,
                                hashmap[ast.ident,
                                        ast.mod_index_entry] index) {

    for (@ast.crate_directive sub_cdir in cdirs) {
        eval_crate_directive(p, e, sub_cdir, prefix,
                             view_items, items, index);
    }
}

impure fn eval_crate_directives_to_mod(parser p,
                                       env e,
                                       vec[@ast.crate_directive] cdirs,
                                       str prefix) -> ast._mod {
    let vec[@ast.view_item] view_items = vec();
    let vec[@ast.item] items = vec();
    auto index = new_str_hash[ast.mod_index_entry]();

    eval_crate_directives(p, e, cdirs, prefix,
                          view_items, items, index);

    ret rec(view_items=view_items, items=items, index=index);
}

impure fn eval_crate_directive_block(parser p,
                                     env e,
                                     &ast.block blk,
                                     str prefix,
                                     &mutable vec[@ast.view_item] view_items,
                                     &mutable vec[@ast.item] items,
                                     hashmap[ast.ident,
                                             ast.mod_index_entry] index) {

    for (@ast.stmt s in blk.node.stmts) {
        alt (s.node) {
            case (ast.stmt_crate_directive(?cdir)) {
                eval_crate_directive(p, e, cdir, prefix,
                                     view_items, items, index);
            }
            case (_) {
                auto sess = p.get_session();
                sess.span_err(s.span,
                              "unsupported stmt in crate-directive block");
            }
        }
    }
}

impure fn eval_crate_directive_expr(parser p,
                                    env e,
                                    @ast.expr x,
                                    str prefix,
                                    &mutable vec[@ast.view_item] view_items,
                                    &mutable vec[@ast.item] items,
                                    hashmap[ast.ident,
                                            ast.mod_index_entry] index) {
    auto sess = p.get_session();

    alt (x.node) {

        case (ast.expr_if(?cond, ?thn, ?elifs, ?elopt, _)) {
            auto cv = eval_expr(sess, e, cond);
            if (!val_is_bool(cv)) {
                sess.span_err(x.span, "bad cond type in 'if'");
            }

            if (val_as_bool(cv)) {
                ret eval_crate_directive_block(p, e, thn, prefix,
                                               view_items, items,
                                               index);
            }

            for (tup(@ast.expr, ast.block) elif in elifs) {
                auto cv = eval_expr(sess, e, elif._0);
                if (!val_is_bool(cv)) {
                    sess.span_err(x.span, "bad cond type in 'else if'");
                }

                if (val_as_bool(cv)) {
                    ret eval_crate_directive_block(p, e, elif._1, prefix,
                                                   view_items, items,
                                                   index);
                }
            }

            alt (elopt) {
                case (some[ast.block](?els)) {
                    ret eval_crate_directive_block(p, e, els, prefix,
                                                   view_items, items,
                                                   index);
                }
                case (_) {
                    // Absent-else is ok.
                }
            }
        }

        case (ast.expr_alt(?v, ?arms, _)) {
            auto vv = eval_expr(sess, e, v);
            for (ast.arm arm in arms) {
                alt (arm.pat.node) {
                    case (ast.pat_lit(?lit, _)) {
                        auto pv = eval_lit(sess, e,
                                           arm.pat.span, lit);
                        if (val_eq(sess, arm.pat.span, vv, pv)) {
                            ret eval_crate_directive_block
                                (p, e, arm.block, prefix,
                                 view_items, items, index);
                        }
                    }
                    case (ast.pat_wild(_)) {
                        ret eval_crate_directive_block
                            (p, e, arm.block, prefix,
                             view_items, items, index);
                    }
                    case (_) {
                        sess.span_err(arm.pat.span,
                                      "bad pattern type in 'alt'");
                    }
                }
            }
            sess.span_err(x.span, "no cases matched in 'alt'");
        }

        case (_) {
            sess.span_err(x.span, "unsupported expr type");
        }
    }
}

impure fn eval_crate_directive(parser p,
                               env e,
                               @ast.crate_directive cdir,
                               str prefix,
                               &mutable vec[@ast.view_item] view_items,
                               &mutable vec[@ast.item] items,
                               hashmap[ast.ident,
                                       ast.mod_index_entry] index) {
    alt (cdir.node) {

        case (ast.cdir_let(?id, ?x, ?cdirs)) {
            auto v = eval_expr(p.get_session(), e, x);
            auto e0 = vec(tup(id, v)) + e;
            eval_crate_directives(p, e0, cdirs, prefix,
                                  view_items, items, index);
        }

        case (ast.cdir_expr(?x)) {
            eval_crate_directive_expr(p, e, x, prefix,
                                      view_items, items, index);
        }

        case (ast.cdir_src_mod(?id, ?file_opt)) {

            auto file_path = id + ".rs";
            alt (file_opt) {
                case (some[filename](?f)) {
                    file_path = f;
                }
                case (none[filename]) {}
            }

            auto full_path = prefix + std.os.path_sep() + file_path;

            auto p0 = new_parser(p.get_session(), 0, full_path);
            auto m0 = parse_mod_items(p0, token.EOF);
            auto im = ast.item_mod(id, m0, p.next_def_id());
            auto i = @spanned(cdir.span, cdir.span, im);
            ast.index_item(index, i);
            append[@ast.item](items, i);
        }

        case (ast.cdir_dir_mod(?id, ?dir_opt, ?cdirs)) {

            auto path = id;
            alt (dir_opt) {
                case (some[filename](?d)) {
                    path = d;
                }
                case (none[filename]) {}
            }

            auto full_path = prefix + std.os.path_sep() + path;
            auto m0 = eval_crate_directives_to_mod(p, e, cdirs, path);
            auto im = ast.item_mod(id, m0, p.next_def_id());
            auto i = @spanned(cdir.span, cdir.span, im);
            ast.index_item(index, i);
            append[@ast.item](items, i);
        }

        case (ast.cdir_view_item(?vi)) {
            append[@ast.view_item](view_items, vi);
            ast.index_view_item(index, vi);
        }

        case (ast.cdir_meta(?mi)) {}
        case (ast.cdir_syntax(?pth)) {}
        case (ast.cdir_auth(?pth, ?eff)) {}
    }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Fix typo in crate directive evaluator.<commit_after>import std._vec;
import std._str;
import std.option;
import std.option.some;
import std.option.none;
import std.map.hashmap;

import driver.session;
import ast.ident;
import front.parser.parser;
import front.parser.spanned;
import front.parser.new_parser;
import front.parser.parse_mod_items;
import util.common;
import util.common.filename;
import util.common.append;
import util.common.span;
import util.common.new_str_hash;

// Simple dynamic-typed value type for eval_expr.
tag val {
    val_bool(bool);
    val_int(int);
    val_str(str);
}

type env = vec[tup(ident, val)];

fn mk_env() -> env {
    let env e = vec();
    ret e;
}

fn val_is_bool(val v) -> bool {
    alt (v) {
        case (val_bool(_)) { ret true; }
        case (_) { }
    }
    ret false;
}

fn val_is_int(val v) -> bool {
    alt (v) {
        case (val_bool(_)) { ret true; }
        case (_) { }
    }
    ret false;
}

fn val_is_str(val v) -> bool {
    alt (v) {
        case (val_str(_)) { ret true; }
        case (_) { }
    }
    ret false;
}

fn val_as_bool(val v) -> bool {
    alt (v) {
        case (val_bool(?b)) { ret b; }
        case (_) { }
    }
    fail;
}

fn val_as_int(val v) -> int {
    alt (v) {
        case (val_int(?i)) { ret i; }
        case (_) { }
    }
    fail;
}

fn val_as_str(val v) -> str {
    alt (v) {
        case (val_str(?s)) { ret s; }
        case (_) { }
    }
    fail;
}

fn lookup(session.session sess, env e, span sp, ident i) -> val {
    for (tup(ident, val) pair in e) {
        if (_str.eq(i, pair._0)) {
            ret pair._1;
        }
    }
    sess.span_err(sp, "unknown variable: " + i);
    fail;
}

fn eval_lit(session.session sess, env e, span sp, @ast.lit lit) -> val {
    alt (lit.node) {
        case (ast.lit_bool(?b)) { ret val_bool(b); }
        case (ast.lit_int(?i)) { ret val_int(i); }
        case (ast.lit_str(?s)) { ret val_str(s); }
        case (_) {
            sess.span_err(sp, "evaluating unsupported literal");
        }
    }
    fail;
}

fn eval_expr(session.session sess, env e, @ast.expr x) -> val {
    alt (x.node) {
        case (ast.expr_path(?pth, _, _)) {
            if (_vec.len[ident](pth.node.idents) == 1u &&
                _vec.len[@ast.ty](pth.node.types) == 0u) {
                ret lookup(sess, e, x.span, pth.node.idents.(0));
            }
            sess.span_err(x.span, "evaluating structured path-name");
        }

        case (ast.expr_lit(?lit, _)) {
            ret eval_lit(sess, e, x.span, lit);
        }

        case (ast.expr_unary(?op, ?a, _)) {
            auto av = eval_expr(sess, e, a);
            alt (op) {
                case (ast.not) {
                    if (val_is_bool(av)) {
                        ret val_bool(!val_as_bool(av));
                    }
                    sess.span_err(x.span, "bad types in '!' expression");
                }
                case (_) {
                    sess.span_err(x.span, "evaluating unsupported unop");
                }
            }
        }

        case (ast.expr_binary(?op, ?a, ?b, _)) {
            auto av = eval_expr(sess, e, a);
            auto bv = eval_expr(sess, e, b);
            alt (op) {
                case (ast.add) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) + val_as_int(bv));
                    }
                    if (val_is_str(av) && val_is_str(bv)) {
                        ret val_str(val_as_str(av) + val_as_str(bv));
                    }
                    sess.span_err(x.span, "bad types in '+' expression");
                }

                case (ast.sub) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) - val_as_int(bv));
                    }
                    sess.span_err(x.span, "bad types in '-' expression");
                }

                case (ast.mul) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) * val_as_int(bv));
                    }
                    sess.span_err(x.span, "bad types in '*' expression");
                }

                case (ast.div) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) / val_as_int(bv));
                    }
                    sess.span_err(x.span, "bad types in '/' expression");
                }

                case (ast.rem) {
                    if (val_is_int(av) && val_is_int(bv)) {
                        ret val_int(val_as_int(av) % val_as_int(bv));
                    }
                    sess.span_err(x.span, "bad types in '%' expression");
                }

                case (ast.and) {
                    if (val_is_bool(av) && val_is_bool(bv)) {
                        ret val_bool(val_as_bool(av) && val_as_bool(bv));
                    }
                    sess.span_err(x.span, "bad types in '&&' expression");
                }

                case (ast.or) {
                    if (val_is_bool(av) && val_is_bool(bv)) {
                        ret val_bool(val_as_bool(av) || val_as_bool(bv));
                    }
                    sess.span_err(x.span, "bad types in '||' expression");
                }

                case (ast.eq) {
                    ret val_bool(val_eq(sess, x.span, av, bv));
                }

                case (ast.ne) {
                    ret val_bool(! val_eq(sess, x.span, av, bv));
                }

                case (_) {
                    sess.span_err(x.span, "evaluating unsupported binop");
                }
            }
        }
        case (_) {
            sess.span_err(x.span, "evaluating unsupported expression");
        }
    }
    fail;
}

fn val_eq(session.session sess, span sp, val av, val bv) -> bool {
    if (val_is_bool(av) && val_is_bool(bv)) {
        ret val_as_bool(av) == val_as_bool(bv);
    }
    if (val_is_int(av) && val_is_int(bv)) {
        ret val_as_int(av) == val_as_int(bv);
    }
    if (val_is_str(av) && val_is_str(bv)) {
        ret _str.eq(val_as_str(av),
                    val_as_str(bv));
    }
    sess.span_err(sp, "bad types in comparison");
    fail;
}

impure fn eval_crate_directives(parser p,
                                env e,
                                vec[@ast.crate_directive] cdirs,
                                str prefix,
                                &mutable vec[@ast.view_item] view_items,
                                &mutable vec[@ast.item] items,
                                hashmap[ast.ident,
                                        ast.mod_index_entry] index) {

    for (@ast.crate_directive sub_cdir in cdirs) {
        eval_crate_directive(p, e, sub_cdir, prefix,
                             view_items, items, index);
    }
}

impure fn eval_crate_directives_to_mod(parser p,
                                       env e,
                                       vec[@ast.crate_directive] cdirs,
                                       str prefix) -> ast._mod {
    let vec[@ast.view_item] view_items = vec();
    let vec[@ast.item] items = vec();
    auto index = new_str_hash[ast.mod_index_entry]();

    eval_crate_directives(p, e, cdirs, prefix,
                          view_items, items, index);

    ret rec(view_items=view_items, items=items, index=index);
}

impure fn eval_crate_directive_block(parser p,
                                     env e,
                                     &ast.block blk,
                                     str prefix,
                                     &mutable vec[@ast.view_item] view_items,
                                     &mutable vec[@ast.item] items,
                                     hashmap[ast.ident,
                                             ast.mod_index_entry] index) {

    for (@ast.stmt s in blk.node.stmts) {
        alt (s.node) {
            case (ast.stmt_crate_directive(?cdir)) {
                eval_crate_directive(p, e, cdir, prefix,
                                     view_items, items, index);
            }
            case (_) {
                auto sess = p.get_session();
                sess.span_err(s.span,
                              "unsupported stmt in crate-directive block");
            }
        }
    }
}

impure fn eval_crate_directive_expr(parser p,
                                    env e,
                                    @ast.expr x,
                                    str prefix,
                                    &mutable vec[@ast.view_item] view_items,
                                    &mutable vec[@ast.item] items,
                                    hashmap[ast.ident,
                                            ast.mod_index_entry] index) {
    auto sess = p.get_session();

    alt (x.node) {

        case (ast.expr_if(?cond, ?thn, ?elifs, ?elopt, _)) {
            auto cv = eval_expr(sess, e, cond);
            if (!val_is_bool(cv)) {
                sess.span_err(x.span, "bad cond type in 'if'");
            }

            if (val_as_bool(cv)) {
                ret eval_crate_directive_block(p, e, thn, prefix,
                                               view_items, items,
                                               index);
            }

            for (tup(@ast.expr, ast.block) elif in elifs) {
                auto cv = eval_expr(sess, e, elif._0);
                if (!val_is_bool(cv)) {
                    sess.span_err(x.span, "bad cond type in 'else if'");
                }

                if (val_as_bool(cv)) {
                    ret eval_crate_directive_block(p, e, elif._1, prefix,
                                                   view_items, items,
                                                   index);
                }
            }

            alt (elopt) {
                case (some[ast.block](?els)) {
                    ret eval_crate_directive_block(p, e, els, prefix,
                                                   view_items, items,
                                                   index);
                }
                case (_) {
                    // Absent-else is ok.
                }
            }
        }

        case (ast.expr_alt(?v, ?arms, _)) {
            auto vv = eval_expr(sess, e, v);
            for (ast.arm arm in arms) {
                alt (arm.pat.node) {
                    case (ast.pat_lit(?lit, _)) {
                        auto pv = eval_lit(sess, e,
                                           arm.pat.span, lit);
                        if (val_eq(sess, arm.pat.span, vv, pv)) {
                            ret eval_crate_directive_block
                                (p, e, arm.block, prefix,
                                 view_items, items, index);
                        }
                    }
                    case (ast.pat_wild(_)) {
                        ret eval_crate_directive_block
                            (p, e, arm.block, prefix,
                             view_items, items, index);
                    }
                    case (_) {
                        sess.span_err(arm.pat.span,
                                      "bad pattern type in 'alt'");
                    }
                }
            }
            sess.span_err(x.span, "no cases matched in 'alt'");
        }

        case (_) {
            sess.span_err(x.span, "unsupported expr type");
        }
    }
}

impure fn eval_crate_directive(parser p,
                               env e,
                               @ast.crate_directive cdir,
                               str prefix,
                               &mutable vec[@ast.view_item] view_items,
                               &mutable vec[@ast.item] items,
                               hashmap[ast.ident,
                                       ast.mod_index_entry] index) {
    alt (cdir.node) {

        case (ast.cdir_let(?id, ?x, ?cdirs)) {
            auto v = eval_expr(p.get_session(), e, x);
            auto e0 = vec(tup(id, v)) + e;
            eval_crate_directives(p, e0, cdirs, prefix,
                                  view_items, items, index);
        }

        case (ast.cdir_expr(?x)) {
            eval_crate_directive_expr(p, e, x, prefix,
                                      view_items, items, index);
        }

        case (ast.cdir_src_mod(?id, ?file_opt)) {

            auto file_path = id + ".rs";
            alt (file_opt) {
                case (some[filename](?f)) {
                    file_path = f;
                }
                case (none[filename]) {}
            }

            auto full_path = prefix + std.os.path_sep() + file_path;

            auto p0 = new_parser(p.get_session(), 0, full_path);
            auto m0 = parse_mod_items(p0, token.EOF);
            auto im = ast.item_mod(id, m0, p.next_def_id());
            auto i = @spanned(cdir.span, cdir.span, im);
            ast.index_item(index, i);
            append[@ast.item](items, i);
        }

        case (ast.cdir_dir_mod(?id, ?dir_opt, ?cdirs)) {

            auto path = id;
            alt (dir_opt) {
                case (some[filename](?d)) {
                    path = d;
                }
                case (none[filename]) {}
            }

            auto full_path = prefix + std.os.path_sep() + path;
            auto m0 = eval_crate_directives_to_mod(p, e, cdirs, full_path);
            auto im = ast.item_mod(id, m0, p.next_def_id());
            auto i = @spanned(cdir.span, cdir.span, im);
            ast.index_item(index, i);
            append[@ast.item](items, i);
        }

        case (ast.cdir_view_item(?vi)) {
            append[@ast.view_item](view_items, vi);
            ast.index_view_item(index, vi);
        }

        case (ast.cdir_meta(?mi)) {}
        case (ast.cdir_syntax(?pth)) {}
        case (ast.cdir_auth(?pth, ?eff)) {}
    }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>