<commit_before>extern crate capnp;
extern crate clap;
extern crate regex;

use std::io;
use std::process;

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

mod entry_capnp;

use std::io::BufRead;
use std::io::Read;
use std::io::Write;

fn cat<R: io::Read, W: io::Write>(mut from: &mut R, mut to: &mut W) -> io::Result<bool> {
    let entry = entry_capnp::read_entry(&mut from).expect("TODO: error type mapping");
    if entry.is_none() {
        return Ok(false);
    }

    let entry: entry_capnp::FileEntry = entry.unwrap();

    assert_eq!(entry.len, copy_upto(&mut from, &mut to, entry.len)?);

    Ok(true)
}

fn grep<R: io::Read>(mut from: &mut R, regex: &regex::Regex) -> io::Result<bool> {
    let entry = entry_capnp::read_entry(&mut from).expect("TODO: error type mapping");
    if entry.is_none() {
        return Ok(false);
    }

    let entry: entry_capnp::FileEntry = entry.unwrap();

    let paths = join_backwards(&entry.paths, "/ /");

    for line in io::BufReader::new((&mut from).take(entry.len)).lines() {
        match line {
            Ok(line) => {
                if regex.is_match(line.as_str()) {
                    println!("{}:{}", paths, line);
                }
            }
            Err(e) => {
                write!(io::stderr(), "skipping non-utf-8 ({}) file: {}\n", e, paths)?;
            }
        }
    }

    Ok(true)
}

fn direct_run<R: io::Read>(mut from: &mut R, cmd: &Vec<&str>) -> io::Result<bool> {

    let entry = entry_capnp::read_entry(&mut from).expect("TODO: error type mapping");
    if entry.is_none() {
        return Ok(false);
    }

    let entry: entry_capnp::FileEntry = entry.unwrap();

    // skip others; assuming they're empty
    if !entry.normal_file {
        assert_eq!(0, entry.len);
        return Ok(true);
    }

    if !entry.content_follows {
        return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                  "Can't do anything for contentless streams"));
    }

    let mut child = process::Command::new(cmd[0])
        .args(&cmd[1..])
        .env("TAR_REALNAME", join_backwards(&entry.paths, "/ /"))
        .env("TAR_FILENAME", entry.paths[0].to_string())
        .env("TAR_SIZE", format!("{}", entry.len))
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::inherit())
        .stderr(process::Stdio::inherit())
        .spawn()?;

    assert_eq!(entry.len, copy_upto(&mut from, &mut child.stdin.as_mut().unwrap(), entry.len)?);

    assert!(child.wait()?.success());

    Ok(true)
}

fn copy_upto<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W, how_much: u64) -> io::Result<u64>
    where R: io::Read, W: io::Write
{
    let mut buf = [0; 8 * 1024];
    let mut written = 0;
    loop {
        let max_to_read = std::cmp::min(how_much - written, buf.len() as u64) as usize;
        let len = match reader.read(&mut buf[0..max_to_read]) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        written += len as u64;
    }
}

fn join_backwards(what: &Vec<String>, join: &str) -> String {
    let mut ret = String::with_capacity(what.len() * 40);

    for i in (1..(what.len() - 1)).rev() {
        ret.push_str(what[i].as_str());
        ret.push_str(join);
    }
    ret.push_str(what[0].as_str());
    ret
}

fn main() {
    let from = io::stdin();
    let mut from = from.lock();

    match App::new("contentin")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .subcommand(SubCommand::with_name("cat")
        )
        .subcommand(SubCommand::with_name("grep")
            .arg(Arg::with_name("pattern")
                .required(true)
                .help("pattern to search for"))
        )
        .subcommand(SubCommand::with_name("run")
                        .setting(clap::AppSettings::TrailingVarArg)
                        .setting(clap::AppSettings::DontDelimitTrailingValues)
                        .arg(Arg::with_name("sh")
                            .long("sh")
                            .help("Run with `sh -c`, and ssh-like quoting behaviour"))
//                      .arg(Arg::with_name("command-failure")
//                          .long("command-failure")
//                          .takes_value(true)
//                          .use_delimiter(false)
//                          .default_value("fatal")
//                          .possible_values(&[
//                              "fatal",
//                              "ignore",
//                          ])
                        .arg(Arg::with_name("command")
                            .required(true)
                            .help("Command to run, and its arguments")
                            .multiple(true))
        )
        .get_matches().subcommand() {
        ("cat", Some(_)) => {
            let stdout = io::stdout();
            let mut stdout = stdout.lock();
            while cat(&mut from, &mut stdout).expect("TODO: handle error") {
            }
        }
        ("grep", Some(matches)) => {
            let pattern = matches.value_of("pattern").unwrap();
            match regex::Regex::new(pattern) {
                Ok(regex) => {
                    while grep(&mut from, &regex).expect("TODO: handle error") {
                    }
                }
                Err(e) => {
                    println!("invalid regex: {} {}", pattern, e);
                    // TODO: return 2;
                }
            }
        }
        ("run", Some(matches)) => {
            let raw_command: Vec<&str> = matches.values_of("command").unwrap().collect();
            let as_dumb_line = raw_command.join(" ");

            let cmd = if matches.is_present("sh") {
                vec!("sh", "-c", as_dumb_line.as_str())
            } else {
                raw_command
            };

            while direct_run(&mut from, &cmd).expect("TODO: handle error") {
            }
        },
        _ => unreachable!(),
    }
}
<commit_msg>abstract away the reader loop<commit_after>extern crate capnp;
extern crate clap;
extern crate regex;

use std::io;
use std::process;

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

mod entry_capnp;

use std::io::BufRead;
use std::io::Read;
use std::io::Write;

fn with_entries<
    R: io::Read,
    F: FnMut(&mut R, entry_capnp::FileEntry) -> io::Result<()>
>(
    mut from: &mut R,
    mut work: F
) -> io::Result<()> {

    loop {
        match entry_capnp::read_entry(&mut from).expect("TODO: error type mapping") {
            None => return Ok(()),
            Some(entry) => if let Err(e) = work(&mut from, entry) {
                return Err(e);
            }
        }
    }
}

fn cat<R: io::Read, W: io::Write>(mut from: &mut R, to: &mut W) -> io::Result<()> {
    with_entries(&mut from, move |from, entry| {
        assert_eq!(entry.len, copy_upto(from, to, entry.len)?);
        Ok(())
    })
}

fn grep<R: io::Read>(mut from: &mut R, regex: &regex::Regex) -> io::Result<()> {
    with_entries(&mut from, move |mut from, entry| {
        let paths = join_backwards(&entry.paths, "/ /");

        for line in io::BufReader::new((&mut from).take(entry.len)).lines() {
            match line {
                Ok(line) => {
                    if regex.is_match(line.as_str()) {
                        println!("{}:{}", paths, line);
                    }
                }
                Err(e) => {
                    write!(io::stderr(), "skipping non-utf-8 ({}) file: {}\n", e, paths)?;
                }
            }
        }

        Ok(())
    })
}

fn direct_run<R: io::Read>(mut from: &mut R, cmd: &Vec<&str>) -> io::Result<()> {
    with_entries(&mut from, move |mut from, entry| {
        // skip others; assuming they're empty
        if !entry.normal_file {
            assert_eq!(0, entry.len);
            return Ok(());
        }

        if !entry.content_follows {
            return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                      "Can't do anything for contentless streams"));
        }

        let mut child = process::Command::new(cmd[0])
            .args(&cmd[1..])
            .env("TAR_REALNAME", join_backwards(&entry.paths, "/ /"))
            .env("TAR_FILENAME", entry.paths[0].to_string())
            .env("TAR_SIZE", format!("{}", entry.len))
            .stdin(process::Stdio::piped())
            .stdout(process::Stdio::inherit())
            .stderr(process::Stdio::inherit())
            .spawn()?;

        assert_eq!(entry.len, copy_upto(&mut from, &mut child.stdin.as_mut().unwrap(), entry.len)?);

        assert!(child.wait()?.success());

        Ok(())
    })
}

fn copy_upto<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W, how_much: u64) -> io::Result<u64>
    where R: io::Read, W: io::Write
{
    let mut buf = [0; 8 * 1024];
    let mut written = 0;
    loop {
        let max_to_read = std::cmp::min(how_much - written, buf.len() as u64) as usize;
        let len = match reader.read(&mut buf[0..max_to_read]) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        written += len as u64;
    }
}

fn join_backwards(what: &Vec<String>, join: &str) -> String {
    let mut ret = String::with_capacity(what.len() * 40);

    for i in (1..(what.len() - 1)).rev() {
        ret.push_str(what[i].as_str());
        ret.push_str(join);
    }
    ret.push_str(what[0].as_str());
    ret
}

fn main() {
    let from = io::stdin();
    let mut from = from.lock();

    match App::new("contentin")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .subcommand(SubCommand::with_name("cat")
        )
        .subcommand(SubCommand::with_name("grep")
            .arg(Arg::with_name("pattern")
                .required(true)
                .help("pattern to search for"))
        )
        .subcommand(SubCommand::with_name("run")
                        .setting(clap::AppSettings::TrailingVarArg)
                        .setting(clap::AppSettings::DontDelimitTrailingValues)
                        .arg(Arg::with_name("sh")
                            .long("sh")
                            .help("Run with `sh -c`, and ssh-like quoting behaviour"))
//                      .arg(Arg::with_name("command-failure")
//                          .long("command-failure")
//                          .takes_value(true)
//                          .use_delimiter(false)
//                          .default_value("fatal")
//                          .possible_values(&[
//                              "fatal",
//                              "ignore",
//                          ])
                        .arg(Arg::with_name("command")
                            .required(true)
                            .help("Command to run, and its arguments")
                            .multiple(true))
        )
        .get_matches().subcommand() {
        ("cat", Some(_)) => {
            let stdout = io::stdout();
            let mut stdout = stdout.lock();
            cat(&mut from, &mut stdout).expect("TODO: handle error");
        }
        ("grep", Some(matches)) => {
            let pattern = matches.value_of("pattern").unwrap();
            match regex::Regex::new(pattern) {
                Ok(regex) => {
                    grep(&mut from, &regex).expect("TODO: handle error")
                }
                Err(e) => {
                    println!("invalid regex: {} {}", pattern, e);
                    // TODO: return 2;
                }
            }
        }
        ("run", Some(matches)) => {
            let raw_command: Vec<&str> = matches.values_of("command").unwrap().collect();
            let as_dumb_line = raw_command.join(" ");

            let cmd = if matches.is_present("sh") {
                vec!("sh", "-c", as_dumb_line.as_str())
            } else {
                raw_command
            };

            direct_run(&mut from, &cmd).expect("TODO: handle error")
        },
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>// check-pass

// Bastion of the Turbofish
// ------------------------
// Beware travellers, lest you venture into waters callous and unforgiving,
// where hope must be abandoned, ere it is cruelly torn from you. For here
// stands the bastion of the Turbofish: an impenetrable fortress holding
// unshaking against those who would dare suggest the supererogation of the
// Turbofish.
//
// Once I was young and foolish and had the impudence to imagine that I could
// shake free from the coils by which that creature had us tightly bound. I
// dared to suggest that there was a better way: a brighter future, in which
// Rustaceans both new and old could be rid of that vile beast. But alas! In
// my foolhardiness my ignorance was unveiled and my dreams were dashed
// unforgivingly against the rock of syntactic ambiguity.
//
// This humble program, small and insignificant though it might seem,
// demonstrates that to which we had previously cast a blind eye: an ambiguity
// in permitting generic arguments to be provided without the consent of the
// Great Turbofish. Should you be so naïve as to try to revolt against its
// mighty clutches, here shall its wrath be indomitably displayed. This
// program must pass for all eternity, fundamentally at odds with an impetuous
// rebellion against the Turbofish.
//
// My heart aches in sorrow, for I know I am defeated. Let this be a warning
// to all those who come after. Here stands the bastion of the Turbofish.
//
// RIP Anna Harren, Guardian Angel of the Hallowed Turbofish. <3

// See https://github.com/rust-lang/rust/pull/53562
// and https://github.com/rust-lang/rfcs/pull/2527
// and https://twitter.com/garblefart/status/1393236602856611843
// for context.

fn main() {
    let (oh, woe, is, me) = ("the", "Turbofish", "remains", "undefeated");
    let _: (bool, bool) = (oh<woe, is>(me));
}
<commit_msg>Integrate context into the memorial to Anna<commit_after>// check-pass

// Bastion of the Turbofish
// ------------------------
// Beware travellers, lest you venture into waters callous and unforgiving,
// where hope must be abandoned, ere it is cruelly torn from you. For here
// stands the bastion of the Turbofish: an impenetrable fortress holding
// unshaking against those who would dare suggest the supererogation of the
// Turbofish.
//
// Once I was young and foolish and had the impudence to imagine that I could
// shake free from the coils by which that creature had us tightly bound. I
// dared to suggest that there was a better way: a brighter future, in which
// Rustaceans both new and old could be rid of that vile beast. But alas! In
// my foolhardiness my ignorance was unveiled and my dreams were dashed
// unforgivingly against the rock of syntactic ambiguity.
//
// This humble program, small and insignificant though it might seem,
// demonstrates that to which we had previously cast a blind eye: an ambiguity
// in permitting generic arguments to be provided without the consent of the
// Great Turbofish. Should you be so naïve as to try to revolt against its
// mighty clutches, here shall its wrath be indomitably displayed. This
// program must pass for all eternity: forever watched by the guardian angel
// which gave this beast its name, and stands fundamentally at odds with the
// impetuous rebellion against the Turbofish.
//
// My heart aches in sorrow, for I know I am defeated. Let this be a warning
// to all those who come after: for they too must overcome the impassible
// hurdle of defeating the great beast, championed by a resolute winged
// guardian.
//
// Here stands the Bastion of the Turbofish, a memorial to Anna Harren,
// Guardian Angel of these Hallowed Grounds. <3

// See https://github.com/rust-lang/rust/pull/53562
// and https://github.com/rust-lang/rfcs/pull/2527
// and https://twitter.com/garblefart/status/1393236602856611843
// for context.

fn main() {
    let (the, guardian, stands, resolute) = ("the", "Turbofish", "remains", "undefeated");
    let _: (bool, bool) = (the<guardian, stands>(resolute));
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![feature(box_patterns, alloc)]

// warnings
#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(std_misc)]
#![feature(str_char)]

extern crate collections;

pub use unknown::UnknownFields;
pub use unknown::UnknownValues;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValuesIter;
pub use unknown::UnknownFieldIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::MessageStatic;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
pub use core::parse_length_delimited_from;
pub use core::parse_length_delimited_from_bytes;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod descriptor;
pub mod codegen;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;

// used by test
pub mod hex;

mod misc;
mod zigzag;
mod maybe_owned_slice;
mod paginate;
mod unknown;
mod strx;
mod descriptorx;

// so `use protobuf::*` could work in descriptor mod
mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use text_format;
    pub use lazy;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValuesIter;
    pub use unknown::UnknownFieldIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
}
<commit_msg>Removed unused feature<commit_after>#![crate_type = "lib"]
#![feature(box_patterns, alloc)]

// warnings
#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(str_char)]

extern crate collections;

pub use unknown::UnknownFields;
pub use unknown::UnknownValues;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValuesIter;
pub use unknown::UnknownFieldIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::MessageStatic;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
pub use core::parse_length_delimited_from;
pub use core::parse_length_delimited_from_bytes;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod descriptor;
pub mod codegen;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;

// used by test
pub mod hex;

mod misc;
mod zigzag;
mod maybe_owned_slice;
mod paginate;
mod unknown;
mod strx;
mod descriptorx;

// so `use protobuf::*` could work in descriptor mod
mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use text_format;
    pub use lazy;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValuesIter;
    pub use unknown::UnknownFieldIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
}
<|endoftext|>


<commit_before>pub fn run_debug_server_udp(host: &str, timeout_in_s: u64) {
    let socket = ::std::net::UdpSocket::bind(host)
        .expect("Failed to create debug server UDP socket");

    socket.set_read_timeout(Some(::std::time::Duration::new(timeout_in_s, 0)))
        .expect("Failed to set read timeout on UDP socket");

    loop {
        let mut buf: [u8; 10000] = [0; 10000 /* should fit alomost any message */];
        let num_bytes = match socket.recv_from(&mut buf) {
            Ok((num_bytes, _)) => num_bytes,
            Err(_) => return,
        };

        if buf[0] == 0x1e && buf[1] == 0x0f {
            let pos = buf[10];
            let total = buf[11];
            let id: u64 = buf[2..10].iter().fold(0, |x, &i| x << 4 | i as u64);

            println!("Received message chunk ({}/{}) for message '{:?}': {}",
                     pos,
                     total,
                     id,
                     String::from_utf8_lossy(&buf[12..num_bytes]));
        } else {
            println!("Received message: {}",
                     String::from_utf8_lossy(&buf[0..num_bytes]));
        }
    }
}
<commit_msg>Fix incorrect bit shifting<commit_after>pub fn run_debug_server_udp(host: &str, timeout_in_s: u64) {
    let socket = ::std::net::UdpSocket::bind(host)
        .expect("Failed to create debug server UDP socket");

    socket.set_read_timeout(Some(::std::time::Duration::new(timeout_in_s, 0)))
        .expect("Failed to set read timeout on UDP socket");

    loop {
        let mut buf: [u8; 10000] = [0; 10000 /* should fit alomost any message */];
        let num_bytes = match socket.recv_from(&mut buf) {
            Ok((num_bytes, _)) => num_bytes,
            Err(_) => return,
        };

        if buf[0] == 0x1e && buf[1] == 0x0f {
            let pos = buf[10];
            let total = buf[11];
            let id: u64 = buf[2..10].iter().fold(0, |x, &i| x << 8 | i as u64);

            println!("Received message chunk ({}/{}) for message '{:?}': {}",
                     pos,
                     total,
                     id,
                     String::from_utf8_lossy(&buf[12..num_bytes]));
        } else {
            println!("Received message: {}",
                     String::from_utf8_lossy(&buf[0..num_bytes]));
        }
    }
}
<|endoftext|>


<commit_before>//! This example demonstrates how to work with structured
//! keys and values without paying expensive (de)serialization
//! costs.
//!
//! The `upsert` function shows how to use structured keys and values.
//!
//! The `variable_lengths` function shows how to put a variable length
//! component in either the beginning or the end of your value.
//!
//! The `hash_join` function shows how to do some SQL-like joins.
//!
//! Running this example several times via `cargo run --example structured`
//! will initialize the count field to 0, and on subsequent runs it will
//! increment it.
use {
    byteorder::{BigEndian, LittleEndian},
    zerocopy::{
        byteorder::U64, AsBytes, FromBytes, LayoutVerified, Unaligned, U16, U32,
    },
};

fn upsert(db: &sled::Db) -> sled::Result<()> {
    // We use `BigEndian` for key types because
    // they preserve lexicographic ordering,
    // which is nice if we ever want to iterate
    // over our items in order. We use the
    // `U64` type from zerocopy because it
    // does not have alignment requirements.
    // sled does not guarantee any particular
    // value alignment as of now.
    #[derive(FromBytes, AsBytes, Unaligned)]
    #[repr(C)]
    struct Key {
        a: U64<BigEndian>,
        b: U64<BigEndian>,
    }

    // We use `LittleEndian` for values because
    // it's possibly cheaper, but the difference
    // isn't likely to be measurable, so honestly
    // use whatever you want for values.
    #[derive(FromBytes, AsBytes, Unaligned)]
    #[repr(C)]
    struct Value {
        count: U64<LittleEndian>,
        whatever: [u8; 16],
    }

    let key = Key { a: U64::new(21), b: U64::new(890) };

    // "UPSERT" functionality
    db.update_and_fetch(key.as_bytes(), |value_opt| {
        if let Some(existing) = value_opt {
            // We need to make a copy that will be written back
            // into the database. This allows other threads that
            // may have witnessed the old version to keep working
            // without taking out any locks. IVec will be
            // stack-allocated until it reaches 22 bytes
            let mut backing_bytes = sled::IVec::from(existing);

            // this verifies that our value is the correct length
            // and alignment (in this case we don't need it to be
            // aligned, because we use the `U64` type from zerocopy)
            let layout: LayoutVerified<&mut [u8], Value> =
                LayoutVerified::new_unaligned(&mut *backing_bytes)
                    .expect("bytes do not fit schema");

            // this lets us work with the underlying bytes as
            // a mutable structured value.
            let value: &mut Value = layout.into_mut();

            let new_count = value.count.get() + 1;

            println!("incrementing count to {}", new_count);

            value.count.set(new_count);

            Some(backing_bytes)
        } else {
            println!("setting count to 0");

            Some(sled::IVec::from(
                Value { count: U64::new(0), whatever: [0; 16] }.as_bytes(),
            ))
        }
    })?;

    Ok(())
}

// Cat values will be:
// favorite_number + battles_won + <home name variable bytes>
#[derive(FromBytes, AsBytes, Unaligned)]
#[repr(C)]
struct CatValue {
    favorite_number: U64<LittleEndian>,
    battles_won: U64<LittleEndian>,
}

// Dog values will be:
// <home name variable bytes> + woof_count + postal_code
#[derive(FromBytes, AsBytes, Unaligned)]
#[repr(C)]
struct DogValue {
    woof_count: U32<LittleEndian>,
    postal_code: U16<LittleEndian>,
}

fn variable_lengths(db: &sled::Db) -> sled::Result<()> {
    // here we will show how we can use zerocopy for inserting
    // fixed-size components, mixed with variable length
    // records on the end or beginning.

    // the hash_join example below shows how to read items
    // out in a way that accounts for the variable portion,
    // using `zerocopy::LayoutVerified::{new_from_prefix, new_from_suffix}`

    let dogs = db.open_tree(b"dogs")?;

    let mut dog2000_value = vec![];
    dog2000_value.extend_from_slice(b"science zone");
    dog2000_value.extend_from_slice(
        DogValue { woof_count: U32::new(666), postal_code: U16::new(42) }
            .as_bytes(),
    );
    dogs.insert("dog2000", dog2000_value)?;

    let mut zed_pup_value = vec![];
    zed_pup_value.extend_from_slice(b"bowling alley");
    zed_pup_value.extend_from_slice(
        DogValue { woof_count: U32::new(32113231), postal_code: U16::new(0) }
            .as_bytes(),
    );
    dogs.insert("zed pup", zed_pup_value)?;

    // IMPORTANT NOTE: the German word for "bark" is "barf"
    let mut klaus_value = vec![];
    klaus_value.extend_from_slice(b"barf shop");
    klaus_value.extend_from_slice(
        DogValue { woof_count: U32::new(0), postal_code: U16::new(12045) }
            .as_bytes(),
    );
    dogs.insert("klaus", klaus_value)?;

    let cats = db.open_tree(b"cats")?;

    let mut laser_cat_value = vec![];
    laser_cat_value.extend_from_slice(
        CatValue {
            favorite_number: U64::new(11),
            battles_won: U64::new(321231321),
        }
        .as_bytes(),
    );
    laser_cat_value.extend_from_slice(b"science zone");
    cats.insert("laser cat", laser_cat_value)?;

    let mut pulsar_cat_value = vec![];
    pulsar_cat_value.extend_from_slice(
        CatValue {
            favorite_number: U64::new(11),
            battles_won: U64::new(321231321),
        }
        .as_bytes(),
    );
    pulsar_cat_value.extend_from_slice(b"science zone");
    cats.insert("pulsar cat", pulsar_cat_value)?;

    let mut fluffy_value = vec![];
    fluffy_value.extend_from_slice(
        CatValue {
            favorite_number: U64::new(11),
            battles_won: U64::new(321231321),
        }
        .as_bytes(),
    );
    fluffy_value.extend_from_slice(b"bowling alley");
    cats.insert("fluffy", fluffy_value)?;

    Ok(())
}

fn hash_join(db: &sled::Db) -> sled::Result<()> {
    // here we will try to find cats and dogs who
    // live in the same home.

    let cats = db.open_tree(b"cats")?;
    let dogs = db.open_tree(b"dogs")?;

    let mut join = std::collections::HashMap::new();

    for name_value_res in &cats {
        // cats are stored as name -> favorite_number + battles_won + home name variable bytes
        let (name, value_bytes) = name_value_res?;
        let (_, home_name): (LayoutVerified<&[u8], CatValue>, &[u8]) =
            LayoutVerified::new_from_prefix(&*value_bytes).unwrap();
        let (ref mut cat_names, _dog_names) =
            join.entry(home_name.to_vec()).or_insert((vec![], vec![]));
        cat_names.push(std::str::from_utf8(&*name).unwrap().to_string());
    }

    for name_value_res in &dogs {
        // dogs are stored as name -> home name variable bytes + woof count + postal code
        let (name, value_bytes) = name_value_res?;

        // note that this is reversed from the cat example above, where
        // the variable bytes are at the other end of the value, and are
        // extracted using new_from_prefix instead of new_from_suffix.
        let (home_name, _dog_value): (_, LayoutVerified<&[u8], DogValue>) =
            LayoutVerified::new_from_suffix(&*value_bytes).unwrap();

        if let Some((_cat_names, ref mut dog_names)) = join.get_mut(home_name) {
            dog_names.push(std::str::from_utf8(&*name).unwrap().to_string());
        }
    }

    for (home, (cats, dogs)) in join {
        println!(
            "the cats {:?} and the dogs {:?} live in the same home of {}",
            cats,
            dogs,
            std::str::from_utf8(&home).unwrap()
        );
    }

    Ok(())
}

fn main() -> sled::Result<()> {
    let db = sled::open("my_database")?;
    upsert(&db)?;
    variable_lengths(&db)?;
    hash_join(&db)?;

    Ok(())
}
<commit_msg>Update structured.rs<commit_after>//! This example demonstrates how to work with structured
//! keys and values without paying expensive (de)serialization
//! costs.
//!
//! The `upsert` function shows how to use structured keys and values.
//!
//! The `variable_lengths` function shows how to put a variable length
//! component in either the beginning or the end of your value.
//!
//! The `hash_join` function shows how to do some SQL-like joins.
//!
//! Running this example several times via `cargo run --example structured`
//! will initialize the count field to 0, and on subsequent runs it will
//! increment it.
use {
    byteorder::{BigEndian, LittleEndian},
    zerocopy::{
        byteorder::U64, AsBytes, FromBytes, LayoutVerified, Unaligned, U16, U32,
    },
};

fn upsert(db: &sled::Db) -> sled::Result<()> {
    // We use `BigEndian` for key types because
    // they preserve lexicographic ordering,
    // which is nice if we ever want to iterate
    // over our items in order. We use the
    // `U64` type from zerocopy because it
    // does not have alignment requirements.
    // sled does not guarantee any particular
    // value alignment as of now.
    #[derive(FromBytes, AsBytes, Unaligned)]
    #[repr(C)]
    struct Key {
        a: U64<BigEndian>,
        b: U64<BigEndian>,
    }

    // We use `LittleEndian` for values because
    // it's possibly cheaper, but the difference
    // isn't likely to be measurable, so honestly
    // use whatever you want for values.
    #[derive(FromBytes, AsBytes, Unaligned)]
    #[repr(C)]
    struct Value {
        count: U64<LittleEndian>,
        whatever: [u8; 16],
    }

    let key = Key { a: U64::new(21), b: U64::new(890) };

    // "UPSERT" functionality
    db.update_and_fetch(key.as_bytes(), |value_opt| {
        if let Some(existing) = value_opt {
            // We need to make a copy that will be written back
            // into the database. This allows other threads that
            // may have witnessed the old version to keep working
            // without taking out any locks. IVec will be
            // stack-allocated until it reaches 22 bytes
            let mut backing_bytes = sled::IVec::from(existing);

            // this verifies that our value is the correct length
            // and alignment (in this case we don't need it to be
            // aligned, because we use the `U64` type from zerocopy)
            let layout: LayoutVerified<&mut [u8], Value> =
                LayoutVerified::new_unaligned(&mut *backing_bytes)
                    .expect("bytes do not fit schema");

            // this lets us work with the underlying bytes as
            // a mutable structured value.
            let value: &mut Value = layout.into_mut();

            let new_count = value.count.get() + 1;

            println!("incrementing count to {}", new_count);

            value.count.set(new_count);

            Some(backing_bytes)
        } else {
            println!("setting count to 0");

            Some(sled::IVec::from(
                Value { count: U64::new(0), whatever: [0; 16] }.as_bytes(),
            ))
        }
    })?;

    Ok(())
}

// Cat values will be:
// favorite_number + battles_won + <home name variable bytes>
#[derive(FromBytes, AsBytes, Unaligned)]
#[repr(C)]
struct CatValue {
    favorite_number: U64<LittleEndian>,
    battles_won: U64<LittleEndian>,
}

// Dog values will be:
// <home name variable bytes> + woof_count + postal_code
#[derive(FromBytes, AsBytes, Unaligned)]
#[repr(C)]
struct DogValue {
    woof_count: U32<LittleEndian>,
    postal_code: U16<LittleEndian>,
}

fn variable_lengths(db: &sled::Db) -> sled::Result<()> {
    // here we will show how we can use zerocopy for inserting
    // fixed-size components, mixed with variable length
    // records on the end or beginning.

    // the hash_join example below shows how to read items
    // out in a way that accounts for the variable portion,
    // using `zerocopy::LayoutVerified::{new_from_prefix, new_from_suffix}`

    let dogs = db.open_tree(b"dogs")?;

    let mut dog2000_value = vec![];
    dog2000_value.extend_from_slice(b"science zone");
    dog2000_value.extend_from_slice(
        DogValue { woof_count: U32::new(666), postal_code: U16::new(42) }
            .as_bytes(),
    );
    dogs.insert("dog2000", dog2000_value)?;

    let mut zed_pup_value = vec![];
    zed_pup_value.extend_from_slice(b"bowling alley");
    zed_pup_value.extend_from_slice(
        DogValue { woof_count: U32::new(32113231), postal_code: U16::new(0) }
            .as_bytes(),
    );
    dogs.insert("zed pup", zed_pup_value)?;

    // IMPORTANT NOTE: German dogs eat food called "barf"
    let mut klaus_value = vec![];
    klaus_value.extend_from_slice(b"barf shop");
    klaus_value.extend_from_slice(
        DogValue { woof_count: U32::new(0), postal_code: U16::new(12045) }
            .as_bytes(),
    );
    dogs.insert("klaus", klaus_value)?;

    let cats = db.open_tree(b"cats")?;

    let mut laser_cat_value = vec![];
    laser_cat_value.extend_from_slice(
        CatValue {
            favorite_number: U64::new(11),
            battles_won: U64::new(321231321),
        }
        .as_bytes(),
    );
    laser_cat_value.extend_from_slice(b"science zone");
    cats.insert("laser cat", laser_cat_value)?;

    let mut pulsar_cat_value = vec![];
    pulsar_cat_value.extend_from_slice(
        CatValue {
            favorite_number: U64::new(11),
            battles_won: U64::new(321231321),
        }
        .as_bytes(),
    );
    pulsar_cat_value.extend_from_slice(b"science zone");
    cats.insert("pulsar cat", pulsar_cat_value)?;

    let mut fluffy_value = vec![];
    fluffy_value.extend_from_slice(
        CatValue {
            favorite_number: U64::new(11),
            battles_won: U64::new(321231321),
        }
        .as_bytes(),
    );
    fluffy_value.extend_from_slice(b"bowling alley");
    cats.insert("fluffy", fluffy_value)?;

    Ok(())
}

fn hash_join(db: &sled::Db) -> sled::Result<()> {
    // here we will try to find cats and dogs who
    // live in the same home.

    let cats = db.open_tree(b"cats")?;
    let dogs = db.open_tree(b"dogs")?;

    let mut join = std::collections::HashMap::new();

    for name_value_res in &cats {
        // cats are stored as name -> favorite_number + battles_won + home name variable bytes
        let (name, value_bytes) = name_value_res?;
        let (_, home_name): (LayoutVerified<&[u8], CatValue>, &[u8]) =
            LayoutVerified::new_from_prefix(&*value_bytes).unwrap();
        let (ref mut cat_names, _dog_names) =
            join.entry(home_name.to_vec()).or_insert((vec![], vec![]));
        cat_names.push(std::str::from_utf8(&*name).unwrap().to_string());
    }

    for name_value_res in &dogs {
        // dogs are stored as name -> home name variable bytes + woof count + postal code
        let (name, value_bytes) = name_value_res?;

        // note that this is reversed from the cat example above, where
        // the variable bytes are at the other end of the value, and are
        // extracted using new_from_prefix instead of new_from_suffix.
        let (home_name, _dog_value): (_, LayoutVerified<&[u8], DogValue>) =
            LayoutVerified::new_from_suffix(&*value_bytes).unwrap();

        if let Some((_cat_names, ref mut dog_names)) = join.get_mut(home_name) {
            dog_names.push(std::str::from_utf8(&*name).unwrap().to_string());
        }
    }

    for (home, (cats, dogs)) in join {
        println!(
            "the cats {:?} and the dogs {:?} live in the same home of {}",
            cats,
            dogs,
            std::str::from_utf8(&home).unwrap()
        );
    }

    Ok(())
}

fn main() -> sled::Result<()> {
    let db = sled::open("my_database")?;
    upsert(&db)?;
    variable_lengths(&db)?;
    hash_join(&db)?;

    Ok(())
}
<|endoftext|>


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

// this file defines CGFloat, as well as stubbed data types.

#![allow(non_camel_case_types)]

use libc;

#[cfg(target_pointer_width = "32")]
pub type boolean_t = i32;
#[cfg(target_pointer_width = "64")]
pub type boolean_t = u32;

// TODO: this is actually a libc::c_float on 32bit
pub type CGFloat = libc::c_double;
pub type CGError = libc::int32_t;

pub type CGAffineTransform = ();

pub const kCGImageAlphaNone: u32 = 0;
pub const kCGImageAlphaPremultipliedLast: u32 = 1;
pub const kCGImageAlphaPremultipliedFirst: u32 = 2;
pub const kCGImageAlphaLast: u32 = 3;
pub const kCGImageAlphaFirst: u32 = 4;
pub const kCGImageAlphaNoneSkipLast: u32 = 5;
pub const kCGImageAlphaNoneSkipFirst: u32 = 6;

<commit_msg>Auto merge of #42 - SSheldon:float_typedef, r=metajack<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// this file defines CGFloat, as well as stubbed data types.

#![allow(non_camel_case_types)]

use libc;

#[cfg(any(target_arch = "x86",
          target_arch = "arm",
          target_arch = "aarch64"))]
pub type boolean_t = libc::c_int;
#[cfg(target_arch = "x86_64")]
pub type boolean_t = libc::c_uint;

#[cfg(target_pointer_width = "64")]
pub type CGFloat = libc::c_double;
#[cfg(not(target_pointer_width = "64"))]
pub type CGFloat = libc::c_float;

pub type CGError = libc::int32_t;

pub type CGAffineTransform = ();

pub const kCGImageAlphaNone: u32 = 0;
pub const kCGImageAlphaPremultipliedLast: u32 = 1;
pub const kCGImageAlphaPremultipliedFirst: u32 = 2;
pub const kCGImageAlphaLast: u32 = 3;
pub const kCGImageAlphaFirst: u32 = 4;
pub const kCGImageAlphaNoneSkipLast: u32 = 5;
pub const kCGImageAlphaNoneSkipFirst: u32 = 6;

<|endoftext|>


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

use libc::c_char;
use libc;

use std::ffi::CString;
use std::mem;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
#[allow(non_camel_case_types)]
pub type id = libc::intptr_t;

#[cfg(target_pointer_width = "32")]
pub type NSInteger = libc::c_int;
#[cfg(target_pointer_width = "32")]
pub type NSUInteger = libc::c_uint;

#[cfg(target_pointer_width = "64")]
pub type NSInteger = libc::c_long;
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = libc::c_ulong;

#[allow(non_upper_case_globals)]
pub const nil: id = 0;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *const libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *const libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
                         types: *const libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *const libc::c_char, value: *mut libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *const libc::c_char, outValue: *mut *mut libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *const libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *const libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL, ...) -> id;
    pub fn objc_msgSend_stret(theReceiver: id, theSelector: SEL, ...);
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *const libc::c_char) -> SEL;
}

/// Returns an Objective-C message send function that returns a type `T`.
pub unsafe fn msg_send<T>() -> extern fn(theReceiver: id, theSelector: SEL, ...) -> T {
    mem::transmute(objc_msgSend)
}

pub unsafe fn msg_send_stret<T>() -> extern fn(theReceiver: id, theSelector: SEL, ...) -> T {
    mem::transmute(objc_msgSend_stret)
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    let name_c_str = CString::from_slice(name.as_bytes());
    unsafe {
        objc_getClass(name_c_str.as_ptr())
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    let name_c_str = CString::from_slice(name.as_bytes());
    unsafe {
        sel_registerName(name_c_str.as_ptr())
    }
}

#[cfg(test)]
mod test {
    use libc;
    use std::ffi::CString;
    use super::*;

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp: id = msg_send()(class("NSApplication"), selector("sharedApplication"));
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let ns_object = class("NSObject");
        let name_c_str = CString::from_slice("MyObject".as_bytes());
        let my_object = unsafe {
            objc_allocateClassPair(ns_object, name_c_str.as_ptr(), 0 as libc::size_t)
        };

        let doSomething = selector("doSomething");
        let types_c_str = CString::from_slice("@@:".as_bytes());
        unsafe {
            let _ = class_addMethod(my_object, doSomething, MyObject_doSomething,
                                    types_c_str.as_ptr());

            objc_registerClassPair(my_object);

            let mut obj: id = msg_send()(my_object, selector("alloc"));
            obj = msg_send()(obj, selector("init"));
            let _: () = msg_send()(obj, selector("doSomething"));
        }
    }
}
<commit_msg>Add Nil<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc::c_char;
use libc;

use std::ffi::CString;
use std::mem;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
#[allow(non_camel_case_types)]
pub type id = libc::intptr_t;

#[cfg(target_pointer_width = "32")]
pub type NSInteger = libc::c_int;
#[cfg(target_pointer_width = "32")]
pub type NSUInteger = libc::c_uint;

#[cfg(target_pointer_width = "64")]
pub type NSInteger = libc::c_long;
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = libc::c_ulong;

#[allow(non_upper_case_globals)]
pub const nil: id = 0;
#[allow(non_upper_case_globals)]
pub const Nil: Class = 0 as Class;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *const libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *const libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
                         types: *const libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *const libc::c_char, value: *mut libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *const libc::c_char, outValue: *mut *mut libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *const libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *const libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL, ...) -> id;
    pub fn objc_msgSend_stret(theReceiver: id, theSelector: SEL, ...);
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *const libc::c_char) -> SEL;
}

/// Returns an Objective-C message send function that returns a type `T`.
pub unsafe fn msg_send<T>() -> extern fn(theReceiver: id, theSelector: SEL, ...) -> T {
    mem::transmute(objc_msgSend)
}

pub unsafe fn msg_send_stret<T>() -> extern fn(theReceiver: id, theSelector: SEL, ...) -> T {
    mem::transmute(objc_msgSend_stret)
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    let name_c_str = CString::from_slice(name.as_bytes());
    unsafe {
        objc_getClass(name_c_str.as_ptr())
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    let name_c_str = CString::from_slice(name.as_bytes());
    unsafe {
        sel_registerName(name_c_str.as_ptr())
    }
}

#[cfg(test)]
mod test {
    use libc;
    use std::ffi::CString;
    use super::*;

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp: id = msg_send()(class("NSApplication"), selector("sharedApplication"));
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let ns_object = class("NSObject");
        let name_c_str = CString::from_slice("MyObject".as_bytes());
        let my_object = unsafe {
            objc_allocateClassPair(ns_object, name_c_str.as_ptr(), 0 as libc::size_t)
        };

        let doSomething = selector("doSomething");
        let types_c_str = CString::from_slice("@@:".as_bytes());
        unsafe {
            let _ = class_addMethod(my_object, doSomething, MyObject_doSomething,
                                    types_c_str.as_ptr());

            objc_registerClassPair(my_object);

            let mut obj: id = msg_send()(my_object, selector("alloc"));
            obj = msg_send()(obj, selector("init"));
            let _: () = msg_send()(obj, selector("doSomething"));
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::collections::VecDeque;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};

extern crate xorshift;
use xorshift::{Rng, SeedableRng, Xorshift128};
type BoardRng = Xorshift128;

extern crate rand;
use rand::prelude::SliceRandom;

extern crate time;
use time::precise_time_ns;

use std::cmp;

extern crate atoi;
use atoi::atoi;

extern crate itertools;
use itertools::Itertools;

use std::rc::Rc;

#[derive(PartialEq,Eq,Debug,Clone)]
pub struct Pos {
	y: i8,
	x: i8
}

impl Hash for Pos {
	fn hash<H: Hasher>(&self,state: &mut H) {
		self.y.hash(state);
		self.x.hash(state);
	}
}

#[derive(Debug)]
struct WallPos {
	y: i8,
	x: i8,
	d: i8
}

#[derive(Debug)]
pub struct Board {
	w: usize,
	h: usize,
	walls: Vec<WallPos>,
	walldist: Vec<Vec<Vec<usize>>>,
	robots: Vec<Pos>,
}

const DIRECTIONS: [Pos; 4] = [
	(Pos{y: 1,x: 0}),
	(Pos{y: 0,x: 1}),
	(Pos{y: -1,x: 0}),
	(Pos{y: 0,x: -1})
];

impl Board {
	fn good_board(&mut self) -> bool {
		let mut gone = vec![vec![false;self.w];self.h];

		fn dfs<'a>(gone: &'a mut Vec<Vec<bool>>,self_: &'a Board,y: usize, x: usize) -> usize {
			//println!("{} {}",y,x);
			if gone[y][x] { return 0; }
			gone[y][x] = true;
			let mut res = 1;
			for i in 0..4 {
				if self_.walldist[y][x][i]<=0 {
					continue;
				}
				let ty = (y as i8 + DIRECTIONS[i].y) as usize;
				let tx = (x as i8 + DIRECTIONS[i].x) as usize;
				if ty < self_.h && tx < self_.w {
					res += dfs(gone,self_,ty,tx);
				}
			}
			return res;
		}

		let cn = dfs(&mut gone,self,0,0);
		//println!("{}",cn);
		if cn != self.h * self.w {
			// all cells aren't connected
			return false;
		}

		//println!("{:?}",self.board);

		for y in 0..self.h {
			for x in 0..self.w {
				let mut d = 0;
				for i in 0..4 {
					if self.walldist[y][x][i]>0 {
						d += 1;
					}
				}
				//println!("{}",d);
				if d < 2 {
					// This cell is not interesting.
					return false;
				}
			}
		}

		return true;
	}

	fn init(&mut self,mut rng: BoardRng,wall_num: usize){
		self.walldist = vec![vec![vec![];self.w];self.h];

		//println!("{} {} {} {}",self.board.len(), self.h, self.board[0].len(), self.w);
		println!("{}",rng.gen_range(0,1000));
		for y in 0..self.h {
			for x in 0..self.w {
				self.walldist[y][x] = vec![self.h-1-y,self.w-1-x,y,x];
			}
		}

		for _ in 0..wall_num {
			let mem_walldist = self.walldist.clone();
			let mut add_walls = vec![];
			let cy = rng.gen_range(0,self.h);
			let cx = rng.gen_range(0,self.w);
			{
				let y = cy + rng.gen_range(0,2);
				let x = cx;
				if 0 < y && y < self.h {
					add_walls.push(WallPos{y: y as i8, x: x as i8, d: 0});

					for ty in 0..y {
						self.walldist[ty][x][0] = cmp::min(y-1-ty,self.walldist[ty][x][0]);
					}
					for ty in y..self.h {
						self.walldist[ty][x][2] = cmp::min(ty-y,self.walldist[ty][x][2]);
					}
				}
			}
			{
				let y = cy;
				let x = cx + rng.gen_range(0,2);
				if 0 < x && x < self.w {
					add_walls.push(WallPos{y: y as i8, x: x as i8, d: 1});
					for tx in 0..x {
						self.walldist[y][tx][1] = cmp::min(x-1-tx,self.walldist[y][tx][1]);
					}
					for tx in x..self.w {
						self.walldist[y][tx][3] = cmp::min(tx-x,self.walldist[y][tx][3]);
					}
				}
			}

			if self.good_board() {
				println!("add walls {:?}",add_walls);
				self.walls.append(&mut add_walls);
			}
			else{
				self.walldist = mem_walldist;
			}
		}

		let mut i = 0;
		while i < 4 {
			let tp = Pos{y: rng.gen_range(0,self.h) as i8, x: rng.gen_range(0,self.w) as i8};
			let mut ok = true;
			for j in 0..i {
				ok &= tp != self.robots[j];
			}
			if ok {
				self.robots.push(tp);
				i += 1;
			}
		}
	}
  pub fn new(board_h: usize,board_w: usize,rng: BoardRng,wall_num: usize) -> Board {
  	let mut res = Board {w: board_w, h: board_h, walls: vec![],walldist: vec![], robots: vec![]};
		res.init(rng,wall_num);
  	return res;
  }
}

#[derive(Debug,Clone,Copy)]
pub struct Move{
	c: usize,
	d: usize
}

struct SinglyLinkedListNode{
	v: Move,
	next: Option<Rc<SinglyLinkedListNode>>
}

struct SinglyLinkedList {
	head: Option<Rc<SinglyLinkedListNode>>
}

impl SinglyLinkedList{
	pub fn nil() -> SinglyLinkedList {
		//SinglyLinkedList{node: SinglyLinkedList_data::Nil}
		SinglyLinkedList{head: None}
	}
	fn cons(&self,data: Move) -> SinglyLinkedList {
   	SinglyLinkedList{head: Some(Rc::new(
   		SinglyLinkedListNode {
   			v: data, next: self.head.clone()
   		}
   	))}
	 	//SinglyLinkedList{node: Some(Box::new((self,data)))}
  	//SinglyLinkedList{node: SinglyLinkedList_data::Cons(Box::new(&self.node),data)}
  }

  fn to_vec(&self) -> Vec<Move> {
  	let mut res = vec![];
  	let mut head = &self.head;
  	while let Some(ref p) = head {
			res.push(p.v);
			head = &p.next;
  	}
  	return res;
  }
}

struct State<'a> {
	bo: &'a Board,
	robots: Vec<Pos>,
	log: SinglyLinkedList
}

impl<'a> State<'a> {
	pub fn init_state(bo:&'a Board,_log: SinglyLinkedList) -> State<'a> {
		State{bo: &bo,robots: bo.robots.clone(), log: SinglyLinkedList::nil()}
	}

	fn move_to(&self,robot_index: usize, robot_dir: usize) -> Option<State<'a>>{
		let dir = &DIRECTIONS[robot_dir];
		let mut p = self.robots[robot_index].clone();
		let mut mind = self.bo.walldist[p.y as usize][p.x as usize][robot_dir] as i8;
		for j in 0..4 {
			if j != robot_index {
				let dx = self.robots[j].x - p.x;
				let dy = self.robots[j].y - p.y;
				if dx.signum() == dir.x.signum() && dy.signum() == dir.y.signum() {
					if dx.signum() == 0 {
						mind = cmp::min(mind,dy.abs()-1);
					}
					else {
						mind = cmp::min(mind,dx.abs()-1);
					}
				}
			}
		}

		if mind == 0 {
			return None
		}

		p = Pos{y: p.y + dir.y * mind, x: p.x + dir.x * mind};

		let tolog = self.log.cons(Move{c: robot_index,d: robot_dir});
		let mut res = State{bo: self.bo,robots: self.robots.clone(),log: tolog};
		res.robots[robot_index] = p;
		Some(res)
	}

	fn enumerate_states(&self) -> Vec<State<'a>> {
		let mut res = vec![];
		for i in 0..self.robots.len() {
			for j in 0..4 {
				if let Some(ts) = self.move_to(i,j) {
					res.push(ts);
				}
			}
		}
		//println!("add {} {}",self.robots.len() ,res.len());
		return res;
	}
}

impl<'a,'b> PartialEq for State<'a> {
	fn eq(&self,ts:&State) -> bool {
		return self.robots == ts.robots;
	}
}
impl<'a,'b> Eq for State<'a> {}

impl<'a,'b> Hash for State<'a> {
	fn hash<H: Hasher>(&self,state: &mut H) {
		self.robots.hash(state);
	}
}

pub fn bfs<'a,'b>(target: u8, bo:&'a Board) -> ((usize,Pos),Vec<Move>){
	//let log = &SinglyLinkedList::Nil;
	let log = SinglyLinkedList::nil();
	let init = State::init_state(&bo,log);
	let mut res = init.log.head.clone();
	let mut goal = (0,init.robots[0].clone());

	//let mut gone: HashSet<State,BuildHasherDefault<FnvHasher>> = HashSet::new();
	let mut gone: HashSet<State> = HashSet::new();

	let mut que = VecDeque::new();
	let mut depth = 0;
	que.push_back(Some(init));
	que.push_back(None);

	let mut found : Vec<Vec<Vec<bool>>> = vec![vec![vec![false;bo.robots.len()];bo.w];bo.h];
	let mut found_count = 0;

	let mut dnum = 1;
	while !que.is_empty() {
		match que.pop_front() {
			Some(Some(st)) => {
				if !gone.contains(&st) {
					dnum += 1;
					//println!("{:?}",st.robots);
					let mut ok = false;
					for i in 0..st.robots.len() {
						let p = &st.robots[i];
						if !found[p.y as usize][p.x as usize][i] {
							//println!("{} {} {} : {} ",p.y,p.x,i,depth);
							found[p.y as usize][p.x as usize][i] = true;
							found_count += 1;
							res = st.log.head.clone();
							goal = (i,p.clone());
							if depth >= target || found_count >= bo.h * bo.w * bo.robots.len() {
								ok = true;
								break;
							}
						}
					}
					if ok { break; }
					for ts in st.enumerate_states() {
						if !gone.contains(&ts) {
							//println!("{:?}",ts.robots);
							que.push_back(Some(ts));
						}
					}
					gone.insert(st);
				}
			},
			Some(None) => {
				depth += 1;
				if depth > target {
					break;
				}
				println!("{} {}",depth,dnum);
				dnum = 0;
				que.push_back(None);
			},
			None => {}
		}
	}

	//return None;
	let l = SinglyLinkedList{head: res};

	return (goal,l.to_vec());
	//return l.to_vec(); //SinglyLinkedList::to_vec(l);
}

fn main(){
	let args: Vec<String> = env::args().collect();
	let (depth,board_h,board_w,wall_num) = match args[1..5].into_iter().map(|x| atoi(x.as_bytes())).tuples().next()  {
		Some((Some(a),Some(b),Some(c),Some(d))) => (a,b,c,d),
		v => panic!("invalid argument. expect \"depth board_h board_w wall_num\", got {:?}.",v)
	};

	let now = precise_time_ns();
	let states = [now, now];
	let stdrng = SeedableRng::from_seed(&states[..]);
	let mut bo = Board::new(board_h,board_w,stdrng,wall_num);
	let ((mut goalcolour,goalpos),mut log) = bfs(depth as u8,&bo);

	//randomize colour
	let mut rng = rand::thread_rng();
	let mut perm: Vec<usize> = (0..bo.robots.len()).collect();
	perm.shuffle(&mut rng);
	let mut perminv: Vec<usize> = vec![0;perm.len()];
	for i in 0..perm.len() {
		perminv[perm[i]] = i;
	}

	goalcolour = perm[goalcolour];
	log = log.into_iter().map(|x| Move{c: perm[x.c],d: x.d}).rev().collect();
	bo.robots = (0..bo.robots.len()).map(|k| bo.robots[perminv[k]].clone()).collect();

	println!("{:?}",bo);
	println!("{:?}",goalcolour);
	println!("{:?}",goalpos);
	println!("{:?}",log);
}

<commit_msg>make a little faster by removing log generation<commit_after>use std::env;
use std::collections::VecDeque;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};

extern crate xorshift;
use xorshift::{Rng, SeedableRng, Xorshift128};
type BoardRng = Xorshift128;

extern crate rand;
use rand::prelude::SliceRandom;

extern crate time;
use time::precise_time_ns;

use std::cmp;

extern crate atoi;
use atoi::atoi;

extern crate itertools;
use itertools::Itertools;

#[derive(PartialEq,Eq,Debug,Clone)]
pub struct Pos {
	y: i8,
	x: i8
}

impl Hash for Pos {
	fn hash<H: Hasher>(&self,state: &mut H) {
		self.y.hash(state);
		self.x.hash(state);
	}
}

#[derive(Debug)]
struct WallPos {
	y: i8,
	x: i8,
	d: i8
}

#[derive(Debug)]
pub struct Board {
	w: usize,
	h: usize,
	walls: Vec<WallPos>,
	walldist: Vec<Vec<Vec<usize>>>,
	robots: Vec<Pos>,
}

const DIRECTIONS: [Pos; 4] = [
	(Pos{y: 1,x: 0}),
	(Pos{y: 0,x: 1}),
	(Pos{y: -1,x: 0}),
	(Pos{y: 0,x: -1})
];

impl Board {
	fn good_board(&mut self) -> bool {
		let mut gone = vec![vec![false;self.w];self.h];

		fn dfs<'a>(gone: &'a mut Vec<Vec<bool>>,self_: &'a Board,y: usize, x: usize) -> usize {
			//println!("{} {}",y,x);
			if gone[y][x] { return 0; }
			gone[y][x] = true;
			let mut res = 1;
			for i in 0..4 {
				if self_.walldist[y][x][i]<=0 {
					continue;
				}
				let ty = (y as i8 + DIRECTIONS[i].y) as usize;
				let tx = (x as i8 + DIRECTIONS[i].x) as usize;
				if ty < self_.h && tx < self_.w {
					res += dfs(gone,self_,ty,tx);
				}
			}
			return res;
		}

		let cn = dfs(&mut gone,self,0,0);
		//println!("{}",cn);
		if cn != self.h * self.w {
			// all cells aren't connected
			return false;
		}

		//println!("{:?}",self.board);

		for y in 0..self.h {
			for x in 0..self.w {
				let mut d = 0;
				for i in 0..4 {
					if self.walldist[y][x][i]>0 {
						d += 1;
					}
				}
				//println!("{}",d);
				if d < 2 {
					// This cell is not interesting.
					return false;
				}
			}
		}

		return true;
	}

	fn init(&mut self,mut rng: BoardRng,wall_num: usize){
		self.walldist = vec![vec![vec![];self.w];self.h];

		//println!("{} {} {} {}",self.board.len(), self.h, self.board[0].len(), self.w);
		println!("{}",rng.gen_range(0,1000));
		for y in 0..self.h {
			for x in 0..self.w {
				self.walldist[y][x] = vec![self.h-1-y,self.w-1-x,y,x];
			}
		}

		for _ in 0..wall_num {
			let mem_walldist = self.walldist.clone();
			let mut add_walls = vec![];
			let cy = rng.gen_range(0,self.h);
			let cx = rng.gen_range(0,self.w);
			{
				let y = cy + rng.gen_range(0,2);
				let x = cx;
				if 0 < y && y < self.h {
					add_walls.push(WallPos{y: y as i8, x: x as i8, d: 0});

					for ty in 0..y {
						self.walldist[ty][x][0] = cmp::min(y-1-ty,self.walldist[ty][x][0]);
					}
					for ty in y..self.h {
						self.walldist[ty][x][2] = cmp::min(ty-y,self.walldist[ty][x][2]);
					}
				}
			}
			{
				let y = cy;
				let x = cx + rng.gen_range(0,2);
				if 0 < x && x < self.w {
					add_walls.push(WallPos{y: y as i8, x: x as i8, d: 1});
					for tx in 0..x {
						self.walldist[y][tx][1] = cmp::min(x-1-tx,self.walldist[y][tx][1]);
					}
					for tx in x..self.w {
						self.walldist[y][tx][3] = cmp::min(tx-x,self.walldist[y][tx][3]);
					}
				}
			}

			if self.good_board() {
				println!("add walls {:?}",add_walls);
				self.walls.append(&mut add_walls);
			}
			else{
				self.walldist = mem_walldist;
			}
		}

		let mut i = 0;
		while i < 4 {
			let tp = Pos{y: rng.gen_range(0,self.h) as i8, x: rng.gen_range(0,self.w) as i8};
			let mut ok = true;
			for j in 0..i {
				ok &= tp != self.robots[j];
			}
			if ok {
				self.robots.push(tp);
				i += 1;
			}
		}
	}
  pub fn new(board_h: usize,board_w: usize,rng: BoardRng,wall_num: usize) -> Board {
  	let mut res = Board {w: board_w, h: board_h, walls: vec![],walldist: vec![], robots: vec![]};
		res.init(rng,wall_num);
  	return res;
  }
}

#[derive(Debug,Clone,Copy)]
pub struct Move{
	c: usize,
	d: usize
}

struct State<'a> {
	bo: &'a Board,
	robots: Vec<Pos>,
	//log: SinglyLinkedList
	log: usize
}

impl<'a> State<'a> {
	pub fn init_state(bo:&'a Board) -> State<'a> {
		//State{bo: &bo,robots: bo.robots.clone(), log: SinglyLinkedList::nil()}
		State{bo: &bo,robots: bo.robots.clone(), log: 1}
	}

	fn move_to(&self,robot_index: usize, robot_dir: usize) -> Option<State<'a>>{
		let dir = &DIRECTIONS[robot_dir];
		let mut p = self.robots[robot_index].clone();
		let mut mind = self.bo.walldist[p.y as usize][p.x as usize][robot_dir] as i8;
		//removing "as i8" by changing type of walldist doesn't make well difference.

		// if mind == 0 { return None } //pruning with little (0.2~3sec) speedup.
		/*
		if robot_dir == 2 {
			for j in 0..4 {
				if j != robot_index {
					if self.robots[j].x == p.x && self.robots[j].y < p.y {
						mind = cmp::min(mind,p.y - self.robots[j].y - 1);
					}
				}
			}
		} else if robot_dir == 0 {
			for j in 0..4 {
				if j != robot_index {
					if self.robots[j].x == p.x && self.robots[j].y > p.y {
						mind = cmp::min(mind,self.robots[j].y - p.y - 1);
					}
				}
			}
		} else {
			for j in 0..4 {
				if j != robot_index {
					let dx = self.robots[j].x - p.x;
					if dx.signum() == dir.x.signum() && self.robots[j].y == p.y {
						mind = cmp::min(mind,dx.abs()-1);
					}
				}
			}
		}
		//unloling also has little speedup (0.2~0.3 sec)
		*/
		for j in 0..4 {
			if j != robot_index {
				let dx = self.robots[j].x - p.x;
				let dy = self.robots[j].y - p.y;
				if dx.signum() == dir.x.signum() && dy.signum() == dir.y.signum() {
					if dx.signum() == 0 {
						mind = cmp::min(mind,dy.abs()-1);
					} else {
						mind = cmp::min(mind,dx.abs()-1);
					}
				}
			}
		}

		if mind == 0 {
			return None
		}

		p = Pos{y: p.y + dir.y * mind, x: p.x + dir.x * mind};

		let tolog = self.log << 4 | robot_index << 2 | robot_dir; //self.log.cons(Move{c: robot_index,d: robot_dir});
		let mut res = State{bo: self.bo,robots: self.robots.clone(),log: tolog};
		res.robots[robot_index] = p;
		Some(res)
	}

	fn enumerate_states(&self) -> Vec<State<'a>> {
		let mut res = vec![];
		for i in 0..self.robots.len() {
			for j in 0..4 {
				if let Some(ts) = self.move_to(i,j) {
					res.push(ts);
				}
			}
		}
		return res;
	}
}

impl<'a> PartialEq for State<'a> {
	fn eq(&self,ts:&State) -> bool {
		return self.robots == ts.robots;
	}
}
impl<'a> Eq for State<'a> {}

impl<'a> Hash for State<'a> {
	fn hash<H: Hasher>(&self,state: &mut H) {
		//Surprisingly, this makes program very slowly!
		//:thinking_face:
		//self.robots[0].y.hash(state);
		self.robots.hash(state);
	}
}

pub fn bfs<'a,'b>(target: u8, bo:&'a Board) -> ((usize,Pos),Vec<Move>){
	let init = State::init_state(&bo);
	//let mut res = init.log.head.clone();
	let mut res = init.log;
	let mut goal = (0,init.robots[0].clone());

	let mut gone: HashSet<State> = HashSet::new();
	//let mut gone: HashSet<Vec<Pos>> = HashSet::new();

	let mut que = VecDeque::new();
	let mut depth = 0;
	que.push_back(Some(init));
	que.push_back(None);

	let mut found : Vec<Vec<Vec<bool>>> = vec![vec![vec![false;bo.robots.len()];bo.w];bo.h];
	let mut found_count = 0;
	let max_pattern_num = bo.h * bo.w * bo.robots.len();

	let mut dnum = 1;
	while !que.is_empty() {
		match que.pop_front() {
			Some(Some(st)) => {
				if !gone.contains(&st) {
					dnum += 1;
					//println!("{:?}",st.robots);
					let mut ok = false;
					for i in 0..st.robots.len() {
						let p = &st.robots[i];
						if !found[p.y as usize][p.x as usize][i] {
							//println!("{} {} {} : {} ",p.y,p.x,i,depth);
							found[p.y as usize][p.x as usize][i] = true;
							found_count += 1;
							//res = st.log.head.clone();
							res = st.log;
							goal = (i,p.clone());
							if depth >= target || found_count >= max_pattern_num {
								ok = true;
								break;
							}
						}
					}
					if ok { break; }
					for ts in st.enumerate_states() {
						//moving gone.contains & gone.insert to here decreased speed.
						//I don't understand why this happened. :thinking_face:
						que.push_back(Some(ts));
					}
					gone.insert(st);
				}
			},
			Some(None) => {
				depth += 1;
				if depth > target {
					break;
				}
				println!("{} {}",depth,dnum);
				dnum = 0;
				que.push_back(None);
			},
			None => {}
		}
	}

	// Faster!!. Haee! 0.69s to 0.53s
	let mut l = vec![];
	while res > 1 {
		let c = (res & 12) >> 2;
		let d = res & 3;
		l.push(Move{c: c, d: d});
		res >>= 4;
	}

	return (goal,l);
	//let l = SinglyLinkedList{head: res};
	//return (goal,l.to_vec());
}

fn main(){
	let args: Vec<String> = env::args().collect();
	let (depth,board_h,board_w,wall_num) = match args[1..5].into_iter().map(|x| atoi(x.as_bytes())).tuples().next()  {
		Some((Some(a),Some(b),Some(c),Some(d))) => (a,b,c,d),
		v => panic!("invalid argument. expect \"depth board_h board_w wall_num\", got {:?}.",v)
	};

	let now = precise_time_ns();
	let states = [now, now];
	let stdrng = SeedableRng::from_seed(&states[..]);
	let mut bo = Board::new(board_h,board_w,stdrng,wall_num);
	let ((mut goalcolour,goalpos),mut log) = bfs(depth as u8,&bo);

	//randomize colour
	let mut rng = rand::thread_rng();
	let mut perm: Vec<usize> = (0..bo.robots.len()).collect();
	perm.shuffle(&mut rng);
	let mut perminv: Vec<usize> = vec![0;perm.len()];
	for i in 0..perm.len() {
		perminv[perm[i]] = i;
	}

	goalcolour = perm[goalcolour];
	log = log.into_iter().map(|x| Move{c: perm[x.c],d: x.d}).rev().collect();
	bo.robots = (0..bo.robots.len()).map(|k| bo.robots[perminv[k]].clone()).collect();

	println!("{:?}",bo);
	println!("{:?}",goalcolour);
	println!("{:?}",goalpos);
	println!("{:?}",log);
}

<|endoftext|>


<commit_before>use std::path::Path;
use std::fs::File;
use std::collections::HashMap;
use std::io::prelude::*;
use toml;
use serde::Serializer;
use serde_json;
use std::result::Result as StdResult;
use semver::Version;

use errors::*;

#[derive(Serialize, Debug)]
pub struct Manifest {
    pub metadata: Metadata,
    pub src: Vec<Src>,
    pub dependencies: Vec<Dependency>,
    pub dev_dependencies: Vec<Dependency>,
    pub targets: Vec<Target>,
}

#[derive(Serialize, Debug)]
pub struct Metadata {
    pub name: String,
    #[serde(serialize_with = "version_to_str")]
    pub version: Version,
    pub authors: Vec<String>,
}

#[derive(Serialize, Debug)]
pub struct Src {
    pub name: String,
    pub path: String,
    pub optional: bool,
}

#[derive(Serialize, Debug)]
pub struct Dependency {
    pub name: String,
    #[serde(serialize_with = "version_to_str")]
    pub version: Version,
    pub optional: bool,
}

#[derive(Serialize, Debug)]
pub struct Target {
    pub name: String,
    pub path: String,
    pub extension: String,
}

impl Manifest {
    pub fn load<P: AsRef<Path>>(file: P) -> Result<Manifest> {
        let mut file = File::open(file).chain_err(|| "Failed to open manifest")?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .chain_err(|| "Failed to read manifest")?;

        let raw: RawManifest = toml::from_str(contents.as_str())
            .chain_err(|| "Failed to parse manifest")?;

        let package_name = raw.package.name;

        let mut src = vec![];
        for (name, value) in raw.src.unwrap_or(HashMap::new()) {
            match value {
                toml::Value::String(path) => {
                    src.push(Src {
                                 name,
                                 path,
                                 optional: false,
                             });
                }
                toml::Value::Table(table) => {
                    src.push(Src {
                                 name,
                                 path: value_to_string(table
                                                           .get("path")
                                                           .ok_or("path is required for src")?)?,
                                 optional: table
                                     .get("optional")
                                     .unwrap_or(&toml::Value::Boolean(false))
                                     .as_bool()
                                     .ok_or("Failed to convert value to boolean")?,
                             });
                }
                _ => bail!("Incompatible type for src"),
            }
        }

        let dependencies = vec![];
        let dev_dependencies = vec![];

        let mut targets = vec![];
        for target in raw.targets.unwrap_or(vec![]) {
            targets.push(Target {
                             name: target.name.unwrap_or(package_name.clone()),
                             path: target.path,
                             extension: target.extension,
                         });
        }

        let parsed = Manifest {
            metadata: Metadata {
                name: package_name,
                version: Version::parse(raw.package.version.as_str())
                    .chain_err(|| "Invalid package version")?,
                authors: raw.package.authors,
            },
            src,
            dependencies,
            dev_dependencies,
            targets,
        };
        Ok(parsed)
    }

    pub fn to_json(&self) -> Result<String> {
        let json = serde_json::to_string_pretty(&self)
            .chain_err(|| "Failed to convert manifest to JSON")?;

        Ok(json)
    }
}

// Deserialize is intentionally loose for user benefit
// toml -> RawManifest -> Manifest

#[derive(Deserialize, Debug)]
struct RawManifest {
    package: RawPackage,
    src: Option<HashMap<String, toml::Value>>,
    dependencies: Option<HashMap<String, toml::Value>>,

    #[serde(rename = "dev-dependencies")]
    dev_dependencies: Option<HashMap<String, toml::Value>>,
    targets: Option<Vec<RawTarget>>,
}

#[derive(Deserialize, Debug)]
struct RawPackage {
    name: String,
    version: String, // TODO semver::Version
    authors: Vec<String>,
}

#[derive(Deserialize, Debug)]
struct RawTarget {
    name: Option<String>,
    path: String,

    // "type" is reserved, rename to extension
    #[serde(rename = "type")]
    extension: String,
}

fn value_to_string(value: &toml::Value) -> Result<String> {
    Ok(value
           .as_str()
           .ok_or("Failed to convert value to string")?
           .to_string())
}

fn version_to_str<S>(version: &Version, serializer: S) -> StdResult<S::Ok, S::Error>
    where S: Serializer
{
    serializer.serialize_str(version.to_string().as_str())
}
<commit_msg>Clean up fmt<commit_after>use std::path::Path;
use std::fs::File;
use std::collections::HashMap;
use std::io::prelude::*;
use toml;
use serde::Serializer;
use serde_json;
use std::result::Result as StdResult;
use semver::Version;

use errors::*;

#[derive(Serialize, Debug)]
pub struct Manifest {
    pub metadata: Metadata,
    pub src: Vec<Src>,
    pub dependencies: Vec<Dependency>,
    pub dev_dependencies: Vec<Dependency>,
    pub targets: Vec<Target>,
}

#[derive(Serialize, Debug)]
pub struct Metadata {
    pub name: String,
    #[serde(serialize_with = "version_to_str")]
    pub version: Version,
    pub authors: Vec<String>,
}

#[derive(Serialize, Debug)]
pub struct Src {
    pub name: String,
    pub path: String,
    pub optional: bool,
}

#[derive(Serialize, Debug)]
pub struct Dependency {
    pub name: String,
    #[serde(serialize_with = "version_to_str")]
    pub version: Version,
    pub optional: bool,
}

#[derive(Serialize, Debug)]
pub struct Target {
    pub name: String,
    pub path: String,
    pub extension: String,
}

impl Manifest {
    pub fn load<P: AsRef<Path>>(file: P) -> Result<Manifest> {
        let mut file = File::open(file).chain_err(|| "Failed to open manifest")?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .chain_err(|| "Failed to read manifest")?;

        let raw: RawManifest = toml::from_str(contents.as_str())
            .chain_err(|| "Failed to parse manifest")?;

        let package_name = raw.package.name;

        let mut src = vec![];
        for (name, value) in raw.src.unwrap_or(HashMap::new()) {
            match value {
                toml::Value::String(path) => {
                    src.push(Src {
                                 name,
                                 path,
                                 optional: false,
                             });
                }
                toml::Value::Table(table) => {
                    let path = table.get("path").ok_or("path is required for src")?;
                    let optional = table
                        .get("optional")
                        .unwrap_or(&toml::Value::Boolean(false));

                    src.push(Src {
                                 name,
                                 path: value_to_string(path)?,
                                 optional: optional
                                     .as_bool()
                                     .ok_or("Failed to convert optional to boolean")?,
                             });
                }
                _ => bail!("Incompatible type for src"),
            }
        }

        let dependencies = vec![];
        let dev_dependencies = vec![];

        let mut targets = vec![];
        for target in raw.targets.unwrap_or(vec![]) {
            targets.push(Target {
                             name: target.name.unwrap_or(package_name.clone()),
                             path: target.path,
                             extension: target.extension,
                         });
        }

        let parsed = Manifest {
            metadata: Metadata {
                name: package_name,
                version: Version::parse(raw.package.version.as_str())
                    .chain_err(|| "Invalid package version")?,
                authors: raw.package.authors,
            },
            src,
            dependencies,
            dev_dependencies,
            targets,
        };
        Ok(parsed)
    }

    pub fn to_json(&self) -> Result<String> {
        let json = serde_json::to_string_pretty(&self)
            .chain_err(|| "Failed to convert manifest to JSON")?;

        Ok(json)
    }
}

// Deserialize is intentionally loose for user benefit
// toml -> RawManifest -> Manifest

#[derive(Deserialize, Debug)]
struct RawManifest {
    package: RawPackage,
    src: Option<HashMap<String, toml::Value>>,
    dependencies: Option<HashMap<String, toml::Value>>,

    #[serde(rename = "dev-dependencies")]
    dev_dependencies: Option<HashMap<String, toml::Value>>,
    targets: Option<Vec<RawTarget>>,
}

#[derive(Deserialize, Debug)]
struct RawPackage {
    name: String,
    version: String, // TODO semver::Version
    authors: Vec<String>,
}

#[derive(Deserialize, Debug)]
struct RawTarget {
    name: Option<String>,
    path: String,

    // "type" is reserved, rename to extension
    #[serde(rename = "type")]
    extension: String,
}

fn value_to_string(value: &toml::Value) -> Result<String> {
    Ok(value
           .as_str()
           .ok_or("Failed to convert value to string")?
           .to_string())
}

fn version_to_str<S>(version: &Version, serializer: S) -> StdResult<S::Ok, S::Error>
    where S: Serializer
{
    serializer.serialize_str(version.to_string().as_str())
}
<|endoftext|>


<commit_before>// FIXME: If two macros in the same module have the same name
// (yes, that's a thing), rustdoc lists both of them on the index page,
// but only documents the first one on the page for the macro.
// Fortunately, this can only happen in document private items mode,
// but it still isn't ideal beahvior.
//
// See https://github.com/rust-lang/rust/pull/88019#discussion_r693920453
//
// compile-flags: --document-private-items

// @has macro_document_private_duplicate/index.html 'Doc 1.'
// @has macro_document_private_duplicate/macro.a_macro.html 'Doc 1.'
/// Doc 1.
macro_rules! a_macro {
    () => ()
}

// @has macro_document_private_duplicate/index.html 'Doc 2.'
// @!has macro_document_private_duplicate/macro.a_macro.html 'Doc 2.'
/// Doc 2.
macro_rules! a_macro {
    () => ()
}
<commit_msg>Disable a spuriously failing test<commit_after>// ignore-test (fails spuriously, see issue #89228)

// FIXME: If two macros in the same module have the same name
// (yes, that's a thing), rustdoc lists both of them on the index page,
// but only documents the first one on the page for the macro.
// Fortunately, this can only happen in document private items mode,
// but it still isn't ideal beahvior.
//
// See https://github.com/rust-lang/rust/pull/88019#discussion_r693920453
//
// compile-flags: --document-private-items

// @has macro_document_private_duplicate/index.html 'Doc 1.'
// @has macro_document_private_duplicate/macro.a_macro.html 'Doc 1.'
/// Doc 1.
macro_rules! a_macro {
    () => ()
}

// @has macro_document_private_duplicate/index.html 'Doc 2.'
// @!has macro_document_private_duplicate/macro.a_macro.html 'Doc 2.'
/// Doc 2.
macro_rules! a_macro {
    () => ()
}
<|endoftext|>


<commit_before>use crate::{
    Client, Result, error,
    proto::Version,
};
use futures::prelude::*;
use romio::TcpStream;
use byteorder::{ByteOrder, LittleEndian};
use serde::{Serialize, Deserialize};
use scram::client::{ScramClient, ServerFirst, ServerFinal};

const NULL_BYTE: u8 = b'\0';

#[derive(Debug)]
struct Session {
    id: u64,
    stream: TcpStream,
}

#[derive(Debug)]
pub struct Connection<'a> {
    client: Client<'a>,
    session: Session,
}

#[derive(Serialize, Deserialize, Debug)]
struct ServerInfo {
    success: bool,
    min_protocol_version: usize,
    max_protocol_version: usize,
    server_version: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct AuthRequest {
    protocol_version: i32,
    authentication_method: String,
    authentication: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct AuthResponse {
    success: bool,
    authentication: Option<String>,
    error_code: Option<usize>,
    error: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
struct AuthConfirmation {
    authentication: String,
}

struct HandShake<'a> {
    // this should be enough for the handshake messages
    buf: [u8; 128],
    conn: Connection<'a>,
}

impl<'a> Connection<'a> {
    pub(crate) async fn new(client: Client<'a>, id: u64) -> Result<Connection<'a>> {
        let cfg = client.config();
        let stream = await!(TcpStream::connect(cfg.server()))?;
        let session = Session { id, stream };
        let conn = Connection { client, session };
        let handshake = HandShake { conn, buf: [0u8; 128] };
        await!(handshake.greet())
    }
}

impl<'a> HandShake<'a> {
    async fn verify_version(&mut self) -> Result<&mut HandShake<'a>> {
        LittleEndian::write_u32(&mut self.buf, Version::V1_0 as u32);
        await!(self.conn.session.stream.write_all(&self.buf[..4]))?;
        await!(self.conn.session.stream.read(&mut self.buf))?;
        let resp = self.read_buf();
        let info: ServerInfo = serde_json::from_slice(resp)?;
        if !info.success {
            return Err(error::Runtime::Internal(resp.to_owned()))?;
        }
        Ok(self)
    }

    async fn greet(mut self) -> Result<Connection<'a>> {
        await!(self.verify_version())?;

        // Send client first message
        let cfg = &self.conn.client.config();
        let scram = ScramClient::new(cfg.user(), cfg.password(), None)?;
        let (scram, msg) = client_first(scram)?;
        await!(self.conn.session.stream.write_all(&msg))?;

        // Send client final message
        await!(self.conn.session.stream.read(&mut self.buf))?;
        let info = AuthResponse::from_slice(self.read_buf())?;
        match info.authentication {
            Some(ref auth) => {
                let (scram, msg) = client_final(scram, auth)?;
                await!(self.conn.session.stream.write_all(&msg))?;
                await!(self.conn.session.stream.read(&mut self.buf))?;
                server_final(scram, self.read_buf())?;
                await!(self.conn.session.stream.flush())?;
            }
            None => {
                let msg = String::from("Server did not send authentication info.");
                return Err(error::Driver::Other(msg))?;
            }
        }

        Ok(self.conn)
    }

    fn read_buf(&self) -> &[u8] {
        let len = self.buf.iter()
            .take_while(|x| **x != NULL_BYTE)
            .count();
        &self.buf[..len]
    }
}

impl AuthResponse {
    fn from_slice(resp: &[u8]) -> Result<Self> {
        let info: AuthResponse = serde_json::from_slice(resp)?;
        if !info.success {
            // If error code is between 10 and 20, this is an auth error
            if let Some(10...20) = info.error_code {
                if let Some(msg) = info.error {
                    return Err(error::Driver::Auth(msg))?;
                }
            }
            return Err(error::Runtime::Internal(resp.to_owned()))?;
        };
        Ok(info)
    }
}

fn client_first<'a>(scram: ScramClient<'a>) -> Result<(ServerFirst<'a>, Vec<u8>)> {
    let (scram, client_first) = scram.client_first();
    let ar = AuthRequest {
        protocol_version: 0,
        authentication_method: String::from("SCRAM-SHA-256"),
        authentication: client_first,
    };
    let mut msg = serde_json::to_vec(&ar)?;
    msg.push(NULL_BYTE);
    Ok((scram, msg))
}

fn client_final<'a>(scram: ServerFirst<'a>, auth: &str) -> Result<(ServerFinal, Vec<u8>)> {
    let scram = scram.handle_server_first(auth)?;
    let (scram, client_final) = scram.client_final();
    let conf = AuthConfirmation { authentication: client_final };
    let mut msg = serde_json::to_vec(&conf)?;
    msg.push(NULL_BYTE);
    Ok((scram, msg))
}

fn server_final(scram: ServerFinal, resp: &[u8]) -> Result<()> {
    let info = AuthResponse::from_slice(resp)?;
    if let Some(auth) = info.authentication {
        if let Err(err) = scram.handle_server_final(&auth) {
            return Err(err)?;
        }
    }
    Ok(())
}
<commit_msg>track broken sessions<commit_after>use crate::{
    Client, Result, error,
    proto::Version,
};
use futures::prelude::*;
use romio::TcpStream;
use byteorder::{ByteOrder, LittleEndian};
use serde::{Serialize, Deserialize};
use scram::client::{ScramClient, ServerFirst, ServerFinal};

const NULL_BYTE: u8 = b'\0';

#[derive(Debug)]
struct Session {
    id: u64,
    broken: bool,
    stream: TcpStream,
}

#[derive(Debug)]
pub struct Connection<'a> {
    client: Client<'a>,
    session: Session,
}

#[derive(Serialize, Deserialize, Debug)]
struct ServerInfo {
    success: bool,
    min_protocol_version: usize,
    max_protocol_version: usize,
    server_version: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct AuthRequest {
    protocol_version: i32,
    authentication_method: String,
    authentication: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct AuthResponse {
    success: bool,
    authentication: Option<String>,
    error_code: Option<usize>,
    error: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
struct AuthConfirmation {
    authentication: String,
}

struct HandShake<'a> {
    // this should be enough for the handshake messages
    buf: [u8; 128],
    conn: Connection<'a>,
}

impl<'a> Connection<'a> {
    pub(crate) async fn new(client: Client<'a>, id: u64) -> Result<Connection<'a>> {
        let cfg = client.config();
        let stream = await!(TcpStream::connect(cfg.server()))?;
        let session = Session { id, stream, broken: false };
        let conn = Connection { client, session };
        let handshake = HandShake { conn, buf: [0u8; 128] };
        await!(handshake.greet())
    }
}

impl<'a> HandShake<'a> {
    async fn verify_version(&mut self) -> Result<&mut HandShake<'a>> {
        LittleEndian::write_u32(&mut self.buf, Version::V1_0 as u32);
        await!(self.conn.session.stream.write_all(&self.buf[..4]))?;
        await!(self.conn.session.stream.read(&mut self.buf))?;
        let resp = self.read_buf();
        let info: ServerInfo = serde_json::from_slice(resp)?;
        if !info.success {
            return Err(error::Runtime::Internal(resp.to_owned()))?;
        }
        Ok(self)
    }

    async fn greet(mut self) -> Result<Connection<'a>> {
        await!(self.verify_version())?;

        // Send client first message
        let cfg = &self.conn.client.config();
        let scram = ScramClient::new(cfg.user(), cfg.password(), None)?;
        let (scram, msg) = client_first(scram)?;
        await!(self.conn.session.stream.write_all(&msg))?;

        // Send client final message
        await!(self.conn.session.stream.read(&mut self.buf))?;
        let info = AuthResponse::from_slice(self.read_buf())?;
        match info.authentication {
            Some(ref auth) => {
                let (scram, msg) = client_final(scram, auth)?;
                await!(self.conn.session.stream.write_all(&msg))?;
                await!(self.conn.session.stream.read(&mut self.buf))?;
                server_final(scram, self.read_buf())?;
                await!(self.conn.session.stream.flush())?;
            }
            None => {
                let msg = String::from("Server did not send authentication info.");
                return Err(error::Driver::Other(msg))?;
            }
        }

        Ok(self.conn)
    }

    fn read_buf(&self) -> &[u8] {
        let len = self.buf.iter()
            .take_while(|x| **x != NULL_BYTE)
            .count();
        &self.buf[..len]
    }
}

impl AuthResponse {
    fn from_slice(resp: &[u8]) -> Result<Self> {
        let info: AuthResponse = serde_json::from_slice(resp)?;
        if !info.success {
            // If error code is between 10 and 20, this is an auth error
            if let Some(10...20) = info.error_code {
                if let Some(msg) = info.error {
                    return Err(error::Driver::Auth(msg))?;
                }
            }
            return Err(error::Runtime::Internal(resp.to_owned()))?;
        };
        Ok(info)
    }
}

fn client_first<'a>(scram: ScramClient<'a>) -> Result<(ServerFirst<'a>, Vec<u8>)> {
    let (scram, client_first) = scram.client_first();
    let ar = AuthRequest {
        protocol_version: 0,
        authentication_method: String::from("SCRAM-SHA-256"),
        authentication: client_first,
    };
    let mut msg = serde_json::to_vec(&ar)?;
    msg.push(NULL_BYTE);
    Ok((scram, msg))
}

fn client_final<'a>(scram: ServerFirst<'a>, auth: &str) -> Result<(ServerFinal, Vec<u8>)> {
    let scram = scram.handle_server_first(auth)?;
    let (scram, client_final) = scram.client_final();
    let conf = AuthConfirmation { authentication: client_final };
    let mut msg = serde_json::to_vec(&conf)?;
    msg.push(NULL_BYTE);
    Ok((scram, msg))
}

fn server_final(scram: ServerFinal, resp: &[u8]) -> Result<()> {
    let info = AuthResponse::from_slice(resp)?;
    if let Some(auth) = info.authentication {
        if let Err(err) = scram.handle_server_final(&auth) {
            return Err(err)?;
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use log::{debug};
use goblin::{Object};
use failure::{Error};
use byteorder::{ByteOrder, LittleEndian};

use super::super::super::arch::{RVA};
use super::super::super::workspace::Workspace;
use super::super::{Analyzer};

pub struct RuntimeFunctionAnalyzer {}

impl RuntimeFunctionAnalyzer {
    pub fn new() -> RuntimeFunctionAnalyzer {
        RuntimeFunctionAnalyzer {}
    }
}

struct RuntimeFunction {
    begin_address: RVA,
    end_address: RVA,
    unwind_data: RVA,
}

impl std::fmt::Debug for RuntimeFunction {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "RUNTIME_FUNCTION(begin: {:#x} end: {:#x} data: {:#x})",
               self.begin_address,
               self.end_address,
               self.unwind_data
        )
    }
}

impl Analyzer for RuntimeFunctionAnalyzer {
    fn get_name(&self) -> String {
        "RUNTIME_FUNCTION analyzer".to_string()
    }

    /// ```
    /// use lancelot::rsrc::*;
    /// use lancelot::arch::*;
    /// use lancelot::analysis::Analyzer;
    /// use lancelot::workspace::Workspace;
    /// use lancelot::analysis::pe::RuntimeFunctionAnalyzer;
    ///
    /// let mut ws = Workspace::from_bytes("k32.dll", &get_buf(Rsrc::K32))
    ///    .disable_analysis()
    ///    .load().unwrap();
    /// let anal = RuntimeFunctionAnalyzer::new();
    /// anal.analyze(&mut ws).unwrap();
    ///
    /// assert!(ws.get_meta(0x72A70).unwrap().is_insn());
    ///
    /// // this function is referenced in RUNTIME_FUNCTIONs,
    /// // and in code, tail jump at 0x1800112C2
    /// //
    /// //     .text:00000001800112C2     jmp     sub_1800019C8
    /// //
    /// assert!(ws.get_meta(0x19C8).unwrap().is_insn());
    /// ```
    fn analyze(&self, ws: &mut Workspace) -> Result<(), Error> {
        let (exception_directory, directory_size) = {
            let pe = match Object::parse(&ws.buf) {
                Ok(Object::PE(pe)) => pe,
                _ => panic!("can't analyze unexpected format"),
            };

            let opt_header = match pe.header.optional_header {
                Some(opt_header) => opt_header,
                _ => return Ok(()),
            };

            let exception_directory = match opt_header.data_directories.get_exception_table() {
                Some(exception_directory) => exception_directory,
                _ => return Ok(()),
            };

            (RVA::from(exception_directory.virtual_address as i64), exception_directory.size)
        };

        debug!("exception directory: {:#x}", exception_directory);

        let buf = ws.read_bytes(exception_directory, directory_size as usize)?;
        let functions: Vec<RVA> = buf
            .chunks_exact(3 * 4)
            .map(|b| RuntimeFunction{
                begin_address: RVA::from(LittleEndian::read_i32(b)),
                end_address: RVA::from(LittleEndian::read_i32(&b[4..])),
                unwind_data: RVA::from(LittleEndian::read_i32(&b[8..])),
            })
            .filter(|rt| {
                if ! ws.probe(rt.begin_address, 1) {
                    return false;
                }
                if ! ws.probe(rt.end_address, 1) {
                    return false;
                }
                if ! ws.probe(rt.unwind_data, 1) {
                    return false;
                }
                return true;
            })
            .map(|rt: RuntimeFunction| -> RVA {
                rt.begin_address
            })
            .collect();

        for rva in functions.iter() {
            debug!("runtime function: {:#x}", rva);
            // RUNTIME_FUNCTION.BeginAddress is often the start of a function, but not always.
            // its the start of a __try block.
            // ref: http://www.osronline.com/article.cfm%5earticle=469.htm
            //
            // so we can't blindly create a function here...
            //
            // we should make a final pass over all defined instructions,
            // and select those with no predecessors as functions.
            ws.make_insn(*rva)?;
            ws.analyze()?;
        }

        Ok(())
    }
}
<commit_msg>analysis/runtimefunctions: tests passing again<commit_after>use log::{debug};
use goblin::{Object};
use failure::{Error};
use byteorder::{ByteOrder, LittleEndian};

use super::super::super::arch::{RVA};
use super::super::super::workspace::Workspace;
use super::super::{Analyzer};

pub struct RuntimeFunctionAnalyzer {}

impl RuntimeFunctionAnalyzer {
    pub fn new() -> RuntimeFunctionAnalyzer {
        RuntimeFunctionAnalyzer {}
    }
}

struct RuntimeFunction {
    begin_address: RVA,
    end_address: RVA,
    unwind_data: RVA,
}

impl std::fmt::Debug for RuntimeFunction {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "RUNTIME_FUNCTION(begin: {:#x} end: {:#x} data: {:#x})",
               self.begin_address,
               self.end_address,
               self.unwind_data
        )
    }
}

impl Analyzer for RuntimeFunctionAnalyzer {
    fn get_name(&self) -> String {
        "RUNTIME_FUNCTION analyzer".to_string()
    }

    /// ```
    /// use lancelot::rsrc::*;
    /// use lancelot::arch::*;
    /// use lancelot::analysis::Analyzer;
    /// use lancelot::workspace::Workspace;
    /// use lancelot::analysis::pe::RuntimeFunctionAnalyzer;
    ///
    /// let mut ws = Workspace::from_bytes("k32.dll", &get_buf(Rsrc::K32))
    ///    .disable_analysis()
    ///    .load().unwrap();
    /// let anal = RuntimeFunctionAnalyzer::new();
    /// anal.analyze(&mut ws).unwrap();
    ///
    /// assert!(ws.get_meta(RVA(0x72A70)).unwrap().is_insn());
    ///
    /// // this function is referenced in RUNTIME_FUNCTIONs,
    /// // and in code, tail jump at 0x1800112C2
    /// //
    /// //     .text:00000001800112C2     jmp     sub_1800019C8
    /// //
    /// assert!(ws.get_meta(RVA(0x19C8)).unwrap().is_insn());
    /// ```
    fn analyze(&self, ws: &mut Workspace) -> Result<(), Error> {
        let (exception_directory, directory_size) = {
            let pe = match Object::parse(&ws.buf) {
                Ok(Object::PE(pe)) => pe,
                _ => panic!("can't analyze unexpected format"),
            };

            let opt_header = match pe.header.optional_header {
                Some(opt_header) => opt_header,
                _ => return Ok(()),
            };

            let exception_directory = match opt_header.data_directories.get_exception_table() {
                Some(exception_directory) => exception_directory,
                _ => return Ok(()),
            };

            (RVA::from(exception_directory.virtual_address as i64), exception_directory.size)
        };

        debug!("exception directory: {:#x}", exception_directory);

        let buf = ws.read_bytes(exception_directory, directory_size as usize)?;
        let functions: Vec<RVA> = buf
            .chunks_exact(3 * 4)
            .map(|b| RuntimeFunction{
                begin_address: RVA::from(LittleEndian::read_i32(b)),
                end_address: RVA::from(LittleEndian::read_i32(&b[4..])),
                unwind_data: RVA::from(LittleEndian::read_i32(&b[8..])),
            })
            .filter(|rt| {
                if ! ws.probe(rt.begin_address, 1) {
                    return false;
                }
                if ! ws.probe(rt.end_address, 1) {
                    return false;
                }
                if ! ws.probe(rt.unwind_data, 1) {
                    return false;
                }
                return true;
            })
            .map(|rt: RuntimeFunction| -> RVA {
                rt.begin_address
            })
            .collect();

        for rva in functions.iter() {
            debug!("runtime function: {:#x}", rva);
            // RUNTIME_FUNCTION.BeginAddress is often the start of a function, but not always.
            // its the start of a __try block.
            // ref: http://www.osronline.com/article.cfm%5earticle=469.htm
            //
            // so we can't blindly create a function here...
            //
            // we should make a final pass over all defined instructions,
            // and select those with no predecessors as functions.
            ws.make_insn(*rva)?;
            ws.analyze()?;
        }

        Ok(())
    }
}
<|endoftext|>