<commit_before>extern crate env_logger;
extern crate lzma_rs;
#[macro_use]
extern crate log;

fn round_trip(x: &[u8]) {
    let mut compressed: Vec<u8> = Vec::new();
    lzma_rs::lzma_compress(&mut std::io::BufReader::new(x), &mut compressed).unwrap();
    info!("Compressed {} -> {} bytes", x.len(), compressed.len());
    debug!("Compressed content: {:?}", compressed);
    let mut bf = std::io::BufReader::new(compressed.as_slice());
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut bf, &mut decomp).unwrap();
    assert_eq!(decomp, x)
}

fn round_trip_with_options(
    x: &[u8],
    encode_options: &lzma_rs::compress::Options,
    decode_options: &lzma_rs::decompress::Options,
) {
    let mut compressed: Vec<u8> = Vec::new();
    lzma_rs::lzma_compress_with_options(
        &mut std::io::BufReader::new(x),
        &mut compressed,
        encode_options,
    )
    .unwrap();
    info!("Compressed {} -> {} bytes", x.len(), compressed.len());
    debug!("Compressed content: {:?}", compressed);
    let mut bf = std::io::BufReader::new(compressed.as_slice());
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress_with_options(&mut bf, &mut decomp, decode_options).unwrap();
    assert_eq!(decomp, x)
}

fn round_trip_file(filename: &str) {
    use std::io::Read;

    let mut x = Vec::new();
    std::fs::File::open(filename)
        .unwrap()
        .read_to_end(&mut x)
        .unwrap();
    round_trip(x.as_slice());

    // Do another round trip, but this time also write it to the header
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(Some(x.len() as u64)),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadFromHeader,
    };
    round_trip_with_options(x.as_slice(), &encode_options, &decode_options);
}

fn decomp_big_file(compfile: &str, plainfile: &str) {
    use std::io::Read;

    let mut expected = Vec::new();
    std::fs::File::open(plainfile)
        .unwrap()
        .read_to_end(&mut expected)
        .unwrap();
    let mut f = std::io::BufReader::new(std::fs::File::open(compfile).unwrap());
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut f, &mut decomp).unwrap();
    assert!(decomp == expected)
}

#[test]
fn decompress_short_header() {
    let _ = env_logger::try_init();
    let mut decomp: Vec<u8> = Vec::new();
    // TODO: compare io::Errors?
    assert_eq!(
        format!(
            "{:?}",
            lzma_rs::lzma_decompress(&mut (b"" as &[u8]), &mut decomp).unwrap_err()
        ),
        String::from("LZMAError(\"LZMA header too short: failed to fill whole buffer\")")
    )
}

#[test]
fn round_trip_basics() {
    let _ = env_logger::try_init();
    round_trip(b"");
    // Note: we use vec! to avoid storing the slice in the binary
    round_trip(vec![0x00; 1_000_000].as_slice());
    round_trip(vec![0xFF; 1_000_000].as_slice());
}

#[test]
fn round_trip_hello() {
    let _ = env_logger::try_init();
    round_trip(b"Hello world");
}

#[test]
fn round_trip_files() {
    let _ = env_logger::try_init();
    round_trip_file("tests/files/foo.txt");
    round_trip_file("tests/files/range-coder-edge-case");
}

#[test]
fn big_file() {
    let _ = env_logger::try_init();
    decomp_big_file("tests/files/foo.txt.lzma", "tests/files/foo.txt");
    decomp_big_file("tests/files/hugedict.txt.lzma", "tests/files/foo.txt");
    decomp_big_file(
        "tests/files/range-coder-edge-case.lzma",
        "tests/files/range-coder-edge-case",
    );
}

#[test]
fn decompress_empty_world() {
    let _ = env_logger::try_init();
    let mut x: &[u8] = b"\x5d\x00\x00\x80\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x83\xff\
                         \xfb\xff\xff\xc0\x00\x00\x00";
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut x, &mut decomp).unwrap();
    assert_eq!(decomp, b"")
}

#[test]
fn decompress_hello_world() {
    let _ = env_logger::try_init();
    let mut x: &[u8] = b"\x5d\x00\x00\x80\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x24\x19\
                         \x49\x98\x6f\x10\x19\xc6\xd7\x31\xeb\x36\x50\xb2\x98\x48\xff\xfe\
                         \xa5\xb0\x00";
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut x, &mut decomp).unwrap();
    assert_eq!(decomp, b"Hello world\x0a")
}

#[test]
fn decompress_huge_dict() {
    // Hello world with a dictionary of size 0x7F7F7F7F
    let _ = env_logger::try_init();
    let mut x: &[u8] = b"\x5d\x7f\x7f\x7f\x7f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x24\x19\
                         \x49\x98\x6f\x10\x19\xc6\xd7\x31\xeb\x36\x50\xb2\x98\x48\xff\xfe\
                         \xa5\xb0\x00";
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut x, &mut decomp).unwrap();
    assert_eq!(decomp, b"Hello world\x0a")
}

#[test]
fn unpacked_size_write_to_header() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(Some(data.len() as u64)),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadFromHeader,
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}

#[test]
fn unpacked_size_provided_outside() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::SkipWritingToHeader,
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::UseProvided(Some(data.len() as u64)),
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}

#[test]
fn unpacked_size_write_some_to_header_but_use_provided_on_read() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(Some(data.len() as u64)),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadHeaderButUseProvided(Some(
            data.len() as u64,
        )),
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}

#[test]
fn unpacked_size_write_none_to_header_and_use_provided_on_read() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(None),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadHeaderButUseProvided(Some(
            data.len() as u64,
        )),
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}

#[test]
fn unpacked_size_write_none_to_header_and_use_provided_none_on_read() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(None),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadHeaderButUseProvided(None),
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}
<commit_msg>Generalize round_trip_with_options test to all tests.<commit_after>extern crate env_logger;
extern crate lzma_rs;
#[macro_use]
extern crate log;

fn round_trip(x: &[u8]) {
    round_trip_no_options(x);

    // Do another round trip, but this time also write it to the header
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(Some(x.len() as u64)),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadFromHeader,
    };
    round_trip_with_options(x, &encode_options, &decode_options);
}

fn round_trip_no_options(x: &[u8]) {
    let mut compressed: Vec<u8> = Vec::new();
    lzma_rs::lzma_compress(&mut std::io::BufReader::new(x), &mut compressed).unwrap();
    info!("Compressed {} -> {} bytes", x.len(), compressed.len());
    debug!("Compressed content: {:?}", compressed);
    let mut bf = std::io::BufReader::new(compressed.as_slice());
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut bf, &mut decomp).unwrap();
    assert_eq!(decomp, x)
}

fn round_trip_with_options(
    x: &[u8],
    encode_options: &lzma_rs::compress::Options,
    decode_options: &lzma_rs::decompress::Options,
) {
    let mut compressed: Vec<u8> = Vec::new();
    lzma_rs::lzma_compress_with_options(
        &mut std::io::BufReader::new(x),
        &mut compressed,
        encode_options,
    )
    .unwrap();
    info!("Compressed {} -> {} bytes", x.len(), compressed.len());
    debug!("Compressed content: {:?}", compressed);
    let mut bf = std::io::BufReader::new(compressed.as_slice());
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress_with_options(&mut bf, &mut decomp, decode_options).unwrap();
    assert_eq!(decomp, x)
}

fn round_trip_file(filename: &str) {
    use std::io::Read;

    let mut x = Vec::new();
    std::fs::File::open(filename)
        .unwrap()
        .read_to_end(&mut x)
        .unwrap();
    round_trip(x.as_slice());
}

fn decomp_big_file(compfile: &str, plainfile: &str) {
    use std::io::Read;

    let mut expected = Vec::new();
    std::fs::File::open(plainfile)
        .unwrap()
        .read_to_end(&mut expected)
        .unwrap();
    let mut f = std::io::BufReader::new(std::fs::File::open(compfile).unwrap());
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut f, &mut decomp).unwrap();
    assert!(decomp == expected)
}

#[test]
fn decompress_short_header() {
    let _ = env_logger::try_init();
    let mut decomp: Vec<u8> = Vec::new();
    // TODO: compare io::Errors?
    assert_eq!(
        format!(
            "{:?}",
            lzma_rs::lzma_decompress(&mut (b"" as &[u8]), &mut decomp).unwrap_err()
        ),
        String::from("LZMAError(\"LZMA header too short: failed to fill whole buffer\")")
    )
}

#[test]
fn round_trip_basics() {
    let _ = env_logger::try_init();
    round_trip(b"");
    // Note: we use vec! to avoid storing the slice in the binary
    round_trip(vec![0x00; 1_000_000].as_slice());
    round_trip(vec![0xFF; 1_000_000].as_slice());
}

#[test]
fn round_trip_hello() {
    let _ = env_logger::try_init();
    round_trip(b"Hello world");
}

#[test]
fn round_trip_files() {
    let _ = env_logger::try_init();
    round_trip_file("tests/files/foo.txt");
    round_trip_file("tests/files/range-coder-edge-case");
}

#[test]
fn big_file() {
    let _ = env_logger::try_init();
    decomp_big_file("tests/files/foo.txt.lzma", "tests/files/foo.txt");
    decomp_big_file("tests/files/hugedict.txt.lzma", "tests/files/foo.txt");
    decomp_big_file(
        "tests/files/range-coder-edge-case.lzma",
        "tests/files/range-coder-edge-case",
    );
}

#[test]
fn decompress_empty_world() {
    let _ = env_logger::try_init();
    let mut x: &[u8] = b"\x5d\x00\x00\x80\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x83\xff\
                         \xfb\xff\xff\xc0\x00\x00\x00";
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut x, &mut decomp).unwrap();
    assert_eq!(decomp, b"")
}

#[test]
fn decompress_hello_world() {
    let _ = env_logger::try_init();
    let mut x: &[u8] = b"\x5d\x00\x00\x80\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x24\x19\
                         \x49\x98\x6f\x10\x19\xc6\xd7\x31\xeb\x36\x50\xb2\x98\x48\xff\xfe\
                         \xa5\xb0\x00";
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut x, &mut decomp).unwrap();
    assert_eq!(decomp, b"Hello world\x0a")
}

#[test]
fn decompress_huge_dict() {
    // Hello world with a dictionary of size 0x7F7F7F7F
    let _ = env_logger::try_init();
    let mut x: &[u8] = b"\x5d\x7f\x7f\x7f\x7f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x24\x19\
                         \x49\x98\x6f\x10\x19\xc6\xd7\x31\xeb\x36\x50\xb2\x98\x48\xff\xfe\
                         \xa5\xb0\x00";
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::lzma_decompress(&mut x, &mut decomp).unwrap();
    assert_eq!(decomp, b"Hello world\x0a")
}

#[test]
fn unpacked_size_write_to_header() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(Some(data.len() as u64)),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadFromHeader,
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}

#[test]
fn unpacked_size_provided_outside() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::SkipWritingToHeader,
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::UseProvided(Some(data.len() as u64)),
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}

#[test]
fn unpacked_size_write_some_to_header_but_use_provided_on_read() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(Some(data.len() as u64)),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadHeaderButUseProvided(Some(
            data.len() as u64,
        )),
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}

#[test]
fn unpacked_size_write_none_to_header_and_use_provided_on_read() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(None),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadHeaderButUseProvided(Some(
            data.len() as u64,
        )),
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}

#[test]
fn unpacked_size_write_none_to_header_and_use_provided_none_on_read() {
    let data = b"Some data";
    let encode_options = lzma_rs::compress::Options {
        unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(None),
    };
    let decode_options = lzma_rs::decompress::Options {
        unpacked_size: lzma_rs::decompress::UnpackedSize::ReadHeaderButUseProvided(None),
    };
    round_trip_with_options(&data[..], &encode_options, &decode_options);
}
<|endoftext|>


<commit_before>use mio::net::{TcpListener, TcpStream};
use mio::*;
use std::sync::{Arc, Barrier};
use std::thread;
use std::time::Duration;

mod util;

use util::{any_local_address, assert_send, assert_sync, init};

#[test]
fn is_send_and_sync() {
    assert_sync::<Poll>();
    assert_send::<Poll>();

    assert_sync::<Registry>();
    assert_send::<Registry>();
}

#[test]
fn run_once_with_nothing() {
    init();

    let mut events = Events::with_capacity(16);
    let mut poll = Poll::new().unwrap();
    poll.poll(&mut events, Some(Duration::from_millis(100)))
        .unwrap();
}

#[test]
fn add_then_drop() {
    init();

    let mut events = Events::with_capacity(16);
    let l = TcpListener::bind(any_local_address()).unwrap();
    let mut poll = Poll::new().unwrap();
    poll.registry()
        .register(&l, Token(1), Interests::READABLE | Interests::WRITABLE)
        .unwrap();
    drop(l);
    poll.poll(&mut events, Some(Duration::from_millis(100)))
        .unwrap();
}

#[test]
fn test_poll_closes_fd() {
    init();

    for _ in 0..2000 {
        let mut poll = Poll::new().unwrap();
        let mut events = Events::with_capacity(4);

        poll.poll(&mut events, Some(Duration::from_millis(0)))
            .unwrap();

        drop(poll);
    }
}

#[test]
fn test_drop_cancels_interest_and_shuts_down() {
    init();

    use mio::net::TcpStream;
    use std::io;
    use std::io::Read;
    use std::net::TcpListener;
    use std::thread;

    let l = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = l.local_addr().unwrap();

    let t = thread::spawn(move || {
        let mut s = l.incoming().next().unwrap().unwrap();
        s.set_read_timeout(Some(Duration::from_secs(5)))
            .expect("set_read_timeout");
        let r = s.read(&mut [0; 16]);
        match r {
            Ok(_) => (),
            Err(e) => {
                if e.kind() != io::ErrorKind::UnexpectedEof {
                    panic!(e);
                }
            }
        }
    });

    let mut poll = Poll::new().unwrap();
    let mut s = TcpStream::connect(addr).unwrap();

    poll.registry()
        .register(&s, Token(1), Interests::READABLE | Interests::WRITABLE)
        .unwrap();
    let mut events = Events::with_capacity(16);
    'outer: loop {
        poll.poll(&mut events, None).unwrap();
        for event in &events {
            if event.token() == Token(1) {
                // connected
                break 'outer;
            }
        }
    }

    let mut b = [0; 1024];
    match s.read(&mut b) {
        Ok(_) => panic!("unexpected ok"),
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => (),
        Err(e) => panic!("unexpected error: {:?}", e),
    }

    drop(s);
    t.join().unwrap();
}

#[test]
fn test_registry_behind_arc() {
    // `Registry` should work behind an `Arc`, being `Sync` and `Send`.
    init();

    let mut poll = Poll::new().unwrap();
    let registry = Arc::new(poll.registry().try_clone().unwrap());
    let mut events = Events::with_capacity(128);

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let addr = listener.local_addr().unwrap();
    let barrier = Arc::new(Barrier::new(3));

    let registry2 = Arc::clone(&registry);
    let registry3 = Arc::clone(&registry);
    let barrier2 = Arc::clone(&barrier);
    let barrier3 = Arc::clone(&barrier);

    let handle1 = thread::spawn(move || {
        registry2
            .register(&listener, Token(0), Interests::READABLE)
            .unwrap();
        barrier2.wait();
    });
    let handle2 = thread::spawn(move || {
        let stream = TcpStream::connect(addr).unwrap();
        registry3
            .register(&stream, Token(1), Interests::READABLE | Interests::WRITABLE)
            .unwrap();
        barrier3.wait();
    });

    poll.poll(&mut events, Some(Duration::from_millis(1000)))
        .unwrap();
    assert!(events.iter().count() >= 1);

    // Let the threads return.
    barrier.wait();

    handle1.join().unwrap();
    handle2.join().unwrap();
}

// On kqueue platforms registering twice (not *re*registering) works.
#[test]
#[cfg(any(target_os = "linux", target_os = "windows"))]
pub fn test_double_register() {
    init();
    let poll = Poll::new().unwrap();

    let l = TcpListener::bind("127.0.0.1:0".parse().unwrap()).unwrap();

    poll.registry()
        .register(&l, Token(0), Interests::READABLE)
        .unwrap();

    assert!(poll
        .registry()
        .register(&l, Token(1), Interests::READABLE)
        .is_err());
}
<commit_msg>Add test in pr #1065<commit_after>use mio::net::{TcpListener, TcpStream};
use mio::*;
use std::net;
use std::sync::{Arc, Barrier};
use std::thread::{self, sleep};
use std::time::Duration;

mod util;

use util::{any_local_address, assert_send, assert_sync, init};

#[test]
fn is_send_and_sync() {
    assert_sync::<Poll>();
    assert_send::<Poll>();

    assert_sync::<Registry>();
    assert_send::<Registry>();
}

#[test]
fn run_once_with_nothing() {
    init();

    let mut events = Events::with_capacity(16);
    let mut poll = Poll::new().unwrap();
    poll.poll(&mut events, Some(Duration::from_millis(100)))
        .unwrap();
}

#[test]
fn add_then_drop() {
    init();

    let mut events = Events::with_capacity(16);
    let l = TcpListener::bind(any_local_address()).unwrap();
    let mut poll = Poll::new().unwrap();
    poll.registry()
        .register(&l, Token(1), Interests::READABLE | Interests::WRITABLE)
        .unwrap();
    drop(l);
    poll.poll(&mut events, Some(Duration::from_millis(100)))
        .unwrap();
}

#[test]
fn zero_duration_polls_events() {
    init();

    let mut poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(16);

    let listener = net::TcpListener::bind(localhost()).unwrap();
    let addr = listener.local_addr().unwrap();

    let streams: Vec<TcpStream> = (0..3)
        .map(|n| {
            let stream = TcpStream::connect(addr).unwrap();
            poll.registry()
                .register(&stream, Token(n), Interests::WRITABLE)
                .unwrap();
            stream
        })
        .collect();

    // Ensure the TcpStreams have some time to connection and for the events to
    // show up.
    sleep(Duration::from_millis(10));

    // Even when passing a zero duration timeout we still want do the system
    // call.
    poll.poll(&mut events, Some(Duration::from_nanos(0)))
        .unwrap();
    assert!(!events.is_empty());

    // Both need to live until here.
    drop(streams);
    drop(listener);
}

#[test]
fn test_poll_closes_fd() {
    init();

    for _ in 0..2000 {
        let mut poll = Poll::new().unwrap();
        let mut events = Events::with_capacity(4);

        poll.poll(&mut events, Some(Duration::from_millis(0)))
            .unwrap();

        drop(poll);
    }
}

#[test]
fn test_drop_cancels_interest_and_shuts_down() {
    init();

    use mio::net::TcpStream;
    use std::io;
    use std::io::Read;
    use std::net::TcpListener;
    use std::thread;

    let l = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = l.local_addr().unwrap();

    let t = thread::spawn(move || {
        let mut s = l.incoming().next().unwrap().unwrap();
        s.set_read_timeout(Some(Duration::from_secs(5)))
            .expect("set_read_timeout");
        let r = s.read(&mut [0; 16]);
        match r {
            Ok(_) => (),
            Err(e) => {
                if e.kind() != io::ErrorKind::UnexpectedEof {
                    panic!(e);
                }
            }
        }
    });

    let mut poll = Poll::new().unwrap();
    let mut s = TcpStream::connect(addr).unwrap();

    poll.registry()
        .register(&s, Token(1), Interests::READABLE | Interests::WRITABLE)
        .unwrap();
    let mut events = Events::with_capacity(16);
    'outer: loop {
        poll.poll(&mut events, None).unwrap();
        for event in &events {
            if event.token() == Token(1) {
                // connected
                break 'outer;
            }
        }
    }

    let mut b = [0; 1024];
    match s.read(&mut b) {
        Ok(_) => panic!("unexpected ok"),
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => (),
        Err(e) => panic!("unexpected error: {:?}", e),
    }

    drop(s);
    t.join().unwrap();
}

#[test]
fn test_registry_behind_arc() {
    // `Registry` should work behind an `Arc`, being `Sync` and `Send`.
    init();

    let mut poll = Poll::new().unwrap();
    let registry = Arc::new(poll.registry().try_clone().unwrap());
    let mut events = Events::with_capacity(128);

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let addr = listener.local_addr().unwrap();
    let barrier = Arc::new(Barrier::new(3));

    let registry2 = Arc::clone(&registry);
    let registry3 = Arc::clone(&registry);
    let barrier2 = Arc::clone(&barrier);
    let barrier3 = Arc::clone(&barrier);

    let handle1 = thread::spawn(move || {
        registry2
            .register(&listener, Token(0), Interests::READABLE)
            .unwrap();
        barrier2.wait();
    });
    let handle2 = thread::spawn(move || {
        let stream = TcpStream::connect(addr).unwrap();
        registry3
            .register(&stream, Token(1), Interests::READABLE | Interests::WRITABLE)
            .unwrap();
        barrier3.wait();
    });

    poll.poll(&mut events, Some(Duration::from_millis(1000)))
        .unwrap();
    assert!(events.iter().count() >= 1);

    // Let the threads return.
    barrier.wait();

    handle1.join().unwrap();
    handle2.join().unwrap();
}

// On kqueue platforms registering twice (not *re*registering) works.
#[test]
#[cfg(any(target_os = "linux", target_os = "windows"))]
pub fn test_double_register() {
    init();
    let poll = Poll::new().unwrap();

    let l = TcpListener::bind("127.0.0.1:0".parse().unwrap()).unwrap();

    poll.registry()
        .register(&l, Token(0), Interests::READABLE)
        .unwrap();

    assert!(poll
        .registry()
        .register(&l, Token(1), Interests::READABLE)
        .is_err());
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::fs::File;
use std::os::unix::io::{FromRawFd, AsRawFd};

use unshare::{Command, Stdio};
use rustc_serialize::json::Json;

use super::super::context::{Context};
use super::super::packages;
use builder::error::StepError;
use builder::distrib::Distribution;
use builder::commands::generic::{command, run};
use config::builders::{NpmSettings, NpmDepInfo};

impl Default for NpmSettings {
    fn default() -> NpmSettings {
        NpmSettings {
            install_node: true,
            npm_exe: "npm".to_string(),
        }
    }
}

fn scan_features(settings: &NpmSettings, pkgs: &Vec<String>)
    -> Vec<packages::Package>
{
    let mut res = vec!();
    res.push(packages::BuildEssential);
    if settings.install_node {
        res.push(packages::NodeJs);
        res.push(packages::NodeJsDev);
        res.push(packages::Npm);
    }
    for name in pkgs.iter() {
        parse_feature(&name, &mut res);
    }
    return res;
}

pub fn parse_feature(info: &str, features: &mut Vec<packages::Package>) {
    // Note: the info is a package name/git-url in NpmInstall but it's just
    // a version number for NpmDependencies. That's how npm works.
    if info[..].starts_with("git://") {
        features.push(packages::Git);
    } // TODO(tailhook) implement whole a lot of other npm version kinds
}

pub fn ensure_npm(distro: &mut Box<Distribution>, ctx: &mut Context,
    features: &[packages::Package])
    -> Result<(), StepError>
{
    packages::ensure_packages(distro, ctx, features)
}

pub fn npm_install(distro: &mut Box<Distribution>, ctx: &mut Context,
    pkgs: &Vec<String>)
    -> Result<(), StepError>
{
    try!(ctx.add_cache_dir(Path::new("/tmp/npm-cache"),
                           "npm-cache".to_string()));
    let features = scan_features(&ctx.npm_settings, pkgs);
    try!(ensure_npm(distro, ctx, &features));

    let mut cmd = try!(command(ctx, &ctx.npm_settings.npm_exe));
    cmd.arg("install");
    cmd.arg("--global");
    cmd.arg("--user=root");
    cmd.arg("--cache=/tmp/npm-cache");
    cmd.args(pkgs);
    run(cmd)
}

fn scan_dic(json: &Json, key: &str, cmd: &mut Command,
    features: &mut Vec<packages::Package>) -> Result<(), StepError>
{
    match json.find(key) {
        Some(&Json::Object(ref ob)) => {
            for (k, v) in ob {
                if !v.is_string() {
                    return Err(StepError::Compat(format!(
                        "Package {:?} has wrong version {:?}", k, v)));
                }
                let s = v.as_string().unwrap();
                parse_feature(&s, features);
                cmd.arg(format!("{}@{}", k, s));
                // TODO(tailhook) check the feature
            }
            Ok(())
        }
        None => {
            Ok(())
        }
        Some(_) => {
            Err(StepError::Compat(format!(
                "The {:?} is not a mapping (JSON object)", key)))
        }
    }
}

pub fn npm_deps(distro: &mut Box<Distribution>, ctx: &mut Context,
    info: &NpmDepInfo)
    -> Result<(), StepError>
{
    try!(ctx.add_cache_dir(Path::new("/tmp/npm-cache"),
                           "npm-cache".to_string()));
    let mut features = scan_features(&ctx.npm_settings, &Vec::new());

    let mut cmd = try!(command(ctx, &ctx.npm_settings.npm_exe));
    cmd.arg("install");
    cmd.arg("--global");
    cmd.arg("--user=root");
    cmd.arg("--cache=/tmp/npm-cache");

    let json = try!(File::open(&Path::new("/work").join(&info.file))
        .map_err(|e| format!("Error opening file {:?}: {}", info.file, e))
        .and_then(|mut f| Json::from_reader(&mut f)
        .map_err(|e| format!("Error parsing json {:?}: {}", info.file, e))));

    if info.package {
        try!(scan_dic(&json, "dependencies", &mut cmd, &mut features));
    }
    if info.dev {
        try!(scan_dic(&json, "devDependencies", &mut cmd, &mut features));
    }
    if info.peer {
        try!(scan_dic(&json, "peerDependencies", &mut cmd, &mut features));
    }
    if info.bundled {
        try!(scan_dic(&json, "bundledDependencies", &mut cmd, &mut features));
        try!(scan_dic(&json, "bundleDependencies", &mut cmd, &mut features));
    }
    if info.optional {
        try!(scan_dic(&json, "optionalDependencies", &mut cmd, &mut features));
    }

    try!(ensure_npm(distro, ctx, &features));

    run(cmd)
}

pub fn list(ctx: &mut Context) -> Result<(), StepError> {
    let path = Path::new("/vagga/container/npm-list.txt");
    let file = try!(File::create(&path)
        .map_err(|e| StepError::Write(path.to_path_buf(), e)));
    let mut cmd = try!(command(ctx, &ctx.npm_settings.npm_exe));
    cmd.arg("ls");
    cmd.arg("--global");
    // TODO(tailhook) fixme in rust 1.6. as_raw_fd -> into_raw_fd
    cmd.stdout(unsafe { Stdio::from_raw_fd(file.as_raw_fd()) });
    run(cmd)
}
<commit_msg>Fix broken NpmDependencies<commit_after>use std::path::Path;
use std::fs::File;
use std::os::unix::io::{FromRawFd, AsRawFd};

use unshare::{Stdio};
use rustc_serialize::json::Json;

use super::super::context::{Context};
use super::super::packages;
use builder::error::StepError;
use builder::distrib::Distribution;
use builder::commands::generic::{command, run};
use config::builders::{NpmSettings, NpmDepInfo};

impl Default for NpmSettings {
    fn default() -> NpmSettings {
        NpmSettings {
            install_node: true,
            npm_exe: "npm".to_string(),
        }
    }
}

fn scan_features(settings: &NpmSettings, pkgs: &Vec<String>)
    -> Vec<packages::Package>
{
    let mut res = vec!();
    res.push(packages::BuildEssential);
    if settings.install_node {
        res.push(packages::NodeJs);
        res.push(packages::NodeJsDev);
        res.push(packages::Npm);
    }
    for name in pkgs.iter() {
        parse_feature(&name, &mut res);
    }
    return res;
}

pub fn parse_feature(info: &str, features: &mut Vec<packages::Package>) {
    // Note: the info is a package name/git-url in NpmInstall but it's just
    // a version number for NpmDependencies. That's how npm works.
    if info[..].starts_with("git://") {
        features.push(packages::Git);
    } // TODO(tailhook) implement whole a lot of other npm version kinds
}

pub fn ensure_npm(distro: &mut Box<Distribution>, ctx: &mut Context,
    features: &[packages::Package])
    -> Result<(), StepError>
{
    packages::ensure_packages(distro, ctx, features)
}

pub fn npm_install(distro: &mut Box<Distribution>, ctx: &mut Context,
    pkgs: &Vec<String>)
    -> Result<(), StepError>
{
    try!(ctx.add_cache_dir(Path::new("/tmp/npm-cache"),
                           "npm-cache".to_string()));
    let features = scan_features(&ctx.npm_settings, pkgs);
    try!(ensure_npm(distro, ctx, &features));

    if pkgs.len() == 0 {
        return Ok(());
    }

    let mut cmd = try!(command(ctx, &ctx.npm_settings.npm_exe));
    cmd.arg("install");
    cmd.arg("--global");
    cmd.arg("--user=root");
    cmd.arg("--cache=/tmp/npm-cache");
    cmd.args(pkgs);
    run(cmd)
}

fn scan_dic(json: &Json, key: &str,
    packages: &mut Vec<String>, features: &mut Vec<packages::Package>)
    -> Result<(), StepError>
{
    match json.find(key) {
        Some(&Json::Object(ref ob)) => {
            for (k, v) in ob {
                if !v.is_string() {
                    return Err(StepError::Compat(format!(
                        "Package {:?} has wrong version {:?}", k, v)));
                }
                let s = v.as_string().unwrap();
                parse_feature(&s, features);
                packages.push(format!("{}@{}", k, s));
                // TODO(tailhook) check the feature
            }
            Ok(())
        }
        None => {
            Ok(())
        }
        Some(_) => {
            Err(StepError::Compat(format!(
                "The {:?} is not a mapping (JSON object)", key)))
        }
    }
}

pub fn npm_deps(distro: &mut Box<Distribution>, ctx: &mut Context,
    info: &NpmDepInfo)
    -> Result<(), StepError>
{
    try!(ctx.add_cache_dir(Path::new("/tmp/npm-cache"),
                           "npm-cache".to_string()));
    let mut features = scan_features(&ctx.npm_settings, &Vec::new());

    let json = try!(File::open(&Path::new("/work").join(&info.file))
        .map_err(|e| format!("Error opening file {:?}: {}", info.file, e))
        .and_then(|mut f| Json::from_reader(&mut f)
        .map_err(|e| format!("Error parsing json {:?}: {}", info.file, e))));
    let mut packages = vec![];

    if info.package {
        try!(scan_dic(&json, "dependencies", &mut packages, &mut features));
    }
    if info.dev {
        try!(scan_dic(&json, "devDependencies", &mut packages, &mut features));
    }
    if info.peer {
        try!(scan_dic(&json, "peerDependencies",
            &mut packages, &mut features));
    }
    if info.bundled {
        try!(scan_dic(&json, "bundledDependencies",
            &mut packages, &mut features));
        try!(scan_dic(&json, "bundleDependencies",
            &mut packages, &mut features));
    }
    if info.optional {
        try!(scan_dic(&json, "optionalDependencies",
            &mut packages, &mut features));
    }

    try!(ensure_npm(distro, ctx, &features));

    if packages.len() == 0 {
        return Ok(());
    }

    let mut cmd = try!(command(ctx, &ctx.npm_settings.npm_exe));
    cmd.arg("install");
    cmd.arg("--global");
    cmd.arg("--user=root");
    cmd.arg("--cache=/tmp/npm-cache");
    cmd.args(&packages);
    run(cmd)
}

pub fn list(ctx: &mut Context) -> Result<(), StepError> {
    let path = Path::new("/vagga/container/npm-list.txt");
    let file = try!(File::create(&path)
        .map_err(|e| StepError::Write(path.to_path_buf(), e)));
    let mut cmd = try!(command(ctx, &ctx.npm_settings.npm_exe));
    cmd.arg("ls");
    cmd.arg("--global");
    // TODO(tailhook) fixme in rust 1.6. as_raw_fd -> into_raw_fd
    cmd.stdout(unsafe { Stdio::from_raw_fd(file.as_raw_fd()) });
    run(cmd)
}
<|endoftext|>


<commit_before>//! Isometric transformations.

#[allow(missing_doc)];

use std::num::{Zero, One};
use std::rand::{Rand, Rng};
use structs::mat::{Mat3, Mat4, Mat5};
use traits::structure::{Dim, Col};
use traits::operations::{Inv};
use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation,
                       Translate, Translation, ToHomogeneous};

use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs};
use structs::rot::{Rot2, Rot3, Rot4};

mod metal;
mod iso_macros;

/// Two dimensional isometry.
///
/// This is the composition of a rotation followed by a translation.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)]
pub struct Iso2<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot2<N>,
    /// The translation applicable by this isometry.
    translation: Vec2<N>
}

/// Three dimensional isometry.
///
/// This is the composition of a rotation followed by a translation.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)]
pub struct Iso3<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot3<N>,
    /// The translation applicable by this isometry.
    translation: Vec3<N>
}

/// Four dimensional isometry.
///
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)]
pub struct Iso4<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot4<N>,
    /// The translation applicable by this isometry.
    translation: Vec4<N>
}

iso_impl!(Iso2, Rot2, Vec2)
double_dispatch_binop_decl_trait!(Iso2, Iso2MulRhs)
mul_redispatch_impl!(Iso2, Iso2MulRhs)
rotation_matrix_impl!(Iso2, Rot2, Vec2, Vec1)
rotation_impl!(Iso2, Rot2, Vec1)
dim_impl!(Iso2, 2)
one_impl!(Iso2)
absolute_rotate_impl!(Iso2, Vec2)
rand_impl!(Iso2)
approx_eq_impl!(Iso2)
to_homogeneous_impl!(Iso2, Mat3)
inv_impl!(Iso2)
transform_impl!(Iso2, Vec2)
transformation_impl!(Iso2)
rotate_impl!(Iso2, Vec2)
translation_impl!(Iso2, Vec2)
translate_impl!(Iso2, Vec2)
iso_mul_iso_impl!(Iso2, Iso2MulRhs)
iso_mul_vec_impl!(Iso2, Vec2, Iso2MulRhs)
vec_mul_iso_impl!(Iso2, Vec2, Vec2MulRhs)

iso_impl!(Iso3, Rot3, Vec3)
double_dispatch_binop_decl_trait!(Iso3, Iso3MulRhs)
mul_redispatch_impl!(Iso3, Iso3MulRhs)
rotation_matrix_impl!(Iso3, Rot3, Vec3, Vec3)
rotation_impl!(Iso3, Rot3, Vec3)
dim_impl!(Iso3, 3)
one_impl!(Iso3)
absolute_rotate_impl!(Iso3, Vec3)
rand_impl!(Iso3)
approx_eq_impl!(Iso3)
to_homogeneous_impl!(Iso3, Mat4)
inv_impl!(Iso3)
transform_impl!(Iso3, Vec3)
transformation_impl!(Iso3)
rotate_impl!(Iso3, Vec3)
translation_impl!(Iso3, Vec3)
translate_impl!(Iso3, Vec3)
iso_mul_iso_impl!(Iso3, Iso3MulRhs)
iso_mul_vec_impl!(Iso3, Vec3, Iso3MulRhs)
vec_mul_iso_impl!(Iso3, Vec3, Vec3MulRhs)

iso_impl!(Iso4, Rot4, Vec4)
double_dispatch_binop_decl_trait!(Iso4, Iso4MulRhs)
mul_redispatch_impl!(Iso4, Iso4MulRhs)
// rotation_matrix_impl!(Iso4, Rot4, Vec4, Vec4)
// rotation_impl!(Iso4, Rot4, Vec4)
dim_impl!(Iso4, 4)
one_impl!(Iso4)
// absolute_rotate_impl!(Iso4, Vec4)
// rand_impl!(Iso4)
approx_eq_impl!(Iso4)
to_homogeneous_impl!(Iso4, Mat5)
inv_impl!(Iso4)
transform_impl!(Iso4, Vec4)
transformation_impl!(Iso4)
// rotate_impl!(Iso4, Vec4)
translation_impl!(Iso4, Vec4)
translate_impl!(Iso4, Vec4)
iso_mul_iso_impl!(Iso4, Iso4MulRhs)
iso_mul_vec_impl!(Iso4, Vec4, Iso4MulRhs)
vec_mul_iso_impl!(Iso4, Vec4, Vec4MulRhs)
<commit_msg>Re-add look_at methods for isometries.<commit_after>//! Isometric transformations.

#[allow(missing_doc)];

use std::num::{Zero, One};
use std::rand::{Rand, Rng};
use structs::mat::{Mat3, Mat4, Mat5};
use traits::structure::{Dim, Col};
use traits::operations::{Inv};
use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation,
                       Translate, Translation, ToHomogeneous};

use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs};
use structs::rot::{Rot2, Rot3, Rot4};

mod metal;
mod iso_macros;

/// Two dimensional isometry.
///
/// This is the composition of a rotation followed by a translation.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)]
pub struct Iso2<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot2<N>,
    /// The translation applicable by this isometry.
    translation: Vec2<N>
}

/// Three dimensional isometry.
///
/// This is the composition of a rotation followed by a translation.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)]
pub struct Iso3<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot3<N>,
    /// The translation applicable by this isometry.
    translation: Vec3<N>
}

/// Four dimensional isometry.
///
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)]
pub struct Iso4<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot4<N>,
    /// The translation applicable by this isometry.
    translation: Vec4<N>
}

impl<N: Clone + Num + Algebraic> Iso3<N> {
    /// Reorient and translate this transformation such that its local `x` axis points to a given
    /// direction.  Note that the usually known `look_at` function does the same thing but with the
    /// `z` axis. See `look_at_z` for that.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with.
    ///   * up - Vector pointing up. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.rotation.look_at(&(*at - *eye), up);
        self.translation = eye.clone();
    }

    /// Reorient and translate this transformation such that its local `z` axis points to a given
    /// direction.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at_z(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.rotation.look_at_z(&(*at - *eye), up);
        self.translation = eye.clone();
    }
}

iso_impl!(Iso2, Rot2, Vec2)
double_dispatch_binop_decl_trait!(Iso2, Iso2MulRhs)
mul_redispatch_impl!(Iso2, Iso2MulRhs)
rotation_matrix_impl!(Iso2, Rot2, Vec2, Vec1)
rotation_impl!(Iso2, Rot2, Vec1)
dim_impl!(Iso2, 2)
one_impl!(Iso2)
absolute_rotate_impl!(Iso2, Vec2)
rand_impl!(Iso2)
approx_eq_impl!(Iso2)
to_homogeneous_impl!(Iso2, Mat3)
inv_impl!(Iso2)
transform_impl!(Iso2, Vec2)
transformation_impl!(Iso2)
rotate_impl!(Iso2, Vec2)
translation_impl!(Iso2, Vec2)
translate_impl!(Iso2, Vec2)
iso_mul_iso_impl!(Iso2, Iso2MulRhs)
iso_mul_vec_impl!(Iso2, Vec2, Iso2MulRhs)
vec_mul_iso_impl!(Iso2, Vec2, Vec2MulRhs)

iso_impl!(Iso3, Rot3, Vec3)
double_dispatch_binop_decl_trait!(Iso3, Iso3MulRhs)
mul_redispatch_impl!(Iso3, Iso3MulRhs)
rotation_matrix_impl!(Iso3, Rot3, Vec3, Vec3)
rotation_impl!(Iso3, Rot3, Vec3)
dim_impl!(Iso3, 3)
one_impl!(Iso3)
absolute_rotate_impl!(Iso3, Vec3)
rand_impl!(Iso3)
approx_eq_impl!(Iso3)
to_homogeneous_impl!(Iso3, Mat4)
inv_impl!(Iso3)
transform_impl!(Iso3, Vec3)
transformation_impl!(Iso3)
rotate_impl!(Iso3, Vec3)
translation_impl!(Iso3, Vec3)
translate_impl!(Iso3, Vec3)
iso_mul_iso_impl!(Iso3, Iso3MulRhs)
iso_mul_vec_impl!(Iso3, Vec3, Iso3MulRhs)
vec_mul_iso_impl!(Iso3, Vec3, Vec3MulRhs)

iso_impl!(Iso4, Rot4, Vec4)
double_dispatch_binop_decl_trait!(Iso4, Iso4MulRhs)
mul_redispatch_impl!(Iso4, Iso4MulRhs)
// rotation_matrix_impl!(Iso4, Rot4, Vec4, Vec4)
// rotation_impl!(Iso4, Rot4, Vec4)
dim_impl!(Iso4, 4)
one_impl!(Iso4)
// absolute_rotate_impl!(Iso4, Vec4)
// rand_impl!(Iso4)
approx_eq_impl!(Iso4)
to_homogeneous_impl!(Iso4, Mat5)
inv_impl!(Iso4)
transform_impl!(Iso4, Vec4)
transformation_impl!(Iso4)
// rotate_impl!(Iso4, Vec4)
translation_impl!(Iso4, Vec4)
translate_impl!(Iso4, Vec4)
iso_mul_iso_impl!(Iso4, Iso4MulRhs)
iso_mul_vec_impl!(Iso4, Vec4, Iso4MulRhs)
vec_mul_iso_impl!(Iso4, Vec4, Vec4MulRhs)
<|endoftext|>


<commit_before>//  _   _
// | |_| |__   ___  ___ __ _
// | __| '_ \ / _ \/ __/ _` |
// | |_| | | |  __/ (_| (_| |
//  \__|_| |_|\___|\___\__,_|
//
// licensed under the MIT license <http://opensource.org/licenses/MIT>
//
// crypt.rs
//   defintions of the AES encryption, decryption, and PBKDF2 key derivation
//   functions required to read and write encrypted profiles.

use std::iter::{repeat};
use crypto::{symmetriccipher, buffer, aes, blockmodes};
use crypto::buffer::{ReadBuffer, WriteBuffer, BufferResult};
use crypto::pbkdf2::{pbkdf2};
use crypto::hmac::{Hmac};
use crypto::sha2::{Sha256};
use crypto::digest::{Digest};
use crypto::fortuna::{Fortuna};
use std::rand::{SeedableRng, Rng}; // FIXME
// use rand::{SeedableRng, Rng};

// ALL the encryption functions thx rust-crypto ^_^
pub fn encrypt(data: &[u8], key: &[u8]) -> Result<Vec<u8>, symmetriccipher::SymmetricCipherError> {
    let mut iv = [0u8; 16];
    let mut f: Fortuna = SeedableRng::from_seed(data);
    f.fill_bytes(&mut iv);

    let mut encryptor = aes::cbc_encryptor(
            aes::KeySize::KeySize256,
            key,
            &iv,
            blockmodes::PkcsPadding);

    let mut final_result = Vec::<u8>::new();
    final_result.push_all(&iv);
    let mut read_buffer = buffer::RefReadBuffer::new(data);
    let mut buffer = [0; 4096];
    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);

    loop {
        let result = try!(encryptor.encrypt(&mut read_buffer, &mut write_buffer, true));

        final_result.push_all(write_buffer.take_read_buffer().take_remaining());

        match result {
            BufferResult::BufferUnderflow => break,
            BufferResult::BufferOverflow => {}
        }
    }

    Ok(final_result)
}

pub fn decrypt(encrypted_data: &[u8], key: &[u8]) -> Result<Vec<u8>, symmetriccipher::SymmetricCipherError> {
    let iv = &encrypted_data[0..16];

    let mut decryptor = aes::cbc_decryptor(
            aes::KeySize::KeySize256,
            key,
            iv,
            blockmodes::PkcsPadding);

    let mut final_result = Vec::<u8>::new();
    let mut read_buffer = buffer::RefReadBuffer::new(&encrypted_data[16..]);
    let mut buffer = [0; 4096];
    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);

    loop {
        let result = try!(decryptor.decrypt(&mut read_buffer, &mut write_buffer, true));
        final_result.push_all(write_buffer.take_read_buffer().take_remaining());
        match result {
            BufferResult::BufferUnderflow => break,
            BufferResult::BufferOverflow => {}
        }
    }

    Ok(final_result)
}

pub fn password_to_key(p: &str) -> Vec<u8> {
    // yehh.... idk
    let mut salt_sha = Sha256::new();
    salt_sha.input(p.as_bytes());
    let salt = salt_sha.result_str();

    let mut mac = Hmac::new(Sha256::new(), p.as_bytes());
    let mut key: Vec<u8> = repeat(0).take(32).collect();

    pbkdf2(&mut mac, salt.as_bytes(), 2056, key.as_mut_slice());

    key
}
<commit_msg>line styling<commit_after>//  _   _
// | |_| |__   ___  ___ __ _
// | __| '_ \ / _ \/ __/ _` |
// | |_| | | |  __/ (_| (_| |
//  \__|_| |_|\___|\___\__,_|
//
// licensed under the MIT license <http://opensource.org/licenses/MIT>
//
// crypt.rs
//   defintions of the AES encryption, decryption, and PBKDF2 key derivation
//   functions required to read and write encrypted profiles.

use std::iter::{repeat};
use crypto::{symmetriccipher, buffer, aes, blockmodes};
use crypto::buffer::{ReadBuffer, WriteBuffer, BufferResult};
use crypto::pbkdf2::{pbkdf2};
use crypto::hmac::{Hmac};
use crypto::sha2::{Sha256};
use crypto::digest::{Digest};
use crypto::fortuna::{Fortuna};
use std::rand::{SeedableRng, Rng}; // FIXME
// use rand::{SeedableRng, Rng};

// ALL the encryption functions thx rust-crypto ^_^
pub fn encrypt(
    data: &[u8],
    key: &[u8]
) -> Result<Vec<u8>, symmetriccipher::SymmetricCipherError> {
    let mut iv = [0u8; 16];
    let mut f: Fortuna = SeedableRng::from_seed(data);
    f.fill_bytes(&mut iv);

    let mut encryptor = aes::cbc_encryptor(
            aes::KeySize::KeySize256,
            key,
            &iv,
            blockmodes::PkcsPadding);

    let mut final_result = Vec::<u8>::new();
    final_result.push_all(&iv);
    let mut read_buffer = buffer::RefReadBuffer::new(data);
    let mut buffer = [0; 4096];
    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);

    loop {
        let result = try!(encryptor.encrypt(
            &mut read_buffer,
            &mut write_buffer,
            true
        ));

        final_result.push_all(
            write_buffer.take_read_buffer().take_remaining()
        );

        match result {
            BufferResult::BufferUnderflow => break,
            BufferResult::BufferOverflow => {}
        }
    }

    Ok(final_result)
}

pub fn decrypt(
    encrypted_data: &[u8],
    key: &[u8]
) -> Result<Vec<u8>, symmetriccipher::SymmetricCipherError> {
    let iv = &encrypted_data[0..16];

    let mut decryptor = aes::cbc_decryptor(
            aes::KeySize::KeySize256,
            key,
            iv,
            blockmodes::PkcsPadding);

    let mut final_result = Vec::<u8>::new();
    let mut read_buffer = buffer::RefReadBuffer::new(&encrypted_data[16..]);
    let mut buffer = [0; 4096];
    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);

    loop {
        let result = try!(decryptor.decrypt(
            &mut read_buffer,
            &mut write_buffer,
            true
        ));
        final_result.push_all(
            write_buffer.take_read_buffer().take_remaining()
        );
        match result {
            BufferResult::BufferUnderflow => break,
            BufferResult::BufferOverflow => {}
        }
    }

    Ok(final_result)
}

pub fn password_to_key(p: &str) -> Vec<u8> {
    // yehh.... idk
    let mut salt_sha = Sha256::new();
    salt_sha.input(p.as_bytes());
    let salt = salt_sha.result_str();

    let mut mac = Hmac::new(Sha256::new(), p.as_bytes());
    let mut key: Vec<u8> = repeat(0).take(32).collect();

    pbkdf2(&mut mac, salt.as_bytes(), 2056, key.as_mut_slice());

    key
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::match_::{get_normalization_operation_name, MATCH_CONSTANTS};
use common::{NamedItem, WithLocation};
use fnv::FnvHashMap;
use graphql_ir::{
    Argument, ConstantValue, Directive, FragmentDefinition, OperationDefinition, Program,
    Selection, Transformed, Transformer, Value,
};
use interner::{Intern, StringKey};
use lazy_static::lazy_static;
use schema::TypeReference;

lazy_static! {
    pub static ref DATA_DRIVEN_DEPENDENCY_METADATA_KEY: StringKey =
        "__dataDrivenDependencyMetadata".intern();
}

pub fn generate_data_driven_dependency_metadata(program: &Program) -> Program {
    let mut transformer = GenerateDataDrivenDependencyMetadata::new(program);
    transformer
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

struct GenerateDataDrivenDependencyMetadata<'s> {
    pub program: &'s Program,
}

impl<'s> GenerateDataDrivenDependencyMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateDataDrivenDependencyMetadata { program }
    }

    fn generate_data_driven_dependency_for_selections(
        &mut self,
        type_: TypeReference,
        selections: &[Selection],
    ) -> Option<Directive> {
        let mut processing_queue: Vec<ProcessingItem<'_>> = vec![ProcessingItem {
            plural: false,
            parent_type: type_,
            selections,
        }];

        let mut module_entries: ModuleEntries = Default::default();

        while !processing_queue.is_empty() {
            if let Some(processing_item) = processing_queue.pop() {
                for selection in processing_item.selections {
                    match selection {
                        Selection::ScalarField(_) | Selection::FragmentSpread(_) => {}
                        Selection::LinkedField(linked_filed) => {
                            let field_type = &self
                                .program
                                .schema
                                .field(linked_filed.definition.item)
                                .type_;
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural || field_type.is_list(),
                                parent_type: field_type.clone(),
                                selections: &linked_filed.selections,
                            });
                        }
                        Selection::InlineFragment(inline_fragment) => {
                            let parent_type = match inline_fragment.type_condition {
                                Some(type_) => TypeReference::Named(type_),
                                None => processing_item.parent_type.clone(),
                            };
                            let module_directive = inline_fragment
                                .directives
                                .named(MATCH_CONSTANTS.custom_module_directive_name);
                            if let Some(module_directive) = module_directive {
                                let id = get_argument_value(
                                    &module_directive,
                                    MATCH_CONSTANTS.js_field_id_arg,
                                );
                                let component = get_argument_value(
                                    &module_directive,
                                    MATCH_CONSTANTS.js_field_module_arg,
                                );
                                let fragment_spread =
                                    inline_fragment.selections.iter().find(|item| match item {
                                        Selection::FragmentSpread(_) => true,
                                        _ => false,
                                    });
                                // This is expected to be a fragment spread
                                let fragment_name = match fragment_spread {
                                    Some(Selection::FragmentSpread(spread)) => spread.fragment.item,
                                    _ => panic!("Expected to have a fragment spread"),
                                };

                                let type_name = self.program.schema.get_type_string(&parent_type);
                                module_entries
                                    .entry(id)
                                    .and_modify(|module_entry| {
                                        module_entry.branches.insert(
                                            type_name.clone(),
                                            Branch {
                                                component,
                                                fragment: get_fragment_filename(fragment_name),
                                            },
                                        );
                                    })
                                    .or_insert(ModuleEntry {
                                        id,
                                        branches: {
                                            let mut map: FnvHashMap<String, Branch> =
                                                Default::default();
                                            map.insert(
                                                type_name.clone(),
                                                Branch {
                                                    component,
                                                    fragment: get_fragment_filename(fragment_name),
                                                },
                                            );
                                            map
                                        },
                                        plural: processing_item.plural,
                                    });
                            }
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural,
                                parent_type,
                                selections: &inline_fragment.selections,
                            });
                        }
                        Selection::Condition(condition) => {
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural,
                                parent_type: processing_item.parent_type.clone(),
                                selections: &condition.selections,
                            });
                        }
                    }
                }
            }
        }

        if !module_entries.is_empty() {
            Some(create_metadata_directive(module_entries))
        } else {
            None
        }
    }
}

#[derive(Debug, Copy, Clone)]
struct Branch {
    component: StringKey,
    fragment: StringKey,
}

type ModuleEntries = FnvHashMap<StringKey, ModuleEntry>;

#[derive(Debug)]
struct ModuleEntry {
    id: StringKey,
    branches: FnvHashMap<String, Branch>,
    plural: bool,
}

#[derive(Debug)]
struct ProcessingItem<'a> {
    plural: bool,
    parent_type: TypeReference,
    selections: &'a [Selection],
}

impl<'s> Transformer for GenerateDataDrivenDependencyMetadata<'s> {
    const NAME: &'static str = "GenerateDataDrivenDependencyMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        if let Some(query_type) = self.program.schema.query_type() {
            let generated_directive = self.generate_data_driven_dependency_for_selections(
                TypeReference::Named(query_type),
                &operation.selections,
            );
            if let Some(generated_directive) = generated_directive {
                let mut next_directives: Vec<Directive> =
                    Vec::with_capacity(operation.directives.len() + 1);
                for diretive in operation.directives.iter() {
                    next_directives.push(diretive.clone());
                }

                next_directives.push(generated_directive);

                Transformed::Replace(OperationDefinition {
                    directives: next_directives,
                    ..operation.clone()
                })
            } else {
                Transformed::Keep
            }
        } else {
            Transformed::Keep
        }
    }

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        let generated_directive = self.generate_data_driven_dependency_for_selections(
            TypeReference::Named(fragment.type_condition),
            &fragment.selections,
        );
        if let Some(generated_directive) = generated_directive {
            let mut next_directives: Vec<Directive> =
                Vec::with_capacity(fragment.directives.len() + 1);
            for diretive in fragment.directives.iter() {
                next_directives.push(diretive.clone());
            }
            next_directives.push(generated_directive);

            Transformed::Replace(FragmentDefinition {
                directives: next_directives,
                ..fragment.clone()
            })
        } else {
            Transformed::Keep
        }
    }
}

fn create_metadata_directive(module_entries: FnvHashMap<StringKey, ModuleEntry>) -> Directive {
    let mut arguments: Vec<Argument> = Vec::with_capacity(module_entries.len());
    for (key, module_entry) in module_entries {
        arguments.push(Argument {
            name: WithLocation::generated(key),
            value: WithLocation::generated(Value::Constant(ConstantValue::String(From::from(
                module_entry,
            )))),
        })
    }
    arguments.sort_unstable_by(|a, b| a.name.item.cmp(&b.name.item));

    Directive {
        name: WithLocation::generated(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY),
        arguments,
    }
}

impl From<ModuleEntry> for StringKey {
    fn from(module_entry: ModuleEntry) -> Self {
        let mut serialized_branches: Vec<(String, String)> =
            Vec::with_capacity(module_entry.branches.len());
        for (id, branch) in module_entry.branches.iter() {
            serialized_branches.push((
                id.clone(),
                format!(
                    "\"{}\":{{\"component\":\"{}\",\"fragment\":\"{}\"}}",
                    id, branch.component, branch.fragment
                ),
            ));
        }

        serialized_branches.sort_unstable_by(|a, b| a.0.cmp(&b.0));

        format!(
            "{{\"branches\":{{{}}},\"plural\":{}}}",
            serialized_branches
                .into_iter()
                .map(|(_, value)| value)
                .collect::<Vec<String>>()
                .join(","),
            module_entry.plural
        )
        .intern()
    }
}

fn get_argument_value(directive: &Directive, argument_name: StringKey) -> StringKey {
    match directive.arguments.named(argument_name).unwrap().value.item {
        Value::Constant(ConstantValue::String(value)) => value,
        _ => panic!(
            "Expected to have a constant string value for argument {}.",
            argument_name
        ),
    }
}

fn get_fragment_filename(fragment_name: StringKey) -> StringKey {
    let mut fragment = String::new();
    get_normalization_operation_name(&mut fragment, fragment_name);
    format!("{}.graphql", fragment).intern()
}
<commit_msg>@ddd - Use parent field type (not fragment) as the key<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::match_::{get_normalization_operation_name, MATCH_CONSTANTS};
use common::{NamedItem, WithLocation};
use fnv::FnvHashMap;
use graphql_ir::{
    Argument, ConstantValue, Directive, FragmentDefinition, OperationDefinition, Program,
    Selection, Transformed, Transformer, Value,
};
use interner::{Intern, StringKey};
use lazy_static::lazy_static;
use schema::TypeReference;

lazy_static! {
    pub static ref DATA_DRIVEN_DEPENDENCY_METADATA_KEY: StringKey =
        "__dataDrivenDependencyMetadata".intern();
}

pub fn generate_data_driven_dependency_metadata(program: &Program) -> Program {
    let mut transformer = GenerateDataDrivenDependencyMetadata::new(program);
    transformer
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

struct GenerateDataDrivenDependencyMetadata<'s> {
    pub program: &'s Program,
}

impl<'s> GenerateDataDrivenDependencyMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateDataDrivenDependencyMetadata { program }
    }

    fn generate_data_driven_dependency_for_selections(
        &mut self,
        type_: TypeReference,
        selections: &[Selection],
    ) -> Option<Directive> {
        let mut processing_queue: Vec<ProcessingItem<'_>> = vec![ProcessingItem {
            plural: false,
            parent_type: type_,
            selections,
        }];

        let mut module_entries: ModuleEntries = Default::default();

        while !processing_queue.is_empty() {
            if let Some(processing_item) = processing_queue.pop() {
                for selection in processing_item.selections {
                    match selection {
                        Selection::ScalarField(_) | Selection::FragmentSpread(_) => {}
                        Selection::LinkedField(linked_filed) => {
                            let field_type = &self
                                .program
                                .schema
                                .field(linked_filed.definition.item)
                                .type_;
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural || field_type.is_list(),
                                parent_type: field_type.clone(),
                                selections: &linked_filed.selections,
                            });
                        }
                        Selection::InlineFragment(inline_fragment) => {
                            let parent_type = match inline_fragment.type_condition {
                                Some(type_) => TypeReference::Named(type_),
                                None => processing_item.parent_type.clone(),
                            };
                            let module_directive = inline_fragment
                                .directives
                                .named(MATCH_CONSTANTS.custom_module_directive_name);
                            if let Some(module_directive) = module_directive {
                                let id = get_argument_value(
                                    &module_directive,
                                    MATCH_CONSTANTS.js_field_id_arg,
                                );
                                let component = get_argument_value(
                                    &module_directive,
                                    MATCH_CONSTANTS.js_field_module_arg,
                                );
                                let fragment_spread =
                                    inline_fragment.selections.iter().find(|item| match item {
                                        Selection::FragmentSpread(_) => true,
                                        _ => false,
                                    });
                                // This is expected to be a fragment spread
                                let fragment_name = match fragment_spread {
                                    Some(Selection::FragmentSpread(spread)) => spread.fragment.item,
                                    _ => panic!("Expected to have a fragment spread"),
                                };

                                let type_name = self
                                    .program
                                    .schema
                                    .get_type_string(&processing_item.parent_type);
                                module_entries
                                    .entry(id)
                                    .and_modify(|module_entry| {
                                        module_entry.branches.insert(
                                            type_name.clone(),
                                            Branch {
                                                component,
                                                fragment: get_fragment_filename(fragment_name),
                                            },
                                        );
                                    })
                                    .or_insert(ModuleEntry {
                                        id,
                                        branches: {
                                            let mut map: FnvHashMap<String, Branch> =
                                                Default::default();
                                            map.insert(
                                                type_name.clone(),
                                                Branch {
                                                    component,
                                                    fragment: get_fragment_filename(fragment_name),
                                                },
                                            );
                                            map
                                        },
                                        plural: processing_item.plural,
                                    });
                            }
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural,
                                parent_type,
                                selections: &inline_fragment.selections,
                            });
                        }
                        Selection::Condition(condition) => {
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural,
                                parent_type: processing_item.parent_type.clone(),
                                selections: &condition.selections,
                            });
                        }
                    }
                }
            }
        }

        if !module_entries.is_empty() {
            Some(create_metadata_directive(module_entries))
        } else {
            None
        }
    }
}

#[derive(Debug, Copy, Clone)]
struct Branch {
    component: StringKey,
    fragment: StringKey,
}

type ModuleEntries = FnvHashMap<StringKey, ModuleEntry>;

#[derive(Debug)]
struct ModuleEntry {
    id: StringKey,
    branches: FnvHashMap<String, Branch>,
    plural: bool,
}

#[derive(Debug)]
struct ProcessingItem<'a> {
    plural: bool,
    parent_type: TypeReference,
    selections: &'a [Selection],
}

impl<'s> Transformer for GenerateDataDrivenDependencyMetadata<'s> {
    const NAME: &'static str = "GenerateDataDrivenDependencyMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        if let Some(query_type) = self.program.schema.query_type() {
            let generated_directive = self.generate_data_driven_dependency_for_selections(
                TypeReference::Named(query_type),
                &operation.selections,
            );
            if let Some(generated_directive) = generated_directive {
                let mut next_directives: Vec<Directive> =
                    Vec::with_capacity(operation.directives.len() + 1);
                for diretive in operation.directives.iter() {
                    next_directives.push(diretive.clone());
                }

                next_directives.push(generated_directive);

                Transformed::Replace(OperationDefinition {
                    directives: next_directives,
                    ..operation.clone()
                })
            } else {
                Transformed::Keep
            }
        } else {
            Transformed::Keep
        }
    }

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        let generated_directive = self.generate_data_driven_dependency_for_selections(
            TypeReference::Named(fragment.type_condition),
            &fragment.selections,
        );
        if let Some(generated_directive) = generated_directive {
            let mut next_directives: Vec<Directive> =
                Vec::with_capacity(fragment.directives.len() + 1);
            for diretive in fragment.directives.iter() {
                next_directives.push(diretive.clone());
            }
            next_directives.push(generated_directive);

            Transformed::Replace(FragmentDefinition {
                directives: next_directives,
                ..fragment.clone()
            })
        } else {
            Transformed::Keep
        }
    }
}

fn create_metadata_directive(module_entries: FnvHashMap<StringKey, ModuleEntry>) -> Directive {
    let mut arguments: Vec<Argument> = Vec::with_capacity(module_entries.len());
    for (key, module_entry) in module_entries {
        arguments.push(Argument {
            name: WithLocation::generated(key),
            value: WithLocation::generated(Value::Constant(ConstantValue::String(From::from(
                module_entry,
            )))),
        })
    }
    arguments.sort_unstable_by(|a, b| a.name.item.cmp(&b.name.item));

    Directive {
        name: WithLocation::generated(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY),
        arguments,
    }
}

impl From<ModuleEntry> for StringKey {
    fn from(module_entry: ModuleEntry) -> Self {
        let mut serialized_branches: Vec<(String, String)> =
            Vec::with_capacity(module_entry.branches.len());
        for (id, branch) in module_entry.branches.iter() {
            serialized_branches.push((
                id.clone(),
                format!(
                    "\"{}\":{{\"component\":\"{}\",\"fragment\":\"{}\"}}",
                    id, branch.component, branch.fragment
                ),
            ));
        }

        serialized_branches.sort_unstable_by(|a, b| a.0.cmp(&b.0));

        format!(
            "{{\"branches\":{{{}}},\"plural\":{}}}",
            serialized_branches
                .into_iter()
                .map(|(_, value)| value)
                .collect::<Vec<String>>()
                .join(","),
            module_entry.plural
        )
        .intern()
    }
}

fn get_argument_value(directive: &Directive, argument_name: StringKey) -> StringKey {
    match directive.arguments.named(argument_name).unwrap().value.item {
        Value::Constant(ConstantValue::String(value)) => value,
        _ => panic!(
            "Expected to have a constant string value for argument {}.",
            argument_name
        ),
    }
}

fn get_fragment_filename(fragment_name: StringKey) -> StringKey {
    let mut fragment = String::new();
    get_normalization_operation_name(&mut fragment, fragment_name);
    format!("{}.graphql", fragment).intern()
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use byteorder::{LittleEndian, ReadBytesExt};
use proptest::{collection::vec, prelude::*};
use schemadb::{
    define_schema,
    schema::{KeyCodec, Schema, ValueCodec},
    ColumnFamilyOptions, ColumnFamilyOptionsMap, SchemaBatch, DB, DEFAULT_CF_NAME,
};

// Creating two schemas that share exactly the same structure but are stored in different column
// families. Also note that the key and value are of the same type `TestField`. By implementing
// both the `KeyCodec<>` and `ValueCodec<>` traits for both schemas, we are able to use it
// everywhere.
define_schema!(TestSchema1, TestField, TestField, "TestCF1");
define_schema!(TestSchema2, TestField, TestField, "TestCF2");

#[derive(Debug, Eq, PartialEq)]
struct TestField(u32);

impl TestField {
    fn to_bytes(&self) -> Result<Vec<u8>> {
        Ok(self.0.to_le_bytes().to_vec())
    }

    fn from_bytes(data: &[u8]) -> Result<Self> {
        let mut reader = std::io::Cursor::new(data);
        Ok(TestField(reader.read_u32::<LittleEndian>()?))
    }
}

impl KeyCodec<TestSchema1> for TestField {
    fn encode_key(&self) -> Result<Vec<u8>> {
        self.to_bytes()
    }

    fn decode_key(data: &[u8]) -> Result<Self> {
        Self::from_bytes(data)
    }
}

impl ValueCodec<TestSchema1> for TestField {
    fn encode_value(&self) -> Result<Vec<u8>> {
        self.to_bytes()
    }

    fn decode_value(data: &[u8]) -> Result<Self> {
        Self::from_bytes(data)
    }
}

impl KeyCodec<TestSchema2> for TestField {
    fn encode_key(&self) -> Result<Vec<u8>> {
        self.to_bytes()
    }

    fn decode_key(data: &[u8]) -> Result<Self> {
        Self::from_bytes(data)
    }
}

impl ValueCodec<TestSchema2> for TestField {
    fn encode_value(&self) -> Result<Vec<u8>> {
        self.to_bytes()
    }

    fn decode_value(data: &[u8]) -> Result<Self> {
        Self::from_bytes(data)
    }
}

fn open_db(dir: &libra_temppath::TempPath) -> DB {
    let cf_opts_map: ColumnFamilyOptionsMap = [
        (DEFAULT_CF_NAME, ColumnFamilyOptions::default()),
        (
            TestSchema1::COLUMN_FAMILY_NAME,
            ColumnFamilyOptions::default(),
        ),
        (
            TestSchema2::COLUMN_FAMILY_NAME,
            ColumnFamilyOptions::default(),
        ),
    ]
    .iter()
    .cloned()
    .collect();
    DB::open(&dir.path(), cf_opts_map).expect("Failed to open DB.")
}

struct TestDB {
    _tmpdir: libra_temppath::TempPath,
    db: DB,
}

impl TestDB {
    fn new() -> Self {
        let tmpdir = libra_temppath::TempPath::new();
        let db = open_db(&tmpdir);

        TestDB {
            _tmpdir: tmpdir,
            db,
        }
    }
}

impl std::ops::Deref for TestDB {
    type Target = DB;

    fn deref(&self) -> &Self::Target {
        &self.db
    }
}

#[test]
fn test_schema_put_get() {
    let db = TestDB::new();

    db.put::<TestSchema1>(&TestField(0), &TestField(0)).unwrap();
    db.put::<TestSchema1>(&TestField(1), &TestField(1)).unwrap();
    db.put::<TestSchema1>(&TestField(2), &TestField(2)).unwrap();
    db.put::<TestSchema2>(&TestField(2), &TestField(3)).unwrap();
    db.put::<TestSchema2>(&TestField(3), &TestField(4)).unwrap();
    db.put::<TestSchema2>(&TestField(4), &TestField(5)).unwrap();

    assert_eq!(
        db.get::<TestSchema1>(&TestField(0)).unwrap(),
        Some(TestField(0)),
    );
    assert_eq!(
        db.get::<TestSchema1>(&TestField(1)).unwrap(),
        Some(TestField(1)),
    );
    assert_eq!(
        db.get::<TestSchema1>(&TestField(2)).unwrap(),
        Some(TestField(2)),
    );
    assert_eq!(db.get::<TestSchema1>(&TestField(3)).unwrap(), None);

    assert_eq!(db.get::<TestSchema2>(&TestField(1)).unwrap(), None);
    assert_eq!(
        db.get::<TestSchema2>(&TestField(2)).unwrap(),
        Some(TestField(3)),
    );
    assert_eq!(
        db.get::<TestSchema2>(&TestField(3)).unwrap(),
        Some(TestField(4)),
    );
    assert_eq!(
        db.get::<TestSchema2>(&TestField(4)).unwrap(),
        Some(TestField(5)),
    );
}

proptest! {
    #![proptest_config(ProptestConfig::with_cases(10))]

    #[test]
    fn test_schema_range_delete(
        ranges_to_delete in vec(
            (0..100u32).prop_flat_map(|begin| (Just(begin), (begin..100u32))), 0..10)
    ) {
        let db = TestDB::new();
        for i in 0..100u32 {
            db.put::<TestSchema1>(&TestField(i), &TestField(i)).unwrap();
        }
        let mut should_exist = [true; 100];
        for (begin, end) in ranges_to_delete {
            db.range_delete::<TestSchema1, TestField>(&TestField(begin), &TestField(end)).unwrap();
            for i in begin..end {
                should_exist[i as usize] = false;
            }
        }

        for (i, should_exist) in should_exist.iter().enumerate() {
            assert_eq!(
                db.get::<TestSchema1>(&TestField(i as u32)).unwrap().is_some(),
                *should_exist,
            )
        }
    }
}

fn collect_values<S: Schema>(db: &TestDB) -> Vec<(S::Key, S::Value)> {
    let mut iter = db
        .iter::<S>(Default::default())
        .expect("Failed to create iterator.");
    iter.seek_to_first().unwrap();
    iter.collect::<Result<Vec<_>>>().unwrap()
}

fn gen_expected_values(values: &[(u32, u32)]) -> Vec<(TestField, TestField)> {
    values
        .iter()
        .cloned()
        .map(|(x, y)| (TestField(x), TestField(y)))
        .collect()
}

#[test]
fn test_single_schema_batch() {
    let db = TestDB::new();

    let mut db_batch = SchemaBatch::new();
    db_batch
        .put::<TestSchema1>(&TestField(0), &TestField(0))
        .unwrap();
    db_batch
        .put::<TestSchema1>(&TestField(1), &TestField(1))
        .unwrap();
    db_batch
        .put::<TestSchema1>(&TestField(2), &TestField(2))
        .unwrap();
    db_batch
        .put::<TestSchema2>(&TestField(3), &TestField(3))
        .unwrap();
    db_batch.delete::<TestSchema2>(&TestField(4)).unwrap();
    db_batch.delete::<TestSchema2>(&TestField(3)).unwrap();
    db_batch
        .put::<TestSchema2>(&TestField(4), &TestField(4))
        .unwrap();
    db_batch
        .put::<TestSchema2>(&TestField(5), &TestField(5))
        .unwrap();
    db.write_schemas(db_batch).unwrap();

    assert_eq!(
        collect_values::<TestSchema1>(&db),
        gen_expected_values(&[(0, 0), (1, 1), (2, 2)]),
    );
    assert_eq!(
        collect_values::<TestSchema2>(&db),
        gen_expected_values(&[(4, 4), (5, 5)]),
    );
}

#[test]
fn test_two_schema_batches() {
    let db = TestDB::new();

    let mut db_batch1 = SchemaBatch::new();
    db_batch1
        .put::<TestSchema1>(&TestField(0), &TestField(0))
        .unwrap();
    db_batch1
        .put::<TestSchema1>(&TestField(1), &TestField(1))
        .unwrap();
    db_batch1
        .put::<TestSchema1>(&TestField(2), &TestField(2))
        .unwrap();
    db_batch1.delete::<TestSchema1>(&TestField(2)).unwrap();
    db.write_schemas(db_batch1).unwrap();

    assert_eq!(
        collect_values::<TestSchema1>(&db),
        gen_expected_values(&[(0, 0), (1, 1)]),
    );

    let mut db_batch2 = SchemaBatch::new();
    db_batch2.delete::<TestSchema2>(&TestField(3)).unwrap();
    db_batch2
        .put::<TestSchema2>(&TestField(3), &TestField(3))
        .unwrap();
    db_batch2
        .put::<TestSchema2>(&TestField(4), &TestField(4))
        .unwrap();
    db_batch2
        .put::<TestSchema2>(&TestField(5), &TestField(5))
        .unwrap();
    db.write_schemas(db_batch2).unwrap();

    assert_eq!(
        collect_values::<TestSchema1>(&db),
        gen_expected_values(&[(0, 0), (1, 1)]),
    );
    assert_eq!(
        collect_values::<TestSchema2>(&db),
        gen_expected_values(&[(3, 3), (4, 4), (5, 5)]),
    );
}

#[test]
fn test_reopen() {
    let tmpdir = libra_temppath::TempPath::new();
    {
        let db = open_db(&tmpdir);
        db.put::<TestSchema1>(&TestField(0), &TestField(0)).unwrap();
        assert_eq!(
            db.get::<TestSchema1>(&TestField(0)).unwrap(),
            Some(TestField(0)),
        );
    }
    {
        let db = open_db(&tmpdir);
        assert_eq!(
            db.get::<TestSchema1>(&TestField(0)).unwrap(),
            Some(TestField(0)),
        );
    }
}

#[test]
fn test_report_size() {
    let db = TestDB::new();

    for i in 0..1000 {
        let mut db_batch = SchemaBatch::new();
        db_batch
            .put::<TestSchema1>(&TestField(i), &TestField(i))
            .unwrap();
        db_batch
            .put::<TestSchema2>(&TestField(i), &TestField(i))
            .unwrap();
        db.write_schemas(db_batch).unwrap();
    }

    db.flush_all(/* sync = */ true).unwrap();

    let cf_sizes = db.get_approximate_sizes_cf().unwrap();
    assert!(*cf_sizes.get("TestCF1").unwrap() > 0);
    assert!(*cf_sizes.get("TestCF2").unwrap() > 0);
    assert_eq!(*cf_sizes.get("default").unwrap(), 0);
}
<commit_msg>[storage] rename should_exist to should_exist_vec in schemadb test<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use byteorder::{LittleEndian, ReadBytesExt};
use proptest::{collection::vec, prelude::*};
use schemadb::{
    define_schema,
    schema::{KeyCodec, Schema, ValueCodec},
    ColumnFamilyOptions, ColumnFamilyOptionsMap, SchemaBatch, DB, DEFAULT_CF_NAME,
};

// Creating two schemas that share exactly the same structure but are stored in different column
// families. Also note that the key and value are of the same type `TestField`. By implementing
// both the `KeyCodec<>` and `ValueCodec<>` traits for both schemas, we are able to use it
// everywhere.
define_schema!(TestSchema1, TestField, TestField, "TestCF1");
define_schema!(TestSchema2, TestField, TestField, "TestCF2");

#[derive(Debug, Eq, PartialEq)]
struct TestField(u32);

impl TestField {
    fn to_bytes(&self) -> Result<Vec<u8>> {
        Ok(self.0.to_le_bytes().to_vec())
    }

    fn from_bytes(data: &[u8]) -> Result<Self> {
        let mut reader = std::io::Cursor::new(data);
        Ok(TestField(reader.read_u32::<LittleEndian>()?))
    }
}

impl KeyCodec<TestSchema1> for TestField {
    fn encode_key(&self) -> Result<Vec<u8>> {
        self.to_bytes()
    }

    fn decode_key(data: &[u8]) -> Result<Self> {
        Self::from_bytes(data)
    }
}

impl ValueCodec<TestSchema1> for TestField {
    fn encode_value(&self) -> Result<Vec<u8>> {
        self.to_bytes()
    }

    fn decode_value(data: &[u8]) -> Result<Self> {
        Self::from_bytes(data)
    }
}

impl KeyCodec<TestSchema2> for TestField {
    fn encode_key(&self) -> Result<Vec<u8>> {
        self.to_bytes()
    }

    fn decode_key(data: &[u8]) -> Result<Self> {
        Self::from_bytes(data)
    }
}

impl ValueCodec<TestSchema2> for TestField {
    fn encode_value(&self) -> Result<Vec<u8>> {
        self.to_bytes()
    }

    fn decode_value(data: &[u8]) -> Result<Self> {
        Self::from_bytes(data)
    }
}

fn open_db(dir: &libra_temppath::TempPath) -> DB {
    let cf_opts_map: ColumnFamilyOptionsMap = [
        (DEFAULT_CF_NAME, ColumnFamilyOptions::default()),
        (
            TestSchema1::COLUMN_FAMILY_NAME,
            ColumnFamilyOptions::default(),
        ),
        (
            TestSchema2::COLUMN_FAMILY_NAME,
            ColumnFamilyOptions::default(),
        ),
    ]
    .iter()
    .cloned()
    .collect();
    DB::open(&dir.path(), cf_opts_map).expect("Failed to open DB.")
}

struct TestDB {
    _tmpdir: libra_temppath::TempPath,
    db: DB,
}

impl TestDB {
    fn new() -> Self {
        let tmpdir = libra_temppath::TempPath::new();
        let db = open_db(&tmpdir);

        TestDB {
            _tmpdir: tmpdir,
            db,
        }
    }
}

impl std::ops::Deref for TestDB {
    type Target = DB;

    fn deref(&self) -> &Self::Target {
        &self.db
    }
}

#[test]
fn test_schema_put_get() {
    let db = TestDB::new();

    db.put::<TestSchema1>(&TestField(0), &TestField(0)).unwrap();
    db.put::<TestSchema1>(&TestField(1), &TestField(1)).unwrap();
    db.put::<TestSchema1>(&TestField(2), &TestField(2)).unwrap();
    db.put::<TestSchema2>(&TestField(2), &TestField(3)).unwrap();
    db.put::<TestSchema2>(&TestField(3), &TestField(4)).unwrap();
    db.put::<TestSchema2>(&TestField(4), &TestField(5)).unwrap();

    assert_eq!(
        db.get::<TestSchema1>(&TestField(0)).unwrap(),
        Some(TestField(0)),
    );
    assert_eq!(
        db.get::<TestSchema1>(&TestField(1)).unwrap(),
        Some(TestField(1)),
    );
    assert_eq!(
        db.get::<TestSchema1>(&TestField(2)).unwrap(),
        Some(TestField(2)),
    );
    assert_eq!(db.get::<TestSchema1>(&TestField(3)).unwrap(), None);

    assert_eq!(db.get::<TestSchema2>(&TestField(1)).unwrap(), None);
    assert_eq!(
        db.get::<TestSchema2>(&TestField(2)).unwrap(),
        Some(TestField(3)),
    );
    assert_eq!(
        db.get::<TestSchema2>(&TestField(3)).unwrap(),
        Some(TestField(4)),
    );
    assert_eq!(
        db.get::<TestSchema2>(&TestField(4)).unwrap(),
        Some(TestField(5)),
    );
}

proptest! {
    #![proptest_config(ProptestConfig::with_cases(10))]

    #[test]
    fn test_schema_range_delete(
        ranges_to_delete in vec(
            (0..100u32).prop_flat_map(|begin| (Just(begin), (begin..100u32))), 0..10)
    ) {
        let db = TestDB::new();
        for i in 0..100u32 {
            db.put::<TestSchema1>(&TestField(i), &TestField(i)).unwrap();
        }
        let mut should_exist_vec = [true; 100];
        for (begin, end) in ranges_to_delete {
            db.range_delete::<TestSchema1, TestField>(&TestField(begin), &TestField(end)).unwrap();
            for i in begin..end {
                should_exist_vec[i as usize] = false;
            }
        }

        for (i, should_exist) in should_exist_vec.iter().enumerate() {
            assert_eq!(
                db.get::<TestSchema1>(&TestField(i as u32)).unwrap().is_some(),
                *should_exist,
            )
        }
    }
}

fn collect_values<S: Schema>(db: &TestDB) -> Vec<(S::Key, S::Value)> {
    let mut iter = db
        .iter::<S>(Default::default())
        .expect("Failed to create iterator.");
    iter.seek_to_first().unwrap();
    iter.collect::<Result<Vec<_>>>().unwrap()
}

fn gen_expected_values(values: &[(u32, u32)]) -> Vec<(TestField, TestField)> {
    values
        .iter()
        .cloned()
        .map(|(x, y)| (TestField(x), TestField(y)))
        .collect()
}

#[test]
fn test_single_schema_batch() {
    let db = TestDB::new();

    let mut db_batch = SchemaBatch::new();
    db_batch
        .put::<TestSchema1>(&TestField(0), &TestField(0))
        .unwrap();
    db_batch
        .put::<TestSchema1>(&TestField(1), &TestField(1))
        .unwrap();
    db_batch
        .put::<TestSchema1>(&TestField(2), &TestField(2))
        .unwrap();
    db_batch
        .put::<TestSchema2>(&TestField(3), &TestField(3))
        .unwrap();
    db_batch.delete::<TestSchema2>(&TestField(4)).unwrap();
    db_batch.delete::<TestSchema2>(&TestField(3)).unwrap();
    db_batch
        .put::<TestSchema2>(&TestField(4), &TestField(4))
        .unwrap();
    db_batch
        .put::<TestSchema2>(&TestField(5), &TestField(5))
        .unwrap();
    db.write_schemas(db_batch).unwrap();

    assert_eq!(
        collect_values::<TestSchema1>(&db),
        gen_expected_values(&[(0, 0), (1, 1), (2, 2)]),
    );
    assert_eq!(
        collect_values::<TestSchema2>(&db),
        gen_expected_values(&[(4, 4), (5, 5)]),
    );
}

#[test]
fn test_two_schema_batches() {
    let db = TestDB::new();

    let mut db_batch1 = SchemaBatch::new();
    db_batch1
        .put::<TestSchema1>(&TestField(0), &TestField(0))
        .unwrap();
    db_batch1
        .put::<TestSchema1>(&TestField(1), &TestField(1))
        .unwrap();
    db_batch1
        .put::<TestSchema1>(&TestField(2), &TestField(2))
        .unwrap();
    db_batch1.delete::<TestSchema1>(&TestField(2)).unwrap();
    db.write_schemas(db_batch1).unwrap();

    assert_eq!(
        collect_values::<TestSchema1>(&db),
        gen_expected_values(&[(0, 0), (1, 1)]),
    );

    let mut db_batch2 = SchemaBatch::new();
    db_batch2.delete::<TestSchema2>(&TestField(3)).unwrap();
    db_batch2
        .put::<TestSchema2>(&TestField(3), &TestField(3))
        .unwrap();
    db_batch2
        .put::<TestSchema2>(&TestField(4), &TestField(4))
        .unwrap();
    db_batch2
        .put::<TestSchema2>(&TestField(5), &TestField(5))
        .unwrap();
    db.write_schemas(db_batch2).unwrap();

    assert_eq!(
        collect_values::<TestSchema1>(&db),
        gen_expected_values(&[(0, 0), (1, 1)]),
    );
    assert_eq!(
        collect_values::<TestSchema2>(&db),
        gen_expected_values(&[(3, 3), (4, 4), (5, 5)]),
    );
}

#[test]
fn test_reopen() {
    let tmpdir = libra_temppath::TempPath::new();
    {
        let db = open_db(&tmpdir);
        db.put::<TestSchema1>(&TestField(0), &TestField(0)).unwrap();
        assert_eq!(
            db.get::<TestSchema1>(&TestField(0)).unwrap(),
            Some(TestField(0)),
        );
    }
    {
        let db = open_db(&tmpdir);
        assert_eq!(
            db.get::<TestSchema1>(&TestField(0)).unwrap(),
            Some(TestField(0)),
        );
    }
}

#[test]
fn test_report_size() {
    let db = TestDB::new();

    for i in 0..1000 {
        let mut db_batch = SchemaBatch::new();
        db_batch
            .put::<TestSchema1>(&TestField(i), &TestField(i))
            .unwrap();
        db_batch
            .put::<TestSchema2>(&TestField(i), &TestField(i))
            .unwrap();
        db.write_schemas(db_batch).unwrap();
    }

    db.flush_all(/* sync = */ true).unwrap();

    let cf_sizes = db.get_approximate_sizes_cf().unwrap();
    assert!(*cf_sizes.get("TestCF1").unwrap() > 0);
    assert!(*cf_sizes.get("TestCF2").unwrap() > 0);
    assert_eq!(*cf_sizes.get("default").unwrap(), 0);
}
<|endoftext|>