<commit_before>use common::R;
use dense_matrix::DenseMatrix;
use sparse_matrix::{SparseMatrix, Symmetric, StructurallySymmetric};

use std::libc::{c_double, c_ulong, c_int, c_uint, c_void, malloc, calloc, realloc, free};
use std::cast;
use std::vec;

pub type lapack_int = c_int; // Adjust according to whether LP64 or ILP64 libraries are being linked.
pub type mkl_int = c_int;    // Adjust according to whether LP64 or ILP64 libraries are being linked.

#[inline(never)]
pub fn init() {
  unsafe {
    init_allocator(cast::transmute(malloc), cast::transmute(calloc), cast::transmute(realloc), cast::transmute(free));
  }
}

#[inline(never)]
pub fn solve_sparse(sys: &SparseMatrix, rhs: &DenseMatrix) -> ~[R] {
  let n = sys.num_rows();

  unsafe {
    let (a, ia, ja) = sys.csr3_ptrs();
    let mut sol = vec::from_elem(n, 0 as R);
    let cpu_cores = 4; // TODO

    let stat = match sys.matrix_type() {
      Symmetric =>
        solve_sparse_symmetric_as_ut_csr3(n as mkl_int, ia, ja, a,
                                          rhs.col_maj_data_ptr(), rhs.num_cols() as mkl_int,
                                          vec::raw::to_mut_ptr(sol),
                                          cpu_cores),
      StructurallySymmetric =>
        solve_sparse_structurally_symmetric_csr3(n as mkl_int, ia, ja, a,
                                                 rhs.col_maj_data_ptr(), rhs.num_cols() as mkl_int,
                                                 vec::raw::to_mut_ptr(sol),
                                                 cpu_cores),
      _ => fail!("Only symmetric and structurally symmetric matrices are currently supported in solve_sparse()."),
    };

    if stat != 0 {
      fail!(format!("solve_sparse_symmetric_as_ut_csr3 failed with error {:d}", stat));
    }

    sol
  }
}

/* TODO: This isn't the preferred way to link anymore (too platform specific), so requires feature gate in wgfem.rs.
         I'm not sure how to specify the -L option otherwise though. */
#[link_args = "-Llib/mkl lib/lapack.o -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -lmkl_core -lmkl_intel_thread -lmkl_core -liomp5 -lpthread"]
extern {

  pub fn init_allocator(malloc_fn: *c_void, calloc_fn: *c_void, realloc_fn: *c_void, free_fn: *c_void);

  pub fn alloc_doubles(num_doubles: c_ulong) -> *mut c_double;

  pub fn alloc_ints(num_ints: c_ulong) -> *mut lapack_int;

  pub fn free_doubles(mem: *mut c_double);

  pub fn free_ints(mem: *mut lapack_int);

  pub fn copy_matrix(from_data: *c_double, num_rows: c_ulong, num_cols: c_ulong, to_data: *mut c_double);

  pub fn copy_upper_triangle(from_data: *c_double, num_rows: c_ulong, num_cols: c_ulong, to_data: *mut c_double);

  /* Dense symmetric matrix system solver. */
  pub fn solve_symmetric_as_col_maj_with_ut_sys(a: *mut c_double,
                                                n: lapack_int,
                                                b: *mut c_double,
                                                nrhs: lapack_int,
                                                ipiv: *mut lapack_int) -> lapack_int;

  /* Sparse symmetric matrix system solver. */
  pub fn solve_sparse_symmetric_as_ut_csr3(n: mkl_int, ia: *mkl_int, ja: *mkl_int, a: *c_double,
                                           b: *c_double, nrhs: mkl_int,
                                           x: *mut c_double,
                                           num_cpu_cores: c_uint) -> mkl_int;

  /* Sparse structurally symmetric matrix system solver. */
  pub fn solve_sparse_structurally_symmetric_csr3(n: mkl_int, ia: *mkl_int, ja: *mkl_int, a: *c_double,
                                                  b: *c_double, nrhs: mkl_int,
                                                  x: *mut c_double,
                                                  num_cpu_cores: c_uint) -> mkl_int;
}

<commit_msg>Fetch num cpus for MKL call.<commit_after>use common::R;
use dense_matrix::DenseMatrix;
use sparse_matrix::{SparseMatrix, Symmetric, StructurallySymmetric};

use std::libc::{c_double, c_ulong, c_int, c_uint, c_void, malloc, calloc, realloc, free};
use std::cast;
use std::vec;
use std::libc;

pub type lapack_int = c_int; // Adjust according to whether LP64 or ILP64 libraries are being linked.
pub type mkl_int = c_int;    // Adjust according to whether LP64 or ILP64 libraries are being linked.

#[inline(never)]
pub fn init() {
  unsafe {
    init_allocator(cast::transmute(malloc), cast::transmute(calloc), cast::transmute(realloc), cast::transmute(free));
  }
}

#[inline(never)]
pub fn solve_sparse(sys: &SparseMatrix, rhs: &DenseMatrix) -> ~[R] {
  let n = sys.num_rows();

  unsafe {
    let (a, ia, ja) = sys.csr3_ptrs();
    let mut sol = vec::from_elem(n, 0 as R);
    let cpu_cores = num_cpus() as c_uint;

    let stat = match sys.matrix_type() {
      Symmetric =>
        solve_sparse_symmetric_as_ut_csr3(n as mkl_int, ia, ja, a,
                                          rhs.col_maj_data_ptr(), rhs.num_cols() as mkl_int,
                                          vec::raw::to_mut_ptr(sol),
                                          cpu_cores),
      StructurallySymmetric =>
        solve_sparse_structurally_symmetric_csr3(n as mkl_int, ia, ja, a,
                                                 rhs.col_maj_data_ptr(), rhs.num_cols() as mkl_int,
                                                 vec::raw::to_mut_ptr(sol),
                                                 cpu_cores),
      _ => fail!("Only symmetric and structurally symmetric matrices are currently supported in solve_sparse()."),
    };

    if stat != 0 {
      fail!(format!("solve_sparse_symmetric_as_ut_csr3 failed with error {:d}", stat));
    }

    sol
  }
}

/* TODO: This isn't the preferred way to link anymore (too platform specific), so requires feature gate in wgfem.rs.
         I'm not sure how to specify the -L option otherwise though. */
#[link_args = "-Llib/mkl lib/lapack.o -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -lmkl_core -lmkl_intel_thread -lmkl_core -liomp5 -lpthread"]
extern {

  pub fn init_allocator(malloc_fn: *c_void, calloc_fn: *c_void, realloc_fn: *c_void, free_fn: *c_void);

  pub fn alloc_doubles(num_doubles: c_ulong) -> *mut c_double;

  pub fn alloc_ints(num_ints: c_ulong) -> *mut lapack_int;

  pub fn free_doubles(mem: *mut c_double);

  pub fn free_ints(mem: *mut lapack_int);

  pub fn copy_matrix(from_data: *c_double, num_rows: c_ulong, num_cols: c_ulong, to_data: *mut c_double);

  pub fn copy_upper_triangle(from_data: *c_double, num_rows: c_ulong, num_cols: c_ulong, to_data: *mut c_double);

  /* Dense symmetric matrix system solver. */
  pub fn solve_symmetric_as_col_maj_with_ut_sys(a: *mut c_double,
                                                n: lapack_int,
                                                b: *mut c_double,
                                                nrhs: lapack_int,
                                                ipiv: *mut lapack_int) -> lapack_int;

  /* Sparse symmetric matrix system solver. */
  pub fn solve_sparse_symmetric_as_ut_csr3(n: mkl_int, ia: *mkl_int, ja: *mkl_int, a: *c_double,
                                           b: *c_double, nrhs: mkl_int,
                                           x: *mut c_double,
                                           num_cpu_cores: c_uint) -> mkl_int;

  /* Sparse structurally symmetric matrix system solver. */
  pub fn solve_sparse_structurally_symmetric_csr3(n: mkl_int, ia: *mkl_int, ja: *mkl_int, a: *c_double,
                                                  b: *c_double, nrhs: mkl_int,
                                                  x: *mut c_double,
                                                  num_cpu_cores: c_uint) -> mkl_int;
}

fn num_cpus() -> uint {
  unsafe {
    return rust_get_num_cpus();
  }

  extern {
    fn rust_get_num_cpus() -> libc::uintptr_t;
  }
}

<|endoftext|>


<commit_before>extern crate test;
extern crate utp;

use test::Bencher;
use std::old_io::test::next_test_ip4;
use utp::UtpStream;
use std::sync::Arc;
use std::thread;

macro_rules! iotry {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("{}", e) })
}

#[bench]
fn bench_connection_setup_and_teardown(b: &mut Bencher) {
    let server_addr = next_test_ip4();
    b.iter(|| {
        let mut server = iotry!(UtpStream::bind(server_addr));

        thread::spawn(move || {
            let mut client = iotry!(UtpStream::connect(server_addr));
            iotry!(client.close());
        });

        iotry!(server.read_to_end());
        iotry!(server.close());
    });
}

#[bench]
fn bench_transfer_one_packet(b: &mut Bencher) {
    let len = 1024;
    let server_addr = next_test_ip4();
    let data = (0..len).map(|x| x as u8).collect::<Vec<u8>>();
    let data_arc = Arc::new(data);

    b.iter(|| {
        let data = data_arc.clone();
        let mut server = iotry!(UtpStream::bind(server_addr));

        thread::spawn(move || {
            let mut client = iotry!(UtpStream::connect(server_addr));
            iotry!(client.write(&data[..]));
            iotry!(client.close());
        });

        iotry!(server.read_to_end());
        iotry!(server.close());
    });
    b.bytes = len as u64;
}

#[bench]
fn bench_transfer_one_megabyte(b: &mut Bencher) {
    let len = 1024 * 1024;
    let server_addr = next_test_ip4();
    let data = (0..len).map(|x| x as u8).collect::<Vec<u8>>();
    let data_arc = Arc::new(data);

    b.iter(|| {
        let data = data_arc.clone();
        let mut server = iotry!(UtpStream::bind(server_addr));

        thread::spawn(move || {
            let mut client = iotry!(UtpStream::connect(server_addr));
            iotry!(client.write(&data[..]));
            iotry!(client.close());
        });

        iotry!(server.read_to_end());
        iotry!(server.close());
    });
    b.bytes = len as u64;
}
<commit_msg>Fix benchmarks.<commit_after>#![feature(old_io, test)]

extern crate test;
extern crate utp;

use test::Bencher;
use utp::UtpStream;
use std::io::{Read, Write};
use std::sync::Arc;
use std::thread;

macro_rules! iotry {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("{}", e) })
}

fn next_test_ip4<'a>() -> (&'a str, u16) {
    use std::old_io::test::next_test_port;
    ("127.0.0.1", next_test_port())
}

#[bench]
fn bench_connection_setup_and_teardown(b: &mut Bencher) {
    let server_addr = next_test_ip4();
    let mut received = vec!();
    b.iter(|| {
        let mut server = iotry!(UtpStream::bind(server_addr));

        thread::spawn(move || {
            let mut client = iotry!(UtpStream::connect(server_addr));
            iotry!(client.close());
        });

        iotry!(server.read_to_end(&mut received));
        iotry!(server.close());
    });
}

#[bench]
fn bench_transfer_one_packet(b: &mut Bencher) {
    let len = 1024;
    let server_addr = next_test_ip4();
    let data = (0..len).map(|x| x as u8).collect::<Vec<u8>>();
    let data_arc = Arc::new(data);
    let mut received = vec!();

    b.iter(|| {
        let data = data_arc.clone();
        let mut server = iotry!(UtpStream::bind(server_addr));

        thread::spawn(move || {
            let mut client = iotry!(UtpStream::connect(server_addr));
            iotry!(client.write(&data[..]));
            iotry!(client.close());
        });

        iotry!(server.read_to_end(&mut received));
        iotry!(server.close());
    });
    b.bytes = len as u64;
}

#[bench]
fn bench_transfer_one_megabyte(b: &mut Bencher) {
    let len = 1024 * 1024;
    let server_addr = next_test_ip4();
    let data = (0..len).map(|x| x as u8).collect::<Vec<u8>>();
    let data_arc = Arc::new(data);
    let mut received = vec!();

    b.iter(|| {
        let data = data_arc.clone();
        let mut server = iotry!(UtpStream::bind(server_addr));

        thread::spawn(move || {
            let mut client = iotry!(UtpStream::connect(server_addr));
            iotry!(client.write(&data[..]));
            iotry!(client.close());
        });

        iotry!(server.read_to_end(&mut received));
        iotry!(server.close());
    });
    b.bytes = len as u64;
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]
#![feature(asm)]
extern crate e2d2;
extern crate fnv;
extern crate time;
extern crate simd;
extern crate getopts;
extern crate rand;
use e2d2::io::*;
use e2d2::headers::*;
use e2d2::packet_batch::*;
use getopts::Options;
use std::collections::HashMap;
use std::env;
use std::time::Duration;
use std::thread;

const CONVERSION_FACTOR: f64 = 1000000000.;

#[inline]
fn rdtscp_unsafe() -> u64 {
    unsafe {
        let low: u32;
        let high: u32;
        asm!("rdtscp"
             : "={eax}" (low), "={edx}" (high)
             :
             : "{ecx}"
             : "volatile");
        ((high as u64) << 32) | (low as u64)
    }
}

#[inline]
fn rdtscp() -> u64 {
    rdtscp_unsafe()
}

#[inline]
fn lat() {
    unsafe {
        asm!("nop"
             :
             :
             :
             : "volatile");
    }
}

#[inline]
fn delay_loop(delay: u64) {
    let mut d = 0;
    while d < delay {
        lat();
        d += 1;
    }
}

fn delay<T: 'static + Batch>(parent: T, delay: u64) -> CompositionBatch {
    parent.parse::<MacHeader>()
          .transform(box move |_, _, _| {
              delay_loop(delay);
          })
          .compose()
}

fn recv_thread(ports: Vec<PmdPort>, queue: i32, core: i32) {
    init_thread(core, core);
    println!("Receiving started");

    let pipelines: Vec<_> = ports.iter()
                                 .map(|port| {
                                     delay(ReceiveBatch::new(port.copy(), queue), 50)
                                         .send(port.copy(), queue)
                                         .compose()
                                 }).collect();
    println!("Running {} pipelines", pipelines.len());
    let mut combined = merge(pipelines);
    loop {
        combined.process();
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optmulti("w", "whitelist", "Whitelist PCI", "PCI");
    opts.optmulti("c", "core", "Core to use", "core");
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("m", "master", "Master core", "master");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };
    if matches.opt_present("h") {
        print!("{}", opts.usage(&format!("Usage: {} [options]", program)));
    }
    let cores_str = matches.opt_strs("c");
    let master_core = matches.opt_str("m")
                             .unwrap_or_else(|| String::from("0"))
                             .parse()
                             .expect("Could not parse master core spec");
    println!("Using master core {}", master_core);

    let whitelisted = matches.opt_strs("w");
    if cores_str.len() > whitelisted.len() {
        println!("More cores than ports");
        std::process::exit(1);
    }
    let cores: Vec<i32> = cores_str.iter()
                                   .map(|n: &String| n.parse().ok().expect(&format!("Core cannot be parsed {}", n)))
                                   .collect();
    for (core, wl) in cores.iter().zip(whitelisted.iter()) {
        println!("Going to use core {} for wl {}", core, wl);
    }
    let mut core_map = HashMap::<i32, Vec<i32>>::with_capacity(cores.len());
    for (core, port) in cores.iter().zip(0..whitelisted.len()) {
        {
            match core_map.get(&core) {
                Some(_) => core_map.get_mut(&core).expect("Incorrect logic").push(port as i32),
                None => {
                    core_map.insert(core.clone(), vec![port as i32]);
                    ()
                }
            }
        }
    }

    init_system_wl(&format!("recv{}", cores_str.join("")),
                   master_core,
                   &whitelisted);
    let ports_by_core: HashMap<_, _> = core_map.iter()
                                               .map(|(core, ports)| {
                                                   let c = core.clone();
                                                   let recv_ports: Vec<_> =
                                                       ports.iter()
                                                            .map(|p| {
                                                                PmdPort::new_mq_port(p.clone() as i32, 1, 1, &[c], &[c])
                                                                    .expect("Could not initialize port")
                                                            })
                                                            .collect();
                                                   (c, recv_ports)
                                               })
                                               .collect();
    const _BATCH: usize = 1 << 10;
    const _CHANNEL_SIZE: usize = 256;
    let _thread: Vec<_> = ports_by_core.iter()
                                       .map(|(core, ports)| {
                                           let c = core.clone();
                                           let p: Vec<_> = ports.iter().map(|p| p.copy()).collect();
                                           std::thread::spawn(move || recv_thread(p, 0, c))
                                       })
                                       .collect();
    let mut pkts_so_far = (0, 0);
    let mut start = time::precise_time_ns() as f64 / CONVERSION_FACTOR;
    let sleep_time = Duration::from_millis(500);
    loop {
        thread::sleep(sleep_time); // Sleep for a bit
        let now = time::precise_time_ns() as f64 / CONVERSION_FACTOR;
        if now - start > 1.0 {
            let pkts = ports_by_core.values()
                                    .map(|pvec| {
                                        pvec.iter()
                                            .map(|p| p.stats(0))
                                            .fold((0, 0), |(r, t), (rp, tp)| (r + rp, t + tp))
                                    })
                                    .fold((0, 0), |(r, t), (rp, tp)| (r + rp, t + tp));
            let start_cycles = rdtscp();
            delay_loop(100);
            let end_cycles = rdtscp();
            let delay = end_cycles - start_cycles;
            println!("{:.2} OVERALL RX {:.2} TX {:.2} CYCLE_PER_DELAY {} {} {}",
                     now - start,
                     (pkts.0 - pkts_so_far.0) as f64 / (now - start),
                     (pkts.1 - pkts_so_far.1) as f64 / (now - start),
                     start_cycles,
                     end_cycles,
                     delay);
            start = now;
            pkts_so_far = pkts;
        }
    }
}
<commit_msg>Take delay as argument<commit_after>#![feature(box_syntax)]
#![feature(asm)]
extern crate e2d2;
extern crate fnv;
extern crate time;
extern crate simd;
extern crate getopts;
extern crate rand;
use e2d2::io::*;
use e2d2::headers::*;
use e2d2::packet_batch::*;
use getopts::Options;
use std::collections::HashMap;
use std::env;
use std::time::Duration;
use std::thread;

const CONVERSION_FACTOR: f64 = 1000000000.;

#[inline]
fn rdtscp_unsafe() -> u64 {
    unsafe {
        let low: u32;
        let high: u32;
        asm!("rdtscp"
             : "={eax}" (low), "={edx}" (high)
             :
             : "{ecx}"
             : "volatile");
        ((high as u64) << 32) | (low as u64)
    }
}

#[inline]
fn rdtscp() -> u64 {
    rdtscp_unsafe()
}

#[inline]
fn lat() {
    unsafe {
        asm!("nop"
             :
             :
             :
             : "volatile");
    }
}

#[inline]
fn delay_loop(delay: u64) {
    let mut d = 0;
    while d < delay {
        lat();
        d += 1;
    }
}

fn delay<T: 'static + Batch>(parent: T, delay: u64) -> CompositionBatch {
    parent.parse::<MacHeader>()
          .transform(box move |_, _, _| {
              delay_loop(delay);
          })
          .compose()
}

fn recv_thread(ports: Vec<PmdPort>, queue: i32, core: i32, delay_arg: u64) {
    init_thread(core, core);
    println!("Receiving started");

    let pipelines: Vec<_> = ports.iter()
                                 .map(|port| {
                                     delay(ReceiveBatch::new(port.copy(), queue), delay_arg)
                                         .send(port.copy(), queue)
                                         .compose()
                                 }).collect();
    println!("Running {} pipelines", pipelines.len());
    let mut combined = merge(pipelines);
    loop {
        combined.process();
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optmulti("w", "whitelist", "Whitelist PCI", "PCI");
    opts.optmulti("c", "core", "Core to use", "core");
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("m", "master", "Master core", "master");
    opts.optopt("d", "delay", "Delay cycles", "cycles");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };
    if matches.opt_present("h") {
        print!("{}", opts.usage(&format!("Usage: {} [options]", program)));
    }
    let cores_str = matches.opt_strs("c");
    let master_core = matches.opt_str("m")
                             .unwrap_or_else(|| String::from("0"))
                             .parse()
                             .expect("Could not parse master core spec");
    let delay_arg = matches.opt_str("d")
                       .unwrap_or_else(|| String::from("100"))
                       .parse()
                       .expect("Could not parse delay");
    println!("Using master core {}", master_core);

    let whitelisted = matches.opt_strs("w");
    if cores_str.len() > whitelisted.len() {
        println!("More cores than ports");
        std::process::exit(1);
    }
    let cores: Vec<i32> = cores_str.iter()
                                   .map(|n: &String| n.parse().ok().expect(&format!("Core cannot be parsed {}", n)))
                                   .collect();
    for (core, wl) in cores.iter().zip(whitelisted.iter()) {
        println!("Going to use core {} for wl {}", core, wl);
    }
    let mut core_map = HashMap::<i32, Vec<i32>>::with_capacity(cores.len());
    for (core, port) in cores.iter().zip(0..whitelisted.len()) {
        {
            match core_map.get(&core) {
                Some(_) => core_map.get_mut(&core).expect("Incorrect logic").push(port as i32),
                None => {
                    core_map.insert(core.clone(), vec![port as i32]);
                    ()
                }
            }
        }
    }

    init_system_wl(&format!("recv{}", cores_str.join("")),
                   master_core,
                   &whitelisted);
    let ports_by_core: HashMap<_, _> = core_map.iter()
                                               .map(|(core, ports)| {
                                                   let c = core.clone();
                                                   let recv_ports: Vec<_> =
                                                       ports.iter()
                                                            .map(|p| {
                                                                PmdPort::new_mq_port(p.clone() as i32, 1, 1, &[c], &[c])
                                                                    .expect("Could not initialize port")
                                                            })
                                                            .collect();
                                                   (c, recv_ports)
                                               })
                                               .collect();
    const _BATCH: usize = 1 << 10;
    const _CHANNEL_SIZE: usize = 256;
    let _thread: Vec<_> = ports_by_core.iter()
                                       .map(|(core, ports)| {
                                           let c = core.clone();
                                           let p: Vec<_> = ports.iter().map(|p| p.copy()).collect();
                                           std::thread::spawn(move || recv_thread(p, 0, c, delay_arg))
                                       })
                                       .collect();
    let mut pkts_so_far = (0, 0);
    let mut start = time::precise_time_ns() as f64 / CONVERSION_FACTOR;
    let sleep_time = Duration::from_millis(500);
    loop {
        thread::sleep(sleep_time); // Sleep for a bit
        let now = time::precise_time_ns() as f64 / CONVERSION_FACTOR;
        if now - start > 1.0 {
            let pkts = ports_by_core.values()
                                    .map(|pvec| {
                                        pvec.iter()
                                            .map(|p| p.stats(0))
                                            .fold((0, 0), |(r, t), (rp, tp)| (r + rp, t + tp))
                                    })
                                    .fold((0, 0), |(r, t), (rp, tp)| (r + rp, t + tp));
            let start_cycles = rdtscp();
            delay_loop(100);
            let end_cycles = rdtscp();
            let delay = end_cycles - start_cycles;
            println!("{:.2} OVERALL RX {:.2} TX {:.2} CYCLE_PER_DELAY {} {} {}",
                     now - start,
                     (pkts.0 - pkts_so_far.0) as f64 / (now - start),
                     (pkts.1 - pkts_so_far.1) as f64 / (now - start),
                     start_cycles,
                     end_cycles,
                     delay);
            start = now;
            pkts_so_far = pkts;
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::path::Path;

use leveldb;
use leveldb::database::Database as LDatabase;
use leveldb::iterator::Iterable;
use leveldb::kv::KV;
use leveldb::options::{Options, ReadOptions, WriteOptions};
use leveldb::snapshots::Snapshots;
use db_key::Key as DBKey;

use futures::{IntoFuture, Done};

// Not quite a fan of this implementation
pub struct Key {
    data: Vec<u8>,
}

impl DBKey for Key {
    fn from_u8(key: &[u8]) -> Self {
        Key { data: key.to_vec() }
    }

    fn as_slice<T, F: Fn(&[u8]) -> T>(&self, f: F) -> T {
        f(&*self.data)
    }
}

#[derive(Debug)]
pub enum Error {
    LevelDBError(leveldb::error::Error),
    IOError(io::Error),
    InvalidBucket,
}

impl Error {
    fn is_level_db_error(&self) -> bool {
        match *self {
            Error::LevelDBError(_) => true,
            _ => false,
        }
    }

    fn is_invalid_bucket(&self) -> bool {
        match *self {
            Error::InvalidBucket(_) => true,
            _ => false,
        }
    }
}

impl PartialEq for Error {
    fn eq(&self, other: &Self) -> bool {
        (self.is_level_db_error() && other.is_level_db_error()) ||
            (self.is_invalid_bucket() && other.is_invalid_bucket())
    }
}

impl Eq for Error {}

impl From<leveldb::error::Error> for Error {
    fn from(e: leveldb::error::Error) -> Self {
        Error::LevelDBError(e)
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::IOError(e)
    }
}

pub trait Database: Send + Sync + 'static {
    fn put(&self, bucket: &[u8], key: &[u8], value: &[u8]) -> Done<(), Error>;
    fn get(&self, bucket: &[u8], key: &[u8]) -> Done<Option<Vec<u8>>, Error>;
    fn list(&self, bucket: &[u8], key: &[u8]) -> Done<Vec<(Vec<u8>, Vec<u8>)>, Error>;
}

pub struct LevelDB<K: DBKey> {
    db: LDatabase<K>,
}

impl<K: DBKey> LevelDB<K> {
    pub fn new(path: &str) -> Result<Self, Error> {
        let mut opts = Options::new();
        opts.create_if_missing = true;
        let db = try!(LDatabase::open(Path::new(path), opts));
        Ok(LevelDB { db: db })
    }

    fn bucket_key(&self, bucket: &[u8], key: &[u8]) -> Vec<u8> {
        let mut k = vec![255];
        k.extend(bucket);
        k.push(255);
        k.extend(key);
        k
    }

    fn strip_bucket(&self, bucket: &[u8], bk: &[u8]) -> Vec<u8> {
        bk[bucket.len() + 2..].to_vec()
    }
}

impl<K: DBKey + 'static> Database for LevelDB<K> {
    fn put(&self, bucket: &[u8], key: &[u8], value: &[u8]) -> Done<(), Error> {
        let write_opts = WriteOptions::new();
        self.db.put(write_opts, K::from_u8(&*self.bucket_key(bucket, key)), value).map_err(|e| Error::LevelDBError(e)).into_future()
    }

    fn get(&self, bucket: &[u8], key: &[u8]) -> Done<Option<Vec<u8>>, Error> {
        let read_opts = ReadOptions::new();
        self.db.get(read_opts, K::from_u8(&*self.bucket_key(bucket, key))).map_err(|e| Error::LevelDBError(e)).into_future()
    }

    fn list(&self, bucket: &[u8], key: &[u8]) -> Done<Vec<(Vec<u8>, Vec<u8>)>, Error> {
        let read_opts = ReadOptions::new();
        let bk = &*self.bucket_key(bucket, key);
        // this is awful, but rust's leveldb lib does not seem to provide filtering for us
        Ok(self.db.snapshot().iter(read_opts).filter(|k| {
            K::as_slice(&k.0, |x| &x[..bk.len()] == bk)
        }).map(|k| (K::as_slice(&k.0, |x| self.strip_bucket(bucket, x)), k.1)).collect()).into_future()
    }
}

#[cfg(test)]
mod test{
    extern crate tempdir;

    use std::fmt;

    use futures::{Future, Task};
    use super::{Database, Key, LevelDB};
    use std::sync::Arc;

    pub fn assert_done<T, F>(mut f: F, result: Result<T::Item, T::Error>)
        where T: Future,
        T::Item: Eq + fmt::Debug,
        T::Error: Eq + fmt::Debug,
        F: FnMut() -> T,
    {
        let mut a = f();
        assert_eq!(&a.poll(&mut Task::new()).unwrap(), &result);
        drop(a);
    }

    #[test]
    fn put_get() {
        let db = Arc::new(LevelDB::<Key>::new(tempdir::TempDir::new("put_get").unwrap().path().to_str().unwrap()).unwrap());
        let bucket = [5, 4, 3, 2, 1];
        let key = [0, 1, 2, 3];
        let value = [4, 6, 8, 10];
        assert_done(move ||  {
            let db = db.clone();
            db.put(&bucket, &key, &value).and_then(move |_| {
                db.get(&bucket, &key)
            })
        }, Ok(Some(value.to_vec())))
    }

    #[test]
    fn put_put_get() {
        let db = Arc::new(LevelDB::<Key>::new(tempdir::TempDir::new("put_get").unwrap().path().to_str().unwrap()).unwrap());
        let bucket = [5, 4, 3, 2, 1];
        let key = [0, 1, 2, 3];
        let value = [4, 6, 8, 10];
        let value2 = [100, 101, 102, 103];
        assert_done(move ||  {
            let db = db.clone();
            db.put(&bucket, &key, &value).and_then(move |_| {
                db.put(&bucket, &key, &value2).and_then(move |_| {
                    db.get(&bucket, &key)
                })
            })
        }, Ok(Some(value2.to_vec())))
    }

    #[test]
    fn get_none() {
        let db = LevelDB::<Key>::new(tempdir::TempDir::new("get_none").unwrap().path().to_str().unwrap()).unwrap();
        let bucket = [5, 4, 3, 2, 1];
        let key = [0, 1, 2, 3];
        assert_done(move ||  {
            db.get(&bucket, &key)
        }, Ok(None));
    }

    #[test]
    fn put_list() {
        let db = Arc::new(LevelDB::<Key>::new(tempdir::TempDir::new("put_list").unwrap().path().to_str().unwrap()).unwrap());
        let bucket = [5, 4, 3, 2, 1];
        let key = [0, 1, 2, 3];
        let value = [4, 6, 8, 10];
        let key2 = [0, 1, 2, 3, 4];
        let value2 = [100, 101, 102, 103, 104];
        assert_done(move ||  {
            let db = db.clone();
            db.put(&bucket, &key, &value).and_then(move |_| {
                db.put(&bucket, &key2, &value2).and_then(move |_| {
                    db.list(&bucket, &key)
                })
            })
        }, Ok(vec![(key.to_vec(), value.to_vec()), (key2.to_vec(), value2.to_vec())]));
    }
}
<commit_msg>Remove extra parenthesis<commit_after>use std::io;
use std::path::Path;

use leveldb;
use leveldb::database::Database as LDatabase;
use leveldb::iterator::Iterable;
use leveldb::kv::KV;
use leveldb::options::{Options, ReadOptions, WriteOptions};
use leveldb::snapshots::Snapshots;
use db_key::Key as DBKey;

use futures::{IntoFuture, Done};

// Not quite a fan of this implementation
pub struct Key {
    data: Vec<u8>,
}

impl DBKey for Key {
    fn from_u8(key: &[u8]) -> Self {
        Key { data: key.to_vec() }
    }

    fn as_slice<T, F: Fn(&[u8]) -> T>(&self, f: F) -> T {
        f(&*self.data)
    }
}

#[derive(Debug)]
pub enum Error {
    LevelDBError(leveldb::error::Error),
    IOError(io::Error),
    InvalidBucket,
}

impl Error {
    fn is_level_db_error(&self) -> bool {
        match *self {
            Error::LevelDBError(_) => true,
            _ => false,
        }
    }

    fn is_invalid_bucket(&self) -> bool {
        match *self {
            Error::InvalidBucket => true,
            _ => false,
        }
    }
}

impl PartialEq for Error {
    fn eq(&self, other: &Self) -> bool {
        (self.is_level_db_error() && other.is_level_db_error()) ||
            (self.is_invalid_bucket() && other.is_invalid_bucket())
    }
}

impl Eq for Error {}

impl From<leveldb::error::Error> for Error {
    fn from(e: leveldb::error::Error) -> Self {
        Error::LevelDBError(e)
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::IOError(e)
    }
}

pub trait Database: Send + Sync + 'static {
    fn put(&self, bucket: &[u8], key: &[u8], value: &[u8]) -> Done<(), Error>;
    fn get(&self, bucket: &[u8], key: &[u8]) -> Done<Option<Vec<u8>>, Error>;
    fn list(&self, bucket: &[u8], key: &[u8]) -> Done<Vec<(Vec<u8>, Vec<u8>)>, Error>;
}

pub struct LevelDB<K: DBKey> {
    db: LDatabase<K>,
}

impl<K: DBKey> LevelDB<K> {
    pub fn new(path: &str) -> Result<Self, Error> {
        let mut opts = Options::new();
        opts.create_if_missing = true;
        let db = try!(LDatabase::open(Path::new(path), opts));
        Ok(LevelDB { db: db })
    }

    fn bucket_key(&self, bucket: &[u8], key: &[u8]) -> Vec<u8> {
        let mut k = vec![255];
        k.extend(bucket);
        k.push(255);
        k.extend(key);
        k
    }

    fn strip_bucket(&self, bucket: &[u8], bk: &[u8]) -> Vec<u8> {
        bk[bucket.len() + 2..].to_vec()
    }
}

impl<K: DBKey + 'static> Database for LevelDB<K> {
    fn put(&self, bucket: &[u8], key: &[u8], value: &[u8]) -> Done<(), Error> {
        let write_opts = WriteOptions::new();
        self.db.put(write_opts, K::from_u8(&*self.bucket_key(bucket, key)), value).map_err(|e| Error::LevelDBError(e)).into_future()
    }

    fn get(&self, bucket: &[u8], key: &[u8]) -> Done<Option<Vec<u8>>, Error> {
        let read_opts = ReadOptions::new();
        self.db.get(read_opts, K::from_u8(&*self.bucket_key(bucket, key))).map_err(|e| Error::LevelDBError(e)).into_future()
    }

    fn list(&self, bucket: &[u8], key: &[u8]) -> Done<Vec<(Vec<u8>, Vec<u8>)>, Error> {
        let read_opts = ReadOptions::new();
        let bk = &*self.bucket_key(bucket, key);
        // this is awful, but rust's leveldb lib does not seem to provide filtering for us
        Ok(self.db.snapshot().iter(read_opts).filter(|k| {
            K::as_slice(&k.0, |x| &x[..bk.len()] == bk)
        }).map(|k| (K::as_slice(&k.0, |x| self.strip_bucket(bucket, x)), k.1)).collect()).into_future()
    }
}

#[cfg(test)]
mod test{
    extern crate tempdir;

    use std::fmt;

    use futures::{Future, Task};
    use super::{Database, Key, LevelDB};
    use std::sync::Arc;

    pub fn assert_done<T, F>(mut f: F, result: Result<T::Item, T::Error>)
        where T: Future,
        T::Item: Eq + fmt::Debug,
        T::Error: Eq + fmt::Debug,
        F: FnMut() -> T,
    {
        let mut a = f();
        assert_eq!(&a.poll(&mut Task::new()).unwrap(), &result);
        drop(a);
    }

    #[test]
    fn put_get() {
        let db = Arc::new(LevelDB::<Key>::new(tempdir::TempDir::new("put_get").unwrap().path().to_str().unwrap()).unwrap());
        let bucket = [5, 4, 3, 2, 1];
        let key = [0, 1, 2, 3];
        let value = [4, 6, 8, 10];
        assert_done(move ||  {
            let db = db.clone();
            db.put(&bucket, &key, &value).and_then(move |_| {
                db.get(&bucket, &key)
            })
        }, Ok(Some(value.to_vec())))
    }

    #[test]
    fn put_put_get() {
        let db = Arc::new(LevelDB::<Key>::new(tempdir::TempDir::new("put_get").unwrap().path().to_str().unwrap()).unwrap());
        let bucket = [5, 4, 3, 2, 1];
        let key = [0, 1, 2, 3];
        let value = [4, 6, 8, 10];
        let value2 = [100, 101, 102, 103];
        assert_done(move ||  {
            let db = db.clone();
            db.put(&bucket, &key, &value).and_then(move |_| {
                db.put(&bucket, &key, &value2).and_then(move |_| {
                    db.get(&bucket, &key)
                })
            })
        }, Ok(Some(value2.to_vec())))
    }

    #[test]
    fn get_none() {
        let db = LevelDB::<Key>::new(tempdir::TempDir::new("get_none").unwrap().path().to_str().unwrap()).unwrap();
        let bucket = [5, 4, 3, 2, 1];
        let key = [0, 1, 2, 3];
        assert_done(move ||  {
            db.get(&bucket, &key)
        }, Ok(None));
    }

    #[test]
    fn put_list() {
        let db = Arc::new(LevelDB::<Key>::new(tempdir::TempDir::new("put_list").unwrap().path().to_str().unwrap()).unwrap());
        let bucket = [5, 4, 3, 2, 1];
        let key = [0, 1, 2, 3];
        let value = [4, 6, 8, 10];
        let key2 = [0, 1, 2, 3, 4];
        let value2 = [100, 101, 102, 103, 104];
        assert_done(move ||  {
            let db = db.clone();
            db.put(&bucket, &key, &value).and_then(move |_| {
                db.put(&bucket, &key2, &value2).and_then(move |_| {
                    db.list(&bucket, &key)
                })
            })
        }, Ok(vec![(key.to_vec(), value.to_vec()), (key2.to_vec(), value2.to_vec())]));
    }
}
<|endoftext|>


<commit_before>use std::io::{File, BufferedReader};
use std::io::SeekStyle::SeekSet;
use std::io::IoResult;
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use elem::{PerElem, Molecule};

#[derive(Show, PartialEq)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_single_data(&mut self, elem: &PerElem) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.get_mut().seek(0, SeekSet).ok().expect("Internal error reading database");
        let mut line_iter = self.db.lines();
        let elem_or_err = |&:line: &IoResult<String>| {
            if let Ok(ref l) = *line {
                l.starts_with(elem.name.as_slice())
            } else {
                true
            }
        };
        match line_iter.find(elem_or_err) {
            Some(Ok(ref line)) => decode_line(line),
            Some(Err(_)) => Err(DatabaseError(CTDatabaseError {
                desc: "Error reading the database".to_string()
            })),
            None => Err(SyntaxError(CTSyntaxError {
                desc: format!("Could not find element: {:?}", elem.name),
                pos: elem.pos,
                len: elem.len,
            })),
        }
    }

    pub fn get_data(&mut self, elems: &Molecule) -> CTResult<Vec<ElemData>> {
        let mut out = Vec::new();
        for elem in elems.iter() {
           match self.get_single_data(elem) {
                Ok(data) => out.push(data),
                Err(e) => return Err(e),
            }
        }
        Ok(out)
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::File;
    use std::io::fs;
    use elem::PerElem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(name).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn multiple_elems() {
        let db_name = "multiple_elems_db";
        let mut db = make_dummy_db(db_name,
            "A;1;Abba;2\n\
            B;3;Beta;4");
        let raw_result = db.get_data(&vec!(
            PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 1 },
            PerElem { name: "A".to_string(), coef: 1, pos: 1, len: 1 }
        ));
        let expected = vec!(
            ElemData {
                short_name: "B".to_string(),
                long_name: "Beta".to_string(),
                mass: 3.0,
                atomic_num: 4,
            },
            ElemData {
                short_name: "A".to_string(),
                long_name: "Abba".to_string(),
                mass: 1.0,
                atomic_num: 2,
            }
        );
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn find_elem() {
        let db_name = "find_elem_db";
        let mut db = make_dummy_db(db_name,
            "A;0;Abba;0\n\
            B;123.456789;Beta;12\n\
            C;0;Coop;0");
        let raw_result = db.get_single_data(
            &PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 2 }
        );
        let expected = ElemData {
            short_name: "B".to_string(),
            long_name: "Beta".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_elem() {
        let db_name = "missing_elem_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let result = db.get_single_data(
            &PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(
            &PerElem { name: "A".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12");
        let result = db.get_single_data(
            &PerElem { name: "A".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<commit_msg>Make ElemData fields public<commit_after>use std::io::{File, BufferedReader};
use std::io::SeekStyle::SeekSet;
use std::io::IoResult;
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use elem::{PerElem, Molecule};

#[derive(Show, PartialEq)]
pub struct ElemData {
    pub short_name: String,
    pub long_name: String,
    pub mass: f64,
    pub atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_single_data(&mut self, elem: &PerElem) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.get_mut().seek(0, SeekSet).ok().expect("Internal error reading database");
        let mut line_iter = self.db.lines();
        let elem_or_err = |&:line: &IoResult<String>| {
            if let Ok(ref l) = *line {
                l.starts_with(elem.name.as_slice())
            } else {
                true
            }
        };
        match line_iter.find(elem_or_err) {
            Some(Ok(ref line)) => decode_line(line),
            Some(Err(_)) => Err(DatabaseError(CTDatabaseError {
                desc: "Error reading the database".to_string()
            })),
            None => Err(SyntaxError(CTSyntaxError {
                desc: format!("Could not find element: {:?}", elem.name),
                pos: elem.pos,
                len: elem.len,
            })),
        }
    }

    pub fn get_data(&mut self, elems: &Molecule) -> CTResult<Vec<ElemData>> {
        let mut out = Vec::new();
        for elem in elems.iter() {
           match self.get_single_data(elem) {
                Ok(data) => out.push(data),
                Err(e) => return Err(e),
            }
        }
        Ok(out)
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::File;
    use std::io::fs;
    use elem::PerElem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(name).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn multiple_elems() {
        let db_name = "multiple_elems_db";
        let mut db = make_dummy_db(db_name,
            "A;1;Abba;2\n\
            B;3;Beta;4");
        let raw_result = db.get_data(&vec!(
            PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 1 },
            PerElem { name: "A".to_string(), coef: 1, pos: 1, len: 1 }
        ));
        let expected = vec!(
            ElemData {
                short_name: "B".to_string(),
                long_name: "Beta".to_string(),
                mass: 3.0,
                atomic_num: 4,
            },
            ElemData {
                short_name: "A".to_string(),
                long_name: "Abba".to_string(),
                mass: 1.0,
                atomic_num: 2,
            }
        );
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn find_elem() {
        let db_name = "find_elem_db";
        let mut db = make_dummy_db(db_name,
            "A;0;Abba;0\n\
            B;123.456789;Beta;12\n\
            C;0;Coop;0");
        let raw_result = db.get_single_data(
            &PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 2 }
        );
        let expected = ElemData {
            short_name: "B".to_string(),
            long_name: "Beta".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_elem() {
        let db_name = "missing_elem_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let result = db.get_single_data(
            &PerElem { name: "B".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(
            &PerElem { name: "A".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12");
        let result = db.get_single_data(
            &PerElem { name: "A".to_string(), coef: 1, pos: 0, len: 2 }
        );
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<|endoftext|>


<commit_before>mod r5rs {
    #[deriving(Eq)]
    enum LDatum {
        LIdent(~str),
        LString(~str),
    }

    struct Parser {
        priv reader: @io::Reader,
        priv buf: char,
        priv has_buf: bool,
        line: uint,
        col: uint,
    }

    pub fn Parser(reader: @io::Reader) -> Parser {
        Parser {
            reader: reader,
            has_buf: false,
            buf: 0 as char,
            line: 1,
            col: 1,
        }
    }

    priv fn id_init(c: char) -> bool {
        match(c) {
            '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' | 'a' .. 'z' | 'A' .. 'Z' => true,
            _ => false,
        }
    }
    pub impl Parser {
        fn parse(&mut self) -> Result<LDatum, ~str> {
            do result::chain(self.parse_datum()) |v| {
                self.consume_whitespace();

                if(self.eof()) {
                    Ok(v)
                } else {
                    Err(~"trailing input")
                }
            }
        }
    }

    priv impl Parser {
        fn eof(&mut self) -> bool {
            !self.has_buf && self.reader.eof()
        }

        fn consume(&mut self) -> char {
            if(self.has_buf) {
                self.has_buf = false;
            } else {
                self.buf = self.reader.read_char();
            }

            if(self.buf == '\n') {
                self.line += 1;
                self.col = 1;
            } else {
                self.col += 1;
            }

            self.buf
        }

        fn lookahead(&mut self) -> char {
            if(!self.has_buf) {
                self.has_buf = true;
                self.buf = self.reader.read_char();
            }
            self.buf
        }

        fn consume_whitespace(&mut self) {
            while(!self.eof()) {
                match(self.lookahead()) {
                    ' '| '\t' | '\r' | '\n' => { self.consume(); },
                    _ => break
                }
            }
        }

        fn parse_datum(&mut self) -> Result<LDatum, ~str> {
            self.consume_whitespace();

            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.lookahead();
            match(c) {
                _ if id_init(c) =>
                    Ok(LIdent(self.parse_ident())),
                '"' => {
                        self.consume();
                        match(self.parse_string()) {
                            Ok(s) => Ok(LString(s)),
                            Err(e) => Err(e),
                        }
                    },
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_ident(&mut self) -> ~str {
            do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.lookahead();

                    match(c) {
                        '0' .. '9' | '+' | '-' | '.' | '@' => wr.write_char(c),
                        _ if id_init(c) => wr.write_char(c),
                        _ => break,
                    }

                    self.consume();
                }
            }
        }

        fn parse_string(&mut self) -> Result<~str, ~str> {
            let mut escape_fail = false;

            let val = do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.consume();
                    match(c) {
                        '\\' => if self.eof() {
                                    escape_fail = true;
                                } else {
                                    wr.write_char(self.consume());
                                },
                        '"' => break,
                        _ => wr.write_char(c),
                    }
                }
            };

            if(escape_fail) {
                Err(~"unexpected EOF")
            } else {
                Ok(val)
            }
        }
    }

    #[test]
    fn test_parse_ident() {
        let test_src = ~"a3!";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LIdent(~"a3!")), val);
        }
    }

    #[test]
    fn test_parse_string() {
        let test_src = ~"\"ab\\\"c\"";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LString(~"ab\"c")), val);
        }
    }
}
<commit_msg>add newline<commit_after>mod r5rs {
    #[deriving(Eq)]
    enum LDatum {
        LIdent(~str),
        LString(~str),
    }

    struct Parser {
        priv reader: @io::Reader,
        priv buf: char,
        priv has_buf: bool,
        line: uint,
        col: uint,
    }

    pub fn Parser(reader: @io::Reader) -> Parser {
        Parser {
            reader: reader,
            has_buf: false,
            buf: 0 as char,
            line: 1,
            col: 1,
        }
    }

    priv fn id_init(c: char) -> bool {
        match(c) {
            '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' | 'a' .. 'z' | 'A' .. 'Z' => true,
            _ => false,
        }
    }

    pub impl Parser {
        fn parse(&mut self) -> Result<LDatum, ~str> {
            do result::chain(self.parse_datum()) |v| {
                self.consume_whitespace();

                if(self.eof()) {
                    Ok(v)
                } else {
                    Err(~"trailing input")
                }
            }
        }
    }

    priv impl Parser {
        fn eof(&mut self) -> bool {
            !self.has_buf && self.reader.eof()
        }

        fn consume(&mut self) -> char {
            if(self.has_buf) {
                self.has_buf = false;
            } else {
                self.buf = self.reader.read_char();
            }

            if(self.buf == '\n') {
                self.line += 1;
                self.col = 1;
            } else {
                self.col += 1;
            }

            self.buf
        }

        fn lookahead(&mut self) -> char {
            if(!self.has_buf) {
                self.has_buf = true;
                self.buf = self.reader.read_char();
            }
            self.buf
        }

        fn consume_whitespace(&mut self) {
            while(!self.eof()) {
                match(self.lookahead()) {
                    ' '| '\t' | '\r' | '\n' => { self.consume(); },
                    _ => break
                }
            }
        }

        fn parse_datum(&mut self) -> Result<LDatum, ~str> {
            self.consume_whitespace();

            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.lookahead();
            match(c) {
                _ if id_init(c) =>
                    Ok(LIdent(self.parse_ident())),
                '"' => {
                        self.consume();
                        match(self.parse_string()) {
                            Ok(s) => Ok(LString(s)),
                            Err(e) => Err(e),
                        }
                    },
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_ident(&mut self) -> ~str {
            do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.lookahead();

                    match(c) {
                        '0' .. '9' | '+' | '-' | '.' | '@' => wr.write_char(c),
                        _ if id_init(c) => wr.write_char(c),
                        _ => break,
                    }

                    self.consume();
                }
            }
        }

        fn parse_string(&mut self) -> Result<~str, ~str> {
            let mut escape_fail = false;

            let val = do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.consume();
                    match(c) {
                        '\\' => if self.eof() {
                                    escape_fail = true;
                                } else {
                                    wr.write_char(self.consume());
                                },
                        '"' => break,
                        _ => wr.write_char(c),
                    }
                }
            };

            if(escape_fail) {
                Err(~"unexpected EOF")
            } else {
                Ok(val)
            }
        }
    }

    #[test]
    fn test_parse_ident() {
        let test_src = ~"a3!";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LIdent(~"a3!")), val);
        }
    }

    #[test]
    fn test_parse_string() {
        let test_src = ~"\"ab\\\"c\"";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LString(~"ab\"c")), val);
        }
    }
}
<|endoftext|>


<commit_before>use super::packet_batch::cast_from_u8;
use std::marker::PhantomData;
use super::super::interface::EndOffset;
use std::any::Any;
use std::cell::Cell;
/// An interface implemented by all batches for iterating through the set of packets in a batch.
/// This is private to the framework and not exposed.
///
/// # Safety
/// These methods are marked unsafe since they return pointers to packet mbufs. As long as packet mbufs are treated
/// correctly (i.e., assumed freed after send, freed correctly, allocated correctly, etc.) this should be safe.
/// Furthermore, dropping a packet might result in unexpected behavior (e.g., packets being skipped) but will not result
/// in crashes. Generally, do not drop or move packets during iteration, it is safer to collect the list/set of
/// packets to be modified and apply this modification later. Everything about iterator invalidation is likely to change
/// later.
pub trait BatchIterator {
    /// Returns the starting index for the packet batch. This allows for cases where the head of the batch is not at
    /// index 0.
    fn start(&mut self) -> usize;

    /// If packets are available, returns the address of the header at index `idx` in the current batch, and the index
    /// for the next packet to be processed. If packets are not available returns None. N.B., header address depends on
    /// the number of parse nodes and composition nodes seen so far.
    unsafe fn next_address(&mut self, idx: usize) -> Option<(*mut u8, Option<&mut Any>, usize)>;

    /// If packets are available, returns the address of the payload at index `idx` in the current batch, and the index
    /// for the next packet to be processed. If packets are not available returns None. N.B., payload address depends on
    /// the number of parse nodes and composition nodes seen so far.
    unsafe fn next_payload(&mut self, idx: usize) -> Option<(*mut u8, *mut u8, usize, Option<&mut Any>, usize)>;

    /// If packets are available, returns the address of the mbuf data_address. This is mostly to allow chained NFs to
    /// begin accessing data from the beginning. Other semantics are identical to `next_address` above.
    unsafe fn next_base_address(&mut self, idx: usize) -> Option<(*mut u8, Option<&mut Any>, usize)>;

    /// If packets are available, returns the address of the mbuf data_address. This is mostly to allow chained NFs to
    /// begin accessing data from the beginning. Other semantics are identical to `next_address` above.
    unsafe fn next_base_payload(&mut self, idx: usize) -> Option<(*mut u8, *mut u8, usize, Option<&mut Any>, usize)>;
}

/// Iterate over packets in a batch. This iterator merely returns the header from the packet, and expects that
/// applications are agnostic to the index for a packet. N.B., this should be used with a for-loop.
pub struct PacketBatchIterator<T>
    where T: EndOffset
{
    idx: Cell<usize>,
    phantom: PhantomData<T>,
}

impl<T> PacketBatchIterator<T>
    where T: EndOffset
{
    #[inline]
    pub fn new(batch: &mut BatchIterator) -> PacketBatchIterator<T> {
        let start = batch.start();
        PacketBatchIterator {
            idx: Cell::new(start),
            phantom: PhantomData,
        }
    }

    #[inline]
    pub fn next<'a>(&'a self, batch: &'a mut BatchIterator) -> Option<(&'a mut T, Option<&'a mut Any>)> {
        let item = unsafe { batch.next_address(self.idx.get()) };
        match item {
            Some((addr, ctx, idx)) => {
                let packet = cast_from_u8::<T>(addr);
                self.idx.set(idx);
                Some((packet, ctx))
            }
            None => None,
        }
    }
}

/// Enumerate packets in a batch, i.e., return both index and packet. Note, the index is meaningless outside of this
/// particular batch, in particular the index does not reveal how many packets are in a batch (batch might not start
/// from the beginning), might not be sequential (lazy filtering), etc. We however do guarantee that the iterator will
/// present monotonically increasing indices. Please do not use the index for anything other than as a handle for
/// packets.
pub struct PacketBatchEnumerator<T>
    where T: EndOffset
{
    idx: Cell<usize>,
    phantom: PhantomData<T>,
}

impl<T> PacketBatchEnumerator<T>
    where T: EndOffset
{
    #[inline]
    pub fn new(batch: &mut BatchIterator) -> PacketBatchEnumerator<T> {
        let start = batch.start();
        PacketBatchEnumerator {
            idx: Cell::new(start),
            phantom: PhantomData,
        }
    }

    #[inline]
    pub fn next<'a>(&'a self, batch: &'a mut BatchIterator) -> Option<(usize, &'a mut T, Option<&'a mut Any>)> {
        let original_idx = self.idx.get();
        let item = unsafe { batch.next_address(original_idx) };
        match item {
            Some((addr, ctx, next_idx)) => {
                let packet = cast_from_u8::<T>(addr);
                self.idx.set(next_idx);
                Some((original_idx, packet, ctx))
            }
            None => None,
        }
    }
}
<commit_msg>Add payload iterator<commit_after>use super::packet_batch::cast_from_u8;
use std::marker::PhantomData;
use super::super::interface::EndOffset;
use std::any::Any;
use std::cell::Cell;
use std::slice::*;
/// An interface implemented by all batches for iterating through the set of packets in a batch.
/// This is private to the framework and not exposed.
///
/// # Safety
/// These methods are marked unsafe since they return pointers to packet mbufs. As long as packet mbufs are treated
/// correctly (i.e., assumed freed after send, freed correctly, allocated correctly, etc.) this should be safe.
/// Furthermore, dropping a packet might result in unexpected behavior (e.g., packets being skipped) but will not result
/// in crashes. Generally, do not drop or move packets during iteration, it is safer to collect the list/set of
/// packets to be modified and apply this modification later. Everything about iterator invalidation is likely to change
/// later.
pub trait BatchIterator {
    /// Returns the starting index for the packet batch. This allows for cases where the head of the batch is not at
    /// index 0.
    fn start(&mut self) -> usize;

    /// If packets are available, returns the address of the header at index `idx` in the current batch, and the index
    /// for the next packet to be processed. If packets are not available returns None. N.B., header address depends on
    /// the number of parse nodes and composition nodes seen so far.
    unsafe fn next_address(&mut self, idx: usize) -> Option<(*mut u8, Option<&mut Any>, usize)>;

    /// If packets are available, returns the address of the header and payload at index `idx` in the current batch, and
    /// the index for the next packet to be processed. If packets are not available returns None. N.B., payload address
    /// depends on the number of parse nodes and composition nodes seen so far.
    unsafe fn next_payload(&mut self, idx: usize) -> Option<(*mut u8, *mut u8, usize, Option<&mut Any>, usize)>;

    /// If packets are available, returns the address of the mbuf data_address. This is mostly to allow chained NFs to
    /// begin accessing data from the beginning. Other semantics are identical to `next_address` above.
    unsafe fn next_base_address(&mut self, idx: usize) -> Option<(*mut u8, Option<&mut Any>, usize)>;

    /// If packets are available, returns the address of the mbuf data_address. This is mostly to allow chained NFs to
    /// begin accessing data from the beginning. Other semantics are identical to `next_address` above.
    unsafe fn next_base_payload(&mut self, idx: usize) -> Option<(*mut u8, *mut u8, usize, Option<&mut Any>, usize)>;
}

/// Iterate over packets in a batch. This iterator merely returns the header from the packet, and expects that
/// applications are agnostic to the index for a packet. N.B., this should be used with a for-loop.
pub struct PacketBatchIterator<T>
    where T: EndOffset
{
    idx: Cell<usize>,
    phantom: PhantomData<T>,
}

impl<T> PacketBatchIterator<T>
    where T: EndOffset
{
    #[inline]
    pub fn new(batch: &mut BatchIterator) -> PacketBatchIterator<T> {
        let start = batch.start();
        PacketBatchIterator {
            idx: Cell::new(start),
            phantom: PhantomData,
        }
    }

    #[inline]
    pub fn next<'a>(&'a self, batch: &'a mut BatchIterator) -> Option<(&'a mut T, Option<&'a mut Any>)> {
        let item = unsafe { batch.next_address(self.idx.get()) };
        match item {
            Some((addr, ctx, idx)) => {
                let packet = cast_from_u8::<T>(addr);
                self.idx.set(idx);
                Some((packet, ctx))
            }
            None => None,
        }
    }
}

/// Enumerate packets in a batch, i.e., return both index and packet. Note, the index is meaningless outside of this
/// particular batch, in particular the index does not reveal how many packets are in a batch (batch might not start
/// from the beginning), might not be sequential (lazy filtering), etc. We however do guarantee that the iterator will
/// present monotonically increasing indices. Please do not use the index for anything other than as a handle for
/// packets.
pub struct PacketBatchEnumerator<T>
    where T: EndOffset
{
    idx: Cell<usize>,
    phantom: PhantomData<T>,
}

impl<T> PacketBatchEnumerator<T>
    where T: EndOffset
{
    #[inline]
    pub fn new(batch: &mut BatchIterator) -> PacketBatchEnumerator<T> {
        let start = batch.start();
        PacketBatchEnumerator {
            idx: Cell::new(start),
            phantom: PhantomData,
        }
    }

    #[inline]
    pub fn next<'a>(&'a self, batch: &'a mut BatchIterator) -> Option<(usize, &'a mut T, Option<&'a mut Any>)> {
        let original_idx = self.idx.get();
        let item = unsafe { batch.next_address(original_idx) };
        match item {
            Some((addr, ctx, next_idx)) => {
                let packet = cast_from_u8::<T>(addr);
                self.idx.set(next_idx);
                Some((original_idx, packet, ctx))
            }
            None => None,
        }
    }
}

pub struct PayloadEnumerator<T>
    where T: EndOffset
{
    idx: Cell<usize>,
    phantom: PhantomData<T>,
}

impl<T> PayloadEnumerator<T>
    where T:EndOffset
{
    #[inline]
    pub fn new(batch: &mut BatchIterator) -> PayloadEnumerator<T> {
        let start = batch.start();
        PayloadEnumerator {
            idx: Cell::new(start),
            phantom: PhantomData,
        }
    }

    #[inline]
    pub fn next<'a>(&'a self, batch: &'a mut BatchIterator)
        -> Option<(usize, &'a mut T, &'a mut [u8], Option<&'a mut Any>)> {
        let original_idx = self.idx.get();
        let item = unsafe { batch.next_payload(original_idx) };
        match item {
            Some((haddr, payload, payload_size, ctx, next_idx)) => {
                let header = cast_from_u8::<T>(haddr);
                // This is safe (assuming our size accounting has been correct so far).
                let payload_slice = unsafe { from_raw_parts_mut::<u8>(payload, payload_size) };
                self.idx.set(next_idx);
                Some((original_idx, header, payload_slice, ctx))
            }
            None => None,
        }
    }
}
<|endoftext|>


<commit_before>use fool::BoolExt;
use std::borrow::Borrow;
use std::collections::{HashSet, VecDeque};

use crate::entity::borrow::{Reborrow, ReborrowInto, ReborrowMut};
use crate::entity::storage::AsStorage;
use crate::entity::view::{Bind, ClosedView};
use crate::graph::edge::{Arc, ArcKey, ArcView};
use crate::graph::geometry::{Geometric, Geometry, GraphGeometry};
use crate::graph::mutation::Consistent;
use crate::graph::vertex::{Vertex, VertexKey, VertexView};
use crate::graph::{GraphError, OptionExt as _, Selector};
use crate::IteratorExt as _;

/// Non-intersecting path.
///
/// A path is an ordered set of vertices that are joined by arcs. Paths are
/// notated as either sequences or sets. An open path over vertices $A$, $B$,
/// and $C$ is notated $\overrightarrow{(A,B,C)}$ and a closed path over the
/// same vertices is notated $\overrightarrow{\\{A,B,C\\}}$.
///
/// `Path` represents non-intersecting paths of the form
/// $\overrightarrow{(A,\cdots,B)}$, where $A$ is the _back_ of the path and $B$
/// is the _front_ of the path. Note that closed paths are always of the form
/// $\overrightarrow{(A,\cdots,A)}$, where the back and front vertices are both
/// $A$ (the same).
#[derive(Clone)]
pub struct Path<B>
where
    B: Reborrow,
    B::Target:
        AsStorage<Arc<Geometry<B>>> + AsStorage<Vertex<Geometry<B>>> + Consistent + Geometric,
{
    keys: VecDeque<ArcKey>,
    storage: B,
}

impl<B, M, G> Path<B>
where
    B: Reborrow<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    // Paths bind multiple keys to storage and so do not support view APIs.
    // This bespoke `bind` function ensures that the path is not empty and that
    // the topology forms a non-intersecting path.
    pub(in crate::graph) fn bind<I>(storage: B, keys: I) -> Result<Self, GraphError>
    where
        I: IntoIterator,
        I::Item: Borrow<VertexKey>,
    {
        let mut keys = keys.into_iter().map(|key| *key.borrow());
        let a = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let b = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let ab = (a, b).into();
        ArcView::bind(storage.reborrow(), ab).ok_or_else(|| GraphError::TopologyNotFound)?;
        let mut path = Path {
            keys: (&[ab]).iter().cloned().collect(),
            storage,
        };
        for key in keys {
            path.push_front(Selector::ByKey(key))?;
        }
        Ok(path)
    }

    pub fn to_ref(&self) -> Path<&M> {
        let storage = self.storage.reborrow();
        let keys = self.keys.iter();
        Path::bind_unchecked(storage, keys)
    }

    /// Pushes a vertex onto the back of the path.
    ///
    /// The back of a path $\overrightarrow{(A,\cdots)}$ is the vertex $A$.
    /// This is the source vertex of the first arc that forms the path.
    ///
    /// The given vertex must be a source vertex of an arc formed with the the
    /// back of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{XA}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{XA}$ inserted into the path
    /// using the given source vertex $X$.
    ///
    /// # Errors
    ///
    /// Returns an error if the path is closed, the given vertex is not found,
    /// or the given vertex does not form an arc with the back of the path.
    pub fn push_back(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let back = self.back();
        let xa = match destination {
            Selector::ByKey(key) => back
                .incoming_arcs()
                .find(|arc| arc.into_source_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = back
                    .adjacent_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (x, back.key()).into()
            }
        };
        let (x, _) = xa.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the front of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_back(xa);
            Ok(xa)
        }
    }

    /// Pops a vertex from the back of the path.
    pub fn pop_back(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_back()
        }
        else {
            None
        }
    }

    /// Pushes a vertex onto the front of the path.
    ///
    /// The front of a path $\overrightarrow{(\cdots,B)}$ is the vertex $B$.
    /// This is the destination vertex of the last arc that forms the path.
    ///
    /// The given vertex must be a destination vertex of an arc formed with the
    /// the front of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{BX}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{BX}$ inserted into the path
    /// using the given source vertex $X$.
    ///
    /// # Errors
    ///
    /// Returns an error if the path is closed, the given vertex is not found,
    /// or the given vertex does not form an arc with the front of the path.
    pub fn push_front(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let front = self.front();
        let bx = match destination {
            Selector::ByKey(key) => front
                .outgoing_arcs()
                .find(|arc| arc.into_destination_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = front
                    .adjacent_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (front.key(), x).into()
            }
        };
        let (_, x) = bx.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the back of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_destination_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_front(bx);
            Ok(bx)
        }
    }

    /// Pops a vertex from the front of the path.
    pub fn pop_front(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_front()
        }
        else {
            None
        }
    }

    /// Gets the vertex at the back of the path.
    pub fn back(&self) -> VertexView<&M> {
        let (key, _) = self.endpoints();
        Bind::bind(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets the vertex at the front of the path.
    pub fn front(&self) -> VertexView<&M> {
        let (_, key) = self.endpoints();
        Bind::bind(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets an iterator over the vertices in the path.
    pub fn vertices<'a>(&'a self) -> impl Iterator<Item = VertexView<&'a M>>
    where
        M: 'a,
    {
        let back = self.back();
        Some(back)
            .into_iter()
            .chain(self.arcs().map(|arc| arc.into_destination_vertex()))
    }

    /// Gets an iterator over the arcs in the path.
    pub fn arcs<'a>(&'a self) -> impl ExactSizeIterator<Item = ArcView<&'a M>>
    where
        M: 'a,
    {
        let storage = self.storage.reborrow();
        self.keys
            .iter()
            .rev()
            .cloned()
            .map(move |key| Bind::bind(storage, key).expect_consistent())
    }

    /// Returns `true` if the path is open.
    ///
    /// An _open path_ is a path that terminates and does **not** form a loop.
    pub fn is_open(&self) -> bool {
        !self.is_closed()
    }

    /// Returns `true` if the path is closed.
    ///
    /// A _closed path_ is a path that forms a loop by starting and ending at
    /// the same vertex.
    pub fn is_closed(&self) -> bool {
        let (a, b) = self.endpoints();
        a == b
    }

    fn bind_unchecked<I>(storage: B, keys: I) -> Self
    where
        I: IntoIterator,
        I::Item: Borrow<ArcKey>,
    {
        let keys = keys.into_iter().map(|key| *key.borrow()).collect();
        Path { storage, keys }
    }

    fn endpoints(&self) -> (VertexKey, VertexKey) {
        let (a, _) = self.keys.back().cloned().expect("empty path").into();
        let (_, b) = self.keys.front().cloned().expect("empty pathy").into();
        (a, b)
    }
}

impl<B, M, G> Path<B>
where
    B: ReborrowMut<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    pub fn to_mut(&mut self) -> Path<&mut M> {
        let storage = self.storage.reborrow_mut();
        let keys = self.keys.iter();
        Path::bind_unchecked(storage, keys)
    }
}

impl<'a, B, M, G> Path<B>
where
    B: ReborrowInto<'a, Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    /// Converts a mutable view into an immutable view.
    ///
    /// This is useful when mutations are not (or no longer) needed and mutual
    /// access is desired.
    pub fn into_ref(self) -> Path<&'a M> {
        let Path { keys, storage, .. } = self;
        Path {
            keys,
            storage: storage.reborrow_into(),
        }
    }

    /// Splits the path into two immutable paths at the given vertex.
    ///
    /// Given a path $\overrightarrow{(A,\cdots,M,\cdots,B)}$, splitting at the
    /// vertex $M$ results in the paths $\overrightarrow{(A,\cdots,M)}$ and
    /// $\overrightarrow{(M,\cdots,B)}$.
    ///
    /// **Splitting a path does not mutate its graph in any way** (unlike
    /// `ArcView::split` or `FaceView::split`, for example). To split a graph
    /// along a path (and thus mutate the graph) use `MeshGraph::split_at_path`.
    ///
    /// It is not possible to split a path at its back or front vertices.
    ///
    /// # Errors
    ///
    /// Returns an error if the given vertex cannot be found or the path cannot
    /// be split at that vertex.
    pub fn split(self, at: Selector<VertexKey>) -> Result<(Path<&'a M>, Path<&'a M>), GraphError> {
        let index = at.index_or_else(|key| {
            self.vertices()
                .keys()
                .enumerate()
                .find(|(_, a)| *a == key)
                .map(|(n, _)| n)
                .ok_or_else(|| GraphError::TopologyNotFound)
        })?;
        if index == 0 || index >= self.keys.len() {
            return Err(GraphError::TopologyMalformed);
        }
        let Path {
            keys: mut right,
            storage,
            ..
        } = self.into_ref();
        let left = right.split_off(index);
        Ok((
            Path::bind_unchecked(storage, left),
            Path::bind_unchecked(storage, right),
        ))
    }
}

impl<B, M, G> PartialEq for Path<B>
where
    B: Reborrow<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    fn eq(&self, other: &Self) -> bool {
        let keys = |path: &Self| path.arcs().keys().collect::<HashSet<_>>();
        keys(self) == keys(other)
    }
}

#[cfg(test)]
mod tests {
    use nalgebra::Point2;

    use crate::graph::{ClosedView, MeshGraph, Selector};
    use crate::prelude::*;
    use crate::primitive::{Tetragon, Trigon};
    use crate::IteratorExt;

    use Selector::ByKey;

    type E2 = Point2<f64>;

    #[test]
    fn open_close() {
        let graph = MeshGraph::<E2>::from_raw_buffers(
            vec![Trigon::from([0usize, 1, 2])],
            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)],
        )
        .unwrap();
        let keys = graph
            .faces()
            .nth(0)
            .unwrap()
            .interior_arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .collect::<Vec<_>>();

        let mut path = graph.path(keys.iter()).unwrap();
        assert!(path.is_open());
        // TODO: Move this assertion to a distinct test.
        assert_eq!(path.vertices().keys().collect::<Vec<_>>(), keys.to_vec());

        path.push_front(ByKey(keys[0])).unwrap();
        assert!(path.is_closed());
        assert_eq!(path.front().key(), path.back().key());
    }

    #[test]
    fn split() {
        let graph =
            MeshGraph::<()>::from_raw_buffers(vec![Tetragon::from([0usize, 1, 2, 3])], vec![(); 4])
                .unwrap();
        let source = graph.vertices().nth(0).unwrap();
        let destination = source
            .into_outgoing_arc()
            .into_next_arc()
            .into_destination_vertex();

        let path = source.shortest_path(destination.key()).unwrap();
        assert_eq!(path.arcs().count(), 2);

        let (left, right) = path.split(ByIndex(1)).unwrap();
        assert_eq!(left.front().key(), right.back().key());
        assert_eq!(left.arcs().count(), 1);
        assert_eq!(right.arcs().count(), 1);
    }
}
<commit_msg>Do not recollect keys when splitting paths.<commit_after>use fool::BoolExt;
use std::borrow::Borrow;
use std::collections::{HashSet, VecDeque};

use crate::entity::borrow::{Reborrow, ReborrowInto, ReborrowMut};
use crate::entity::storage::AsStorage;
use crate::entity::view::{Bind, ClosedView};
use crate::graph::edge::{Arc, ArcKey, ArcView};
use crate::graph::geometry::{Geometric, Geometry, GraphGeometry};
use crate::graph::mutation::Consistent;
use crate::graph::vertex::{Vertex, VertexKey, VertexView};
use crate::graph::{GraphError, OptionExt as _, Selector};
use crate::IteratorExt as _;

/// Non-intersecting path.
///
/// A path is an ordered set of vertices that are joined by arcs. Paths are
/// notated as either sequences or sets. An open path over vertices $A$, $B$,
/// and $C$ is notated $\overrightarrow{(A,B,C)}$ and a closed path over the
/// same vertices is notated $\overrightarrow{\\{A,B,C\\}}$.
///
/// `Path` represents non-intersecting paths of the form
/// $\overrightarrow{(A,\cdots,B)}$, where $A$ is the _back_ of the path and $B$
/// is the _front_ of the path. Note that closed paths are always of the form
/// $\overrightarrow{(A,\cdots,A)}$, where the back and front vertices are both
/// $A$ (the same).
#[derive(Clone)]
pub struct Path<B>
where
    B: Reborrow,
    B::Target:
        AsStorage<Arc<Geometry<B>>> + AsStorage<Vertex<Geometry<B>>> + Consistent + Geometric,
{
    keys: VecDeque<ArcKey>,
    storage: B,
}

impl<B, M, G> Path<B>
where
    B: Reborrow<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    // Paths bind multiple keys to storage and so do not support view APIs.
    // This bespoke `bind` function ensures that the path is not empty and that
    // the topology forms a non-intersecting path.
    pub(in crate::graph) fn bind<I>(storage: B, keys: I) -> Result<Self, GraphError>
    where
        I: IntoIterator,
        I::Item: Borrow<VertexKey>,
    {
        let mut keys = keys.into_iter().map(|key| *key.borrow());
        let a = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let b = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let ab = (a, b).into();
        ArcView::bind(storage.reborrow(), ab).ok_or_else(|| GraphError::TopologyNotFound)?;
        let mut path = Path {
            keys: (&[ab]).iter().cloned().collect(),
            storage,
        };
        for key in keys {
            path.push_front(Selector::ByKey(key))?;
        }
        Ok(path)
    }

    pub fn to_ref(&self) -> Path<&M> {
        let storage = self.storage.reborrow();
        let keys = self.keys.iter();
        Path::bind_unchecked(storage, keys)
    }

    /// Pushes a vertex onto the back of the path.
    ///
    /// The back of a path $\overrightarrow{(A,\cdots)}$ is the vertex $A$.
    /// This is the source vertex of the first arc that forms the path.
    ///
    /// The given vertex must be a source vertex of an arc formed with the the
    /// back of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{XA}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{XA}$ inserted into the path
    /// using the given source vertex $X$.
    ///
    /// # Errors
    ///
    /// Returns an error if the path is closed, the given vertex is not found,
    /// or the given vertex does not form an arc with the back of the path.
    pub fn push_back(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let back = self.back();
        let xa = match destination {
            Selector::ByKey(key) => back
                .incoming_arcs()
                .find(|arc| arc.into_source_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = back
                    .adjacent_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (x, back.key()).into()
            }
        };
        let (x, _) = xa.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the front of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_back(xa);
            Ok(xa)
        }
    }

    /// Pops a vertex from the back of the path.
    pub fn pop_back(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_back()
        }
        else {
            None
        }
    }

    /// Pushes a vertex onto the front of the path.
    ///
    /// The front of a path $\overrightarrow{(\cdots,B)}$ is the vertex $B$.
    /// This is the destination vertex of the last arc that forms the path.
    ///
    /// The given vertex must be a destination vertex of an arc formed with the
    /// the front of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{BX}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{BX}$ inserted into the path
    /// using the given source vertex $X$.
    ///
    /// # Errors
    ///
    /// Returns an error if the path is closed, the given vertex is not found,
    /// or the given vertex does not form an arc with the front of the path.
    pub fn push_front(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let front = self.front();
        let bx = match destination {
            Selector::ByKey(key) => front
                .outgoing_arcs()
                .find(|arc| arc.into_destination_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = front
                    .adjacent_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (front.key(), x).into()
            }
        };
        let (_, x) = bx.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the back of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_destination_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_front(bx);
            Ok(bx)
        }
    }

    /// Pops a vertex from the front of the path.
    pub fn pop_front(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_front()
        }
        else {
            None
        }
    }

    /// Gets the vertex at the back of the path.
    pub fn back(&self) -> VertexView<&M> {
        let (key, _) = self.endpoints();
        Bind::bind(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets the vertex at the front of the path.
    pub fn front(&self) -> VertexView<&M> {
        let (_, key) = self.endpoints();
        Bind::bind(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets an iterator over the vertices in the path.
    pub fn vertices<'a>(&'a self) -> impl Iterator<Item = VertexView<&'a M>>
    where
        M: 'a,
    {
        let back = self.back();
        Some(back)
            .into_iter()
            .chain(self.arcs().map(|arc| arc.into_destination_vertex()))
    }

    /// Gets an iterator over the arcs in the path.
    pub fn arcs<'a>(&'a self) -> impl ExactSizeIterator<Item = ArcView<&'a M>>
    where
        M: 'a,
    {
        let storage = self.storage.reborrow();
        self.keys
            .iter()
            .rev()
            .cloned()
            .map(move |key| Bind::bind(storage, key).expect_consistent())
    }

    /// Returns `true` if the path is open.
    ///
    /// An _open path_ is a path that terminates and does **not** form a loop.
    pub fn is_open(&self) -> bool {
        !self.is_closed()
    }

    /// Returns `true` if the path is closed.
    ///
    /// A _closed path_ is a path that forms a loop by starting and ending at
    /// the same vertex.
    pub fn is_closed(&self) -> bool {
        let (a, b) = self.endpoints();
        a == b
    }

    fn bind_unchecked<I>(storage: B, keys: I) -> Self
    where
        I: IntoIterator,
        I::Item: Borrow<ArcKey>,
    {
        let keys = keys.into_iter().map(|key| *key.borrow()).collect();
        Path { storage, keys }
    }

    fn endpoints(&self) -> (VertexKey, VertexKey) {
        let (a, _) = self.keys.back().cloned().expect("empty path").into();
        let (_, b) = self.keys.front().cloned().expect("empty pathy").into();
        (a, b)
    }
}

impl<B, M, G> Path<B>
where
    B: ReborrowMut<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    pub fn to_mut(&mut self) -> Path<&mut M> {
        let storage = self.storage.reborrow_mut();
        let keys = self.keys.iter();
        Path::bind_unchecked(storage, keys)
    }
}

impl<'a, B, M, G> Path<B>
where
    B: ReborrowInto<'a, Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    /// Converts a mutable view into an immutable view.
    ///
    /// This is useful when mutations are not (or no longer) needed and mutual
    /// access is desired.
    pub fn into_ref(self) -> Path<&'a M> {
        let Path { keys, storage, .. } = self;
        Path {
            keys,
            storage: storage.reborrow_into(),
        }
    }

    /// Splits the path into two immutable paths at the given vertex.
    ///
    /// Given a path $\overrightarrow{(A,\cdots,M,\cdots,B)}$, splitting at the
    /// vertex $M$ results in the paths $\overrightarrow{(A,\cdots,M)}$ and
    /// $\overrightarrow{(M,\cdots,B)}$.
    ///
    /// **Splitting a path does not mutate its graph in any way** (unlike
    /// `ArcView::split` or `FaceView::split`, for example). To split a graph
    /// along a path (and thus mutate the graph) use `MeshGraph::split_at_path`.
    ///
    /// It is not possible to split a path at its back or front vertices.
    ///
    /// # Errors
    ///
    /// Returns an error if the given vertex cannot be found or the path cannot
    /// be split at that vertex.
    pub fn split(self, at: Selector<VertexKey>) -> Result<(Path<&'a M>, Path<&'a M>), GraphError> {
        let index = at.index_or_else(|key| {
            self.vertices()
                .keys()
                .enumerate()
                .find(|(_, a)| *a == key)
                .map(|(n, _)| n)
                .ok_or_else(|| GraphError::TopologyNotFound)
        })?;
        if index == 0 || index >= self.keys.len() {
            return Err(GraphError::TopologyMalformed);
        }
        let Path {
            keys: mut right,
            storage,
            ..
        } = self.into_ref();
        let left = right.split_off(index);
        Ok((
            Path {
                keys: left,
                storage,
            },
            Path {
                keys: right,
                storage,
            },
        ))
    }
}

impl<B, M, G> PartialEq for Path<B>
where
    B: Reborrow<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    fn eq(&self, other: &Self) -> bool {
        let keys = |path: &Self| path.arcs().keys().collect::<HashSet<_>>();
        keys(self) == keys(other)
    }
}

#[cfg(test)]
mod tests {
    use nalgebra::Point2;

    use crate::graph::{ClosedView, MeshGraph, Selector};
    use crate::prelude::*;
    use crate::primitive::{Tetragon, Trigon};
    use crate::IteratorExt;

    use Selector::ByKey;

    type E2 = Point2<f64>;

    #[test]
    fn open_close() {
        let graph = MeshGraph::<E2>::from_raw_buffers(
            vec![Trigon::from([0usize, 1, 2])],
            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)],
        )
        .unwrap();
        let keys = graph
            .faces()
            .nth(0)
            .unwrap()
            .interior_arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .collect::<Vec<_>>();

        let mut path = graph.path(keys.iter()).unwrap();
        assert!(path.is_open());
        // TODO: Move this assertion to a distinct test.
        assert_eq!(path.vertices().keys().collect::<Vec<_>>(), keys.to_vec());

        path.push_front(ByKey(keys[0])).unwrap();
        assert!(path.is_closed());
        assert_eq!(path.front().key(), path.back().key());
    }

    #[test]
    fn split() {
        let graph =
            MeshGraph::<()>::from_raw_buffers(vec![Tetragon::from([0usize, 1, 2, 3])], vec![(); 4])
                .unwrap();
        let source = graph.vertices().nth(0).unwrap();
        let destination = source
            .into_outgoing_arc()
            .into_next_arc()
            .into_destination_vertex();

        let path = source.shortest_path(destination.key()).unwrap();
        assert_eq!(path.arcs().count(), 2);

        let (left, right) = path.split(ByIndex(1)).unwrap();
        assert_eq!(left.front().key(), right.back().key());
        assert_eq!(left.arcs().count(), 1);
        assert_eq!(right.arcs().count(), 1);
    }
}
<|endoftext|>


<commit_before>pub use std::{
    any::{Any, TypeId},
    cell::RefCell,
    collections::HashMap,
    fmt::Debug,
    rc::Rc,
};

pub use dces::prelude::*;

pub use crate::{
    core::macros::*, core::*, proc_macros::*, render::prelude::*, utils::prelude::*,
    widgets::prelude::*, Application,
};
<commit_msg>orbtk: update prelude documentation<commit_after>/// This module pre-selects commonly used OrbTk crates and put them into scope.
pub use std::{
    any::{Any, TypeId},
    cell::RefCell,
    collections::HashMap,
    fmt::Debug,
    rc::Rc,
};

pub use dces::prelude::*;

pub use crate::{
    core::macros::*, core::*, proc_macros::*, render::prelude::*, utils::prelude::*,
    widgets::prelude::*, Application,
};
<|endoftext|>