<commit_before>extern crate breakpad_symbols;
extern crate disasm;
extern crate env_logger;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate log;
extern crate minidump;
extern crate minidump_common;
extern crate reqwest;
#[allow(unused_imports)]
#[macro_use]
extern crate structopt;

use breakpad_symbols::{HttpSymbolSupplier, SimpleFrame, Symbolizer};
use disasm::{Color, CpuArch, SourceLocation, SourceLookup};
use failure::Error;
use minidump::system_info::Cpu;
use minidump::{
    Minidump, MinidumpException, MinidumpMemoryList, MinidumpModule, MinidumpModuleList,
    MinidumpSystemInfo,
};
use minidump_common::traits::Module;
use reqwest::blocking::Client;
use std::env;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(StructOpt)]
#[structopt(
    name = "get-minidump-instructions",
    about = "Display instructions from a minidump"
)]
struct GetMinidumpInstructions {
    #[structopt(long = "color", help = "Enable colored output")]
    color: Option<Color>,
    #[structopt(help = "Input minidump", parse(from_os_str))]
    minidump: PathBuf,
    #[structopt(help = "Symbol paths", parse(from_os_str))]
    symbol_paths: Vec<PathBuf>,
}

#[derive(StructOpt)]
#[structopt(
    name = "dumpstack",
    about = "Display possible stack frames from a minidump"
)]
struct DumpStack {
    #[structopt(help = "Input minidump", parse(from_os_str))]
    minidump: PathBuf,
    #[structopt(help = "Symbol paths", parse(from_os_str))]
    symbol_paths: Vec<PathBuf>,
    #[structopt(
        short = "a",
        help = "Show stack addresses that don't resolve to functions"
    )]
    all: bool,
}

struct SymLookup {
    modules: MinidumpModuleList,
    symbolizer: Symbolizer,
    client: Client,
}

struct HgWebFile {
    host: String,
    repo: String,
    rev: String,
    path: String,
}

struct GitHubFile {
    repo: String,
    rev: String,
    path: String,
}

trait VCSFile {
    fn raw_url(&self) -> String;
    fn annotate_url(&self, line: u64) -> String;
    fn as_local_filename(&self) -> String;
}

impl VCSFile for HgWebFile {
    fn raw_url(&self) -> String {
        format!(
            "https://{}/{}/raw-file/{}/{}",
            self.host, self.repo, self.rev, self.path
        )
    }

    fn annotate_url(&self, line: u64) -> String {
        format!(
            "https://{}/{}/annotate/{}/{}#l{}",
            self.host, self.repo, self.rev, self.path, line
        )
    }
    fn as_local_filename(&self) -> String {
        format!("{}_{}_{}", self.host, self.rev, self.path).replace('/', "_")
    }
}

impl VCSFile for GitHubFile {
    fn raw_url(&self) -> String {
        format!(
            "http://raw.githubusercontent.com/{}/{}/{}",
            self.repo, self.rev, self.path
        )
    }
    fn annotate_url(&self, line: u64) -> String {
        format!(
            "https://github.com/{}/blob/{}/{}#L{}",
            self.repo, self.rev, self.path, line
        )
    }
    fn as_local_filename(&self) -> String {
        format!("{}_{}_{}", self.repo, self.rev, self.path).replace('/', "_")
    }
}

fn file_exists(path: &Path) -> bool {
    fs::metadata(path).is_ok()
}

fn fetch_url_to_path(client: &Client, url: &str, path: &Path) -> Result<(), Error> {
    debug!("fetch_url_to_path({}, {:?})", url, path);
    let mut res = client.get(url).send()?.error_for_status()?;
    debug!("fetch_url_to_path: HTTP success");
    let mut tmp_path = path.to_owned().into_os_string();
    tmp_path.push(".tmp");
    {
        let mut f = File::create(&tmp_path)?;
        res.copy_to(&mut f)?;
    }
    fs::rename(&tmp_path, &path)?;
    Ok(())
}

fn parse_vcs_info(filename: &str) -> Result<Box<dyn VCSFile>, Error> {
    let mut bits = filename.split(':');
    Ok(match (bits.next(), bits.next(), bits.next(), bits.next()) {
        (Some("hg"), Some(repo), Some(path), Some(rev)) if repo.starts_with("hg.mozilla.org/") => {
            let mut s = repo.splitn(2, '/');
            let host = s.next().unwrap().to_owned();
            let repo = s.next().unwrap().to_owned();
            let path = path.to_owned();
            let rev = rev.to_owned();
            Box::new(HgWebFile {
                host,
                repo,
                rev,
                path,
            })
        }
        (Some("git"), Some(repo), Some(path), Some(rev)) if repo.starts_with("github.com/") => {
            let repo = repo.splitn(2, '/').nth(1).unwrap().to_owned();
            let path = path.to_owned();
            let rev = rev.to_owned();
            Box::new(GitHubFile { repo, rev, path })
        }
        _ => return Err(format_err!("No VCS info in filename")),
    })
}

fn maybe_fetch_source_file(client: &Client, url: &str, path: &Path) -> Result<(), Error> {
    if file_exists(path) {
        Ok(())
    } else {
        fetch_url_to_path(client, url, path)
    }
}

impl SourceLookup for SymLookup {
    fn lookup(&mut self, address: u64) -> Option<SourceLocation> {
        self.modules.module_at_address(address).and_then(|module| {
            let mut frame = SimpleFrame::with_instruction(address);
            self.symbolizer.fill_symbol(module, &mut frame);
            let SimpleFrame {
                source_file,
                source_line,
                ..
            } = frame;
            if let (Some(file), Some(line)) = (source_file, source_line) {
                let line = line as u64;
                match parse_vcs_info(&file) {
                    Ok(info) => {
                        let url = info.raw_url();
                        let local = env::temp_dir().join(info.as_local_filename());
                        if maybe_fetch_source_file(&self.client, &url, &local).is_ok() {
                            return Some(SourceLocation {
                                file: local.to_string_lossy().into_owned(),
                                file_display: Some(info.annotate_url(line)),
                                line,
                            });
                        }
                    }
                    _ => {}
                }
                // If fetching the file doesn't work, just hand back the original filename.
                Some(SourceLocation {
                    file: file.into(),
                    file_display: None,
                    line,
                })
            } else {
                // We didn't find any source info.
                None
            }
        })
    }
}

fn handle_symbol_paths(symbol_paths: Vec<PathBuf>) -> Result<Symbolizer, Error> {
    let tmp_path = env::temp_dir().join("symbols");
    fs::create_dir_all(&tmp_path)?;
    let (symbol_paths, symbol_urls) = if symbol_paths.is_empty() {
        // Use the Mozilla symbol server if no symbol paths are supplied.
        let symbol_urls = vec!["https://symbols.mozilla.org/".to_owned()];
        (symbol_paths, symbol_urls)
    } else {
        let urls = symbol_paths
            .iter()
            .filter(|p| p.starts_with("http"))
            .filter_map(|p| p.to_str().map(str::to_owned))
            .collect();
        let paths = symbol_paths
            .into_iter()
            .filter(|p| !p.starts_with("http"))
            .collect();
        (paths, urls)
    };
    let supplier = HttpSymbolSupplier::new(symbol_urls, tmp_path, symbol_paths);
    Ok(Symbolizer::new(supplier))
}

pub fn get_minidump_instructions() -> Result<(), Error> {
    env_logger::init();
    let GetMinidumpInstructions {
        color,
        minidump,
        symbol_paths,
    } = GetMinidumpInstructions::from_args();
    let dump = Minidump::read_path(&minidump)?;
    let modules = dump.get_stream::<MinidumpModuleList>()?;
    let exception = dump.get_stream::<MinidumpException>()?;
    let context = exception
        .context
        .as_ref()
        .ok_or(format_err!("Missing exception context"))?;
    let ip = context.get_instruction_pointer();
    let memory_list = dump.get_stream::<MinidumpMemoryList>()?;
    let memory = memory_list.memory_at_address(ip)
        .ok_or(format_err!("Minidump doesn't contain a memory region that contains the instruction pointer from the exception record"))?;
    let sys_info = dump.get_stream::<MinidumpSystemInfo>()?;
    let arch = match sys_info.cpu {
        Cpu::X86 => CpuArch::X86,
        Cpu::X86_64 => CpuArch::X86_64,
        Cpu::Arm64 => CpuArch::ARM64,
        _ => {
            return Err(format_err!(
                "Unsupported CPU architecture: {}",
                sys_info.cpu
            ))
        }
    };
    let symbolizer = handle_symbol_paths(symbol_paths)?;
    let client = Client::new();
    let mut lookup = SymLookup {
        modules,
        symbolizer,
        client,
    };
    println!("Faulting instruction pointer: {:#x}", ip);
    info!(
        "Disassembling {} bytes starting at {:#x} of arch {:?}",
        memory.bytes.len(),
        memory.base_address,
        arch
    );
    disasm::disasm_bytes(
        &memory.bytes[ip as usize - memory.base_address as usize..],
        ip,
        arch,
        color.unwrap_or(Color::Auto),
        Some(ip),
        &mut lookup,
    )?;
    Ok(())
}

fn basename(f: &str) -> &str {
    match f.rfind(|c| c == '/' || c == '\\') {
        None => f,
        Some(index) => &f[(index + 1)..],
    }
}

fn print_frame(module: &MinidumpModule, frame: SimpleFrame) {
    print!("{}", basename(&module.code_file()));
    if let Some(ref func) = frame.function {
        print!("!{}", func);
        if let (Some(ref file), Some(line)) = (frame.source_file, frame.source_line) {
            print!(" [");
            match parse_vcs_info(file) {
                Ok(info) => print!("{}", info.annotate_url(line as u64)),
                _ => print!("{} : {}", basename(file), line),
            }
            if let Some(line_base) = frame.source_line_base {
                print!(" + {}", frame.instruction - line_base);
            }
            print!("]");
        } else if let Some(func_base) = frame.function_base {
            print!(" + {:#x}", frame.instruction - func_base);
        }
    } else {
        print!(" + {:#x}", frame.instruction - module.base_address());
    }
    println!();
}

pub fn dump_minidump_stack() -> Result<(), Error> {
    env_logger::init();
    let DumpStack {
        all,
        minidump,
        symbol_paths,
    } = DumpStack::from_args();
    info!("Reading minidump {:?}", minidump);
    let dump = Minidump::read_path(&minidump)?;
    let symbolizer = handle_symbol_paths(symbol_paths)?;
    let modules = dump.get_stream::<MinidumpModuleList>()?;
    let memory_list = dump.get_stream::<MinidumpMemoryList>()?;
    let sys_info = dump.get_stream::<MinidumpSystemInfo>()?;
    let wordsize = match sys_info.cpu {
        Cpu::X86 | Cpu::Ppc | Cpu::Sparc | Cpu::Arm => 4,
        Cpu::X86_64 | Cpu::Ppc64 | Cpu::Arm64 => 8,
        Cpu::Unknown(u) => bail!("Unknown cpu: {:#x}", u),
    };
    // TODO: provide a commandline option for the address.
    // Default to the top of the crashing stack.
    let exception = dump.get_stream::<MinidumpException>()?;
    let context = exception
        .context
        .as_ref()
        .ok_or(format_err!("Missing exception context"))?;
    let sp = context.get_stack_pointer();
    info!("Stack pointer: {:#x}", sp);
    let memory = memory_list.memory_at_address(sp).ok_or_else(|| {
        format_err!(
            "Minidump doesn't contain a memory region that contains address {:#x}",
            sp
        )
    })?;
    for addr in (memory.base_address..memory.base_address + memory.size).step_by(wordsize) {
        let instruction = match wordsize {
            4 => memory.get_memory_at_address::<u32>(addr).map(|i| i as u64),
            8 => memory.get_memory_at_address::<u64>(addr),
            _ => unreachable!(),
        };
        if let Some(instruction) = instruction {
            if let Some(module) = modules.module_at_address(instruction) {
                let mut frame = SimpleFrame::with_instruction(instruction);
                symbolizer.fill_symbol(module, &mut frame);
                if frame.function.is_some() || all {
                    print!("{:#0width$x} ", addr, width = wordsize * 2);
                    print_frame(module, frame);
                }
            }
        }
    }
    Ok(())
}
<commit_msg>Still more clippy errors<commit_after>extern crate breakpad_symbols;
extern crate disasm;
extern crate env_logger;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate log;
extern crate minidump;
extern crate minidump_common;
extern crate reqwest;
#[allow(unused_imports)]
#[macro_use]
extern crate structopt;

use breakpad_symbols::{HttpSymbolSupplier, SimpleFrame, Symbolizer};
use disasm::{Color, CpuArch, SourceLocation, SourceLookup};
use failure::Error;
use minidump::system_info::Cpu;
use minidump::{
    Minidump, MinidumpException, MinidumpMemoryList, MinidumpModule, MinidumpModuleList,
    MinidumpSystemInfo,
};
use minidump_common::traits::Module;
use reqwest::blocking::Client;
use std::env;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(StructOpt)]
#[structopt(
    name = "get-minidump-instructions",
    about = "Display instructions from a minidump"
)]
struct GetMinidumpInstructions {
    #[structopt(long = "color", help = "Enable colored output")]
    color: Option<Color>,
    #[structopt(help = "Input minidump", parse(from_os_str))]
    minidump: PathBuf,
    #[structopt(help = "Symbol paths", parse(from_os_str))]
    symbol_paths: Vec<PathBuf>,
}

#[derive(StructOpt)]
#[structopt(
    name = "dumpstack",
    about = "Display possible stack frames from a minidump"
)]
struct DumpStack {
    #[structopt(help = "Input minidump", parse(from_os_str))]
    minidump: PathBuf,
    #[structopt(help = "Symbol paths", parse(from_os_str))]
    symbol_paths: Vec<PathBuf>,
    #[structopt(
        short = "a",
        help = "Show stack addresses that don't resolve to functions"
    )]
    all: bool,
}

struct SymLookup {
    modules: MinidumpModuleList,
    symbolizer: Symbolizer,
    client: Client,
}

struct HgWebFile {
    host: String,
    repo: String,
    rev: String,
    path: String,
}

struct GitHubFile {
    repo: String,
    rev: String,
    path: String,
}

trait VCSFile {
    fn raw_url(&self) -> String;
    fn annotate_url(&self, line: u64) -> String;
    fn as_local_filename(&self) -> String;
}

impl VCSFile for HgWebFile {
    fn raw_url(&self) -> String {
        format!(
            "https://{}/{}/raw-file/{}/{}",
            self.host, self.repo, self.rev, self.path
        )
    }

    fn annotate_url(&self, line: u64) -> String {
        format!(
            "https://{}/{}/annotate/{}/{}#l{}",
            self.host, self.repo, self.rev, self.path, line
        )
    }
    fn as_local_filename(&self) -> String {
        format!("{}_{}_{}", self.host, self.rev, self.path).replace('/', "_")
    }
}

impl VCSFile for GitHubFile {
    fn raw_url(&self) -> String {
        format!(
            "http://raw.githubusercontent.com/{}/{}/{}",
            self.repo, self.rev, self.path
        )
    }
    fn annotate_url(&self, line: u64) -> String {
        format!(
            "https://github.com/{}/blob/{}/{}#L{}",
            self.repo, self.rev, self.path, line
        )
    }
    fn as_local_filename(&self) -> String {
        format!("{}_{}_{}", self.repo, self.rev, self.path).replace('/', "_")
    }
}

fn file_exists(path: &Path) -> bool {
    fs::metadata(path).is_ok()
}

fn fetch_url_to_path(client: &Client, url: &str, path: &Path) -> Result<(), Error> {
    debug!("fetch_url_to_path({}, {:?})", url, path);
    let mut res = client.get(url).send()?.error_for_status()?;
    debug!("fetch_url_to_path: HTTP success");
    let mut tmp_path = path.to_owned().into_os_string();
    tmp_path.push(".tmp");
    {
        let mut f = File::create(&tmp_path)?;
        res.copy_to(&mut f)?;
    }
    fs::rename(&tmp_path, &path)?;
    Ok(())
}

fn parse_vcs_info(filename: &str) -> Result<Box<dyn VCSFile>, Error> {
    let mut bits = filename.split(':');
    Ok(match (bits.next(), bits.next(), bits.next(), bits.next()) {
        (Some("hg"), Some(repo), Some(path), Some(rev)) if repo.starts_with("hg.mozilla.org/") => {
            let mut s = repo.splitn(2, '/');
            let host = s.next().unwrap().to_owned();
            let repo = s.next().unwrap().to_owned();
            let path = path.to_owned();
            let rev = rev.to_owned();
            Box::new(HgWebFile {
                host,
                repo,
                rev,
                path,
            })
        }
        (Some("git"), Some(repo), Some(path), Some(rev)) if repo.starts_with("github.com/") => {
            let repo = repo.splitn(2, '/').nth(1).unwrap().to_owned();
            let path = path.to_owned();
            let rev = rev.to_owned();
            Box::new(GitHubFile { repo, rev, path })
        }
        _ => return Err(format_err!("No VCS info in filename")),
    })
}

fn maybe_fetch_source_file(client: &Client, url: &str, path: &Path) -> Result<(), Error> {
    if file_exists(path) {
        Ok(())
    } else {
        fetch_url_to_path(client, url, path)
    }
}

impl SourceLookup for SymLookup {
    fn lookup(&mut self, address: u64) -> Option<SourceLocation> {
        self.modules.module_at_address(address).and_then(|module| {
            let mut frame = SimpleFrame::with_instruction(address);
            self.symbolizer.fill_symbol(module, &mut frame);
            let SimpleFrame {
                source_file,
                source_line,
                ..
            } = frame;
            if let (Some(file), Some(line)) = (source_file, source_line) {
                let line = line as u64;
                if let Ok(info) = parse_vcs_info(&file) {
                    let url = info.raw_url();
                    let local = env::temp_dir().join(info.as_local_filename());
                    if maybe_fetch_source_file(&self.client, &url, &local).is_ok() {
                        return Some(SourceLocation {
                            file: local.to_string_lossy().into_owned(),
                            file_display: Some(info.annotate_url(line)),
                            line,
                        });
                    }
                }
                // If fetching the file doesn't work, just hand back the original filename.
                Some(SourceLocation {
                    file,
                    file_display: None,
                    line,
                })
            } else {
                // We didn't find any source info.
                None
            }
        })
    }
}

fn handle_symbol_paths(symbol_paths: Vec<PathBuf>) -> Result<Symbolizer, Error> {
    let tmp_path = env::temp_dir().join("symbols");
    fs::create_dir_all(&tmp_path)?;
    let (symbol_paths, symbol_urls) = if symbol_paths.is_empty() {
        // Use the Mozilla symbol server if no symbol paths are supplied.
        let symbol_urls = vec!["https://symbols.mozilla.org/".to_owned()];
        (symbol_paths, symbol_urls)
    } else {
        let urls = symbol_paths
            .iter()
            .filter(|p| p.starts_with("http"))
            .filter_map(|p| p.to_str().map(str::to_owned))
            .collect();
        let paths = symbol_paths
            .into_iter()
            .filter(|p| !p.starts_with("http"))
            .collect();
        (paths, urls)
    };
    let supplier = HttpSymbolSupplier::new(symbol_urls, tmp_path, symbol_paths);
    Ok(Symbolizer::new(supplier))
}

pub fn get_minidump_instructions() -> Result<(), Error> {
    env_logger::init();
    let GetMinidumpInstructions {
        color,
        minidump,
        symbol_paths,
    } = GetMinidumpInstructions::from_args();
    let dump = Minidump::read_path(&minidump)?;
    let modules = dump.get_stream::<MinidumpModuleList>()?;
    let exception = dump.get_stream::<MinidumpException>()?;
    let context = exception
        .context
        .as_ref()
        .ok_or_else(|| format_err!("Missing exception context"))?;
    let ip = context.get_instruction_pointer();
    let memory_list = dump.get_stream::<MinidumpMemoryList>()?;
    let memory = memory_list.memory_at_address(ip)
        .ok_or_else(|| format_err!("Minidump doesn't contain a memory region that contains the instruction pointer from the exception record"))?;
    let sys_info = dump.get_stream::<MinidumpSystemInfo>()?;
    let arch = match sys_info.cpu {
        Cpu::X86 => CpuArch::X86,
        Cpu::X86_64 => CpuArch::X86_64,
        Cpu::Arm64 => CpuArch::ARM64,
        _ => {
            return Err(format_err!(
                "Unsupported CPU architecture: {}",
                sys_info.cpu
            ))
        }
    };
    let symbolizer = handle_symbol_paths(symbol_paths)?;
    let client = Client::new();
    let mut lookup = SymLookup {
        modules,
        symbolizer,
        client,
    };
    println!("Faulting instruction pointer: {:#x}", ip);
    info!(
        "Disassembling {} bytes starting at {:#x} of arch {:?}",
        memory.bytes.len(),
        memory.base_address,
        arch
    );
    disasm::disasm_bytes(
        &memory.bytes[ip as usize - memory.base_address as usize..],
        ip,
        arch,
        color.unwrap_or(Color::Auto),
        Some(ip),
        &mut lookup,
    )?;
    Ok(())
}

fn basename(f: &str) -> &str {
    match f.rfind(|c| c == '/' || c == '\\') {
        None => f,
        Some(index) => &f[(index + 1)..],
    }
}

fn print_frame(module: &MinidumpModule, frame: SimpleFrame) {
    print!("{}", basename(&module.code_file()));
    if let Some(ref func) = frame.function {
        print!("!{}", func);
        if let (Some(ref file), Some(line)) = (frame.source_file, frame.source_line) {
            print!(" [");
            match parse_vcs_info(file) {
                Ok(info) => print!("{}", info.annotate_url(line as u64)),
                _ => print!("{} : {}", basename(file), line),
            }
            if let Some(line_base) = frame.source_line_base {
                print!(" + {}", frame.instruction - line_base);
            }
            print!("]");
        } else if let Some(func_base) = frame.function_base {
            print!(" + {:#x}", frame.instruction - func_base);
        }
    } else {
        print!(" + {:#x}", frame.instruction - module.base_address());
    }
    println!();
}

pub fn dump_minidump_stack() -> Result<(), Error> {
    env_logger::init();
    let DumpStack {
        all,
        minidump,
        symbol_paths,
    } = DumpStack::from_args();
    info!("Reading minidump {:?}", minidump);
    let dump = Minidump::read_path(&minidump)?;
    let symbolizer = handle_symbol_paths(symbol_paths)?;
    let modules = dump.get_stream::<MinidumpModuleList>()?;
    let memory_list = dump.get_stream::<MinidumpMemoryList>()?;
    let sys_info = dump.get_stream::<MinidumpSystemInfo>()?;
    let wordsize = match sys_info.cpu {
        Cpu::X86 | Cpu::Ppc | Cpu::Sparc | Cpu::Arm => 4,
        Cpu::X86_64 | Cpu::Ppc64 | Cpu::Arm64 => 8,
        Cpu::Unknown(u) => bail!("Unknown cpu: {:#x}", u),
    };
    // TODO: provide a commandline option for the address.
    // Default to the top of the crashing stack.
    let exception = dump.get_stream::<MinidumpException>()?;
    let context = exception
        .context
        .as_ref()
        .ok_or_else(|| format_err!("Missing exception context"))?;
    let sp = context.get_stack_pointer();
    info!("Stack pointer: {:#x}", sp);
    let memory = memory_list.memory_at_address(sp).ok_or_else(|| {
        format_err!(
            "Minidump doesn't contain a memory region that contains address {:#x}",
            sp
        )
    })?;
    for addr in (memory.base_address..memory.base_address + memory.size).step_by(wordsize) {
        let instruction = match wordsize {
            4 => memory.get_memory_at_address::<u32>(addr).map(|i| i as u64),
            8 => memory.get_memory_at_address::<u64>(addr),
            _ => unreachable!(),
        };
        if let Some(instruction) = instruction {
            if let Some(module) = modules.module_at_address(instruction) {
                let mut frame = SimpleFrame::with_instruction(instruction);
                symbolizer.fill_symbol(module, &mut frame);
                if frame.function.is_some() || all {
                    print!("{:#0width$x} ", addr, width = wordsize * 2);
                    print_frame(module, frame);
                }
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
pub mod compiler_test;

compiler_tests! {
    add0_0: "0+0" => result(0),
    add0_1: "0+1" => result(1),
    add1_0: "1+0" => result(1),
    add1_1: "1+1" => result(2),
    add123_123: "123+123" => result(246),
    add1_2_3: "1+2+3" => result(6),

    sub0_0: "0-0" => result(0),
    sub1_1: "1-1" => result(0),
    sub2_1: "2-1" => result(1),
    sub1_2: "1-2" => result(-1),
    sub1_0: "1-0" => result(1),
    sub369_123: "369-123" => result(246),
    sub6_2_1: "6-2-1" => result(3),

    mul0_0: "0*0" => result(0),
    mul0_1: "0*1" => result(0),
    mul1_0: "1*0" => result(0),
    mul1_1: "1*1" => result(1),
    mul11_11: "11*11" => result(121),
    mul2_3_4: "2*3*4" => result(24),

    div0_1: "0/1" => result(0),
    div12_1: "12/1" => result(12),
    div12_3: "12/3" => result(4),
    div11_11: "11/11" => result(1),
    div24_3_4: "24/3/4" => result(2),

    div0_0: "0/0" => error(DivideByZero@1) result(error),
    div1_0: "1/0" => error(DivideByZero@1) result(error),

    muladd2_3_4: "2*3+4" => result(10),
    muladd2_3_4_neg: "-2*3+4" => result(-2),
    muladd2_3_4_pos: "+2*3+4" => result(10),

    divadd2_3_4: "30/2*3" => result(45),
    divadd2_3_4_neg: "-30/2*3" => result(-45),
    divadd2_3_4_pos: "+30/2*3" => result(45),

    addsub0_0_0: "0+0-0" => result(0),
    addsub0_0_0_neg: "-0+0-0" => result(0),
    addsub0_0_0_pos: "+0+0-0" => result(0),
    addsub1_2_3: "1+2-3" => result(0),
    addsub1_2_3_neg: "-1+2-3" => result(-2),
    addsub1_2_3_pos: "+1+2-3" => result(0),

    subadd0_0_0: "0-0+0" => result(0),
    subadd0_0_0_neg: "-0-0+0" => result(0),
    subadd0_0_0_pos: "+0-0+0" => result(0),
    subadd1_2_3: "1-2+3" => result(2),
    subadd1_2_3_neg: "-1-2+3" => result(0),
    subadd1_2_3_pos: "+1-2+3" => result(2),

    neg_0: "-0" => result(0),
    neg_1: "-1" => result(-1),
    pos_0: "+0" => result(0),
    pos_1: "+1" => result(1),

    trailing_neg: "0-" => error(UnrecognizedOperator@1) result(error),
    trailing_pos: "0+" => error(UnrecognizedOperator@1) result(error),
    neg_only:      "-" => error(MissingRightOperand@0) result(error),
    pos_only:      "+" => error(MissingRightOperand@0) result(error),
    plus_minus: "1+-2" => error(UnrecognizedOperator@[1-2]) result(error),

    addmul2_3_4: "2+3*4" => error(OperatorsOutOfPrecedenceOrder@3) result(error),

    adddiv2_3_4: "2+3/4" => error(OperatorsOutOfPrecedenceOrder@3) result(error),
}
<commit_msg>Test fractionals<commit_after>#[macro_use]
pub mod compiler_test;

compiler_tests! {
    add0_0: "0+0" => result(0),
    add0_1: "0+1" => result(1),
    add1_0: "1+0" => result(1),
    add1_1: "1+1" => result(2),
    add123_123: "123+123" => result(246),
    add1_2_3: "1+2+3" => result(6),

    sub0_0: "0-0" => result(0),
    sub1_1: "1-1" => result(0),
    sub2_1: "2-1" => result(1),
    sub1_2: "1-2" => result(-1),
    sub1_0: "1-0" => result(1),
    sub369_123: "369-123" => result(246),
    sub6_2_1: "6-2-1" => result(3),

    mul0_0: "0*0" => result(0),
    mul0_1: "0*1" => result(0),
    mul1_0: "1*0" => result(0),
    mul1_1: "1*1" => result(1),
    mul11_11: "11*11" => result(121),
    mul2_3_4: "2*3*4" => result(24),

    div0_1: "0/1" => result(0),
    div12_1: "12/1" => result(12),
    div12_3: "12/3" => result(4),
    div11_11: "11/11" => result(1),
    div24_3_4: "24/3/4" => result(2),
    div1_2: "1/2" => result(BigRational::new(1.into(), 2.into())),
    div15_7: "15/7" => result(BigRational::new(15.into(), 7.into())),
    div45_3_7: "45/3/7" => result(BigRational::new(15.into(), 7.into())),

    div0_0: "0/0" => error(DivideByZero@1) result(error),
    div1_0: "1/0" => error(DivideByZero@1) result(error),

    muladd2_3_4: "2*3+4" => result(10),
    muladd2_3_4_neg: "-2*3+4" => result(-2),
    muladd2_3_4_pos: "+2*3+4" => result(10),

    divadd2_3_4: "30/2*3" => result(45),
    divadd2_3_4_neg: "-30/2*3" => result(-45),
    divadd2_3_4_pos: "+30/2*3" => result(45),

    addsub0_0_0: "0+0-0" => result(0),
    addsub0_0_0_neg: "-0+0-0" => result(0),
    addsub0_0_0_pos: "+0+0-0" => result(0),
    addsub1_2_3: "1+2-3" => result(0),
    addsub1_2_3_neg: "-1+2-3" => result(-2),
    addsub1_2_3_pos: "+1+2-3" => result(0),

    subadd0_0_0: "0-0+0" => result(0),
    subadd0_0_0_neg: "-0-0+0" => result(0),
    subadd0_0_0_pos: "+0-0+0" => result(0),
    subadd1_2_3: "1-2+3" => result(2),
    subadd1_2_3_neg: "-1-2+3" => result(0),
    subadd1_2_3_pos: "+1-2+3" => result(2),

    neg_0: "-0" => result(0),
    neg_1: "-1" => result(-1),
    pos_0: "+0" => result(0),
    pos_1: "+1" => result(1),

    trailing_neg: "0-" => error(UnrecognizedOperator@1) result(error),
    trailing_pos: "0+" => error(UnrecognizedOperator@1) result(error),
    neg_only:      "-" => error(MissingRightOperand@0) result(error),
    pos_only:      "+" => error(MissingRightOperand@0) result(error),
    plus_minus: "1+-2" => error(UnrecognizedOperator@[1-2]) result(error),

    addmul2_3_4: "2+3*4" => error(OperatorsOutOfPrecedenceOrder@3) result(error),

    adddiv2_3_4: "2+3/4" => error(OperatorsOutOfPrecedenceOrder@3) result(error),
}
<|endoftext|>


<commit_before>use types::*;
use types::flags::*;
use types::generation::*;
use types::parsing::*;

use cookie_factory::GenError;

pub mod metadata {
    use super::*;

    pub const NAME:          &'static str   = "{{protocol.name}}";
    pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
    pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
    pub const REVISION:      ShortShortUInt = {{protocol.revision}};
    pub const PORT:          LongUInt       = {{protocol.port}};
    pub const COPYRIGHT:     &'static str   = r#"{{copyright}}"#;
}

pub mod constants {
    use super::*;

    {{#each protocol.constants as |constant| ~}}
    pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
    {{/each ~}}
}

pub enum AMQPError {
    Soft(AMQPSoftError),
    Hard(AMQPHardError),
}

impl AMQPError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPError::Soft(ref s) => s.get_id(),
            AMQPError::Hard(ref h) => h.get_id(),
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
        AMQPSoftError::from_id(id).map(AMQPError::Soft).or_else(|| AMQPHardError::from_id(id).map(AMQPError::Hard))
    }
}

pub enum AMQPSoftError {
    {{#each protocol.soft_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPSoftError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.soft_errors as |constant| ~}}
            AMQPSoftError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
        match id {
            {{#each protocol.soft_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

pub enum AMQPHardError {
    {{#each protocol.hard_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPHardError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.hard_errors as |constant| ~}}
            AMQPHardError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
        match id {
            {{#each protocol.hard_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

{{#each protocol.classes as |class| ~}}
use self::{{snake class.name}}::parse_{{snake class.name}};
{{/each ~}}

named!(pub parse_class<AMQPClass>, switch!(parse_id,
    {{#each protocol.classes as |class| ~}}
    {{class.id}} => map!(call!(parse_{{snake class.name}}), AMQPClass::{{camel class.name}}) {{#unless @last ~}}|{{/unless ~}}
    {{/each ~}}
));

pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    match *class {
        {{#each protocol.classes as |class| ~}}
        AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name}}(input, {{snake class.name}}),
        {{/each ~}}
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
    {{#each protocol.classes as |class| ~}}
    {{camel class.name}}({{snake class.name}}::AMQPMethod),
    {{/each ~}}
}

{{#each protocol.classes as |class|}}
pub mod {{snake class.name}} {
    use super::*;

    named!(pub parse_{{snake class.name}}<{{snake class.name}}::AMQPMethod>, switch!(parse_id,
        {{#each class.methods as |method| ~}}
        {{method.id}} => map!(call!(parse_{{snake method.name}}), AMQPMethod::{{camel method.name}}) {{#unless @last ~}}|{{/unless ~}}
        {{/each ~}}
    ));

    pub fn gen_{{snake class.name}}<'a>(input: (&'a mut [u8], usize), method: &AMQPMethod) -> Result<(&'a mut [u8], usize), GenError> {
        match *method {
            {{#each class.methods as |method| ~}}
            AMQPMethod::{{camel method.name}}(ref {{snake method.name}}) => {
                do_gen!(input,
                    gen_id(&{{class.id}}) >>
                    gen_{{snake method.name}}({{snake method.name}})
                )
            },
            {{/each ~}}
        }
    }

    #[derive(Clone, Debug, PartialEq)]
    pub enum AMQPMethod {
        {{#each class.methods as |method| ~}}
        {{camel method.name}}({{camel method.name}}),
        {{/each ~}}
    }

    {{#each class.methods as |method|}}
    #[derive(Clone, Debug, PartialEq)]
    pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        pub {{snake argument.name}}: {{argument.type}},
        {{else}}
        {{#each_flag argument as |flag| ~}}
        pub {{snake flag.name}}: Boolean,
        {{/each_flag ~}}
        {{/if ~}}
        {{/each_argument ~}}
    }

    named!(pub parse_{{snake method.name}}<{{camel method.name}}>, do_parse!(
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        {{snake argument.name}}: parse_{{snake_type argument.type}} >>
        {{else}}
        /* FIXME: support multiple flags structs? */
        flags: apply!(parse_flags, &[
            {{#each_flag argument as |flag| ~}}
            "{{flag.name}}",
            {{/each_flag ~}}
        ]) >>
        {{/if ~}}
        {{/each_argument ~}}
        ({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            {{snake argument.name}}: {{snake argument.name}},
            {{else}}
            {{#each_flag argument as |flag| ~}}
            {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
            {{/each_flag ~}}
            {{/if ~}}
            {{/each_argument ~}}
        })
    ));

    pub fn gen_{{snake method.name}}<'a>(input: (&'a mut [u8], usize), {{#if method.has_arguments ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
        {{#if method.has_flags ~}}
        /* FIXME: support multiple flags structs? */
        let mut flags = AMQPFlags::default();
        {{#each_argument method.arguments as |argument| ~}}
        {{#unless argument_is_value ~}}
        {{#each_flag argument as |flag| ~}}
        flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
        {{/each_flag ~}}
        {{/unless ~}}
        {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
            gen_id(&{{method.id}})
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
            >> gen_flags(&flags)
            {{/if ~}}
            {{/each_argument ~}}
        )
    }
    {{/each ~}}
    {{#if class.has_properties ~}}
    #[derive(Clone, Debug, PartialEq)]
    pub struct AMQPProperties {
        {{#each class.properties as |property| ~}}
        {{snake property.name}}: Option<{{property.type}}>,
        {{/each ~}}
    }

    impl Default for AMQPProperties {
        fn default() -> AMQPProperties {
            AMQPProperties {
                {{#each class.properties as |property| ~}}
                {{snake property.name}}: None,
                {{/each ~}}
            }
        }
    }

    impl AMQPProperties {
        {{#each class.properties as |property| ~}}
        pub fn with_{{snake property.name}}(mut self, value: {{property.type}}) -> AMQPProperties {
            self.{{snake property.name}} = Some(value);
            self
        }
        {{/each ~}}

        pub fn bitmask(&self) -> ShortUInt {
            {{#each class.properties as |property| ~}}
            (if self.{{snake property.name}}.is_some() { 1 << (15 - {{@index}}) } else { 0 }) {{#unless @last ~}} + {{/unless ~}}
            {{/each ~}}
        }
    }

    named!(pub parse_properties<AMQPProperties>, do_parse!(
        flags: parse_short_uint >>
        {{#each class.properties as |property| ~}}
        {{snake property.name}}: cond!(flags & (1 << (15 - {{@index}})) != 0, parse_{{snake_type property.type}}) >>
        {{/each ~}}
        (AMQPProperties {
            {{#each class.properties as |property| ~}}
            {{snake property.name}}: {{snake property.name}},
            {{/each ~}}
        })
    ));

    pub fn gen_properties<'a>(input:(&'a mut [u8],usize), props: &AMQPProperties) -> Result<(&'a mut [u8],usize),GenError> {
        do_gen!(input,
            gen_short_uint(&props.bitmask())
            {{#each class.properties as |property| ~}}
            >> gen_cond!(props.{{snake property.name}}.is_some(), gen_call!(gen_{{snake_type property.type}}, &props.{{snake property.name}}.as_ref().unwrap()))
            {{/each ~}}
        )
    }
    {{/if ~}}
}
{{/each ~}}
<commit_msg>protocol: add accessors for basicProperties fields<commit_after>use types::*;
use types::flags::*;
use types::generation::*;
use types::parsing::*;

use cookie_factory::GenError;

pub mod metadata {
    use super::*;

    pub const NAME:          &'static str   = "{{protocol.name}}";
    pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
    pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
    pub const REVISION:      ShortShortUInt = {{protocol.revision}};
    pub const PORT:          LongUInt       = {{protocol.port}};
    pub const COPYRIGHT:     &'static str   = r#"{{copyright}}"#;
}

pub mod constants {
    use super::*;

    {{#each protocol.constants as |constant| ~}}
    pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
    {{/each ~}}
}

pub enum AMQPError {
    Soft(AMQPSoftError),
    Hard(AMQPHardError),
}

impl AMQPError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPError::Soft(ref s) => s.get_id(),
            AMQPError::Hard(ref h) => h.get_id(),
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
        AMQPSoftError::from_id(id).map(AMQPError::Soft).or_else(|| AMQPHardError::from_id(id).map(AMQPError::Hard))
    }
}

pub enum AMQPSoftError {
    {{#each protocol.soft_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPSoftError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.soft_errors as |constant| ~}}
            AMQPSoftError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
        match id {
            {{#each protocol.soft_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

pub enum AMQPHardError {
    {{#each protocol.hard_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPHardError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.hard_errors as |constant| ~}}
            AMQPHardError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
        match id {
            {{#each protocol.hard_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

{{#each protocol.classes as |class| ~}}
use self::{{snake class.name}}::parse_{{snake class.name}};
{{/each ~}}

named!(pub parse_class<AMQPClass>, switch!(parse_id,
    {{#each protocol.classes as |class| ~}}
    {{class.id}} => map!(call!(parse_{{snake class.name}}), AMQPClass::{{camel class.name}}) {{#unless @last ~}}|{{/unless ~}}
    {{/each ~}}
));

pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    match *class {
        {{#each protocol.classes as |class| ~}}
        AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name}}(input, {{snake class.name}}),
        {{/each ~}}
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
    {{#each protocol.classes as |class| ~}}
    {{camel class.name}}({{snake class.name}}::AMQPMethod),
    {{/each ~}}
}

{{#each protocol.classes as |class|}}
pub mod {{snake class.name}} {
    use super::*;

    named!(pub parse_{{snake class.name}}<{{snake class.name}}::AMQPMethod>, switch!(parse_id,
        {{#each class.methods as |method| ~}}
        {{method.id}} => map!(call!(parse_{{snake method.name}}), AMQPMethod::{{camel method.name}}) {{#unless @last ~}}|{{/unless ~}}
        {{/each ~}}
    ));

    pub fn gen_{{snake class.name}}<'a>(input: (&'a mut [u8], usize), method: &AMQPMethod) -> Result<(&'a mut [u8], usize), GenError> {
        match *method {
            {{#each class.methods as |method| ~}}
            AMQPMethod::{{camel method.name}}(ref {{snake method.name}}) => {
                do_gen!(input,
                    gen_id(&{{class.id}}) >>
                    gen_{{snake method.name}}({{snake method.name}})
                )
            },
            {{/each ~}}
        }
    }

    #[derive(Clone, Debug, PartialEq)]
    pub enum AMQPMethod {
        {{#each class.methods as |method| ~}}
        {{camel method.name}}({{camel method.name}}),
        {{/each ~}}
    }

    {{#each class.methods as |method|}}
    #[derive(Clone, Debug, PartialEq)]
    pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        pub {{snake argument.name}}: {{argument.type}},
        {{else}}
        {{#each_flag argument as |flag| ~}}
        pub {{snake flag.name}}: Boolean,
        {{/each_flag ~}}
        {{/if ~}}
        {{/each_argument ~}}
    }

    named!(pub parse_{{snake method.name}}<{{camel method.name}}>, do_parse!(
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        {{snake argument.name}}: parse_{{snake_type argument.type}} >>
        {{else}}
        /* FIXME: support multiple flags structs? */
        flags: apply!(parse_flags, &[
            {{#each_flag argument as |flag| ~}}
            "{{flag.name}}",
            {{/each_flag ~}}
        ]) >>
        {{/if ~}}
        {{/each_argument ~}}
        ({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            {{snake argument.name}}: {{snake argument.name}},
            {{else}}
            {{#each_flag argument as |flag| ~}}
            {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
            {{/each_flag ~}}
            {{/if ~}}
            {{/each_argument ~}}
        })
    ));

    pub fn gen_{{snake method.name}}<'a>(input: (&'a mut [u8], usize), {{#if method.has_arguments ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
        {{#if method.has_flags ~}}
        /* FIXME: support multiple flags structs? */
        let mut flags = AMQPFlags::default();
        {{#each_argument method.arguments as |argument| ~}}
        {{#unless argument_is_value ~}}
        {{#each_flag argument as |flag| ~}}
        flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
        {{/each_flag ~}}
        {{/unless ~}}
        {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
            gen_id(&{{method.id}})
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
            >> gen_flags(&flags)
            {{/if ~}}
            {{/each_argument ~}}
        )
    }
    {{/each ~}}
    {{#if class.has_properties ~}}
    #[derive(Clone, Debug, PartialEq)]
    pub struct AMQPProperties {
        {{#each class.properties as |property| ~}}
        {{snake property.name}}: Option<{{property.type}}>,
        {{/each ~}}
    }

    impl Default for AMQPProperties {
        fn default() -> AMQPProperties {
            AMQPProperties {
                {{#each class.properties as |property| ~}}
                {{snake property.name}}: None,
                {{/each ~}}
            }
        }
    }

    impl AMQPProperties {
        {{#each class.properties as |property| ~}}
        pub fn with_{{snake property.name}}(mut self, value: {{property.type}}) -> AMQPProperties {
            self.{{snake property.name}} = Some(value);
            self
        }
        {{/each ~}}

        {{#each class.properties as |property| ~}}
        pub fn {{snake property.name}}(&self) -> &Option<{{property.type}}> {
            &self.{{snake property.name}}
        }
        {{/each ~}}

        pub fn bitmask(&self) -> ShortUInt {
            {{#each class.properties as |property| ~}}
            (if self.{{snake property.name}}.is_some() { 1 << (15 - {{@index}}) } else { 0 }) {{#unless @last ~}} + {{/unless ~}}
            {{/each ~}}
        }
    }

    named!(pub parse_properties<AMQPProperties>, do_parse!(
        flags: parse_short_uint >>
        {{#each class.properties as |property| ~}}
        {{snake property.name}}: cond!(flags & (1 << (15 - {{@index}})) != 0, parse_{{snake_type property.type}}) >>
        {{/each ~}}
        (AMQPProperties {
            {{#each class.properties as |property| ~}}
            {{snake property.name}}: {{snake property.name}},
            {{/each ~}}
        })
    ));

    pub fn gen_properties<'a>(input:(&'a mut [u8],usize), props: &AMQPProperties) -> Result<(&'a mut [u8],usize),GenError> {
        do_gen!(input,
            gen_short_uint(&props.bitmask())
            {{#each class.properties as |property| ~}}
            >> gen_cond!(props.{{snake property.name}}.is_some(), gen_call!(gen_{{snake_type property.type}}, &props.{{snake property.name}}.as_ref().unwrap()))
            {{/each ~}}
        )
    }
    {{/if ~}}
}
{{/each ~}}
<|endoftext|>


<commit_before>extern crate glob;
extern crate prost_build;

fn main() {
    use glob::glob;

    prost_build::compile_protos(&["../common_protos/scaii.proto"], &["../common_protos"]).unwrap();

    // Make our protobuf file a reason to recompile
    // (See http://doc.crates.io/build-script.html for more info
    // on outputs)
    for entry in glob("../common_protos/*.rs") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }

    // Unfortunately, rerun-if-changed overrides Cargo's default handling, which
    // is to rerun if any of our files change, so we have to re-add all our source
    // files
    println!("cargo:rerun-if-changed=Cargo.toml");

    for entry in glob("src/*.rs").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display())
        }
    }
}
<commit_msg>fixup! fixup! Add new protos to build script<commit_after>extern crate glob;
extern crate prost_build;

fn main() {
    use glob::glob;

    prost_build::compile_protos(&["../common_protos/scaii.proto"], &["../common_protos"]).unwrap();

    // Make our protobuf file a reason to recompile
    // (See http://doc.crates.io/build-script.html for more info
    // on outputs)
    for entry in glob("../common_protos/*.rs").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }

    // Unfortunately, rerun-if-changed overrides Cargo's default handling, which
    // is to rerun if any of our files change, so we have to re-add all our source
    // files
    println!("cargo:rerun-if-changed=Cargo.toml");
    println!("cargo:rerun-if-changed=build.rs");

    for entry in glob("src/*.rs").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display())
        }
    }
}
<|endoftext|>


<commit_before>extern crate phf_codegen;

use std::env;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

fn main() {
    generate_phf_of_svg_attributes();
}

/// Creates a perfect hash function (PHF) to map SVG attribute names to enum values.
fn generate_phf_of_svg_attributes() {
    // (attribute name, Rust enum value)
    //
    // Keep this in sync with rsvg-attributes.h
    let attribute_defs = [("alternate", "Alternate"),
                          ("amplitude", "Amplitude"),
                          ("azimuth", "Azimuth"),
                          ("baseFrequency", "BaseFrequency"),
                          ("baseline-shift", "BaselineShift"),
                          ("bias", "Bias"),
                          ("class", "Class"),
                          ("clip-path", "ClipPath"),
                          ("clip-rule", "ClipRule"),
                          ("clipPathUnits", "ClipPathUnits"),
                          ("color", "Color"),
                          ("comp-op", "CompOp"),
                          ("cx", "Cx"),
                          ("cy", "Cy"),
                          ("d", "D"),
                          ("diffuseConstant", "DiffuseConstant"),
                          ("direction", "Direction"),
                          ("display", "Display"),
                          ("divisor", "Divisor"),
                          ("dx", "Dx"),
                          ("dy", "Dy"),
                          ("edgeMode", "EdgeMode"),
                          ("elevation", "Elevation"),
                          ("enable-background", "EnableBackground"),
                          ("encoding", "Encoding"),
                          ("exponent", "Exponent"),
                          ("fill", "Fill"),
                          ("fill-opacity", "FillOpacity"),
                          ("fill-rule", "FillRule"),
                          ("filter", "Filter"),
                          ("filterUnits", "FilterUnits"),
                          ("flood-color", "FloodColor"),
                          ("flood-opacity", "FloodOpacity"),
                          ("font-family", "FontFamily"),
                          ("font-size", "FontSize"),
                          ("font-stretch", "FontStretch"),
                          ("font-style", "FontStyle"),
                          ("font-variant", "FontVariant"),
                          ("font-weight", "FontWeight"),
                          ("fx", "Fx"),
                          ("fy", "Fy"),
                          ("gradientTransform", "GradientTransform"),
                          ("gradientUnits", "GradientUnits"),
                          ("height", "Height"),
                          ("href", "Href"),
                          ("id", "Id"),
                          ("in", "In"),
                          ("in2", "In2"),
                          ("intercept", "Intercept"),
                          ("k1", "K1"),
                          ("k2", "K2"),
                          ("k3", "K3"),
                          ("k4", "K4"),
                          ("kernelMatrix", "KernelMatrix"),
                          ("kernelUnitLength", "KernelUnitLength"),
                          ("letter-spacing", "LetterSpacing"),
                          ("lighting-color", "LightingColor"),
                          ("limitingConeAngle", "LimitingConeAngle"),
                          ("marker", "Marker"),
                          ("marker-end", "MarkerEnd"),
                          ("marker-mid", "MarkerMid"),
                          ("marker-start", "MarkerStart"),
                          ("markerHeight", "MarkerHeight"),
                          ("markerUnits", "MarkerUnits"),
                          ("markerWidth", "MarkerWidth"),
                          ("mask", "Mask"),
                          ("maskContentUnits", "MaskContentUnits"),
                          ("maskUnits", "MaskUnits"),
                          ("mode", "Mode"),
                          ("numOctaves", "NumOctaves"),
                          ("offset", "Offset"),
                          ("opacity", "Opacity"),
                          ("operator", "Operator"),
                          ("order", "Order"),
                          ("orient", "Orient"),
                          ("overflow", "Overflow"),
                          ("parse", "Parse"),
                          ("path", "Path"),
                          ("patternContentUnits", "PatternContentUnits"),
                          ("patternTransform", "PatternTransform"),
                          ("patternUnits", "PatternUnits"),
                          ("points", "Points"),
                          ("pointsAtX", "PointsAtX"),
                          ("pointsAtY", "PointsAtY"),
                          ("pointsAtZ", "PointsAtZ"),
                          ("preserveAlpha", "PreserveAlpha"),
                          ("preserveAspectRatio", "PreserveAspectRatio"),
                          ("primitiveUnits", "PrimitiveUnits"),
                          ("r", "R"),
                          ("radius", "Radius"),
                          ("refX", "RefX"),
                          ("refY", "RefY"),
                          ("requiredExtensions", "RequiredExtensions"),
                          ("requiredFeatures", "RequiredFeatures"),
                          ("result", "Result"),
                          ("rx", "Rx"),
                          ("ry", "Ry"),
                          ("scale", "Scale"),
                          ("seed", "Seed"),
                          ("shape-rendering", "ShapeRendering"),
                          ("slope", "Slope"),
                          ("specularConstant", "SpecularConstant"),
                          ("specularExponent", "SpecularExponent"),
                          ("spreadMethod", "SpreadMethod"),
                          ("stdDeviation", "StdDeviation"),
                          ("stitchTiles", "StitchTiles"),
                          ("stop-color", "StopColor"),
                          ("stop-opacity", "StopOpacity"),
                          ("stroke", "Stroke"),
                          ("stroke-dasharray", "StrokeDasharray"),
                          ("stroke-dashoffset", "StrokeDashoffset"),
                          ("stroke-linecap", "StrokeLinecap"),
                          ("stroke-linejoin", "StrokeLinejoin"),
                          ("stroke-miterlimit", "StrokeMiterlimit"),
                          ("stroke-opacity", "StrokeOpacity"),
                          ("stroke-width", "StrokeWidth"),
                          ("style", "Style"),
                          ("surfaceScale", "SurfaceScale"),
                          ("systemLanguage", "SystemLanguage"),
                          ("tableValues", "TableValues"),
                          ("targetX", "TargetX"),
                          ("targetY", "TargetY"),
                          ("text-anchor", "TextAnchor"),
                          ("text-decoration", "TextDecoration"),
                          ("text-rendering", "TextRendering"),
                          ("transform", "Transform"),
                          ("type", "Type"),
                          ("unicode-bidi", "UnicodeBidi"),
                          ("values", "Values"),
                          ("verts", "Verts"),
                          ("viewBox", "ViewBox"),
                          ("visibility", "Visibility"),
                          ("width", "Width"),
                          ("writing-mode", "WritingMode"),
                          ("x", "X"),
                          ("x1", "X1"),
                          ("y1", "Y1"),
                          ("x2", "X2"),
                          ("y2", "Y2"),
                          ("xChannelSelector", "XChannelSelector"),
                          ("xlink:href", "XlinkHref"),
                          ("xml:lang", "XmlLang"),
                          ("xml:space", "XmlSpace"),
                          ("y", "Y"),
                          ("yChannelSelector", "YChannelSelector"),
                          ("z", "Z")];

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("attributes-codegen.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    writeln!(&mut file, "#[repr(C)]").unwrap();
    writeln!(&mut file, "#[derive(Debug, Clone, Copy, PartialEq)]").unwrap();
    writeln!(&mut file, "pub enum Attribute {{").unwrap();

    for &(_, valname) in attribute_defs.iter() {
        writeln!(&mut file, "    {},", valname).unwrap();
    }

    writeln!(&mut file, "}}").unwrap();

    writeln!(&mut file, "static ATTRIBUTES: phf::Map<&'static str, Attribute> = ").unwrap();

    let mut map = phf_codegen::Map::new();
    map.phf_path("phf");
    for &(name, valname) in attribute_defs.iter() {
        let valname = ["Attribute::", valname].concat();
        map.entry(name, &valname);
    }

    map.build(&mut file).unwrap();
    writeln!(&mut file, ";").unwrap();
}
<commit_msg>rustfmt: Skip the attribute slice in build.rs<commit_after>extern crate phf_codegen;

use std::env;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

fn main() {
    generate_phf_of_svg_attributes();
}

/// Creates a perfect hash function (PHF) to map SVG attribute names to enum values.
fn generate_phf_of_svg_attributes() {
    // (attribute name, Rust enum value)
    //
    // Keep this in sync with rsvg-attributes.h
    #[cfg_attr(rustfmt, rustfmt_skip)]
    let attribute_defs = [
        ( "alternate",          "Alternate" ),
        ( "amplitude",          "Amplitude" ),
        ( "azimuth",            "Azimuth" ),
        ( "baseFrequency",      "BaseFrequency" ),
        ( "baseline-shift",     "BaselineShift" ),
        ( "bias",               "Bias" ),
        ( "class",              "Class" ),
        ( "clip-path",          "ClipPath" ),
        ( "clip-rule",          "ClipRule" ),
        ( "clipPathUnits",      "ClipPathUnits" ),
        ( "color",              "Color" ),
        ( "comp-op",            "CompOp" ),
        ( "cx",                 "Cx" ),
        ( "cy",                 "Cy" ),
        ( "d",                  "D" ),
        ( "diffuseConstant",    "DiffuseConstant" ),
        ( "direction",          "Direction" ),
        ( "display",            "Display" ),
        ( "divisor",            "Divisor" ),
        ( "dx",                 "Dx" ),
        ( "dy",                 "Dy" ),
        ( "edgeMode",           "EdgeMode" ),
        ( "elevation",          "Elevation" ),
        ( "enable-background",  "EnableBackground" ),
        ( "encoding",           "Encoding" ),
        ( "exponent",           "Exponent" ),
        ( "fill",               "Fill" ),
        ( "fill-opacity",       "FillOpacity" ),
        ( "fill-rule",          "FillRule" ),
        ( "filter",             "Filter" ),
        ( "filterUnits",        "FilterUnits" ),
        ( "flood-color",        "FloodColor" ),
        ( "flood-opacity",      "FloodOpacity" ),
        ( "font-family",        "FontFamily" ),
        ( "font-size",          "FontSize" ),
        ( "font-stretch",       "FontStretch" ),
        ( "font-style",         "FontStyle" ),
        ( "font-variant",       "FontVariant" ),
        ( "font-weight",        "FontWeight" ),
        ( "fx",                 "Fx" ),
        ( "fy",                 "Fy" ),
        ( "gradientTransform",  "GradientTransform" ),
        ( "gradientUnits",      "GradientUnits" ),
        ( "height",             "Height" ),
        ( "href",               "Href" ),
        ( "id",                 "Id" ),
        ( "in",                 "In" ),
        ( "in2",                "In2" ),
        ( "intercept",          "Intercept" ),
        ( "k1",                 "K1" ),
        ( "k2",                 "K2" ),
        ( "k3",                 "K3" ),
        ( "k4",                 "K4" ),
        ( "kernelMatrix",       "KernelMatrix" ),
        ( "kernelUnitLength",   "KernelUnitLength" ),
        ( "letter-spacing",     "LetterSpacing" ),
        ( "lighting-color",     "LightingColor" ),
        ( "limitingConeAngle",  "LimitingConeAngle" ),
        ( "marker",             "Marker" ),
        ( "marker-end",         "MarkerEnd" ),
        ( "marker-mid",         "MarkerMid" ),
        ( "marker-start",       "MarkerStart" ),
        ( "markerHeight",       "MarkerHeight" ),
        ( "markerUnits",        "MarkerUnits" ),
        ( "markerWidth",        "MarkerWidth" ),
        ( "mask",               "Mask" ),
        ( "maskContentUnits",   "MaskContentUnits" ),
        ( "maskUnits",          "MaskUnits" ),
        ( "mode",               "Mode" ),
        ( "numOctaves",         "NumOctaves" ),
        ( "offset",             "Offset" ),
        ( "opacity",            "Opacity" ),
        ( "operator",           "Operator" ),
        ( "order",              "Order" ),
        ( "orient",             "Orient" ),
        ( "overflow",           "Overflow" ),
        ( "parse",              "Parse" ),
        ( "path",               "Path" ),
        ( "patternContentUnits", "PatternContentUnits" ),
        ( "patternTransform",   "PatternTransform" ),
        ( "patternUnits",       "PatternUnits" ),
        ( "points",             "Points" ),
        ( "pointsAtX",          "PointsAtX" ),
        ( "pointsAtY",          "PointsAtY" ),
        ( "pointsAtZ",          "PointsAtZ" ),
        ( "preserveAlpha",      "PreserveAlpha" ),
        ( "preserveAspectRatio", "PreserveAspectRatio" ),
        ( "primitiveUnits",     "PrimitiveUnits" ),
        ( "r",                  "R" ),
        ( "radius",             "Radius" ),
        ( "refX",               "RefX" ),
        ( "refY",               "RefY" ),
        ( "requiredExtensions", "RequiredExtensions" ),
        ( "requiredFeatures",   "RequiredFeatures" ),
        ( "result",             "Result" ),
        ( "rx",                 "Rx" ),
        ( "ry",                 "Ry" ),
        ( "scale",              "Scale" ),
        ( "seed",               "Seed" ),
        ( "shape-rendering",    "ShapeRendering" ),
        ( "slope",              "Slope" ),
        ( "specularConstant",   "SpecularConstant" ),
        ( "specularExponent",   "SpecularExponent" ),
        ( "spreadMethod",       "SpreadMethod" ),
        ( "stdDeviation",       "StdDeviation" ),
        ( "stitchTiles",        "StitchTiles" ),
        ( "stop-color",         "StopColor" ),
        ( "stop-opacity",       "StopOpacity" ),
        ( "stroke",             "Stroke" ),
        ( "stroke-dasharray",   "StrokeDasharray" ),
        ( "stroke-dashoffset",  "StrokeDashoffset" ),
        ( "stroke-linecap",     "StrokeLinecap" ),
        ( "stroke-linejoin",    "StrokeLinejoin" ),
        ( "stroke-miterlimit",  "StrokeMiterlimit" ),
        ( "stroke-opacity",     "StrokeOpacity" ),
        ( "stroke-width",       "StrokeWidth" ),
        ( "style",              "Style" ),
        ( "surfaceScale",       "SurfaceScale" ),
        ( "systemLanguage",     "SystemLanguage" ),
        ( "tableValues",        "TableValues" ),
        ( "targetX",            "TargetX" ),
        ( "targetY",            "TargetY" ),
        ( "text-anchor",        "TextAnchor" ),
        ( "text-decoration",    "TextDecoration" ),
        ( "text-rendering",     "TextRendering" ),
        ( "transform",          "Transform" ),
        ( "type",               "Type" ),
        ( "unicode-bidi",       "UnicodeBidi" ),
        ( "values",             "Values" ),
        ( "verts",              "Verts" ),
        ( "viewBox",            "ViewBox" ),
        ( "visibility",         "Visibility" ),
        ( "width",              "Width" ),
        ( "writing-mode",       "WritingMode" ),
        ( "x",                  "X" ),
        ( "x1",                 "X1" ),
        ( "y1",                 "Y1" ),
        ( "x2",                 "X2" ),
        ( "y2",                 "Y2" ),
        ( "xChannelSelector",   "XChannelSelector" ),
        ( "xlink:href",         "XlinkHref" ),
        ( "xml:lang",           "XmlLang" ),
        ( "xml:space",          "XmlSpace" ),
        ( "y",                  "Y" ),
        ( "yChannelSelector",   "YChannelSelector" ),
        ( "z",                  "Z" ),
    ];

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("attributes-codegen.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    writeln!(&mut file, "#[repr(C)]").unwrap();
    writeln!(&mut file, "#[derive(Debug, Clone, Copy, PartialEq)]").unwrap();
    writeln!(&mut file, "pub enum Attribute {{").unwrap();

    for &(_, valname) in attribute_defs.iter() {
        writeln!(&mut file, "    {},", valname).unwrap();
    }

    writeln!(&mut file, "}}").unwrap();

    writeln!(&mut file, "static ATTRIBUTES: phf::Map<&'static str, Attribute> = ").unwrap();

    let mut map = phf_codegen::Map::new();
    map.phf_path("phf");
    for &(name, valname) in attribute_defs.iter() {
        let valname = ["Attribute::", valname].concat();
        map.entry(name, &valname);
    }

    map.build(&mut file).unwrap();
    writeln!(&mut file, ";").unwrap();
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar)]

extern crate rustc;
extern crate syntax;

use std::gc::{GC, Gc};
use syntax::parse::token;
use syntax::ast;
use syntax::ext::base;
use syntax::ext::quote::rt::ToSource;
use syntax::codemap;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut ::rustc::plugin::Registry) {
    reg.register_syntax_extension(token::intern("export_lua_module"), base::ItemModifier(expand_lua_module));
}

// handler for export_lua_module
pub fn expand_lua_module(ecx: &mut base::ExtCtxt, span: codemap::Span, meta_item: Gc<ast::MetaItem>, input_item: Gc<ast::Item>)
    -> Gc<ast::Item>
{
    // checking that the input item is a module
    let module = match input_item.node {
        ast::ItemMod(ref module) => module,
        _ => {
            ecx.span_err(input_item.span, "`export_lua_module` extension is only allowed on modules");
            return input_item
        }
    };

    // creating the new item that will be returned by the function
    // it is just a clone of the input with more elements added to it
    let mut newItem = input_item.deref().clone();
    newItem.vis = ast::Public;
    if input_item.vis != ast::Public {
        ecx.span_warn(input_item.span, "`export_lua_module` will turn the module into a public module");
    }

    // creating an array of the lines of code to add to the main Lua entry point
    let moduleHandlerBody: Vec<String> = {
        let mut moduleHandlerBody = Vec::new();

        for moditem in module.items.iter() {
            let moditem_name = moditem.ident.to_source();

            match moditem.node {
                ast::ItemFn(..) | ast::ItemStatic(..) =>
                    moduleHandlerBody.push(format!(r#"
                        table.set("{0}".to_string(), {0});
                    "#, moditem_name)),

                _ => {
                    ecx.span_warn(moditem.span,
                        format!("item `{}` is neiter a function nor a static and will thus be ignored by `export_lua_module`",
                            moditem_name).as_slice());
                    continue
                }
            };
        }

        moduleHandlerBody
    };

    // adding extern crate declarations
    {
        let generatedCodeContent = format!(r#"
            mod x {{
                extern crate lua = "rust-hl-lua";
                extern crate libc;
            }}
        "#);

        // creating a new Rust parser from this
        let mut parser = ::syntax::parse::new_parser_from_source_str(ecx.parse_sess(), ecx.cfg(), "".to_string(), generatedCodeContent);

        // getting all the items defined inside "generateCodeContent"
        match parser.parse_item_with_outer_attributes() {
            None => (),
            Some(m) => {
                let mut m = match m.node {
                    ast::ItemMod(ref m) => m, _ => { ecx.span_err(span, "internal error in the library"); return input_item; }
                };

                let ref mut mutNewItem = match &mut newItem.node {
                    &ast::ItemMod(ref mut m) => m,
                    _ => { ecx.span_err(span, "internal error in the library"); return input_item; }
                };

                for i in m.view_items.iter() {
                    mutNewItem.view_items.unshift(i.clone())
                }
            }
        }

        if !parser.eat(&token::EOF) {
            ecx.span_err(input_item.span, "internal error in the library");
            return input_item;
        }
    }

    // generating the source code that we will add inside the module
    {
        let generatedCodeContent = format!(r#"
            #[no_mangle]
            pub extern "C" fn luaopen_{0}(lua: *mut self::libc::c_void) -> self::libc::c_int {{
                unsafe {{
                    let mut lua = self::lua::Lua::from_existing_state(lua, false);
                    let mut table = lua.load_new_table();

                    {1}

                    ::std::mem::forget(table);
                    1
               }}
            }}
        "#, input_item.ident.to_source(), moduleHandlerBody.connect("\n"));

        // creating a new Rust parser from this
        let mut parser = ::syntax::parse::new_parser_from_source_str(ecx.parse_sess(), ecx.cfg(), "".to_string(), generatedCodeContent);

        // getting all the items defined inside "generateCodeContent"
        loop {
            match parser.parse_item_with_outer_attributes() {
                None => break,
                Some(i) => match &mut newItem.node {
                    // moving them into "newItem"
                    &ast::ItemMod(ref mut m) => m.items.push(i),
                    _ => { ecx.span_err(span, "internal error in the library"); return input_item; }
                }
            }
        }

        if !parser.eat(&token::EOF) {
            ecx.span_err(input_item.span, "internal error in the library");
            return input_item;
        }
    }

    // returning
    box(GC) newItem
}
<commit_msg>Fix warnings when compiling modules lib<commit_after>#![feature(plugin_registrar)]

extern crate rustc;
extern crate syntax;

use std::gc::{GC, Gc};
use syntax::parse::token;
use syntax::ast;
use syntax::ext::base;
use syntax::ext::quote::rt::ToSource;
use syntax::codemap;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut ::rustc::plugin::Registry) {
    reg.register_syntax_extension(token::intern("export_lua_module"), base::ItemModifier(expand_lua_module));
}

// handler for export_lua_module
pub fn expand_lua_module(ecx: &mut base::ExtCtxt, span: codemap::Span, _: Gc<ast::MetaItem>, input_item: Gc<ast::Item>)
    -> Gc<ast::Item>
{
    // checking that the input item is a module
    let module = match input_item.node {
        ast::ItemMod(ref module) => module,
        _ => {
            ecx.span_err(input_item.span, "`export_lua_module` extension is only allowed on modules");
            return input_item
        }
    };

    // creating the new item that will be returned by the function
    // it is just a clone of the input with more elements added to it
    let mut newItem = input_item.deref().clone();
    newItem.vis = ast::Public;
    if input_item.vis != ast::Public {
        ecx.span_warn(input_item.span, "`export_lua_module` will turn the module into a public module");
    }

    // creating an array of the lines of code to add to the main Lua entry point
    let moduleHandlerBody: Vec<String> = {
        let mut moduleHandlerBody = Vec::new();

        for moditem in module.items.iter() {
            let moditem_name = moditem.ident.to_source();

            match moditem.node {
                ast::ItemFn(..) | ast::ItemStatic(..) =>
                    moduleHandlerBody.push(format!(r#"
                        table.set("{0}".to_string(), {0});
                    "#, moditem_name)),

                _ => {
                    ecx.span_warn(moditem.span,
                        format!("item `{}` is neiter a function nor a static and will thus be ignored by `export_lua_module`",
                            moditem_name).as_slice());
                    continue
                }
            };
        }

        moduleHandlerBody
    };

    // adding extern crate declarations
    {
        let generatedCodeContent = format!(r#"
            mod x {{
                extern crate lua = "rust-hl-lua";
                extern crate libc;
            }}
        "#);

        // creating a new Rust parser from this
        let mut parser = ::syntax::parse::new_parser_from_source_str(ecx.parse_sess(), ecx.cfg(), "".to_string(), generatedCodeContent);

        // getting all the items defined inside "generateCodeContent"
        match parser.parse_item_with_outer_attributes() {
            None => (),
            Some(m) => {
                let m = match m.node {
                    ast::ItemMod(ref m) => m,
                    _ => { ecx.span_err(span, "internal error in the library"); return input_item; }
                };

                let ref mut mutNewItem = match &mut newItem.node {
                    &ast::ItemMod(ref mut m) => m,
                    _ => { ecx.span_err(span, "internal error in the library"); return input_item; }
                };

                for i in m.view_items.iter() {
                    mutNewItem.view_items.unshift(i.clone())
                }
            }
        }

        if !parser.eat(&token::EOF) {
            ecx.span_err(input_item.span, "internal error in the library");
            return input_item;
        }
    }

    // generating the source code that we will add inside the module
    {
        let generatedCodeContent = format!(r#"
            #[no_mangle]
            pub extern "C" fn luaopen_{0}(lua: *mut self::libc::c_void) -> self::libc::c_int {{
                unsafe {{
                    let mut lua = self::lua::Lua::from_existing_state(lua, false);
                    let mut table = lua.load_new_table();

                    {1}

                    ::std::mem::forget(table);
                    1
               }}
            }}
        "#, input_item.ident.to_source(), moduleHandlerBody.connect("\n"));

        // creating a new Rust parser from this
        let mut parser = ::syntax::parse::new_parser_from_source_str(ecx.parse_sess(), ecx.cfg(), "".to_string(), generatedCodeContent);

        // getting all the items defined inside "generateCodeContent"
        loop {
            match parser.parse_item_with_outer_attributes() {
                None => break,
                Some(i) => match &mut newItem.node {
                    // moving them into "newItem"
                    &ast::ItemMod(ref mut m) => m.items.push(i),
                    _ => { ecx.span_err(span, "internal error in the library"); return input_item; }
                }
            }
        }

        if !parser.eat(&token::EOF) {
            ecx.span_err(input_item.span, "internal error in the library");
            return input_item;
        }
    }

    // returning
    box(GC) newItem
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::str::FromStr;
use std::fmt;

use rocket::fairing::AdHoc;
use toml;
use serde::de::{self, Deserialize, Deserializer, Visitor};

/// This struct is used to hold meta data for contexts to be passed to [`Template::render`]
///
/// [`Template::render`]: https://api.rocket.rs/rocket_contrib/struct.Template.html#method.render
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Metadata {
    title: String,
    description: String,
    authors: Vec<Author>,
    // TODO add more fields
}

impl Metadata {
    pub fn fairing() -> AdHoc {
        AdHoc::on_attach(|rocket| {
            let mut input = String::new();
            File::open("Satellite.toml").and_then(|mut f| {
                f.read_to_string(&mut input)
            }).unwrap();

            let metadata: Result<Metadata, _> = toml::from_str(input.as_str());

            match metadata {
                Ok(metadata) => Ok(rocket.manage(metadata)),
                Err(e) => {
                    println!("{}", e);
                    Err(rocket)
                },
            }
        })
    }
}

/// Holds the name and email address of one author.
/// Used in [`Metadata`]: struct.Metadata.html
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct Author {
    name: String,
    email: String,
}

impl FromStr for Author {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use regex::Regex;
        let re = Regex::new(r"(.*) <([a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*)>").unwrap();

        let cap = re.captures_iter(s).next().ok_or(())?;
        let name = cap.get(1).map(|m| m.as_str().to_string()).unwrap_or_default();
        let email = cap.get(2).map(|m| m.as_str().to_string()).unwrap_or_default();

        Ok(Author { name, email })
    }
}

impl<'de> Deserialize<'de> for Author {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        struct AuthorStringVisitor;

        impl<'de> Visitor<'de> for AuthorStringVisitor {
            type Value = Author;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "a string in the format 'Name <email@example.com>'")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                where E: de::Error
            {
                Author::from_str(v).map_err(|_| E::custom(format!("'{}' is not in the format 'Name <email@example.com>'", v)))
            }
        }

        deserializer.deserialize_str(AuthorStringVisitor)
    }
}

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

    #[test]
    fn deserialize_author() {
        assert_eq!(Ok(Author {
            name: "Random Name".to_string(),
            email: "random@mail.tld".to_string(),
        }), "Random Name <random@mail.tld>".parse());

        assert!("".parse::<Author>().is_err());
        assert!("<>".parse::<Author>().is_err());
        assert!("<random@mail.tld>".parse::<Author>().is_err());
        assert!("Random Name".parse::<Author>().is_err());
    }

    #[test]
    fn deserialize_metadata() {
        let data = r#"
            title = "Some Title"
            description = "Some description"
            authors = [
                "Name <email@author.com>",
                "Another <another@author.net>"
            ]
        "#;

        let meta: Metadata = toml::from_str(data).unwrap();

        assert_eq!(meta, Metadata {
            title: "Some Title".to_string(),
            description: "Some description".to_string(),
            authors: vec![
                Author {
                    name: "Name".to_string(),
                    email: "email@author.com".to_string(),
                },
                Author {
                    name: "Another".to_string(),
                    email: "another@author.net".to_string(),
                }
            ],
        });
    }

}<commit_msg>Added actual parse error type for Author parsing<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::str::FromStr;
use std::fmt;

use rocket::fairing::AdHoc;
use toml;
use serde::de::{self, Deserialize, Deserializer, Visitor};

/// This struct is used to hold meta data for contexts to be passed to [`Template::render`]
///
/// [`Template::render`]: https://api.rocket.rs/rocket_contrib/struct.Template.html#method.render
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Metadata {
    title: String,
    description: String,
    authors: Vec<Author>,
    // TODO add more fields
}

impl Metadata {
    pub fn fairing() -> AdHoc {
        AdHoc::on_attach(|rocket| {
            let mut input = String::new();
            File::open("Satellite.toml").and_then(|mut f| {
                f.read_to_string(&mut input)
            }).unwrap();

            let metadata: Result<Metadata, _> = toml::from_str(input.as_str());

            match metadata {
                Ok(metadata) => Ok(rocket.manage(metadata)),
                Err(e) => {
                    println!("{}", e);
                    Err(rocket)
                },
            }
        })
    }
}

/// Holds the name and email address of one author.
/// Used in [`Metadata`]: struct.Metadata.html
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct Author {
    name: String,
    email: String,
}

impl FromStr for Author {
    type Err = AuthorParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use regex::Regex;
        let re = Regex::new(r"(.*) <([a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*)>").unwrap();

        let cap = re.captures_iter(s).next().ok_or(AuthorParseError)?;
        let name = cap.get(1).map(|m| m.as_str().to_string()).unwrap_or_default();
        let email = cap.get(2).map(|m| m.as_str().to_string()).unwrap_or_default();

        Ok(Author { name, email })
    }
}

impl<'de> Deserialize<'de> for Author {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        struct AuthorStringVisitor;

        impl<'de> Visitor<'de> for AuthorStringVisitor {
            type Value = Author;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "a string in the format 'Name <email@example.com>'")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                where E: de::Error
            {
                Author::from_str(v).map_err(|_| E::custom(format!("'{}' is not in the format 'Name <email@example.com>'", v)))
            }
        }

        deserializer.deserialize_str(AuthorStringVisitor)
    }
}

struct AuthorParseError;

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

    #[test]
    fn deserialize_author() {
        assert_eq!(Ok(Author {
            name: "Random Name".to_string(),
            email: "random@mail.tld".to_string(),
        }), "Random Name <random@mail.tld>".parse());

        assert!("".parse::<Author>().is_err());
        assert!("<>".parse::<Author>().is_err());
        assert!("<random@mail.tld>".parse::<Author>().is_err());
        assert!("Random Name".parse::<Author>().is_err());
    }

    #[test]
    fn deserialize_metadata() {
        let data = r#"
            title = "Some Title"
            description = "Some description"
            authors = [
                "Name <email@author.com>",
                "Another <another@author.net>"
            ]
        "#;

        let meta: Metadata = toml::from_str(data).unwrap();

        assert_eq!(meta, Metadata {
            title: "Some Title".to_string(),
            description: "Some description".to_string(),
            authors: vec![
                Author {
                    name: "Name".to_string(),
                    email: "email@author.com".to_string(),
                },
                Author {
                    name: "Another".to_string(),
                    email: "another@author.net".to_string(),
                }
            ],
        });
    }

}<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;
use std::io;

use crate::credential::CredentialsError;

use super::proto::xml::util::XmlParseError;
use super::request::{BufferedHttpResponse, HttpDispatchError};
use crate::client::SignAndDispatchError;

/// Generic error type returned by all rusoto requests.
#[derive(Debug, PartialEq)]
pub enum RusotoError<E> {
    /// A service-specific error occurred.
    Service(E),
    /// An error occurred dispatching the HTTP request
    HttpDispatch(HttpDispatchError),
    /// An error was encountered with AWS credentials.
    Credentials(CredentialsError),
    /// A validation error occurred.  Details from AWS are provided.
    Validation(String),
    /// An error occurred parsing the response payload.
    ParseError(String),
    /// An unknown error occurred.  The raw HTTP response is provided.
    Unknown(BufferedHttpResponse),
    /// An error occurred when attempting to run a future as blocking
    Blocking,
}

/// Result carrying a generic `RusotoError`.
pub type RusotoResult<T, E> = Result<T, RusotoError<E>>;

impl<E> From<XmlParseError> for RusotoError<E> {
    fn from(err: XmlParseError) -> Self {
        let XmlParseError(message) = err;
        RusotoError::ParseError(message)
    }
}

impl<E> From<serde_json::error::Error> for RusotoError<E> {
    fn from(err: serde_json::error::Error) -> Self {
        RusotoError::ParseError(err.to_string())
    }
}

impl<E> From<CredentialsError> for RusotoError<E> {
    fn from(err: CredentialsError) -> Self {
        RusotoError::Credentials(err)
    }
}

impl<E> From<HttpDispatchError> for RusotoError<E> {
    fn from(err: HttpDispatchError) -> Self {
        RusotoError::HttpDispatch(err)
    }
}

impl<E> From<SignAndDispatchError> for RusotoError<E> {
    fn from(err: SignAndDispatchError) -> Self {
        match err {
            SignAndDispatchError::Credentials(e) => Self::from(e),
            SignAndDispatchError::Dispatch(e) => Self::from(e),
        }
    }
}

impl<E> From<io::Error> for RusotoError<E> {
    fn from(err: io::Error) -> Self {
        RusotoError::HttpDispatch(HttpDispatchError::from(err))
    }
}

impl<E: Error + 'static> fmt::Display for RusotoError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RusotoError::Service(ref err) => write!(f, "{}", err),
            RusotoError::Validation(ref cause) => write!(f, "{}", cause),
            RusotoError::Credentials(ref err) => write!(f, "{}", err),
            RusotoError::HttpDispatch(ref dispatch_error) => write!(f, "{}", dispatch_error),
            RusotoError::ParseError(ref cause) => write!(f, "{}", cause),
            RusotoError::Unknown(ref cause) => write!(f, "{}", cause.body_as_str()),
            RusotoError::Blocking => write!(f, "Failed to run blocking future"),
        }
    }
}

impl<E: Error + 'static> Error for RusotoError<E> {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            RusotoError::Service(ref err) => Some(err),
            RusotoError::Credentials(ref err) => Some(err),
            RusotoError::HttpDispatch(ref err) => Some(err),
            _ => None,
        }
    }
}
<commit_msg>Improve Display on RusotoError::Unknown<commit_after>use std::error::Error;
use std::fmt;
use std::io;

use crate::credential::CredentialsError;

use super::proto::xml::util::XmlParseError;
use super::request::{BufferedHttpResponse, HttpDispatchError};
use crate::client::SignAndDispatchError;

/// Generic error type returned by all rusoto requests.
#[derive(Debug, PartialEq)]
pub enum RusotoError<E> {
    /// A service-specific error occurred.
    Service(E),
    /// An error occurred dispatching the HTTP request
    HttpDispatch(HttpDispatchError),
    /// An error was encountered with AWS credentials.
    Credentials(CredentialsError),
    /// A validation error occurred.  Details from AWS are provided.
    Validation(String),
    /// An error occurred parsing the response payload.
    ParseError(String),
    /// An unknown error occurred.  The raw HTTP response is provided.
    Unknown(BufferedHttpResponse),
    /// An error occurred when attempting to run a future as blocking
    Blocking,
}

/// Result carrying a generic `RusotoError`.
pub type RusotoResult<T, E> = Result<T, RusotoError<E>>;

/// Header used by AWS on responses to identify the request
pub const AWS_REQUEST_ID_HEADER: &str = "x-amzn-requestid";

impl<E> From<XmlParseError> for RusotoError<E> {
    fn from(err: XmlParseError) -> Self {
        let XmlParseError(message) = err;
        RusotoError::ParseError(message)
    }
}

impl<E> From<serde_json::error::Error> for RusotoError<E> {
    fn from(err: serde_json::error::Error) -> Self {
        RusotoError::ParseError(err.to_string())
    }
}

impl<E> From<CredentialsError> for RusotoError<E> {
    fn from(err: CredentialsError) -> Self {
        RusotoError::Credentials(err)
    }
}

impl<E> From<HttpDispatchError> for RusotoError<E> {
    fn from(err: HttpDispatchError) -> Self {
        RusotoError::HttpDispatch(err)
    }
}

impl<E> From<SignAndDispatchError> for RusotoError<E> {
    fn from(err: SignAndDispatchError) -> Self {
        match err {
            SignAndDispatchError::Credentials(e) => Self::from(e),
            SignAndDispatchError::Dispatch(e) => Self::from(e),
        }
    }
}

impl<E> From<io::Error> for RusotoError<E> {
    fn from(err: io::Error) -> Self {
        RusotoError::HttpDispatch(HttpDispatchError::from(err))
    }
}

impl<E: Error + 'static> fmt::Display for RusotoError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RusotoError::Service(ref err) => write!(f, "{}", err),
            RusotoError::Validation(ref cause) => write!(f, "{}", cause),
            RusotoError::Credentials(ref err) => write!(f, "{}", err),
            RusotoError::HttpDispatch(ref dispatch_error) => write!(f, "{}", dispatch_error),
            RusotoError::ParseError(ref cause) => write!(f, "{}", cause),
            RusotoError::Unknown(ref cause) => write!(
                f,
                "Request ID: {:?} Body: {}",
                cause.headers.get(AWS_REQUEST_ID_HEADER),
                cause.body_as_str()
            ),
            RusotoError::Blocking => write!(f, "Failed to run blocking future"),
        }
    }
}

impl<E: Error + 'static> Error for RusotoError<E> {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            RusotoError::Service(ref err) => Some(err),
            RusotoError::Credentials(ref err) => Some(err),
            RusotoError::HttpDispatch(ref err) => Some(err),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>fn is_saddle_point(input: &[Vec<u64>], px: usize, py: usize) -> bool {
    let value = input[py][px];

    for y in 0..input.len() {
        if input[y][px] < value {
            return false;
        }
    }

    for x in 0..input[0].len() {
        if input[py][x] > value {
            return false;
        }
    }

    true
}

pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let mut saddle_points = Vec::new();

    for y in 0..input.len() {
        for x in 0..input[y].len() {
            if is_saddle_point(input, x, y) {
                saddle_points.push((y, x));
            }
        }
    }

    saddle_points
}
<commit_msg>Improve solution for Saddle Points<commit_after>pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let mut row_max = vec![Vec::new(); input.len()];
    let mut col_min: Vec<Vec<(usize, u64)>> = vec![Vec::new(); input[0].len()];

    for (row, values) in input.iter().enumerate() {
        for (col, &value) in values.iter().enumerate() {
            let mut c = &mut col_min[col];

            if c.is_empty() || c[0].1 == value {
                c.push((row, value));
            } else if c[0].1 > value {
                c.clear();
                c.push((row, value));
            }

            let mut r = &mut row_max[row];

            if r.is_empty() || r[0] == value {
                r.push(value);
            } else if r[0] < value {
                r.clear();
                r.push(value);
            }
        }
    }

    col_min
        .iter()
        .enumerate()
        .fold(Vec::new(), |mut points, (col, values)| {
            let mut col_points = values
                .iter()
                .filter(|c| row_max[c.0].contains(&c.1))
                .map(|c| (c.0, col))
                .collect();

            points.append(&mut col_points);
            points
        })
}
<|endoftext|>