<commit_before>use std::collections::HashMap;

// FIXME: Try the efficient algorithm (takes only O(n) time with additional O(n) space)
// https://de.wikipedia.org/wiki/Suffix-Array-Induced-Sorting
pub fn bwt(mut input: Vec<u8>) -> Vec<u8> {
    input.push(0);

    // get the sorted suffix array
    let mut rotations = (0..input.len()).map(|i| &input[i..]).collect::<Vec<_>>();
    rotations.sort();
    let mut rots = vec![0; input.len()];

    // BWT[i] = S[SA[i] - 1]
    for i in 0..input.len() {
        if rotations[i].len() == input.len() {
            rots[i] = 0;
        } else {
            rots[i] = input[input.len() - rotations[i].len() - 1];
        }
    }

    rots
}

pub fn occurrence_index(input: &[u8]) -> HashMap<u8, usize> {
    // get the byte distribution
    let mut map = HashMap::new();
    for i in input {
        let mut count = map.entry(*i).or_insert(0);
        *count += 1;
    }

    // sort the bytes and locate the index of their first occurrences
    let mut chars = map.keys().collect::<Vec<_>>();
    chars.sort();

    let mut idx = 0;
    let mut occ_map = HashMap::new();
    for i in chars {
        occ_map.insert(*i, idx);
        idx += *map.get(i).unwrap();
    }

    occ_map
}

pub fn ibwt(input: Vec<u8>) -> Vec<u8> {
    let mut occ_map = occurrence_index(&input);

    // generate the LF vector
    let mut lf = vec![0; input.len()];
    for (i, c) in input.iter().enumerate() {
        let mut val = occ_map.get_mut(&c).unwrap();
        lf[i] = *val;
        *val += 1;
    }

    let mut idx = 0;
    // construct the sequence by traversing through the LF vector
    let mut output = vec![0; input.len()];
    for i in (0..(input.len() - 1)).rev() {
        output[i] = input[idx];
        idx = lf[idx];
    }

    output.pop();
    output
}
<commit_msg>Simple FM index (very inefficient)<commit_after>use std::collections::HashMap;

// FIXME: Try the efficient algorithm (takes only O(n) time with additional O(n) space)
// https://de.wikipedia.org/wiki/Suffix-Array-Induced-Sorting
pub fn bwt(mut input: Vec<u8>) -> Vec<u8> {
    input.push(0);

    // get the sorted suffix array
    let mut rotations = (0..input.len()).map(|i| &input[i..]).collect::<Vec<_>>();
    rotations.sort();
    let mut rots = vec![0; input.len()];

    // BWT[i] = S[SA[i] - 1]
    for i in 0..input.len() {
        if rotations[i].len() == input.len() {
            rots[i] = 0;
        } else {
            rots[i] = input[input.len() - rotations[i].len() - 1];
        }
    }

    rots
}

pub fn occurrence_index(input: &[u8]) -> HashMap<u8, usize> {
    // get the byte distribution
    let mut map = HashMap::new();
    for i in input {
        let mut count = map.entry(*i).or_insert(0);
        *count += 1;
    }

    // sort the bytes and locate the index of their first occurrences
    let mut chars = map.keys().collect::<Vec<_>>();
    chars.sort();

    let mut idx = 0;
    let mut occ_map = HashMap::new();
    for i in chars {
        occ_map.insert(*i, idx);
        idx += *map.get(i).unwrap();
    }

    occ_map
}

pub fn ibwt(input: Vec<u8>) -> Vec<u8> {
    let mut occ_map = occurrence_index(&input);

    // generate the LF vector
    let mut lf = vec![0; input.len()];
    for (i, c) in input.iter().enumerate() {
        let mut val = occ_map.get_mut(&c).unwrap();
        lf[i] = *val;
        *val += 1;
    }

    let mut idx = 0;
    // construct the sequence by traversing through the LF vector
    let mut output = vec![0; input.len()];
    for i in (0..(input.len() - 1)).rev() {
        output[i] = input[idx];
        idx = lf[idx];
    }

    output.pop();
    output
}

pub struct FMIndex {
    data: Vec<u8>,
    occ_map: HashMap<u8, usize>,
}

impl FMIndex {
    pub fn new(data: Vec<u8>) -> FMIndex {
        let bwt_data = bwt(data);
        FMIndex {
            occ_map: occurrence_index(&bwt_data),
            data: bwt_data,
        }
    }

    fn nearest_lf(&self, idx: usize, ch: u8) -> usize {
        match self.occ_map.get(&ch) {
            Some(occ) => occ + self.data[0..idx].iter().filter(|&i| *i == ch).count(),
            None => 0,
        }
    }

    // FIXME: We need "checkpointed" index!
    pub fn search(&mut self, query: &str) -> Vec<usize> {
        let (mut top, mut bottom) = (0, self.data.len());
        for ch in query.as_bytes().iter().rev() {
            top = self.nearest_lf(top, *ch);
            bottom = self.nearest_lf(bottom, *ch);
        }

        let mut results = vec![];

        for idx in top..bottom {
            let mut pos = 0;
            let mut i = idx;
            while self.data[i] != 0 {
                pos += 1;
                i = self.nearest_lf(i, self.data[i]);
            }

            results.push(pos);
        }

        return results
    }
}
<|endoftext|>


<commit_before>#[desc = "C64 emulator"];
#[copyright = "Andreas Neuhaus <info@zargony.com>"];
#[license = "MIT"];

use cpu::cpu::CPU;
use cpu::mos6510::Mos6510;
use mem::{Addressable, Ram, Rom, SharedMemory};

pub mod cpu {
	pub mod cpu;
	pub mod mos6502;
	pub mod mos6510;
}
pub mod mem;

fn main () {
	let mut c64 = C64::new();
	c64.run();
}

// General information on C64 : http://unusedino.de/ec64/technical/aay/c64/
// Useful emulator information: http://emudocs.org/?page=Commodore%2064
// C64 memory map overview: http://www.c64-wiki.com/index.php/Memory_Map
// Details about the PLA: http://www.c64-wiki.de/index.php/PLA_(C64-Chip)
// Even more PLA details: http://skoe.de/docs/c64-dissected/pla/c64_pla_dissected_r1.1_a4ss.pdf

// 64K RAM (not every part is always accessible)
// 8K BASIC ROM at $A000
// 4K character ROM at $D000
// 8K kernal ROM at $E000

struct C64Memory {
	ram: Ram<u16>,
	kernal: Rom<u16>,
	basic: Rom<u16>,
	characters: Rom<u16>,
}

impl C64Memory {
	fn new () -> C64Memory {
		C64Memory {
			ram: Ram::new(),
			kernal: Rom::new(&Path::new("c64/kernal.rom")),
			basic: Rom::new(&Path::new("c64/basic.rom")),
			characters: Rom::new(&Path::new("c64/characters.rom")),
		}
	}
}

impl Addressable<u16> for C64Memory {
	fn get (&self, addr: u16) -> u8 {
		match addr {
			// TODO: Switch memory access based on LORAM/HIRAM/CHAREN
			0xa000..0xbfff => self.basic.get(addr - 0xa000),
			0xd000..0xdfff => self.characters.get(addr - 0xd000),
			0xe000..0xffff => self.kernal.get(addr - 0xe000),
			_              => self.ram.get(addr),
		}
	}

	fn set (&mut self, addr: u16, data: u8) {
		self.ram.set(addr, data);
	}
}

pub struct C64 {
	priv cpu: Mos6510,
	priv mem: SharedMemory<C64Memory>,
}

impl C64 {
	pub fn new () -> C64 {
		C64 {
			cpu: Mos6510::new(),
			mem: SharedMemory::new(C64Memory::new()),
		}
	}

	pub fn run (&mut self) {
		// TODO
	}
}
<commit_msg>Adapt c64 emulator to new cpu interface<commit_after>#[desc = "C64 emulator"];
#[copyright = "Andreas Neuhaus <info@zargony.com>"];
#[license = "MIT"];

use cpu::cpu::CPU;
use cpu::mos6510::Mos6510;
use mem::{Addressable, Ram, Rom, SharedMemory};

pub mod cpu {
	pub mod cpu;
	pub mod mos6502;
	pub mod mos6510;
}
pub mod mem;

fn main () {
	let mut c64 = C64::new();
	c64.run();
}

// General information on C64 : http://unusedino.de/ec64/technical/aay/c64/
// Useful emulator information: http://emudocs.org/?page=Commodore%2064
// C64 memory map overview: http://www.c64-wiki.com/index.php/Memory_Map
// Details about the PLA: http://www.c64-wiki.de/index.php/PLA_(C64-Chip)
// Even more PLA details: http://skoe.de/docs/c64-dissected/pla/c64_pla_dissected_r1.1_a4ss.pdf

// 64K RAM (not every part is always accessible)
// 8K BASIC ROM at $A000
// 4K character ROM at $D000
// 8K kernal ROM at $E000

struct C64Memory {
	ram: Ram<u16>,
	kernal: Rom<u16>,
	basic: Rom<u16>,
	characters: Rom<u16>,
}

impl C64Memory {
	fn new () -> C64Memory {
		C64Memory {
			ram: Ram::new(),
			kernal: Rom::new(&Path::new("c64/kernal.rom")),
			basic: Rom::new(&Path::new("c64/basic.rom")),
			characters: Rom::new(&Path::new("c64/characters.rom")),
		}
	}
}

impl Addressable<u16> for C64Memory {
	fn get (&self, addr: u16) -> u8 {
		match addr {
			// TODO: Switch memory access based on LORAM/HIRAM/CHAREN
			0xa000..0xbfff => self.basic.get(addr - 0xa000),
			0xd000..0xdfff => self.characters.get(addr - 0xd000),
			0xe000..0xffff => self.kernal.get(addr - 0xe000),
			_              => self.ram.get(addr),
		}
	}

	fn set (&mut self, addr: u16, data: u8) {
		self.ram.set(addr, data);
	}
}

pub struct C64 {
	priv cpu: Mos6510<SharedMemory<C64Memory>>,
	priv mem: SharedMemory<C64Memory>,
}

impl C64 {
	pub fn new () -> C64 {
		let mem = SharedMemory::new(C64Memory::new());
		C64 {
			cpu: Mos6510::new(mem.clone()),
			mem: mem,
		}
	}

	pub fn run (&mut self) {
		// TODO
	}
}
<|endoftext|>


<commit_before>extern crate rand;

use rand::Rng;

use std::thread::sleep;
use std::time::Duration;

use std::io::stdout;
use std::io::Write;

// A struct to contain info we need to print with every character
pub struct Control {
    pub seed: f64,
    pub spread: f64,
    pub frequency: f64,
    pub background_mode: bool,
    pub dialup_mode: bool,
    pub print_color: bool,
}

// This used to have more of a reason to exist, however now all its functionality is in
// print_chars_lol(). It takes in an iterator over lines and prints them all.
// At the end, it resets the foreground color
pub fn print_lines_lol<I: Iterator<Item=S>, S: AsRef<str>>(lines: I, c: &mut Control) {
    for line in lines {
        print_chars_lol(line.as_ref().chars().chain(Some('\n')), c, false);
    }
    if c.print_color {
        print!("\x1b[39m");
    }
}

// Takes in s an iterator over characters
// duplicates escape sequences, otherwise prints printable characters with colored_print
// Print newlines correctly, resetting background
// If constantly_flush is on, it won't wait till a newline to flush stdout
pub fn print_chars_lol<I: Iterator<Item=char>>(mut iter: I, c: &mut Control, constantly_flush: bool) {
    let original_seed = c.seed;
    let mut ignore_whitespace = c.background_mode;

    if !c.print_color {
        for character in iter {
            print!("{}", character);
        }
        return;
    }

    while let Some(character) = iter.next() {
        match character {
        // Consume escape sequences
        '\x1b' => {
            // Escape sequences seem to be one of many different categories: https://en.wikipedia.org/wiki/ANSI_escape_code
            // CSI sequences are \e \[ [bytes in 0x30-0x3F] [bytes in 0x20-0x2F] [final byte in 0x40-0x7E]
            // nF Escape seq are \e [bytes in 0x20-0x2F] [byte in 0x30-0x7E]
            // Fp Escape seq are \e [byte in 0x30-0x3F] [I have no idea, but `sl` creates one where the next byte is the end of the escape sequence, so assume that]
            // Fe Escape seq are \e [byte in 0x40-0x5F] [I have no idea, '' though sl doesn't make one]
            // Fs Escape seq are \e [byte in 0x60-0x7E] [I have no idea, '' though sl doesn't make one]
            // Otherwise the next byte is the whole escape sequence (maybe? I can't exactly tell, but I will go with it)
            // We will consume up to, but not through, the next printable character
            // In addition, we print everything in the escape sequence, even if it is a color (that will be overriden)
            print!("\x1b");
            let mut escape_sequence_character = iter.next().expect("Escape character with no escape sequence after it");
            print!("{}", escape_sequence_character);
            match escape_sequence_character {
            '[' => {
                loop {
                    escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x30' ..= '\x3F' => continue,
                    '\x20' ..= '\x2F' => {
                        loop {
                            escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                            print!("{}", escape_sequence_character);
                            match escape_sequence_character {
                            '\x20' ..= '\x2F' => continue,
                            '\x40' ..= '\x7E' => break,
                            _ => panic!("CSI escape sequence terminated with an incorrect value"),
                            }
                        }
                        break;
                    },
                    '\x40' ..= '\x7E' => break,
                    _ => panic!("CSI escape sequence terminated with an incorrect value"),
                    }
                }
            },
            '\x20' ..= '\x2F' => {
                loop {
                    escape_sequence_character = iter.next().expect("nF escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x20' ..= '\x2F' => continue,
                    '\x30' ..= '\x7E' => break,
                    _ => panic!("nF escape sequence terminated with an incorrect value"),
                    }
                }
            },
//            '\x30' ..= '\x3F' => panic!("Fp escape sequences are not supported"),
//            '\x40' ..= '\x5F' => panic!("Fe escape sequences are not supported"),
//            '\x60' ..= '\x7E' => panic!("Fs escape sequences are not supported"),
            // be lazy and assume in all other cases we consume exactly 1 byte
            _ => (),
            }
        },
        // Newlines print escape sequences to end background prints, and in dialup mode sleep, and
        // reset the seed of the coloring and the value of ignore_whitespace
        '\n' => {
            if c.print_color {
                // Reset the background color only, as we don't have to reset the foreground till
                // the end of the program
                // We reset the background here because otherwise it bleeds all the way to the next line
                if c.background_mode {
                    print!("\x1b[49m");
                }
            }
            println!();
            if c.dialup_mode {
                let stall = Duration::from_millis(rand::thread_rng().gen_range(30, 700));
                sleep(stall);
            }

            c.seed = original_seed + 1.0; // Reset the seed, but bump it a bit
            ignore_whitespace = c.background_mode;
        },
        // If not an escape sequence or a newline, print a colorful escape sequence and then the
        // character
        _ => {
            // In background mode, don't print colorful whitespace until the first printable character
            if ignore_whitespace && character.is_whitespace() {
                print!("{}", character);
                continue;
            } else {
                ignore_whitespace = false;
            }

            colored_print(character, c);
            c.seed += 1.0;
        },
        }

        // If we should constantly flush, flush after each completed sequence, and also reset
        // colors because otherwise weird things happen
        if constantly_flush {
            reset_colors(c);
            stdout().flush().unwrap();
        }
    }
}

fn reset_colors(c: &Control) {
    if c.print_color {
        // Reset the background color
        if c.background_mode {
            print!("\x1b[49m");
        }

        // Reset the foreground color
        print!("\x1b[39m");
    }
}

fn colored_print(character: char, c: &mut Control) {
    if c.background_mode {
        let bg = get_color_tuple(c);
        let fg = calc_fg_color(bg);
        print!(
            "\x1b[38;2;{};{};{};48;2;{};{};{}m{}",
            fg.0, fg.1, fg.2, bg.0, bg.1, bg.2, character
        );
    } else {
        let fg = get_color_tuple(c);
        print!("\x1b[38;2;{};{};{}m{}", fg.0, fg.1, fg.2, character);
    }
}

fn calc_fg_color(bg: (u8, u8, u8)) -> (u8, u8, u8) {
    // Currently, it only computes the forground clolor based on some threshold
    // on grayscale value.
    // TODO: Add a better algorithm for computing forground color
    if conv_grayscale(bg) > 0xA0_u8 {
        (0u8, 0u8, 0u8)
    } else {
        (0xffu8, 0xffu8, 0xffu8)
    }
}

fn linear_to_srgb(intensity: f64) -> f64 {
    if intensity <= 0.003_130_8 {
        12.92 * intensity
    } else {
        1.055 * intensity.powf(1.0 / 2.4) - 0.055
    }
}

fn srgb_to_linear(intensity: f64) -> f64 {
    if intensity < 0.04045 {
        intensity / 12.92
    } else {
        ((intensity + 0.055) / 1.055).powf(2.4)
    }
}

fn conv_grayscale(color: (u8, u8, u8)) -> u8 {
    // See https://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
    const SCALE: f64 = 256.0;

    // Changing SRGB to Linear for gamma correction
    let red = srgb_to_linear(f64::from(color.0) / SCALE);
    let green = srgb_to_linear(f64::from(color.1) / SCALE);
    let blue = srgb_to_linear(f64::from(color.2) / SCALE);

    // Converting to grayscale
    let gray_linear = red * 0.299 + green * 0.587 + blue * 0.114;

    // Gamma correction
    let gray_srgb = linear_to_srgb(gray_linear);

    (gray_srgb * SCALE) as u8
}

fn get_color_tuple(c: &Control) -> (u8, u8, u8) {
    let i = c.frequency * c.seed / c.spread;
    let red = i.sin() * 127.00 + 128.00;
    let green = (i + (std::f64::consts::PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
    let blue = (i + (std::f64::consts::PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;

    (red as u8, green as u8, blue as u8)
}
<commit_msg>Fix #19<commit_after>extern crate rand;

use rand::Rng;

use std::thread::sleep;
use std::time::Duration;

use std::io::stdout;
use std::io::Write;

// A struct to contain info we need to print with every character
pub struct Control {
    pub seed: f64,
    pub spread: f64,
    pub frequency: f64,
    pub background_mode: bool,
    pub dialup_mode: bool,
    pub print_color: bool,
}

// This used to have more of a reason to exist, however now all its functionality is in
// print_chars_lol(). It takes in an iterator over lines and prints them all.
// At the end, it resets the foreground color
pub fn print_lines_lol<I: Iterator<Item=S>, S: AsRef<str>>(lines: I, c: &mut Control) {
    for line in lines {
        print_chars_lol(line.as_ref().chars().chain(Some('\n')), c, false);
    }
    if c.print_color {
        print!("\x1b[39m");
    }
}

// Takes in s an iterator over characters
// duplicates escape sequences, otherwise prints printable characters with colored_print
// Print newlines correctly, resetting background
// If constantly_flush is on, it won't wait till a newline to flush stdout
pub fn print_chars_lol<I: Iterator<Item=char>>(mut iter: I, c: &mut Control, constantly_flush: bool) {
    let mut original_seed = c.seed;
    let mut ignore_whitespace = c.background_mode;

    if !c.print_color {
        for character in iter {
            print!("{}", character);
        }
        return;
    }

    while let Some(character) = iter.next() {
        match character {
        // Consume escape sequences
        '\x1b' => {
            // Escape sequences seem to be one of many different categories: https://en.wikipedia.org/wiki/ANSI_escape_code
            // CSI sequences are \e \[ [bytes in 0x30-0x3F] [bytes in 0x20-0x2F] [final byte in 0x40-0x7E]
            // nF Escape seq are \e [bytes in 0x20-0x2F] [byte in 0x30-0x7E]
            // Fp Escape seq are \e [byte in 0x30-0x3F] [I have no idea, but `sl` creates one where the next byte is the end of the escape sequence, so assume that]
            // Fe Escape seq are \e [byte in 0x40-0x5F] [I have no idea, '' though sl doesn't make one]
            // Fs Escape seq are \e [byte in 0x60-0x7E] [I have no idea, '' though sl doesn't make one]
            // Otherwise the next byte is the whole escape sequence (maybe? I can't exactly tell, but I will go with it)
            // We will consume up to, but not through, the next printable character
            // In addition, we print everything in the escape sequence, even if it is a color (that will be overriden)
            print!("\x1b");
            let mut escape_sequence_character = iter.next().expect("Escape character with no escape sequence after it");
            print!("{}", escape_sequence_character);
            match escape_sequence_character {
            '[' => {
                loop {
                    escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x30' ..= '\x3F' => continue,
                    '\x20' ..= '\x2F' => {
                        loop {
                            escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                            print!("{}", escape_sequence_character);
                            match escape_sequence_character {
                            '\x20' ..= '\x2F' => continue,
                            '\x40' ..= '\x7E' => break,
                            _ => panic!("CSI escape sequence terminated with an incorrect value"),
                            }
                        }
                        break;
                    },
                    '\x40' ..= '\x7E' => break,
                    _ => panic!("CSI escape sequence terminated with an incorrect value"),
                    }
                }
            },
            '\x20' ..= '\x2F' => {
                loop {
                    escape_sequence_character = iter.next().expect("nF escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x20' ..= '\x2F' => continue,
                    '\x30' ..= '\x7E' => break,
                    _ => panic!("nF escape sequence terminated with an incorrect value"),
                    }
                }
            },
//            '\x30' ..= '\x3F' => panic!("Fp escape sequences are not supported"),
//            '\x40' ..= '\x5F' => panic!("Fe escape sequences are not supported"),
//            '\x60' ..= '\x7E' => panic!("Fs escape sequences are not supported"),
            // be lazy and assume in all other cases we consume exactly 1 byte
            _ => (),
            }
        },
        // Newlines print escape sequences to end background prints, and in dialup mode sleep, and
        // reset the seed of the coloring and the value of ignore_whitespace
        '\n' => {
            if c.print_color {
                // Reset the background color only, as we don't have to reset the foreground till
                // the end of the program
                // We reset the background here because otherwise it bleeds all the way to the next line
                if c.background_mode {
                    print!("\x1b[49m");
                }
            }
            println!();
            if c.dialup_mode {
                let stall = Duration::from_millis(rand::thread_rng().gen_range(30, 700));
                sleep(stall);
            }

            original_seed += 1.0;
            c.seed = original_seed; // Reset the seed, but bump it a bit
            ignore_whitespace = c.background_mode;
        },
        // If not an escape sequence or a newline, print a colorful escape sequence and then the
        // character
        _ => {
            // In background mode, don't print colorful whitespace until the first printable character
            if ignore_whitespace && character.is_whitespace() {
                print!("{}", character);
                continue;
            } else {
                ignore_whitespace = false;
            }

            colored_print(character, c);
            c.seed += 1.0;
        },
        }

        // If we should constantly flush, flush after each completed sequence, and also reset
        // colors because otherwise weird things happen
        if constantly_flush {
            reset_colors(c);
            stdout().flush().unwrap();
        }
    }
}

fn reset_colors(c: &Control) {
    if c.print_color {
        // Reset the background color
        if c.background_mode {
            print!("\x1b[49m");
        }

        // Reset the foreground color
        print!("\x1b[39m");
    }
}

fn colored_print(character: char, c: &mut Control) {
    if c.background_mode {
        let bg = get_color_tuple(c);
        let fg = calc_fg_color(bg);
        print!(
            "\x1b[38;2;{};{};{};48;2;{};{};{}m{}",
            fg.0, fg.1, fg.2, bg.0, bg.1, bg.2, character
        );
    } else {
        let fg = get_color_tuple(c);
        print!("\x1b[38;2;{};{};{}m{}", fg.0, fg.1, fg.2, character);
    }
}

fn calc_fg_color(bg: (u8, u8, u8)) -> (u8, u8, u8) {
    // Currently, it only computes the forground clolor based on some threshold
    // on grayscale value.
    // TODO: Add a better algorithm for computing forground color
    if conv_grayscale(bg) > 0xA0_u8 {
        (0u8, 0u8, 0u8)
    } else {
        (0xffu8, 0xffu8, 0xffu8)
    }
}

fn linear_to_srgb(intensity: f64) -> f64 {
    if intensity <= 0.003_130_8 {
        12.92 * intensity
    } else {
        1.055 * intensity.powf(1.0 / 2.4) - 0.055
    }
}

fn srgb_to_linear(intensity: f64) -> f64 {
    if intensity < 0.04045 {
        intensity / 12.92
    } else {
        ((intensity + 0.055) / 1.055).powf(2.4)
    }
}

fn conv_grayscale(color: (u8, u8, u8)) -> u8 {
    // See https://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
    const SCALE: f64 = 256.0;

    // Changing SRGB to Linear for gamma correction
    let red = srgb_to_linear(f64::from(color.0) / SCALE);
    let green = srgb_to_linear(f64::from(color.1) / SCALE);
    let blue = srgb_to_linear(f64::from(color.2) / SCALE);

    // Converting to grayscale
    let gray_linear = red * 0.299 + green * 0.587 + blue * 0.114;

    // Gamma correction
    let gray_srgb = linear_to_srgb(gray_linear);

    (gray_srgb * SCALE) as u8
}

fn get_color_tuple(c: &Control) -> (u8, u8, u8) {
    let i = c.frequency * c.seed / c.spread;
    let red = i.sin() * 127.00 + 128.00;
    let green = (i + (std::f64::consts::PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
    let blue = (i + (std::f64::consts::PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;

    (red as u8, green as u8, blue as u8)
}
<|endoftext|>


<commit_before>extern crate clap;
use clap::{App, ArgMatches};

pub struct ModuleConfig {
    pub load : bool,
}

impl ModuleConfig {
    pub fn new() -> ModuleConfig {
        ModuleConfig {
            load: false,
        }
    }
}

pub struct Config<'a> {
    pub module_configs  : Vec<ModuleConfig>,
    pub cli_matches     : ArgMatches<'a, 'a>,
}

impl<'a> Config<'a> {
    pub fn new(app : clap::App<'a, 'a, 'a, 'a, 'a, 'a>) -> Config<'a> {
        Config {
            module_configs: vec![],
            cli_matches: app.get_matches(),
        }
    }

    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbose")
    }

    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }
}

<commit_msg>Fix: Runtime.is_{verbose,debugging}<commit_after>extern crate clap;
use clap::{App, ArgMatches};

pub struct ModuleConfig {
    pub load : bool,
}

impl ModuleConfig {
    pub fn new() -> ModuleConfig {
        ModuleConfig {
            load: false,
        }
    }
}

pub struct Config<'a> {
    pub module_configs  : Vec<ModuleConfig>,
    pub cli_matches     : ArgMatches<'a, 'a>,
}

impl<'a> Config<'a> {
    pub fn new(app : clap::App<'a, 'a, 'a, 'a, 'a, 'a>) -> Config<'a> {
        Config {
            module_configs: vec![],
            cli_matches: app.get_matches(),
        }
    }

    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbose") || self.is_debugging()
    }

    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debug")
    }
}

<|endoftext|>


<commit_before>use std::path::MAIN_SEPARATOR;
use std::process::Command;

use clap::{App, Arg, Error};

#[derive(Debug)]
pub struct Args {
    pub cmd: String,
    pub paths: Vec<String>,
    pub filters: Vec<String>,
    pub ignores: Vec<String>,
    pub clear_screen: bool,
    pub signal: Option<String>,
    pub restart: bool,
    pub debug: bool,
    pub run_initially: bool,
    pub no_vcs_ignore: bool,
    pub once: bool,
    pub poll: bool,
    pub poll_interval: u32,
}

#[cfg(target_family = "windows")]
pub fn clear_screen() {
    let _ = Command::new("cls").status();
}

#[cfg(target_family = "unix")]
pub fn clear_screen() {
    let _ = Command::new("clear").status();
}

#[allow(unknown_lints)]
#[allow(or_fun_call)]
pub fn get_args() -> Args {
    let args =
        App::new("watchexec")
            .version(crate_version!())
            .about("Execute commands when watched files change")
            .arg(Arg::with_name("command")
                     .help("Command to execute")
                     .multiple(true)
                     .required(true))
            .arg(Arg::with_name("extensions")
                     .help("Comma-separated list of file extensions to watch (js,css,html)")
                     .short("e")
                     .long("exts")
                     .takes_value(true))
            .arg(Arg::with_name("path")
                     .help("Watch a specific directory")
                     .short("w")
                     .long("watch")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true))
            .arg(Arg::with_name("clear")
                     .help("Clear screen before executing command")
                     .short("c")
                     .long("clear"))
            .arg(Arg::with_name("restart")
                     .help("Restart the process if it's still running")
                     .short("r")
                     .long("restart"))
            .arg(Arg::with_name("signal")
                     .help("Send signal to process upon changes, e.g. SIGHUP")
                     .short("s")
                     .long("signal")
                     .takes_value(true)
                     .number_of_values(1)
                     .value_name("signal"))
            .arg(Arg::with_name("debug")
                     .help("Print debugging messages to stderr")
                     .short("d")
                     .long("debug"))
            .arg(Arg::with_name("filter")
                     .help("Ignore all modifications except those matching the pattern")
                     .short("f")
                     .long("filter")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true)
                     .value_name("pattern"))
            .arg(Arg::with_name("ignore")
                     .help("Ignore modifications to paths matching the pattern")
                     .short("i")
                     .long("ignore")
                     .number_of_values(1)
                     .multiple(true)
                     .takes_value(true)
                     .value_name("pattern"))
            .arg(Arg::with_name("no-vcs-ignore")
                     .help("Skip auto-loading of .gitignore files for filtering")
                     .long("no-vcs-ignore"))
            .arg(Arg::with_name("postpone")
                     .help("Wait until first change to execute command")
                     .short("p")
                     .long("postpone"))
            .arg(Arg::with_name("poll")
                     .help("Forces polling mode")
                     .long("force-poll")
                     .value_name("interval"))
            .arg(Arg::with_name("once").short("1").hidden(true))
            .get_matches();

    let cmd = values_t!(args.values_of("command"), String).unwrap().join(" ");
    let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]);
    let signal = args.value_of("signal").map(str::to_string); // Convert Option<&str> to Option<String>

    let mut filters = values_t!(args.values_of("filter"), String).unwrap_or(vec![]);

    if let Some(extensions) = args.values_of("extensions") {
        for exts in extensions {
            filters.extend(exts.split(',')
                .filter(|ext| !ext.is_empty())
                .map(|ext| format!("*.{}", ext.replace(".", ""))));

        }
    }

    let mut ignores = vec![];
    let default_ignores = vec![format!("*{}.*{}*", MAIN_SEPARATOR, MAIN_SEPARATOR),
                               format!("*{}.DS_Store", MAIN_SEPARATOR),
                               String::from("*.pyc"),
                               String::from("*.swp")];

    ignores.extend(default_ignores);
    ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or(vec![]));

    let poll_interval = if args.occurrences_of("poll") > 0 {
        value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
    } else {
        1000
    };

    if signal.is_some() && args.is_present("postpone") {
        // TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
        Error::value_validation_auto(format!("--postpone and --signal are mutually exclusive"))
            .exit();
    }

    Args {
        cmd: cmd,
        paths: paths,
        filters: filters,
        ignores: ignores,
        signal: signal,
        clear_screen: args.is_present("clear"),
        restart: args.is_present("restart"),
        debug: args.is_present("debug"),
        run_initially: !args.is_present("postpone"),
        no_vcs_ignore: args.is_present("no-vcs-ignore"),
        once: args.is_present("once"),
        poll: args.occurrences_of("poll") > 0,
        poll_interval: poll_interval,
    }
}
<commit_msg>Re-add --kill flag for compatibility<commit_after>use std::path::MAIN_SEPARATOR;
use std::process::Command;

use clap::{App, Arg, Error};

#[derive(Debug)]
pub struct Args {
    pub cmd: String,
    pub paths: Vec<String>,
    pub filters: Vec<String>,
    pub ignores: Vec<String>,
    pub clear_screen: bool,
    pub signal: Option<String>,
    pub restart: bool,
    pub debug: bool,
    pub run_initially: bool,
    pub no_vcs_ignore: bool,
    pub once: bool,
    pub poll: bool,
    pub poll_interval: u32,
}

#[cfg(target_family = "windows")]
pub fn clear_screen() {
    let _ = Command::new("cls").status();
}

#[cfg(target_family = "unix")]
pub fn clear_screen() {
    let _ = Command::new("clear").status();
}

#[allow(unknown_lints)]
#[allow(or_fun_call)]
pub fn get_args() -> Args {
    let args = App::new("watchexec")
        .version(crate_version!())
        .about("Execute commands when watched files change")
        .arg(Arg::with_name("command")
                 .help("Command to execute")
                 .multiple(true)
                 .required(true))
        .arg(Arg::with_name("extensions")
                 .help("Comma-separated list of file extensions to watch (js,css,html)")
                 .short("e")
                 .long("exts")
                 .takes_value(true))
        .arg(Arg::with_name("path")
                 .help("Watch a specific directory")
                 .short("w")
                 .long("watch")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true))
        .arg(Arg::with_name("clear")
                 .help("Clear screen before executing command")
                 .short("c")
                 .long("clear"))
        .arg(Arg::with_name("restart")
                 .help("Restart the process if it's still running")
                 .short("r")
                 .long("restart"))
        .arg(Arg::with_name("signal")
                 .help("Send signal to process upon changes, e.g. SIGHUP")
                 .short("s")
                 .long("signal")
                 .takes_value(true)
                 .number_of_values(1)
                 .value_name("signal"))
        .arg(Arg::with_name("kill")
                 .help("Send SIGKILL to child processes (deprecated, use -s SIGKILL instead)")
                 .short("k")
                 .long("kill"))
        .arg(Arg::with_name("debug")
                 .help("Print debugging messages to stderr")
                 .short("d")
                 .long("debug"))
        .arg(Arg::with_name("filter")
                 .help("Ignore all modifications except those matching the pattern")
                 .short("f")
                 .long("filter")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true)
                 .value_name("pattern"))
        .arg(Arg::with_name("ignore")
                 .help("Ignore modifications to paths matching the pattern")
                 .short("i")
                 .long("ignore")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true)
                 .value_name("pattern"))
        .arg(Arg::with_name("no-vcs-ignore")
                 .help("Skip auto-loading of .gitignore files for filtering")
                 .long("no-vcs-ignore"))
        .arg(Arg::with_name("postpone")
                 .help("Wait until first change to execute command")
                 .short("p")
                 .long("postpone"))
        .arg(Arg::with_name("poll")
                 .help("Forces polling mode")
                 .long("force-poll")
                 .value_name("interval"))
        .arg(Arg::with_name("once").short("1").hidden(true))
        .get_matches();

    let cmd = values_t!(args.values_of("command"), String)
        .unwrap()
        .join(" ");
    let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]);

    // Treat --kill as --signal SIGKILL (for compatibility with older syntax)
    let signal = match args.is_present("kill") {
        true => Some("SIGKILL".to_string()),
        false => args.value_of("signal").map(str::to_string), // Convert Option<&str> to Option<String>
    };

    let mut filters = values_t!(args.values_of("filter"), String).unwrap_or(vec![]);

    if let Some(extensions) = args.values_of("extensions") {
        for exts in extensions {
            filters.extend(exts.split(',')
                               .filter(|ext| !ext.is_empty())
                               .map(|ext| format!("*.{}", ext.replace(".", ""))));

        }
    }

    let mut ignores = vec![];
    let default_ignores = vec![format!("*{}.*{}*", MAIN_SEPARATOR, MAIN_SEPARATOR),
                               format!("*{}.DS_Store", MAIN_SEPARATOR),
                               String::from("*.pyc"),
                               String::from("*.swp")];

    ignores.extend(default_ignores);
    ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or(vec![]));

    let poll_interval = if args.occurrences_of("poll") > 0 {
        value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
    } else {
        1000
    };

    if signal.is_some() && args.is_present("postpone") {
        // TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
        Error::value_validation_auto(format!("--postpone and --signal are mutually exclusive"))
            .exit();
    }

    if signal.is_some() && args.is_present("kill") {
        // TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
        Error::value_validation_auto(format!("--kill and --signal is ambiguous.\n       Hint: Use only '--signal SIGKILL' without --kill"))
            .exit();
    }

    Args {
        cmd: cmd,
        paths: paths,
        filters: filters,
        ignores: ignores,
        signal: signal,
        clear_screen: args.is_present("clear"),
        restart: args.is_present("restart"),
        debug: args.is_present("debug"),
        run_initially: !args.is_present("postpone"),
        no_vcs_ignore: args.is_present("no-vcs-ignore"),
        once: args.is_present("once"),
        poll: args.occurrences_of("poll") > 0,
        poll_interval: poll_interval,
    }
}
<|endoftext|>


<commit_before>/// Supply the command line.

use std::fmt;

use clap::{Arg, ArgMatches, App, AppSettings, SubCommand};

// TODO: define this as the thing that `cli` actually returns (instead of
// TODO: `ArgMatches`.
struct Args {}

// TODO: figure out a way, eventually, to customize arguments based on whatever
// external tools are supplied---without requiring a rebuild. (Compare what
// Cargo does.)
pub fn cli<'a, 'b>(additional_args: &[Arg<'a, 'b>],
                   additional_subcommands: &[App<'a, 'b>])
                   -> ArgMatches<'a> {

  let mut args = vec![];
  args.extend_from_slice(additional_args);

  let mut subcommands = vec![
    generate(),
    new(),
  ];

  subcommands.extend_from_slice(additional_subcommands);

  App::new("Lightning")
    .setting(AppSettings::ArgRequiredElseHelp)
    .version("0.1.0")
    .author(crate_authors!())
    .about("A fast, reliable, configurable static site generator.")
    .subcommands(subcommands)
    .args(&args)
    .get_matches()
}

pub enum Commands {
  Generate,
  New,
  Unspecified,
}

impl fmt::Display for Commands {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Commands::Generate => write!(f, "generate"),
      Commands::New => write!(f, "new"),
      _ => write!(f, "error!!!"),  // TODO: something else!
    }
  }
}

impl<'a> From<&'a str> for Commands {
  fn from(s: &str) -> Commands {
    match s {
      "generate" => Commands::Generate,
      "new" => Commands::New,
      _ => Commands::Unspecified,
    }
  }
}

// -- TODO: I feel like the following should be namespaced somehow?

/// Generate the site.
fn generate<'a, 'b>() -> App<'a, 'b> {
  SubCommand::with_name("generate")
    .about("Generate the site")
    .arg(Arg::with_name("local")
      .help("Use local paths to resources")
      .long("local"))
    .arg(Arg::with_name("serve")
      .short("s")
      .long("serve")
      .alias("server"))
}

/// Generate a new item from a template.
///
/// TODO: different templates will take different args---figure out what the
/// best way to programmatically generate new options for these based on the
/// state of the file system where it's run is, so that e.g. the user (*me*,
/// initially!) can e.g. just specify a location for new templates in the
/// configuration file, drop a template in there, and have the generator pick it
/// up correctly as one of the options.
fn new<'a, 'b>() -> App<'a, 'b> {
  SubCommand::with_name("new")
    .about("Create an item from a template")
    .arg(Arg::with_name("template")
      .help("The name of the template to generate, e.g. `post`")
      .index(1)
      .required(true)
      .possible_values(&["post"]))
    .arg(Arg::with_name("title")
      .help("The title to use in the template")
      .index(2)
      .required(true)
      .takes_value(true))
}
<commit_msg>Move a long CLI TODO to a GitHub issue.<commit_after>/// Supply the command line.

use std::fmt;

use clap::{Arg, ArgMatches, App, AppSettings, SubCommand};

// TODO: define this as the thing that `cli` actually returns (instead of
// TODO: `ArgMatches`.
struct Args {}

// TODO: figure out a way, eventually, to customize arguments based on whatever
// external tools are supplied---without requiring a rebuild. (Compare what
// Cargo does.)
pub fn cli<'a, 'b>(additional_args: &[Arg<'a, 'b>],
                   additional_subcommands: &[App<'a, 'b>])
                   -> ArgMatches<'a> {

  let mut args = vec![];
  args.extend_from_slice(additional_args);

  let mut subcommands = vec![
    generate(),
    new(),
  ];

  subcommands.extend_from_slice(additional_subcommands);

  App::new("Lightning")
    .setting(AppSettings::ArgRequiredElseHelp)
    .version("0.1.0")
    .author(crate_authors!())
    .about("A fast, reliable, configurable static site generator.")
    .subcommands(subcommands)
    .args(&args)
    .get_matches()
}

pub enum Commands {
  Generate,
  New,
  Unspecified,
}

impl fmt::Display for Commands {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Commands::Generate => write!(f, "generate"),
      Commands::New => write!(f, "new"),
      _ => write!(f, "error!!!"),  // TODO: something else!
    }
  }
}

impl<'a> From<&'a str> for Commands {
  fn from(s: &str) -> Commands {
    match s {
      "generate" => Commands::Generate,
      "new" => Commands::New,
      _ => Commands::Unspecified,
    }
  }
}

// -- TODO: I feel like the following should be namespaced somehow?

/// Generate the site.
fn generate<'a, 'b>() -> App<'a, 'b> {
  SubCommand::with_name("generate")
    .about("Generate the site")
    .arg(Arg::with_name("local")
      .help("Use local paths to resources")
      .long("local"))
    .arg(Arg::with_name("serve")
      .short("s")
      .long("serve")
      .alias("server"))
}

/// Generate a new item from a template.
fn new<'a, 'b>() -> App<'a, 'b> {
  SubCommand::with_name("new")
    .about("Create an item from a template")
    .arg(Arg::with_name("template")
      .help("The name of the template to generate, e.g. `post`")
      .index(1)
      .required(true)
      .possible_values(&["post"]))
    .arg(Arg::with_name("title")
      .help("The title to use in the template")
      .index(2)
      .required(true)
      .takes_value(true))
}
<|endoftext|>


<commit_before>use csv;
use std::{cmp, error, fmt};
use std::error::Error;
use term_painter::{Attr, Color, ToStyle};
use term_size;
use textwrap;

pub trait Helpful {
    fn help(&self) -> String;
}

#[derive(Clone, Debug)]
pub enum Location {
    FileLineColumn(String, usize, usize),
    FileRowField(String, usize, usize),
    FileLine(String, usize),
    File(String),
    Unspecified,
}

impl fmt::Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Location::FileLineColumn(ref file, line, col) => write!(f, "{}:{}:{}", file, line, col),
            Location::FileRowField(ref file, row, field) => {
                write!(f, "{}:{}[{}]", file, row, field)
            }
            Location::FileLine(ref file, line) => write!(f, "{}:{}]", file, line),
            Location::File(ref file) => write!(f, "{}", file),
            Location::Unspecified => Ok(()),
        }
    }
}

#[derive(Debug)]
pub struct ErrorWithLocation<E> {
    location: Location,
    error: E,
}

impl<E> ErrorWithLocation<E> {
    pub fn new<F: Into<E>>(location: Location, error: F) -> ErrorWithLocation<E> {
        ErrorWithLocation {
            location: location,
            error: error.into(),
        }
    }

    pub fn from_error<F: Into<E>>(other: F) -> ErrorWithLocation<E> {
        ErrorWithLocation::new(Location::Unspecified, other.into())
    }
}

impl<E: fmt::Display + Helpful> ErrorWithLocation<E> {
    pub fn print_help(&self) {
        println!("{}{} {}",
                 Attr::Bold.paint((Color::Red.paint("error"))),
                 Attr::Bold.paint(":"),
                 Attr::Bold.paint(self.error()));
        match *self.location() {
            Location::Unspecified => (),
            _ => println!("  --> {}", Color::Yellow.paint(self.location())),
        }

        let dims = term_size::dimensions().unwrap_or((80, 25));

        let term_width = cmp::max(dims.0, 4);
        let out = textwrap::wrap(self.error.help().as_str(), term_width - 3)
            .into_iter()
            .map(|line| textwrap::indent(line.as_str(), "   "))
            .fold(String::new(), |s1, s2| s1 + s2.as_str());
        println!("{}", out);
    }
}

impl<E> ErrorWithLocation<E> {
    pub fn error(&self) -> &E {
        &self.error
    }

    pub fn into_error(self) -> E {
        self.error
    }

    pub fn location(&self) -> &Location {
        &self.location
    }
}

impl<E: fmt::Display> fmt::Display for ErrorWithLocation<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self.location() {
            Location::Unspecified => write!(f, "{}", self.error()),
            _ => write!(f, "{}: {}", self.location(), self.error()),
        }
    }
}

impl<E: error::Error> error::Error for ErrorWithLocation<E> {
    fn description(&self) -> &str {
        self.error.description()
    }

    fn cause(&self) -> Option<&error::Error> {
        Some(self.error())
    }
}

impl<E> From<E> for ErrorWithLocation<E> {
    fn from(e: E) -> ErrorWithLocation<E> {
        ErrorWithLocation::from_error(e)
    }
}

#[derive(Debug)]
pub enum CheckError {
    NotASchema,
    SchemaNotAFile,
    InvalidCsvxFilename,
    SchemaLoadError(SchemaLoadError),
    SchemaPathUtf8Error,
}

impl From<SchemaLoadError> for CheckError {
    fn from(e: SchemaLoadError) -> CheckError {
        CheckError::SchemaLoadError(e)
    }
}

impl fmt::Display for CheckError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}", cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl error::Error for CheckError {
    fn description(&self) -> &str {
        match *self {
            CheckError::NotASchema => "not a schema",
            CheckError::SchemaNotAFile => "schema is not a file",
            CheckError::InvalidCsvxFilename => "filename is not a valid CSVX filename",
            CheckError::SchemaLoadError(_) => "could not load schema",
            CheckError::SchemaPathUtf8Error => "filename UTF8 decoding error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CheckError::SchemaLoadError(ref e) => Some(e),
            _ => None,
        }
    }
}

impl Helpful for CheckError {
    fn help(&self) -> String {
        match *self {
            CheckError::NotASchema => {
                "The file you provided is not a schema. The third field of \
                the filename must be of the form `csvx-schema-` followed by \
                the version number. As an example, when defining a schema \
                named `animals-2`, with a date of Dec 31st, 2015 and CSVX \
                version 5, the resulting filename should be: \
                `animals-2_20151231_csvx-schema-5.csv`. \n\
                Note that filenames are case sensitive!"
                        .to_owned()
            }
            CheckError::SchemaNotAFile => "The schema you supplied is not a valid file".to_owned(),
            CheckError::InvalidCsvxFilename => {
                "The filename provided is not in a valid CSVX form. CSVX \
                filenames have three components: The table name, date and \
                schema name. All components must be lowercase letters, \
                numbers or hyphens and start with a letter.\n\n\
                The table name component identifies the file or rather the \
                table it was exported from.\n\
                The date component is for the date the file was exported on.\n\
                The schema name component indicates which schema should be \
                used to validate its contents.\n\n\
                Example: With a table name of `nyc-zoo`, a date of Dec 31st, \
                2015 and using a schema named `animals-2`, the resulting \
                filename should be `nyc-zoo_20151231_animals-2.csv`."
                        .to_owned()
            }
            CheckError::SchemaPathUtf8Error => {
                "The filename you supplied contained UTF-8 errors. CSVX \
                filenames should only contain ASCII characters, please rename \
                the file and try again."
                        .to_owned()
            }
            CheckError::SchemaLoadError(ref e) => e.help(),
        }
    }
}

#[derive(Clone, Debug)]
pub enum ColumnConstraintsError {
    MalformedConstraint,
    UnknownConstraint(String),
}

#[derive(Clone, Debug)]
pub enum ColumnTypeError {
    UnknownType,
}

#[derive(Debug)]
pub enum SchemaLoadError {
    Csv(csv::Error),
    MissingHeader,
    BadHeader,
    BadIdentifier(usize, String),
    BadType(usize, ColumnTypeError),
    BadConstraints(usize, ColumnConstraintsError),
}

impl fmt::Display for SchemaLoadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}", cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl error::Error for SchemaLoadError {
    fn description(&self) -> &str {
        match *self {
            _ => "TBW",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            _ => None,
        }
    }
}

impl Helpful for SchemaLoadError {
    fn help(&self) -> String {
        "FIXME".to_owned()
    }
}

impl From<csv::Error> for SchemaLoadError {
    fn from(e: csv::Error) -> SchemaLoadError {
        SchemaLoadError::Csv(e)
    }
}

#[derive(Debug)]
pub enum ValidationError {
    Csv(csv::Error),
    MissingHeaders,
    HeaderMismatch(usize, String),
    RowLengthMismatch(usize),
    ValueError(usize, usize, ValueError),
}

#[derive(Debug)]
pub enum ValueError {
    NonNullable,
    InvalidBool,
    InvalidInt,
    InvalidEnum,
    InvalidDecimal,
    InvalidDate,
    InvalidDateTime,
    InvalidTime,
}
<commit_msg>Added `convert` convenience function.<commit_after>use csv;
use std::{cmp, error, fmt};
use std::error::Error;
use term_painter::{Attr, Color, ToStyle};
use term_size;
use textwrap;

pub trait Helpful {
    fn help(&self) -> String;
}

#[derive(Clone, Debug)]
pub enum Location {
    FileLineColumn(String, usize, usize),
    FileRowField(String, usize, usize),
    FileLine(String, usize),
    File(String),
    Unspecified,
}

impl fmt::Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Location::FileLineColumn(ref file, line, col) => write!(f, "{}:{}:{}", file, line, col),
            Location::FileRowField(ref file, row, field) => {
                write!(f, "{}:{}[{}]", file, row, field)
            }
            Location::FileLine(ref file, line) => write!(f, "{}:{}]", file, line),
            Location::File(ref file) => write!(f, "{}", file),
            Location::Unspecified => Ok(()),
        }
    }
}

#[derive(Debug)]
pub struct ErrorWithLocation<E> {
    location: Location,
    error: E,
}

impl<E> ErrorWithLocation<E> {
    pub fn new<F: Into<E>>(location: Location, error: F) -> ErrorWithLocation<E> {
        ErrorWithLocation {
            location: location,
            error: error.into(),
        }
    }

    pub fn from_error<F: Into<E>>(other: F) -> ErrorWithLocation<E> {
        ErrorWithLocation::new(Location::Unspecified, other.into())
    }

    pub fn convert<F: From<E>>(self) -> ErrorWithLocation<F> {
        ErrorWithLocation {
            location: self.location,
            error: self.error.into(),
        }
    }
}

impl<E: fmt::Display + Helpful> ErrorWithLocation<E> {
    pub fn print_help(&self) {
        println!("{}{} {}",
                 Attr::Bold.paint((Color::Red.paint("error"))),
                 Attr::Bold.paint(":"),
                 Attr::Bold.paint(self.error()));
        match *self.location() {
            Location::Unspecified => (),
            _ => println!("  --> {}", Color::Yellow.paint(self.location())),
        }

        let dims = term_size::dimensions().unwrap_or((80, 25));

        let term_width = cmp::max(dims.0, 4);
        let out = textwrap::wrap(self.error.help().as_str(), term_width - 3)
            .into_iter()
            .map(|line| textwrap::indent(line.as_str(), "   "))
            .fold(String::new(), |s1, s2| s1 + s2.as_str());
        println!("{}", out);
    }
}

impl<E> ErrorWithLocation<E> {
    pub fn error(&self) -> &E {
        &self.error
    }

    pub fn into_error(self) -> E {
        self.error
    }

    pub fn location(&self) -> &Location {
        &self.location
    }
}

impl<E: fmt::Display> fmt::Display for ErrorWithLocation<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self.location() {
            Location::Unspecified => write!(f, "{}", self.error()),
            _ => write!(f, "{}: {}", self.location(), self.error()),
        }
    }
}

impl<E: error::Error> error::Error for ErrorWithLocation<E> {
    fn description(&self) -> &str {
        self.error.description()
    }

    fn cause(&self) -> Option<&error::Error> {
        Some(self.error())
    }
}

impl<E> From<E> for ErrorWithLocation<E> {
    fn from(e: E) -> ErrorWithLocation<E> {
        ErrorWithLocation::from_error(e)
    }
}

#[derive(Debug)]
pub enum CheckError {
    NotASchema,
    SchemaNotAFile,
    InvalidCsvxFilename,
    SchemaLoadError(SchemaLoadError),
    SchemaPathUtf8Error,
}

impl From<SchemaLoadError> for CheckError {
    fn from(e: SchemaLoadError) -> CheckError {
        CheckError::SchemaLoadError(e)
    }
}

impl fmt::Display for CheckError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}", cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl error::Error for CheckError {
    fn description(&self) -> &str {
        match *self {
            CheckError::NotASchema => "not a schema",
            CheckError::SchemaNotAFile => "schema is not a file",
            CheckError::InvalidCsvxFilename => "filename is not a valid CSVX filename",
            CheckError::SchemaLoadError(_) => "could not load schema",
            CheckError::SchemaPathUtf8Error => "filename UTF8 decoding error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CheckError::SchemaLoadError(ref e) => Some(e),
            _ => None,
        }
    }
}

impl Helpful for CheckError {
    fn help(&self) -> String {
        match *self {
            CheckError::NotASchema => {
                "The file you provided is not a schema. The third field of \
                the filename must be of the form `csvx-schema-` followed by \
                the version number. As an example, when defining a schema \
                named `animals-2`, with a date of Dec 31st, 2015 and CSVX \
                version 5, the resulting filename should be: \
                `animals-2_20151231_csvx-schema-5.csv`. \n\
                Note that filenames are case sensitive!"
                        .to_owned()
            }
            CheckError::SchemaNotAFile => "The schema you supplied is not a valid file".to_owned(),
            CheckError::InvalidCsvxFilename => {
                "The filename provided is not in a valid CSVX form. CSVX \
                filenames have three components: The table name, date and \
                schema name. All components must be lowercase letters, \
                numbers or hyphens and start with a letter.\n\n\
                The table name component identifies the file or rather the \
                table it was exported from.\n\
                The date component is for the date the file was exported on.\n\
                The schema name component indicates which schema should be \
                used to validate its contents.\n\n\
                Example: With a table name of `nyc-zoo`, a date of Dec 31st, \
                2015 and using a schema named `animals-2`, the resulting \
                filename should be `nyc-zoo_20151231_animals-2.csv`."
                        .to_owned()
            }
            CheckError::SchemaPathUtf8Error => {
                "The filename you supplied contained UTF-8 errors. CSVX \
                filenames should only contain ASCII characters, please rename \
                the file and try again."
                        .to_owned()
            }
            CheckError::SchemaLoadError(ref e) => e.help(),
        }
    }
}

#[derive(Clone, Debug)]
pub enum ColumnConstraintsError {
    MalformedConstraint,
    UnknownConstraint(String),
}

#[derive(Clone, Debug)]
pub enum ColumnTypeError {
    UnknownType,
}

#[derive(Debug)]
pub enum SchemaLoadError {
    Csv(csv::Error),
    MissingHeader,
    BadHeader,
    BadIdentifier(usize, String),
    BadType(usize, ColumnTypeError),
    BadConstraints(usize, ColumnConstraintsError),
}

impl fmt::Display for SchemaLoadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}", cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl error::Error for SchemaLoadError {
    fn description(&self) -> &str {
        match *self {
            _ => "TBW",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            _ => None,
        }
    }
}

impl Helpful for SchemaLoadError {
    fn help(&self) -> String {
        "FIXME".to_owned()
    }
}

impl From<csv::Error> for SchemaLoadError {
    fn from(e: csv::Error) -> SchemaLoadError {
        SchemaLoadError::Csv(e)
    }
}

#[derive(Debug)]
pub enum ValidationError {
    Csv(csv::Error),
    MissingHeaders,
    HeaderMismatch(usize, String),
    RowLengthMismatch(usize),
    ValueError(usize, usize, ValueError),
}

#[derive(Debug)]
pub enum ValueError {
    NonNullable,
    InvalidBool,
    InvalidInt,
    InvalidEnum,
    InvalidDecimal,
    InvalidDate,
    InvalidDateTime,
    InvalidTime,
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library Developers
//
// 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 byteorder::{LE, ReadBytesExt};

use Error;

use std::{fmt, io};

/// Represents a Glb loader error.
#[derive(Debug)]
pub enum GlbError {
    /// Io error occured.
    IoError(::std::io::Error),
    /// Unsupported version.
    Version(u32),
    /// Magic says that file is not glTF.
    Magic([u8; 4]),
    /// Length specified in GLB header exceeeds that of slice.
    Length {
        /// length specified in GLB header.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Stream ended before we could read the chunk.
    ChunkLength {
        /// chunkType error happened at.
        ty: ChunkType,
        /// chunkLength.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Chunk of this chunkType was not expected.
    ChunkType(ChunkType),
    /// Unknown chunk type.
    UnknownChunkType([u8; 4]),
}

/// The contents of a .glb file.
#[derive(Clone, Debug)]
pub struct Glb<'a> {
    /// The header section of the `.glb` file.
    pub header: Header,
    /// The JSON section of the `.glb` file.
    pub json: &'a [u8],
    /// The optional BIN section of the `.glb` file.
    pub bin: Option<&'a [u8]>,
}

/// The header section of a .glb file.
#[derive(Copy, Clone, Debug)]
pub struct Header {
    /// Must be `b"glTF"`.
    pub magic: [u8; 4],
    /// Must be `2`.
    pub version: u32,
    /// Must match the length of the parent .glb file.
    pub length: u32,
}

/// GLB chunk type.
#[derive(Copy, Clone, Debug)]
pub enum ChunkType {
    /// JSON chunk.
    Json,
    /// BIN\0 chunk.
    Bin,
}

/// Chunk header with no data read yet.
#[derive(Copy, Clone, Debug)]
struct ChunkHeader {
    /// The length of the chunk data in byte excluding the header.
    length: u32,
    /// Chunk type.
    ty: ChunkType,
}

impl Header {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, GlbError> {
        use self::GlbError::IoError;
        let mut magic = [0; 4];
        reader.read_exact(&mut magic).map_err(IoError)?;
        // We only validate magic as we don't care for version and length of
        // contents, the caller does.  Let them decide what to do next with
        // regard to version and length.
        if &magic == b"glTF" {
            Ok(Self {
                magic,
                version: reader.read_u32::<LE>().map_err(IoError)?,
                length: reader.read_u32::<LE>().map_err(IoError)?,
            })
        } else {
            Err(GlbError::Magic(magic))
        }
    }
}

impl ChunkHeader {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, GlbError> {
        use self::GlbError::IoError;
        let length = reader.read_u32::<LE>().map_err(IoError)?;
        let mut ty = [0; 4];
        reader.read_exact(&mut ty).map_err(IoError)?;
        let ty = match &ty {
            b"JSON" => Ok(ChunkType::Json),
            b"BIN\0" => Ok(ChunkType::Bin),
            _ => Err(GlbError::UnknownChunkType(ty)),
        }?;
        Ok(Self { length, ty })
    }
}

impl<'a> Glb<'a> {
    /// Splits loaded GLB into its three chunks.
    ///
    /// * Mandatory GLB header.
    /// * Mandatory JSON chunk.
    /// * Optional BIN chunk.
    pub fn from_slice(mut data: &'a [u8]) -> Result<Self, Error> {
        let header = Header::from_reader(&mut data)
            .and_then(|header| if header.length as usize <= data.len() {
                Ok(header)
            } else {
                Err(GlbError::Length {
                    length: header.length,
                    length_read: data.len(),
                })
            })
            .map_err(Error::Glb)?;
        match header.version {
            2 => Self::from_v2(data)
                .map(|(json, bin)| Glb { header, json, bin })
                .map_err(Error::Glb),
            x => Err(Error::Glb(GlbError::Version(x)))
        }
    }

    /// Does the loading job for you.  Provided buf will be cleared before new
    /// data will be written.  When error happens, if only header was read, buf
    /// will not be mutated, otherwise, buf will be empty.
    pub fn from_reader<R: io::Read>(mut reader: R,
                                    buf: &'a mut Vec<u8>) -> Result<Self, Error> {
        let header = Header::from_reader(&mut reader).map_err(Error::Glb)?;
        match header.version {
            2 => {
                buf.clear();
                buf.reserve(header.length as usize);
                // SAFETY: We are doing unsafe operation on a user-supplied
                // container!  Make sure not to expose user to uninitialized
                // data if an error happens during reading.
                //
                // It is guaranteed by reserve's implementation that the reserve
                // call will make buf's capacity _at least_ header.length.
                //
                // We do not read contents of the Vec unless it is fully
                // initialized.
                unsafe { buf.set_len(header.length as usize) };
                if let Err(e) = reader.read(buf)
                    .map_err(GlbError::IoError)
                    .and_then(|len| if len == header.length as usize {
                        Ok(())
                    } else {
                        Err(GlbError::Length {
                            length: header.length,
                            length_read: len,
                        })
                    })
                {
                    // SAFETY: It is safe to not run destructors because u8 has
                    // none.
                    unsafe { buf.set_len(0) };
                    Err(Error::Glb(e))
                } else {
                    Self::from_v2(buf)
                       .map(|(json, bin)| Glb { header, json, bin })
                       .map_err(Error::Glb)
                }
            }
            x => Err(Error::Glb(GlbError::Version(x)))
        }
    }

    /// Loads GLB for glTF 2.
    fn from_v2(mut data: &'a [u8]) -> Result<(&'a [u8], Option<&'a [u8]>), GlbError> {
        let (json, mut data) = ChunkHeader::from_reader(&mut data)
            .and_then(|json_h| if let ChunkType::Json = json_h.ty {
                Ok(json_h)
            } else {
                Err(GlbError::ChunkType(json_h.ty))
            })
            .and_then(|json_h| if json_h.length as usize <= data.len() {
                Ok(json_h)
            } else {
                Err(GlbError::ChunkLength {
                    ty: json_h.ty,
                    length: json_h.length,
                    length_read: data.len(),
                })
            })
            // PANIC: We have verified that json_h.length is no greater than
            // that of data.len().
            .map(|json_h| data.split_at(json_h.length as usize))?;

        let bin = if data.len() > 0 {
            ChunkHeader::from_reader(&mut data)
                .and_then(|bin_h| if let ChunkType::Bin = bin_h.ty {
                    Ok(bin_h)
                } else {
                    Err(GlbError::ChunkType(bin_h.ty))
                })
                .and_then(|bin_h| if bin_h.length as usize <= data.len() {
                    Ok(bin_h)
                } else {
                    Err(GlbError::ChunkLength {
                        ty: bin_h.ty,
                        length: bin_h.length,
                        length_read: data.len(),
                    })
                })
                // PANIC: we have verified that bin_h.length is no greater than
                // that of data.len().
                .map(|bin_h| data.split_at(bin_h.length as usize))
                .map(|(x, _)| Some(x))?
        } else {
            None
        };
        Ok((json, bin))
    }
}

impl fmt::Display for GlbError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl ::std::error::Error for GlbError {
    fn description(&self) -> &str {
         match *self {
             GlbError::IoError(ref e) => e.description(),
             GlbError::Version(_) => "unsupported version",
             GlbError::Magic(_) => "not glTF magic",
             GlbError::Length { .. } => "could not completely read the object",
             GlbError::ChunkLength { ty, .. } => match ty {
                 ChunkType::Json => "JSON chunk length exceeds that of slice",
                 ChunkType::Bin => "BIN\\0 chunk length exceeds that of slice",
                 _ => "chunk length exceeds that of slice",
             },
             GlbError::ChunkType(ty) => match ty {
                 ChunkType::Json => "was not expecting JSON chunk",
                 ChunkType::Bin => "was not expecting BIN\\0 chunk",
                 _ => "was not expecting a chunk",
             },
             GlbError::UnknownChunkType(ty) => "unknown chunk type",
        }
    }
}
<commit_msg>Remove dead code<commit_after>
// Copyright 2017 The gltf Library Developers
//
// 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 byteorder::{LE, ReadBytesExt};

use Error;

use std::{fmt, io};

/// Represents a Glb loader error.
#[derive(Debug)]
pub enum GlbError {
    /// Io error occured.
    IoError(::std::io::Error),
    /// Unsupported version.
    Version(u32),
    /// Magic says that file is not glTF.
    Magic([u8; 4]),
    /// Length specified in GLB header exceeeds that of slice.
    Length {
        /// length specified in GLB header.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Stream ended before we could read the chunk.
    ChunkLength {
        /// chunkType error happened at.
        ty: ChunkType,
        /// chunkLength.
        length: u32,
        /// Actual length of data read.
        length_read: usize,
    },
    /// Chunk of this chunkType was not expected.
    ChunkType(ChunkType),
    /// Unknown chunk type.
    UnknownChunkType([u8; 4]),
}

/// The contents of a .glb file.
#[derive(Clone, Debug)]
pub struct Glb<'a> {
    /// The header section of the `.glb` file.
    pub header: Header,
    /// The JSON section of the `.glb` file.
    pub json: &'a [u8],
    /// The optional BIN section of the `.glb` file.
    pub bin: Option<&'a [u8]>,
}

/// The header section of a .glb file.
#[derive(Copy, Clone, Debug)]
pub struct Header {
    /// Must be `b"glTF"`.
    pub magic: [u8; 4],
    /// Must be `2`.
    pub version: u32,
    /// Must match the length of the parent .glb file.
    pub length: u32,
}

/// GLB chunk type.
#[derive(Copy, Clone, Debug)]
pub enum ChunkType {
    /// JSON chunk.
    Json,
    /// BIN\0 chunk.
    Bin,
}

/// Chunk header with no data read yet.
#[derive(Copy, Clone, Debug)]
struct ChunkHeader {
    /// The length of the chunk data in byte excluding the header.
    length: u32,
    /// Chunk type.
    ty: ChunkType,
}

impl Header {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, GlbError> {
        use self::GlbError::IoError;
        let mut magic = [0; 4];
        reader.read_exact(&mut magic).map_err(IoError)?;
        // We only validate magic as we don't care for version and length of
        // contents, the caller does.  Let them decide what to do next with
        // regard to version and length.
        if &magic == b"glTF" {
            Ok(Self {
                magic,
                version: reader.read_u32::<LE>().map_err(IoError)?,
                length: reader.read_u32::<LE>().map_err(IoError)?,
            })
        } else {
            Err(GlbError::Magic(magic))
        }
    }
}

impl ChunkHeader {
    fn from_reader<R: io::Read>(mut reader: R) -> Result<Self, GlbError> {
        use self::GlbError::IoError;
        let length = reader.read_u32::<LE>().map_err(IoError)?;
        let mut ty = [0; 4];
        reader.read_exact(&mut ty).map_err(IoError)?;
        let ty = match &ty {
            b"JSON" => Ok(ChunkType::Json),
            b"BIN\0" => Ok(ChunkType::Bin),
            _ => Err(GlbError::UnknownChunkType(ty)),
        }?;
        Ok(Self { length, ty })
    }
}

impl<'a> Glb<'a> {
    /// Splits loaded GLB into its three chunks.
    ///
    /// * Mandatory GLB header.
    /// * Mandatory JSON chunk.
    /// * Optional BIN chunk.
    pub fn from_slice(mut data: &'a [u8]) -> Result<Self, Error> {
        let header = Header::from_reader(&mut data)
            .and_then(|header| if header.length as usize <= data.len() {
                Ok(header)
            } else {
                Err(GlbError::Length {
                    length: header.length,
                    length_read: data.len(),
                })
            })
            .map_err(Error::Glb)?;
        match header.version {
            2 => Self::from_v2(data)
                .map(|(json, bin)| Glb { header, json, bin })
                .map_err(Error::Glb),
            x => Err(Error::Glb(GlbError::Version(x)))
        }
    }

    /// Does the loading job for you.  Provided buf will be cleared before new
    /// data will be written.  When error happens, if only header was read, buf
    /// will not be mutated, otherwise, buf will be empty.
    pub fn from_reader<R: io::Read>(mut reader: R,
                                    buf: &'a mut Vec<u8>) -> Result<Self, Error> {
        let header = Header::from_reader(&mut reader).map_err(Error::Glb)?;
        match header.version {
            2 => {
                buf.clear();
                buf.reserve(header.length as usize);
                // SAFETY: We are doing unsafe operation on a user-supplied
                // container!  Make sure not to expose user to uninitialized
                // data if an error happens during reading.
                //
                // It is guaranteed by reserve's implementation that the reserve
                // call will make buf's capacity _at least_ header.length.
                //
                // We do not read contents of the Vec unless it is fully
                // initialized.
                unsafe { buf.set_len(header.length as usize) };
                if let Err(e) = reader.read(buf)
                    .map_err(GlbError::IoError)
                    .and_then(|len| if len == header.length as usize {
                        Ok(())
                    } else {
                        Err(GlbError::Length {
                            length: header.length,
                            length_read: len,
                        })
                    })
                {
                    // SAFETY: It is safe to not run destructors because u8 has
                    // none.
                    unsafe { buf.set_len(0) };
                    Err(Error::Glb(e))
                } else {
                    Self::from_v2(buf)
                       .map(|(json, bin)| Glb { header, json, bin })
                       .map_err(Error::Glb)
                }
            }
            x => Err(Error::Glb(GlbError::Version(x)))
        }
    }

    /// Loads GLB for glTF 2.
    fn from_v2(mut data: &'a [u8]) -> Result<(&'a [u8], Option<&'a [u8]>), GlbError> {
        let (json, mut data) = ChunkHeader::from_reader(&mut data)
            .and_then(|json_h| if let ChunkType::Json = json_h.ty {
                Ok(json_h)
            } else {
                Err(GlbError::ChunkType(json_h.ty))
            })
            .and_then(|json_h| if json_h.length as usize <= data.len() {
                Ok(json_h)
            } else {
                Err(GlbError::ChunkLength {
                    ty: json_h.ty,
                    length: json_h.length,
                    length_read: data.len(),
                })
            })
            // PANIC: We have verified that json_h.length is no greater than
            // that of data.len().
            .map(|json_h| data.split_at(json_h.length as usize))?;

        let bin = if data.len() > 0 {
            ChunkHeader::from_reader(&mut data)
                .and_then(|bin_h| if let ChunkType::Bin = bin_h.ty {
                    Ok(bin_h)
                } else {
                    Err(GlbError::ChunkType(bin_h.ty))
                })
                .and_then(|bin_h| if bin_h.length as usize <= data.len() {
                    Ok(bin_h)
                } else {
                    Err(GlbError::ChunkLength {
                        ty: bin_h.ty,
                        length: bin_h.length,
                        length_read: data.len(),
                    })
                })
                // PANIC: we have verified that bin_h.length is no greater than
                // that of data.len().
                .map(|bin_h| data.split_at(bin_h.length as usize))
                .map(|(x, _)| Some(x))?
        } else {
            None
        };
        Ok((json, bin))
    }
}

impl fmt::Display for GlbError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl ::std::error::Error for GlbError {
    fn description(&self) -> &str {
         match *self {
             GlbError::IoError(ref e) => e.description(),
             GlbError::Version(_) => "unsupported version",
             GlbError::Magic(_) => "not glTF magic",
             GlbError::Length { .. } => "could not completely read the object",
             GlbError::ChunkLength { ty, .. } => match ty {
                 ChunkType::Json => "JSON chunk length exceeds that of slice",
                 ChunkType::Bin => "BIN\\0 chunk length exceeds that of slice",
             },
             GlbError::ChunkType(ty) => match ty {
                 ChunkType::Json => "was not expecting JSON chunk",
                 ChunkType::Bin => "was not expecting BIN\\0 chunk",
             },
             GlbError::UnknownChunkType(_) => "unknown chunk type",
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

#![feature(globs)]

#![crate_name="capnpc"]
#![crate_type = "lib"]

extern crate capnp;

pub mod schema_capnp;
pub mod codegen;

<commit_msg>fill in lib.rs<commit_after>/*
 * Copyright (c) 2013-2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

#![feature(globs)]

#![crate_name="capnpc"]
#![crate_type = "lib"]

extern crate capnp;

pub mod schema_capnp;
pub mod codegen;

pub fn compile(prefix : Path, files : &[Path]) {

    let out_dir = ::std::os::getenv("OUT_DIR").unwrap();

    let mut command = ::std::io::Command::new("capnp");
    command
        .arg("compile")
        .arg(format!("-o/bin/cat:{}", out_dir))
        .arg(format!("--src-prefix={}", prefix.display()));

    for file in files.iter() {
        command.arg(format!("{}", prefix.join(file).display()));
    }

    command.stdout(::std::io::process::CreatePipe(false, true));

    match command.spawn() {
        Ok(ref mut p) =>  {
            let mut child_stdout = p.stdout.take().unwrap();
            ::codegen::main(&mut child_stdout).unwrap();
        }
        Err(e) => {
            println!("could not start process: {}", e);
        }
    }

}

<|endoftext|>


<commit_before>#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]

extern crate libc;

use libc::{c_char, c_int, c_uchar, c_void};
use libc::size_t;

macro_rules! opaque {
    ($name:ident) => {
        #[repr(C)]
        pub struct $name {
            _private: [u8; 0]
        }
    };
}

// These are opaque types that LevelDB uses.
opaque!(leveldb_t);
opaque!(leveldb_cache_t);
opaque!(leveldb_comparator_t);
opaque!(leveldb_env_t);
opaque!(leveldb_filelock_t);
opaque!(leveldb_filterpolicy_t);
opaque!(leveldb_iterator_t);
opaque!(leveldb_logger_t);
opaque!(leveldb_options_t);
opaque!(leveldb_randomfile_t);
opaque!(leveldb_readoptions_t);
opaque!(leveldb_seqfile_t);
opaque!(leveldb_snapshot_t);
opaque!(leveldb_writablefile_t);
opaque!(leveldb_writebatch_t);
opaque!(leveldb_writeoptions_t);

#[repr(C)]
#[derive(Copy,Clone)]
pub enum Compression {
  No = 0,
  Snappy = 1
}

extern "C" {
    // DB operations
    pub fn leveldb_open(options: *const leveldb_options_t, name: *const c_char, errptr: *mut *mut c_char) -> *mut leveldb_t;
    pub fn leveldb_close(db: *mut leveldb_t);
    pub fn leveldb_put(db: *mut leveldb_t, options: *const leveldb_writeoptions_t, key: *const c_char, keylen: size_t, val: *const c_char, vallen: size_t, errptr: *mut *mut c_char);
    pub fn leveldb_delete(db: *mut leveldb_t, options: *const leveldb_writeoptions_t, key: *const c_char, keylen: size_t, errptr: *mut *mut c_char);
    pub fn leveldb_write(db: *mut leveldb_t, options: *const leveldb_writeoptions_t, batch: *mut leveldb_writebatch_t, errptr: *mut *mut c_char);
    pub fn leveldb_get(db: *mut leveldb_t, options: *const leveldb_readoptions_t, key: *const c_char, keylen: size_t, vallen: *mut size_t, errptr: *mut *mut c_char) -> *mut c_char;
    pub fn leveldb_create_iterator(db: *mut leveldb_t, options: *const leveldb_readoptions_t) -> *mut leveldb_iterator_t;
    pub fn leveldb_create_snapshot(db: *mut leveldb_t) -> *mut leveldb_snapshot_t;
    pub fn leveldb_release_snapshot(db: *mut leveldb_t, snapshot: *const leveldb_snapshot_t);
    pub fn leveldb_property_value(db: *mut leveldb_t, propname: *const c_char) -> *mut c_char;

    // TODO: const'ness of pointers here is in question
    pub fn leveldb_approximate_sizes(db: *mut leveldb_t, num_ranges: c_int, range_start_key: *const *const c_char, range_start_key_len: *const size_t, range_limit_key: *const *const c_char, range_limit_key_len: *const size_t, sizes: *mut u64);
    pub fn leveldb_compact_range(db: *mut leveldb_t, start_key: *const c_char, start_key_len: size_t, limit_key: *const c_char, limit_key_len: size_t);

    // Management operations
    pub fn leveldb_destroy_db(options: *const leveldb_options_t, name: *const c_char, errptr: *mut *mut c_char);
    pub fn leveldb_repair_db(options: *const leveldb_options_t, name: *const c_char, errptr: *mut *mut c_char);

    // Iterator
    pub fn leveldb_iter_destroy(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_valid(it: *const leveldb_iterator_t) -> c_uchar;
    pub fn leveldb_iter_seek_to_first(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_seek_to_last(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_seek(it: *mut leveldb_iterator_t, k: *const c_char, klen: size_t);
    pub fn leveldb_iter_next(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_prev(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_key(it: *const leveldb_iterator_t, klen: *const size_t) -> *const c_char;
    pub fn leveldb_iter_value(it: *const leveldb_iterator_t, vlen: *const size_t) -> *const c_char;
    pub fn leveldb_iter_get_error(it: *const leveldb_iterator_t, errptr: *const *const c_char);

    // Write batch
    pub fn leveldb_writebatch_create() -> *mut leveldb_writebatch_t;
    pub fn leveldb_writebatch_destroy(b: *mut leveldb_writebatch_t);
    pub fn leveldb_writebatch_clear(b: *mut leveldb_writebatch_t);
    pub fn leveldb_writebatch_put(b: *mut leveldb_writebatch_t, key: *const c_char, keylen: size_t, val: *const c_char, vallen: size_t);
    pub fn leveldb_writebatch_delete(b: *mut leveldb_writebatch_t, key: *const c_char, keylen: size_t);
    pub fn leveldb_writebatch_iterate(
        b: *mut leveldb_writebatch_t,
        state: *mut c_void,
        put: extern fn(*mut c_void, *const c_char, size_t, *const c_char, size_t),
        deleted: extern fn(*mut c_void, *const c_char, size_t)
    );

    // Options
    pub fn leveldb_options_create() -> *mut leveldb_options_t;
    pub fn leveldb_options_destroy(o: *mut leveldb_options_t);
    pub fn leveldb_options_set_comparator(o: *mut leveldb_options_t, c: *mut leveldb_comparator_t);
    pub fn leveldb_options_set_filter_policy(o: *mut leveldb_options_t, c: *mut leveldb_filterpolicy_t);
    pub fn leveldb_options_set_create_if_missing(o: *mut leveldb_options_t, val: c_uchar);
    pub fn leveldb_options_set_error_if_exists(o: *mut leveldb_options_t, val: c_uchar);
    pub fn leveldb_options_set_paranoid_checks(o: *mut leveldb_options_t, val: c_uchar);
    pub fn leveldb_options_set_env(o: *mut leveldb_options_t, env: *mut leveldb_env_t);
    pub fn leveldb_options_set_info_log(o: *mut leveldb_options_t, logger: *mut leveldb_logger_t);
    pub fn leveldb_options_set_write_buffer_size(o: *mut leveldb_options_t, size: size_t);
    pub fn leveldb_options_set_max_open_files(o: *mut leveldb_options_t, num: c_int);
    pub fn leveldb_options_set_cache(o: *mut leveldb_options_t, cache: *mut leveldb_cache_t);
    pub fn leveldb_options_set_block_size(o: *mut leveldb_options_t, size: size_t);
    pub fn leveldb_options_set_block_restart_interval(o: *mut leveldb_options_t, interval: c_int);
    pub fn leveldb_options_set_compression(o: *mut leveldb_options_t, val: Compression);

    // Comparator
    pub fn leveldb_comparator_create(
        state: *mut c_void,
        destructor: extern fn(*mut c_void),
        compare: extern fn(*mut c_void, *const c_char, size_t, *const c_char, size_t) -> c_int,
        name: extern fn(*mut c_void) -> *const c_char
    ) -> *mut leveldb_comparator_t;
    pub fn leveldb_comparator_destroy(c: *mut leveldb_comparator_t);

    // Filter policy
    //pub leveldb_filterpolicy_create(state: *mut c_void, /* TODO */) -> *mut leveldb_filterpolicy_t;
    /*
        extern leveldb_filterpolicy_t* leveldb_filterpolicy_create(
            void* state,
            void (*destructor)(void*),
            char* (*create_filter)(
                void*,
                const char* const* key_array, const size_t* key_length_array,
                int num_keys,
                size_t* filter_length),
            unsigned char (*key_may_match)(
                void*,
                const char* key, size_t length,
                const char* filter, size_t filter_length),
            const char* (*name)(void*));
    */
    pub fn leveldb_filterpolicy_destroy(p: *mut leveldb_filterpolicy_t);
    pub fn leveldb_filterpolicy_create_bloom(bits_per_key: c_int) -> *mut leveldb_filterpolicy_t;

    // Read options
    pub fn leveldb_readoptions_create() -> *mut leveldb_readoptions_t;
    pub fn leveldb_readoptions_destroy(o: *mut leveldb_readoptions_t);
    pub fn leveldb_readoptions_set_verify_checksums(o: *mut leveldb_readoptions_t, val: c_uchar);
    pub fn leveldb_readoptions_set_fill_cache(o: *mut leveldb_readoptions_t, val: c_uchar);
    pub fn leveldb_readoptions_set_snapshot(o: *mut leveldb_readoptions_t, snapshot: *const leveldb_snapshot_t);

    // Write options
    pub fn leveldb_writeoptions_create() -> *mut leveldb_writeoptions_t;
    pub fn leveldb_writeoptions_destroy(o: *mut leveldb_writeoptions_t);
    pub fn leveldb_writeoptions_set_sync(o: *mut leveldb_writeoptions_t, val: c_uchar);

    // Cache
    pub fn leveldb_cache_create_lru(capacity: size_t) -> *mut leveldb_cache_t;
    pub fn leveldb_cache_destroy(c: *mut leveldb_cache_t);

    // Env
    pub fn leveldb_create_default_env() -> *mut leveldb_env_t;
    pub fn leveldb_env_destroy(e: *mut leveldb_env_t);

    // Utility
    pub fn leveldb_free(ptr: *mut c_void);

    // Versioning
    pub fn leveldb_major_version() -> c_int;
    pub fn leveldb_minor_version() -> c_int;
}
<commit_msg>add docs for leveldb_options_set_create_if_missing()<commit_after>#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]

extern crate libc;

use libc::{c_char, c_int, c_uchar, c_void};
use libc::size_t;

macro_rules! opaque {
    ($name:ident) => {
        #[repr(C)]
        pub struct $name {
            _private: [u8; 0]
        }
    };
}

// These are opaque types that LevelDB uses.
opaque!(leveldb_t);
opaque!(leveldb_cache_t);
opaque!(leveldb_comparator_t);
opaque!(leveldb_env_t);
opaque!(leveldb_filelock_t);
opaque!(leveldb_filterpolicy_t);
opaque!(leveldb_iterator_t);
opaque!(leveldb_logger_t);
opaque!(leveldb_options_t);
opaque!(leveldb_randomfile_t);
opaque!(leveldb_readoptions_t);
opaque!(leveldb_seqfile_t);
opaque!(leveldb_snapshot_t);
opaque!(leveldb_writablefile_t);
opaque!(leveldb_writebatch_t);
opaque!(leveldb_writeoptions_t);

#[repr(C)]
#[derive(Copy,Clone)]
pub enum Compression {
  No = 0,
  Snappy = 1
}

extern "C" {
    // DB operations
    pub fn leveldb_open(options: *const leveldb_options_t, name: *const c_char, errptr: *mut *mut c_char) -> *mut leveldb_t;
    pub fn leveldb_close(db: *mut leveldb_t);
    pub fn leveldb_put(db: *mut leveldb_t, options: *const leveldb_writeoptions_t, key: *const c_char, keylen: size_t, val: *const c_char, vallen: size_t, errptr: *mut *mut c_char);
    pub fn leveldb_delete(db: *mut leveldb_t, options: *const leveldb_writeoptions_t, key: *const c_char, keylen: size_t, errptr: *mut *mut c_char);
    pub fn leveldb_write(db: *mut leveldb_t, options: *const leveldb_writeoptions_t, batch: *mut leveldb_writebatch_t, errptr: *mut *mut c_char);
    pub fn leveldb_get(db: *mut leveldb_t, options: *const leveldb_readoptions_t, key: *const c_char, keylen: size_t, vallen: *mut size_t, errptr: *mut *mut c_char) -> *mut c_char;
    pub fn leveldb_create_iterator(db: *mut leveldb_t, options: *const leveldb_readoptions_t) -> *mut leveldb_iterator_t;
    pub fn leveldb_create_snapshot(db: *mut leveldb_t) -> *mut leveldb_snapshot_t;
    pub fn leveldb_release_snapshot(db: *mut leveldb_t, snapshot: *const leveldb_snapshot_t);
    pub fn leveldb_property_value(db: *mut leveldb_t, propname: *const c_char) -> *mut c_char;

    // TODO: const'ness of pointers here is in question
    pub fn leveldb_approximate_sizes(db: *mut leveldb_t, num_ranges: c_int, range_start_key: *const *const c_char, range_start_key_len: *const size_t, range_limit_key: *const *const c_char, range_limit_key_len: *const size_t, sizes: *mut u64);
    pub fn leveldb_compact_range(db: *mut leveldb_t, start_key: *const c_char, start_key_len: size_t, limit_key: *const c_char, limit_key_len: size_t);

    // Management operations
    pub fn leveldb_destroy_db(options: *const leveldb_options_t, name: *const c_char, errptr: *mut *mut c_char);
    pub fn leveldb_repair_db(options: *const leveldb_options_t, name: *const c_char, errptr: *mut *mut c_char);

    // Iterator
    pub fn leveldb_iter_destroy(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_valid(it: *const leveldb_iterator_t) -> c_uchar;
    pub fn leveldb_iter_seek_to_first(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_seek_to_last(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_seek(it: *mut leveldb_iterator_t, k: *const c_char, klen: size_t);
    pub fn leveldb_iter_next(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_prev(it: *mut leveldb_iterator_t);
    pub fn leveldb_iter_key(it: *const leveldb_iterator_t, klen: *const size_t) -> *const c_char;
    pub fn leveldb_iter_value(it: *const leveldb_iterator_t, vlen: *const size_t) -> *const c_char;
    pub fn leveldb_iter_get_error(it: *const leveldb_iterator_t, errptr: *const *const c_char);

    // Write batch
    pub fn leveldb_writebatch_create() -> *mut leveldb_writebatch_t;
    pub fn leveldb_writebatch_destroy(b: *mut leveldb_writebatch_t);
    pub fn leveldb_writebatch_clear(b: *mut leveldb_writebatch_t);
    pub fn leveldb_writebatch_put(b: *mut leveldb_writebatch_t, key: *const c_char, keylen: size_t, val: *const c_char, vallen: size_t);
    pub fn leveldb_writebatch_delete(b: *mut leveldb_writebatch_t, key: *const c_char, keylen: size_t);
    pub fn leveldb_writebatch_iterate(
        b: *mut leveldb_writebatch_t,
        state: *mut c_void,
        put: extern fn(*mut c_void, *const c_char, size_t, *const c_char, size_t),
        deleted: extern fn(*mut c_void, *const c_char, size_t)
    );

    // Options
    pub fn leveldb_options_create() -> *mut leveldb_options_t;
    pub fn leveldb_options_destroy(o: *mut leveldb_options_t);
    pub fn leveldb_options_set_comparator(o: *mut leveldb_options_t, c: *mut leveldb_comparator_t);
    pub fn leveldb_options_set_filter_policy(o: *mut leveldb_options_t, c: *mut leveldb_filterpolicy_t);
    ///  Modify `o` to specify whether a new database should be created if none exists yet
    ///
    /// - If `val` is != 0, new database creation is enabled
    /// - If `val` is 0,    no new database will be created if none exists yet
    pub fn leveldb_options_set_create_if_missing(o: *mut leveldb_options_t, val: c_uchar);
    pub fn leveldb_options_set_error_if_exists(o: *mut leveldb_options_t, val: c_uchar);
    pub fn leveldb_options_set_paranoid_checks(o: *mut leveldb_options_t, val: c_uchar);
    pub fn leveldb_options_set_env(o: *mut leveldb_options_t, env: *mut leveldb_env_t);
    pub fn leveldb_options_set_info_log(o: *mut leveldb_options_t, logger: *mut leveldb_logger_t);
    pub fn leveldb_options_set_write_buffer_size(o: *mut leveldb_options_t, size: size_t);
    pub fn leveldb_options_set_max_open_files(o: *mut leveldb_options_t, num: c_int);
    pub fn leveldb_options_set_cache(o: *mut leveldb_options_t, cache: *mut leveldb_cache_t);
    pub fn leveldb_options_set_block_size(o: *mut leveldb_options_t, size: size_t);
    pub fn leveldb_options_set_block_restart_interval(o: *mut leveldb_options_t, interval: c_int);
    pub fn leveldb_options_set_compression(o: *mut leveldb_options_t, val: Compression);

    // Comparator
    pub fn leveldb_comparator_create(
        state: *mut c_void,
        destructor: extern fn(*mut c_void),
        compare: extern fn(*mut c_void, *const c_char, size_t, *const c_char, size_t) -> c_int,
        name: extern fn(*mut c_void) -> *const c_char
    ) -> *mut leveldb_comparator_t;
    pub fn leveldb_comparator_destroy(c: *mut leveldb_comparator_t);

    // Filter policy
    //pub leveldb_filterpolicy_create(state: *mut c_void, /* TODO */) -> *mut leveldb_filterpolicy_t;
    /*
        extern leveldb_filterpolicy_t* leveldb_filterpolicy_create(
            void* state,
            void (*destructor)(void*),
            char* (*create_filter)(
                void*,
                const char* const* key_array, const size_t* key_length_array,
                int num_keys,
                size_t* filter_length),
            unsigned char (*key_may_match)(
                void*,
                const char* key, size_t length,
                const char* filter, size_t filter_length),
            const char* (*name)(void*));
    */
    pub fn leveldb_filterpolicy_destroy(p: *mut leveldb_filterpolicy_t);
    pub fn leveldb_filterpolicy_create_bloom(bits_per_key: c_int) -> *mut leveldb_filterpolicy_t;

    // Read options
    pub fn leveldb_readoptions_create() -> *mut leveldb_readoptions_t;
    pub fn leveldb_readoptions_destroy(o: *mut leveldb_readoptions_t);
    pub fn leveldb_readoptions_set_verify_checksums(o: *mut leveldb_readoptions_t, val: c_uchar);
    pub fn leveldb_readoptions_set_fill_cache(o: *mut leveldb_readoptions_t, val: c_uchar);
    pub fn leveldb_readoptions_set_snapshot(o: *mut leveldb_readoptions_t, snapshot: *const leveldb_snapshot_t);

    // Write options
    pub fn leveldb_writeoptions_create() -> *mut leveldb_writeoptions_t;
    pub fn leveldb_writeoptions_destroy(o: *mut leveldb_writeoptions_t);
    pub fn leveldb_writeoptions_set_sync(o: *mut leveldb_writeoptions_t, val: c_uchar);

    // Cache
    pub fn leveldb_cache_create_lru(capacity: size_t) -> *mut leveldb_cache_t;
    pub fn leveldb_cache_destroy(c: *mut leveldb_cache_t);

    // Env
    pub fn leveldb_create_default_env() -> *mut leveldb_env_t;
    pub fn leveldb_env_destroy(e: *mut leveldb_env_t);

    // Utility
    pub fn leveldb_free(ptr: *mut c_void);

    // Versioning
    pub fn leveldb_major_version() -> c_int;
    pub fn leveldb_minor_version() -> c_int;
}
<|endoftext|>