<commit_before>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().unwrap());
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

// CIs usually do it automatically but for normal users libsass would be missing
fn init_submodule() {
    Command::new("git")
        .arg("submodule")
        .arg("init")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success();
    Command::new("git")
        .arg("submodule")
        .arg("update")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success();
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().unwrap().join("libsass")
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let libprobe = | lib: &str | -> bool {
      Command::new("cc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success()
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("error running make");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    }
    else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    }
    else {
        panic!("no c++ library found");
    }

}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("error running devenv");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let search = Command::new("which")
        .args(&["msbuild.exe"])
        .output()
        .expect("Could not search for msbuild.exe on path");
    let mut msbuild = if search.status.success() {
        Command::new("msbuild.exe")
    } else {
        cc::windows_registry::find(target.as_str(), "msbuild.exe")
            .expect("Could not find msbuild.exe on the registry")
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());

    let r = msbuild
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/m:{}", jobs).as_str(),
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("error running msbuild");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    init_submodule();
    compile();
}
<commit_msg>Differentiate macos<commit_after>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().unwrap());
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

// CIs usually do it automatically but for normal users libsass would be missing
fn init_submodule() {
    Command::new("git")
        .arg("submodule")
        .arg("init")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success();
    Command::new("git")
        .arg("submodule")
        .arg("update")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success();
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().unwrap().join("libsass")
}

#[cfg(not(target_os = "macos"))]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        panic!("no c++ library found");
    }
}

#[cfg(target_os = "macos")]
fn _compile(libprobe: fn(&str) -> bool) {

    if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else {
        panic!("no c++ library found");
    }
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("error running make");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    let libprobe = | lib: &str | -> bool {
      Command::new("cc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success()
    };
    _compile(libprobe);
}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("error running devenv");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let search = Command::new("which")
        .args(&["msbuild.exe"])
        .output()
        .expect("Could not search for msbuild.exe on path");
    let mut msbuild = if search.status.success() {
        Command::new("msbuild.exe")
    } else {
        cc::windows_registry::find(target.as_str(), "msbuild.exe")
            .expect("Could not find msbuild.exe on the registry")
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());

    let r = msbuild
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/m:{}", jobs).as_str(),
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("error running msbuild");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    init_submodule();
    compile();
}
<|endoftext|>


<commit_before>//@ignore-target-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance

use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;
use std::time::{Duration, Instant};

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
fn check_barriers() {
    let mut handles = Vec::with_capacity(10);
    let barrier = Arc::new(Barrier::new(10));
    for _ in 0..10 {
        let c = barrier.clone();
        // The same messages will be printed together.
        // You will NOT see any interleaving.
        handles.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }
    // Wait for other threads to finish.
    for handle in handles {
        handle.join().unwrap();
    }
}

// Check if Rust conditional variables are working.

/// The test taken from the Rust documentation.
fn check_conditional_variables_notify_one() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Spawn a new thread.
    let t = thread::spawn(move || {
        thread::yield_now();
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to fully start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }

    t.join().unwrap();
}

/// Test that waiting on a conditional variable with a timeout does not
/// deadlock.
fn check_conditional_variables_timed_wait_timeout() {
    let lock = Mutex::new(());
    let cvar = Condvar::new();
    let guard = lock.lock().unwrap();
    let now = Instant::now();
    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
    assert!(timeout.timed_out());
    let elapsed_time = now.elapsed().as_millis();
    assert!(100 <= elapsed_time && elapsed_time <= 1000);
}

/// Test that signaling a conditional variable when waiting with a timeout works
/// as expected.
fn check_conditional_variables_timed_wait_notimeout() {
    let pair = Arc::new((Mutex::new(()), Condvar::new()));
    let pair2 = pair.clone();

    let (lock, cvar) = &*pair;
    let guard = lock.lock().unwrap();

    let handle = thread::spawn(move || {
        let (_lock, cvar) = &*pair2;
        cvar.notify_one();
    });

    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(1000)).unwrap();
    assert!(!timeout.timed_out());
    handle.join().unwrap();
}

// Check if locks are working.

fn check_mutex() {
    let data = Arc::new(Mutex::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_lock().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_write() {
    let data = Arc::new(RwLock::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.write().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_write().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_read_no_deadlock() {
    let l1 = Arc::new(RwLock::new(0));
    let l2 = Arc::new(RwLock::new(0));

    let l1_copy = Arc::clone(&l1);
    let l2_copy = Arc::clone(&l2);
    let _guard1 = l1.read().unwrap();
    let handle = thread::spawn(move || {
        let _guard2 = l2_copy.read().unwrap();
        thread::yield_now();
        let _guard1 = l1_copy.read().unwrap();
    });
    thread::yield_now();
    let _guard2 = l2.read().unwrap();
    handle.join().unwrap();
}

// Check if Rust once statics are working.

static mut VAL: usize = 0;
static INIT: Once = Once::new();

fn get_cached_val() -> usize {
    unsafe {
        INIT.call_once(|| {
            VAL = expensive_computation();
        });
        VAL
    }
}

fn expensive_computation() -> usize {
    let mut i = 1;
    let mut c = 1;
    while i < 1000 {
        i *= c;
        c += 1;
    }
    i
}

/// The test taken from the Rust documentation.
fn check_once() {
    let handles: Vec<_> = (0..10)
        .map(|_| {
            thread::spawn(|| {
                thread::yield_now();
                let val = get_cached_val();
                assert_eq!(val, 5040);
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap();
    }
}

fn park_timeout() {
    let start = Instant::now();

    thread::park_timeout(Duration::from_millis(200));
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn park_unpark() {
    let t1 = thread::current();
    let t2 = thread::spawn(move || {
        thread::park();
        thread::sleep(Duration::from_millis(200));
        t1.unpark();
    });

    let start = Instant::now();

    t2.thread().unpark();
    thread::park();
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));

    t2.join().unwrap();
}

fn main() {
    check_barriers();
    check_conditional_variables_notify_one();
    check_conditional_variables_timed_wait_timeout();
    check_conditional_variables_timed_wait_notimeout();
    check_mutex();
    check_rwlock_write();
    check_rwlock_read_no_deadlock();
    check_once();
    park_timeout();
    park_unpark();
}
<commit_msg>work harder around notorious macos unrealiability<commit_after>//@ignore-target-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance

use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;
use std::time::{Duration, Instant};

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
fn check_barriers() {
    let mut handles = Vec::with_capacity(10);
    let barrier = Arc::new(Barrier::new(10));
    for _ in 0..10 {
        let c = barrier.clone();
        // The same messages will be printed together.
        // You will NOT see any interleaving.
        handles.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }
    // Wait for other threads to finish.
    for handle in handles {
        handle.join().unwrap();
    }
}

// Check if Rust conditional variables are working.

/// The test taken from the Rust documentation.
fn check_conditional_variables_notify_one() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Spawn a new thread.
    let t = thread::spawn(move || {
        thread::yield_now();
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to fully start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }

    t.join().unwrap();
}

/// Test that waiting on a conditional variable with a timeout does not
/// deadlock.
fn check_conditional_variables_timed_wait_timeout() {
    let lock = Mutex::new(());
    let cvar = Condvar::new();
    let guard = lock.lock().unwrap();
    let now = Instant::now();
    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
    assert!(timeout.timed_out());
    let elapsed_time = now.elapsed().as_millis();
    assert!(100 <= elapsed_time && elapsed_time <= 1000);
}

/// Test that signaling a conditional variable when waiting with a timeout works
/// as expected.
fn check_conditional_variables_timed_wait_notimeout() {
    let pair = Arc::new((Mutex::new(()), Condvar::new()));
    let pair2 = pair.clone();

    let (lock, cvar) = &*pair;
    let guard = lock.lock().unwrap();

    let handle = thread::spawn(move || {
        let (_lock, cvar) = &*pair2;
        cvar.notify_one();
    });

    // macOS runners are very unreliable.
    let timeout = if cfg!(target_os = "macos") { 2000 } else { 500 };
    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(timeout)).unwrap();
    assert!(!timeout.timed_out());
    handle.join().unwrap();
}

// Check if locks are working.

fn check_mutex() {
    let data = Arc::new(Mutex::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_lock().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_write() {
    let data = Arc::new(RwLock::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.write().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_write().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_read_no_deadlock() {
    let l1 = Arc::new(RwLock::new(0));
    let l2 = Arc::new(RwLock::new(0));

    let l1_copy = Arc::clone(&l1);
    let l2_copy = Arc::clone(&l2);
    let _guard1 = l1.read().unwrap();
    let handle = thread::spawn(move || {
        let _guard2 = l2_copy.read().unwrap();
        thread::yield_now();
        let _guard1 = l1_copy.read().unwrap();
    });
    thread::yield_now();
    let _guard2 = l2.read().unwrap();
    handle.join().unwrap();
}

// Check if Rust once statics are working.

static mut VAL: usize = 0;
static INIT: Once = Once::new();

fn get_cached_val() -> usize {
    unsafe {
        INIT.call_once(|| {
            VAL = expensive_computation();
        });
        VAL
    }
}

fn expensive_computation() -> usize {
    let mut i = 1;
    let mut c = 1;
    while i < 1000 {
        i *= c;
        c += 1;
    }
    i
}

/// The test taken from the Rust documentation.
fn check_once() {
    let handles: Vec<_> = (0..10)
        .map(|_| {
            thread::spawn(|| {
                thread::yield_now();
                let val = get_cached_val();
                assert_eq!(val, 5040);
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap();
    }
}

fn park_timeout() {
    let start = Instant::now();

    thread::park_timeout(Duration::from_millis(200));
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn park_unpark() {
    let t1 = thread::current();
    let t2 = thread::spawn(move || {
        thread::park();
        thread::sleep(Duration::from_millis(200));
        t1.unpark();
    });

    let start = Instant::now();

    t2.thread().unpark();
    thread::park();
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));

    t2.join().unwrap();
}

fn main() {
    check_barriers();
    check_conditional_variables_notify_one();
    check_conditional_variables_timed_wait_timeout();
    check_conditional_variables_timed_wait_notimeout();
    check_mutex();
    check_rwlock_write();
    check_rwlock_read_no_deadlock();
    check_once();
    park_timeout();
    park_unpark();
}
<|endoftext|>


<commit_before>use std::time::Duration;
use std::ops::AddAssign;
use ggez::{Context, GameResult, graphics, event};

mod well;
mod tetromino;
mod shapes;
mod bag;
mod util;

use ggez::event::*;
use self::well::Well;
use self::tetromino::Piece;
use self::bag::PieceBag;
use self::util::DurationExt;

const BLOCK_SIZE: f32 = 30.0;
const FALL_SPEED: f64 = 0.5;
const INPUT_DELAY_TIME: f64 = 0.05;

#[derive(Copy, Clone, Debug)]
pub struct Position {
    x: i32,
    y: i32,
}

impl Position {
    fn new(x: i32, y: i32) -> Self {
        Self {
            x: x,
            y: y,
        }
    }
}

impl AddAssign for Position {
    fn add_assign(&mut self, other: Position) {
        *self = Position {
            x: self.x + other.x,
            y: self.y + other.y,
        };
    }
}

#[derive(Debug, Copy, Clone)]
pub struct InputStateField {
    is_active: bool,
    delay_timer: f64,
}

impl Default for InputStateField {
    fn default() -> Self {
        InputStateField {
            is_active: false,
            delay_timer: INPUT_DELAY_TIME,
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct InputState {
    left: InputStateField,
    right: InputStateField,
    soft_drop: InputStateField,
    hard_drop: InputStateField,
    rotate_clockwise: InputStateField,
    rotate_counterclockwise: InputStateField,
    drop: InputStateField,
}

impl Default for InputState {
    fn default() -> Self {

        InputState {
            left: InputStateField::default(),
            right: InputStateField::default(),
            soft_drop: InputStateField::default(),
            hard_drop: InputStateField::default(),
            rotate_clockwise: InputStateField::default(),
            rotate_counterclockwise: InputStateField::default(),
            drop: InputStateField::default(),
        }
    }
}

pub struct PlayState {
    input: InputState,
    prev_input: InputState,

    well: Well,
    bag: PieceBag,
    current_piece: Piece,

    fall_timer: f64,
    score: u32,
    cleared_lines: u16,
    level: u32,
    game_over: bool,

    // temp
    image: graphics::Image,
}

impl PlayState {
    pub fn new(ctx: &mut Context) -> GameResult<PlayState> {
        let image = graphics::Image::new(ctx, "/block.png")?;
        let mut bag = PieceBag::new();
        let first_piece = bag.take_piece();

        let state = PlayState {
            input: InputState::default(),
            prev_input: InputState::default(),

            well: Well::new(),
            bag: bag,
            current_piece: first_piece,

            fall_timer: 0.0,
            score: 0,
            cleared_lines: 0,
            level: 0,
            game_over: false,

            image: image,
        };

        Ok(state)
    }

    fn handle_user_input(&mut self, dt: Duration) -> GameResult<()> {
        if self.input.left.is_active {
            self.input.left.delay_timer += dt.as_subsec_millis();
            if self.input.left.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(-1, 0));
                self.input.left.delay_timer = 0.0;
            }
        } else if self.input.right.is_active {
            self.input.right.delay_timer += dt.as_subsec_millis();
            if self.input.right.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(1, 0));
                self.input.right.delay_timer = 0.0;
            }
        } else if self.input.soft_drop.is_active {
            self.input.soft_drop.delay_timer += dt.as_subsec_millis();
            if self.input.soft_drop.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(0, 1));
                self.input.soft_drop.delay_timer = 0.0;
            }
        } else if self.input.rotate_clockwise.is_active {
            if self.input.rotate_clockwise.is_active != self.prev_input.rotate_clockwise.is_active {
                self.rotate_piece(1);
            }
        } else if self.input.rotate_counterclockwise.is_active {
            if self.input.rotate_counterclockwise.is_active != self.prev_input.rotate_counterclockwise.is_active {
                self.rotate_piece(-1);
            }
        } else if self.input.hard_drop.is_active {
            if self.input.hard_drop.is_active != self.prev_input.hard_drop.is_active {
                self.current_piece.top_left = self.current_piece.get_shadow_position();
                self.well.land(&self.current_piece);
                self.current_piece = self.bag.take_piece();
            }
        }

        Ok(())
    }

    fn move_piece(&mut self, potential_new_position: Position) {
        self.current_piece.potential_top_left += potential_new_position;
        let current_shape = self.current_piece.get_shape();
        let collision_found = self.well
            .check_for_collisions(&current_shape, &self.current_piece.potential_top_left);

        if collision_found {
            self.current_piece.potential_top_left = self.current_piece.top_left;
        }

        self.current_piece.top_left = self.current_piece.potential_top_left; // advance tetromino
    }

    fn rotate_piece(&mut self, direction: i32) {
        let next_shape = self.current_piece.get_next_shape(direction);
        let collision_found = self.well
            .check_for_collisions(&next_shape, &self.current_piece.top_left);

        if !collision_found {
            self.current_piece.change_shape(direction);
        } else {
            // wall kick attempt!
            // need to do 2 checks:
            // move one piece to the right & perform all above checks
            let mut potential_position = self.current_piece.top_left; // creates a copy of 'Position' struct
            potential_position.x += 1;
            let collision_found = self.well
                .check_for_collisions(&next_shape, &potential_position);

            if !collision_found {
                self.current_piece.top_left = potential_position;
                self.current_piece.potential_top_left = potential_position;
                self.current_piece.change_shape(direction);
            } else {
                let mut potential_position = self.current_piece.top_left;
                potential_position.x -= 1;
                let collision_found = self.well
                    .check_for_collisions(&next_shape, &potential_position);

                if !collision_found {
                    self.current_piece.top_left = potential_position;
                    self.current_piece.potential_top_left = potential_position;
                    self.current_piece.change_shape(direction);
                }
            }
        }

    }

    /// Advance the fall time. If enough time has passed, allow gravity to
    /// affect the current piece.
    /// Returns a `GameResult<false>` if a landing occured.
    /// Returns a `GameResult<true>` if no landing occured and the piece can advance.
    fn handle_gravity(&mut self, dt: Duration) -> GameResult<bool> {
        self.fall_timer += dt.as_subsec_millis();

        if self.fall_timer >= FALL_SPEED {
            let current_shape = self.current_piece.get_shape();
            self.fall_timer = 0.0;
            self.current_piece.potential_top_left.y += 1;

            let did_land = self.well
                .check_for_landing(&current_shape, &self.current_piece.potential_top_left);

            if did_land {
                if self.current_piece.top_left.y < 2 {
                    println!("game over!");
                    self.game_over = true;
                    return Ok(false);
                }

                // game isn't over - take another piece and move to next frame
                self.well.land(&self.current_piece);
                self.current_piece = self.bag.take_piece();
                return Ok(false);
            }

            // piece did not land - advance!
            self.current_piece.top_left = self.current_piece.potential_top_left;
        }

        Ok(true)
    }

    fn handle_shadow_piece(&mut self) -> GameResult<()> {
        let mut shadow_position = self.current_piece.top_left;
        let mut potential_shadow_position = shadow_position;
        loop {
            potential_shadow_position.y += 1;
            let collision_found = self.well
                .check_for_landing(&self.current_piece.get_shape(), &potential_shadow_position);

            if collision_found {
                break;
            }

            shadow_position = potential_shadow_position;
            self.current_piece.set_shadow_position(shadow_position);
        }

        Ok(())
    }

    fn handle_line_clears(&mut self) -> GameResult<()> {
        // check for line clears
        let mut lines_cleared = 0;
        for r in (0..self.well.data.len()).rev() {
            let mut is_row_filled = true;
            for (c, _) in self.well.data[r].iter().enumerate() {
                if self.well.data[r][c] == 0 {
                    is_row_filled = false;
                    break; // no need to continue iterating, line is not clear...
                }
            }

            if is_row_filled {
                // TODO: implement more line clearing algorithms
                // TODO: make the current line clearing algorithm user selectable
                self.well.naive_line_clear(r);
                lines_cleared += 1;
            }
        }

        // add to score
        let level = self.level;
        match lines_cleared {
            1 => self.increase_score(40, level),
            2 => self.increase_score(100, level),
            3 => self.increase_score(300, level),
            4 => self.increase_score(1200, level),
            _ => (),
        }

        self.cleared_lines += lines_cleared;

        Ok(())
    }

    fn increase_score(&mut self, base_score: u32, level: u32) {
        self.score += base_score * (level + 1);
    }
}

impl event::EventHandler for PlayState {
    fn update(&mut self, _: &mut Context, dt: Duration) -> GameResult<()> {
        println!("[state.update] Start of update method");
        println!("[state.update] current score: {}", self.score);

        if self.game_over {
            // do game over stuff
            return Ok(());
        }

        // TODO: handle/respond user input
        self.handle_user_input(dt)?;

        // handle shadow piece
        // TODO: put behind option
        self.handle_shadow_piece()?;

        // handle gravity - return from update if our current piece landed
        if let Ok(false) = self.handle_gravity(dt) {
            return Ok(());
        }

        self.handle_line_clears()?;

        self.prev_input = self.input;

        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::Color::new(0.0, 0.0, 0.0, 255.0));
        graphics::clear(ctx);

        self.well.draw(ctx, &self.image)?;
        self.current_piece
            .draw_shadow(ctx, &self.image, &self.current_piece.get_shadow_position())?;
        self.current_piece.draw(ctx, &self.image)?;

        graphics::present(ctx);

        Ok(())
    }

    fn key_down_event(&mut self, keycode: Keycode, _keymod: Mod, _repeat: bool) {
        match keycode {
            Keycode::Left => self.input.left.is_active = true,
            Keycode::Right => self.input.right.is_active = true,
            Keycode::Up => self.input.hard_drop.is_active = true,
            Keycode::Down => self.input.soft_drop.is_active = true,
            Keycode::Z => self.input.rotate_counterclockwise.is_active = true,
            Keycode::X => self.input.rotate_clockwise.is_active = true,
            _ => (),
        }

    }

    fn key_up_event(&mut self, keycode: Keycode, _keymod: Mod, _repeat: bool) {
        match keycode {
            Keycode::Left => {
                self.input.left.is_active = false;
                self.input.left.delay_timer = INPUT_DELAY_TIME;
            }
            Keycode::Right => {
                self.input.right.is_active = false;
                self.input.right.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Up => {
                self.input.hard_drop.is_active = false;
                self.input.hard_drop.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Down => {
                self.input.soft_drop.is_active = false;
                self.input.soft_drop.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Z => {
                self.input.rotate_counterclockwise.is_active = false;
                self.input.rotate_counterclockwise.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::X => {
                self.input.rotate_clockwise.is_active = false;
                self.input.rotate_clockwise.delay_timer = INPUT_DELAY_TIME;
            },
            _ => (),
        }
    }
}
<commit_msg>bye bye println-per-frames<commit_after>use std::time::Duration;
use std::ops::AddAssign;
use ggez::{Context, GameResult, graphics, event};

mod well;
mod tetromino;
mod shapes;
mod bag;
mod util;

use ggez::event::*;
use self::well::Well;
use self::tetromino::Piece;
use self::bag::PieceBag;
use self::util::DurationExt;

const BLOCK_SIZE: f32 = 30.0;
const FALL_SPEED: f64 = 0.5;
const INPUT_DELAY_TIME: f64 = 0.05;

#[derive(Copy, Clone, Debug)]
pub struct Position {
    x: i32,
    y: i32,
}

impl Position {
    fn new(x: i32, y: i32) -> Self {
        Self {
            x: x,
            y: y,
        }
    }
}

impl AddAssign for Position {
    fn add_assign(&mut self, other: Position) {
        *self = Position {
            x: self.x + other.x,
            y: self.y + other.y,
        };
    }
}

#[derive(Debug, Copy, Clone)]
pub struct InputStateField {
    is_active: bool,
    delay_timer: f64,
}

impl Default for InputStateField {
    fn default() -> Self {
        InputStateField {
            is_active: false,
            delay_timer: INPUT_DELAY_TIME,
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct InputState {
    left: InputStateField,
    right: InputStateField,
    soft_drop: InputStateField,
    hard_drop: InputStateField,
    rotate_clockwise: InputStateField,
    rotate_counterclockwise: InputStateField,
    drop: InputStateField,
}

impl Default for InputState {
    fn default() -> Self {

        InputState {
            left: InputStateField::default(),
            right: InputStateField::default(),
            soft_drop: InputStateField::default(),
            hard_drop: InputStateField::default(),
            rotate_clockwise: InputStateField::default(),
            rotate_counterclockwise: InputStateField::default(),
            drop: InputStateField::default(),
        }
    }
}

pub struct PlayState {
    input: InputState,
    prev_input: InputState,

    well: Well,
    bag: PieceBag,
    current_piece: Piece,

    fall_timer: f64,
    score: u32,
    cleared_lines: u16,
    level: u32,
    game_over: bool,

    // temp
    image: graphics::Image,
}

impl PlayState {
    pub fn new(ctx: &mut Context) -> GameResult<PlayState> {
        let image = graphics::Image::new(ctx, "/block.png")?;
        let mut bag = PieceBag::new();
        let first_piece = bag.take_piece();

        let state = PlayState {
            input: InputState::default(),
            prev_input: InputState::default(),

            well: Well::new(),
            bag: bag,
            current_piece: first_piece,

            fall_timer: 0.0,
            score: 0,
            cleared_lines: 0,
            level: 0,
            game_over: false,

            image: image,
        };

        Ok(state)
    }

    fn handle_user_input(&mut self, dt: Duration) -> GameResult<()> {
        if self.input.left.is_active {
            self.input.left.delay_timer += dt.as_subsec_millis();
            if self.input.left.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(-1, 0));
                self.input.left.delay_timer = 0.0;
            }
        } else if self.input.right.is_active {
            self.input.right.delay_timer += dt.as_subsec_millis();
            if self.input.right.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(1, 0));
                self.input.right.delay_timer = 0.0;
            }
        } else if self.input.soft_drop.is_active {
            self.input.soft_drop.delay_timer += dt.as_subsec_millis();
            if self.input.soft_drop.delay_timer >= INPUT_DELAY_TIME {
                self.move_piece(Position::new(0, 1));
                self.input.soft_drop.delay_timer = 0.0;
            }
        } else if self.input.rotate_clockwise.is_active {
            if self.input.rotate_clockwise.is_active != self.prev_input.rotate_clockwise.is_active {
                self.rotate_piece(1);
            }
        } else if self.input.rotate_counterclockwise.is_active {
            if self.input.rotate_counterclockwise.is_active != self.prev_input.rotate_counterclockwise.is_active {
                self.rotate_piece(-1);
            }
        } else if self.input.hard_drop.is_active {
            if self.input.hard_drop.is_active != self.prev_input.hard_drop.is_active {
                self.current_piece.top_left = self.current_piece.get_shadow_position();
                self.well.land(&self.current_piece);
                self.current_piece = self.bag.take_piece();
            }
        }

        Ok(())
    }

    fn move_piece(&mut self, potential_new_position: Position) {
        self.current_piece.potential_top_left += potential_new_position;
        let current_shape = self.current_piece.get_shape();
        let collision_found = self.well
            .check_for_collisions(&current_shape, &self.current_piece.potential_top_left);

        if collision_found {
            self.current_piece.potential_top_left = self.current_piece.top_left;
        }

        self.current_piece.top_left = self.current_piece.potential_top_left; // advance tetromino
    }

    fn rotate_piece(&mut self, direction: i32) {
        let next_shape = self.current_piece.get_next_shape(direction);
        let collision_found = self.well
            .check_for_collisions(&next_shape, &self.current_piece.top_left);

        if !collision_found {
            self.current_piece.change_shape(direction);
        } else {
            // wall kick attempt!
            // need to do 2 checks:
            // move one piece to the right & perform all above checks
            let mut potential_position = self.current_piece.top_left; // creates a copy of 'Position' struct
            potential_position.x += 1;
            let collision_found = self.well
                .check_for_collisions(&next_shape, &potential_position);

            if !collision_found {
                self.current_piece.top_left = potential_position;
                self.current_piece.potential_top_left = potential_position;
                self.current_piece.change_shape(direction);
            } else {
                let mut potential_position = self.current_piece.top_left;
                potential_position.x -= 1;
                let collision_found = self.well
                    .check_for_collisions(&next_shape, &potential_position);

                if !collision_found {
                    self.current_piece.top_left = potential_position;
                    self.current_piece.potential_top_left = potential_position;
                    self.current_piece.change_shape(direction);
                }
            }
        }

    }

    /// Advance the fall time. If enough time has passed, allow gravity to
    /// affect the current piece.
    /// Returns a `GameResult<false>` if a landing occured.
    /// Returns a `GameResult<true>` if no landing occured and the piece can advance.
    fn handle_gravity(&mut self, dt: Duration) -> GameResult<bool> {
        self.fall_timer += dt.as_subsec_millis();

        if self.fall_timer >= FALL_SPEED {
            let current_shape = self.current_piece.get_shape();
            self.fall_timer = 0.0;
            self.current_piece.potential_top_left.y += 1;

            let did_land = self.well
                .check_for_landing(&current_shape, &self.current_piece.potential_top_left);

            if did_land {
                if self.current_piece.top_left.y < 2 {
                    println!("game over!");
                    self.game_over = true;
                    return Ok(false);
                }

                // game isn't over - take another piece and move to next frame
                self.well.land(&self.current_piece);
                self.current_piece = self.bag.take_piece();
                return Ok(false);
            }

            // piece did not land - advance!
            self.current_piece.top_left = self.current_piece.potential_top_left;
        }

        Ok(true)
    }

    fn handle_shadow_piece(&mut self) -> GameResult<()> {
        let mut shadow_position = self.current_piece.top_left;
        let mut potential_shadow_position = shadow_position;
        loop {
            potential_shadow_position.y += 1;
            let collision_found = self.well
                .check_for_landing(&self.current_piece.get_shape(), &potential_shadow_position);

            if collision_found {
                break;
            }

            shadow_position = potential_shadow_position;
            self.current_piece.set_shadow_position(shadow_position);
        }

        Ok(())
    }

    fn handle_line_clears(&mut self) -> GameResult<()> {
        // check for line clears
        let mut lines_cleared = 0;
        for r in (0..self.well.data.len()).rev() {
            let mut is_row_filled = true;
            for (c, _) in self.well.data[r].iter().enumerate() {
                if self.well.data[r][c] == 0 {
                    is_row_filled = false;
                    break; // no need to continue iterating, line is not clear...
                }
            }

            if is_row_filled {
                // TODO: implement more line clearing algorithms
                // TODO: make the current line clearing algorithm user selectable
                self.well.naive_line_clear(r);
                lines_cleared += 1;
            }
        }

        // add to score
        let level = self.level;
        match lines_cleared {
            1 => self.increase_score(40, level),
            2 => self.increase_score(100, level),
            3 => self.increase_score(300, level),
            4 => self.increase_score(1200, level),
            _ => (),
        }

        self.cleared_lines += lines_cleared;

        Ok(())
    }

    fn increase_score(&mut self, base_score: u32, level: u32) {
        self.score += base_score * (level + 1);
    }
}

impl event::EventHandler for PlayState {
    fn update(&mut self, _: &mut Context, dt: Duration) -> GameResult<()> {
        if self.game_over {
            // do game over stuff
            return Ok(());
        }

        // TODO: handle/respond user input
        self.handle_user_input(dt)?;

        // handle shadow piece
        // TODO: put behind option
        self.handle_shadow_piece()?;

        // handle gravity - return from update if our current piece landed
        if let Ok(false) = self.handle_gravity(dt) {
            return Ok(());
        }

        self.handle_line_clears()?;

        self.prev_input = self.input;

        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::Color::new(0.0, 0.0, 0.0, 255.0));
        graphics::clear(ctx);

        self.well.draw(ctx, &self.image)?;
        self.current_piece
            .draw_shadow(ctx, &self.image, &self.current_piece.get_shadow_position())?;
        self.current_piece.draw(ctx, &self.image)?;

        graphics::present(ctx);

        Ok(())
    }

    fn key_down_event(&mut self, keycode: Keycode, _keymod: Mod, _repeat: bool) {
        match keycode {
            Keycode::Left => self.input.left.is_active = true,
            Keycode::Right => self.input.right.is_active = true,
            Keycode::Up => self.input.hard_drop.is_active = true,
            Keycode::Down => self.input.soft_drop.is_active = true,
            Keycode::Z => self.input.rotate_counterclockwise.is_active = true,
            Keycode::X => self.input.rotate_clockwise.is_active = true,
            _ => (),
        }

    }

    fn key_up_event(&mut self, keycode: Keycode, _keymod: Mod, _repeat: bool) {
        match keycode {
            Keycode::Left => {
                self.input.left.is_active = false;
                self.input.left.delay_timer = INPUT_DELAY_TIME;
            }
            Keycode::Right => {
                self.input.right.is_active = false;
                self.input.right.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Up => {
                self.input.hard_drop.is_active = false;
                self.input.hard_drop.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Down => {
                self.input.soft_drop.is_active = false;
                self.input.soft_drop.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::Z => {
                self.input.rotate_counterclockwise.is_active = false;
                self.input.rotate_counterclockwise.delay_timer = INPUT_DELAY_TIME;
            },
            Keycode::X => {
                self.input.rotate_clockwise.is_active = false;
                self.input.rotate_clockwise.delay_timer = INPUT_DELAY_TIME;
            },
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! A headless window implementation.

use crate::window_trait::WindowPortsMethods;
use glutin;
use euclid::{default::Size2D as UntypedSize2D, Point2D, Scale, Size2D};
use gleam::gl;
use servo::compositing::windowing::{AnimationState, WindowEvent};
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
use servo::servo_config::opts;
use servo::servo_geometry::DeviceIndependentPixel;
use servo::style_traits::DevicePixel;
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize};
use servo_media::player::context as MediaPlayerCtxt;
use std::cell::Cell;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::ffi::CString;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::mem;
use std::os::raw::c_void;
use std::ptr;
use std::rc::Rc;

#[cfg(any(target_os = "linux", target_os = "macos"))]
struct HeadlessContext {
    width: u32,
    height: u32,
    _context: osmesa_sys::OSMesaContext,
    _buffer: Vec<u32>,
}

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
struct HeadlessContext {
    width: u32,
    height: u32,
}

impl HeadlessContext {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    fn new(width: u32, height: u32, share: Option<&HeadlessContext>) -> HeadlessContext {
        let mut attribs = Vec::new();

        attribs.push(osmesa_sys::OSMESA_PROFILE);
        attribs.push(osmesa_sys::OSMESA_CORE_PROFILE);
        attribs.push(osmesa_sys::OSMESA_CONTEXT_MAJOR_VERSION);
        attribs.push(3);
        attribs.push(osmesa_sys::OSMESA_CONTEXT_MINOR_VERSION);
        attribs.push(3);
        attribs.push(0);

        let share = share.map_or(ptr::null_mut(), |share| share.context as *mut _);

        let context = unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), share) };

        assert!(!context.is_null());

        let mut buffer = vec![0; (width * height) as usize];

        unsafe {
            let ret = osmesa_sys::OSMesaMakeCurrent(
                context,
                buffer.as_mut_ptr() as *mut _,
                gl::UNSIGNED_BYTE,
                width as i32,
                height as i32,
            );
            assert_ne!(ret, 0);
        };

        HeadlessContext {
            width: width,
            height: height,
            _context: context,
            _buffer: buffer,
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
    fn new(width: u32, height: u32, _share: Option<&HeadlessContext>) -> HeadlessContext {
        HeadlessContext {
            width: width,
            height: height,
        }
    }

    #[cfg(any(target_os = "linux", target_os = "macos"))]
    fn get_proc_address(s: &str) -> *const c_void {
        let c_str = CString::new(s).expect("Unable to create CString");
        unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) }
    }

    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
    fn get_proc_address(_: &str) -> *const c_void {
        ptr::null() as *const _
    }
}

pub struct Window {
    context: HeadlessContext,
    animation_state: Cell<AnimationState>,
    fullscreen: Cell<bool>,
    gl: Rc<dyn gl::Gl>,
}

impl Window {
    pub fn new(size: Size2D<u32, DeviceIndependentPixel>) -> Rc<dyn WindowPortsMethods> {
        let context = HeadlessContext::new(size.width, size.height, None);
        let gl = unsafe { gl::GlFns::load_with(|s| HeadlessContext::get_proc_address(s)) };

        // Print some information about the headless renderer that
        // can be useful in diagnosing CI failures on build machines.
        println!("{}", gl.get_string(gl::VENDOR));
        println!("{}", gl.get_string(gl::RENDERER));
        println!("{}", gl.get_string(gl::VERSION));

        let window = Window {
            context,
            gl,
            animation_state: Cell::new(AnimationState::Idle),
            fullscreen: Cell::new(false),
        };

        Rc::new(window)
    }

    fn servo_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
        match opts::get().device_pixels_per_px {
            Some(device_pixels_per_px) => Scale::new(device_pixels_per_px),
            _ => Scale::new(1.0),
        }
    }
}

impl WindowPortsMethods for Window {
    fn get_events(&self) -> Vec<WindowEvent> {
        vec![]
    }

    fn has_events(&self) -> bool {
        false
    }

    fn id(&self) -> Option<glutin::WindowId> {
        None
    }

    fn page_height(&self) -> f32 {
        let dpr = self.servo_hidpi_factor();
        self.context.height as f32 * dpr.get()
    }

    fn set_fullscreen(&self, state: bool) {
        self.fullscreen.set(state);
    }

    fn get_fullscreen(&self) -> bool {
        return self.fullscreen.get();
    }

    fn is_animating(&self) -> bool {
        self.animation_state.get() == AnimationState::Animating
    }

    fn winit_event_to_servo_event(&self, _event: glutin::WindowEvent) {
        // Not expecting any winit events.
    }
}

impl WindowMethods for Window {
    fn gl(&self) -> Rc<dyn gl::Gl> {
        self.gl.clone()
    }

    fn get_coordinates(&self) -> EmbedderCoordinates {
        let dpr = self.servo_hidpi_factor();
        let size =
            (Size2D::new(self.context.width, self.context.height).to_f32() * dpr).to_i32();
        let viewport = DeviceIntRect::new(Point2D::zero(), size);
        let framebuffer = DeviceIntSize::from_untyped(size.to_untyped());
        EmbedderCoordinates {
            viewport,
            framebuffer,
            window: (size, Point2D::zero()),
            screen: size,
            screen_avail: size,
            hidpi_factor: dpr,
        }
    }

    fn present(&self) {}

    fn set_animation_state(&self, state: AnimationState) {
        self.animation_state.set(state);
    }

    fn prepare_for_composite(&self) { }

    fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
        MediaPlayerCtxt::GlContext::Unknown
    }

    fn get_native_display(&self) -> MediaPlayerCtxt::NativeDisplay {
        MediaPlayerCtxt::NativeDisplay::Unknown
    }

    fn get_gl_api(&self) -> MediaPlayerCtxt::GlApi {
        MediaPlayerCtxt::GlApi::None
    }
}

impl webxr::glwindow::GlWindow for Window {
    fn make_current(&mut self) {}
    fn swap_buffers(&mut self) {}
    fn size(&self) -> UntypedSize2D<gl::GLsizei> {
        let dpr = self.servo_hidpi_factor().get();
        Size2D::new((self.context.width as f32 * dpr) as gl::GLsizei, (self.context.height as f32 * dpr) as gl::GLsizei)
    }
    fn new_window(&self) -> Result<Box<dyn webxr::glwindow::GlWindow>, ()> {
        let width = self.context.width;
        let height = self.context.height;
        let share = Some(&self.context);
        let context = HeadlessContext::new(width, height, share);
        let gl = self.gl.clone();
        Ok(Box::new(Window {
            context,
            gl,
            animation_state: Cell::new(AnimationState::Idle),
            fullscreen: Cell::new(false),
        }))
    }
}
<commit_msg>Make headless window set current GL context before compositing.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! A headless window implementation.

use crate::window_trait::WindowPortsMethods;
use glutin;
use euclid::{default::Size2D as UntypedSize2D, Point2D, Scale, Size2D};
use gleam::gl;
use servo::compositing::windowing::{AnimationState, WindowEvent};
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
use servo::servo_config::opts;
use servo::servo_geometry::DeviceIndependentPixel;
use servo::style_traits::DevicePixel;
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize};
use servo_media::player::context as MediaPlayerCtxt;
use std::cell::Cell;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::cell::RefCell;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::ffi::CString;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::mem;
use std::os::raw::c_void;
use std::ptr;
use std::rc::Rc;

#[cfg(any(target_os = "linux", target_os = "macos"))]
struct HeadlessContext {
    width: u32,
    height: u32,
    context: osmesa_sys::OSMesaContext,
    buffer: RefCell<Vec<u32>>,
}

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
struct HeadlessContext {
    width: u32,
    height: u32,
}

impl HeadlessContext {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    fn new(width: u32, height: u32, share: Option<&HeadlessContext>) -> HeadlessContext {
        let mut attribs = Vec::new();

        attribs.push(osmesa_sys::OSMESA_PROFILE);
        attribs.push(osmesa_sys::OSMESA_CORE_PROFILE);
        attribs.push(osmesa_sys::OSMESA_CONTEXT_MAJOR_VERSION);
        attribs.push(3);
        attribs.push(osmesa_sys::OSMESA_CONTEXT_MINOR_VERSION);
        attribs.push(3);
        attribs.push(0);

        let share = share.map_or(ptr::null_mut(), |share| share.context as *mut _);

        let context = unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), share) };

        assert!(!context.is_null());

        HeadlessContext {
            width: width,
            height: height,
            context: context,
            buffer: RefCell::new(vec![0; (width * height) as usize]),
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
    fn new(width: u32, height: u32, _share: Option<&HeadlessContext>) -> HeadlessContext {
        HeadlessContext {
            width: width,
            height: height,
        }
    }

    #[cfg(any(target_os = "linux", target_os = "macos"))]
    fn get_proc_address(s: &str) -> *const c_void {
        let c_str = CString::new(s).expect("Unable to create CString");
        unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) }
    }

    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
    fn get_proc_address(_: &str) -> *const c_void {
        ptr::null() as *const _
    }
}

pub struct Window {
    context: HeadlessContext,
    animation_state: Cell<AnimationState>,
    fullscreen: Cell<bool>,
    gl: Rc<dyn gl::Gl>,
}

impl Window {
    pub fn new(size: Size2D<u32, DeviceIndependentPixel>) -> Rc<dyn WindowPortsMethods> {
        let context = HeadlessContext::new(size.width, size.height, None);
        let gl = unsafe { gl::GlFns::load_with(|s| HeadlessContext::get_proc_address(s)) };

        // Print some information about the headless renderer that
        // can be useful in diagnosing CI failures on build machines.
        println!("{}", gl.get_string(gl::VENDOR));
        println!("{}", gl.get_string(gl::RENDERER));
        println!("{}", gl.get_string(gl::VERSION));

        let window = Window {
            context,
            gl,
            animation_state: Cell::new(AnimationState::Idle),
            fullscreen: Cell::new(false),
        };

        Rc::new(window)
    }

    fn servo_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
        match opts::get().device_pixels_per_px {
            Some(device_pixels_per_px) => Scale::new(device_pixels_per_px),
            _ => Scale::new(1.0),
        }
    }
}

impl WindowPortsMethods for Window {
    fn get_events(&self) -> Vec<WindowEvent> {
        vec![]
    }

    fn has_events(&self) -> bool {
        false
    }

    fn id(&self) -> Option<glutin::WindowId> {
        None
    }

    fn page_height(&self) -> f32 {
        let dpr = self.servo_hidpi_factor();
        self.context.height as f32 * dpr.get()
    }

    fn set_fullscreen(&self, state: bool) {
        self.fullscreen.set(state);
    }

    fn get_fullscreen(&self) -> bool {
        return self.fullscreen.get();
    }

    fn is_animating(&self) -> bool {
        self.animation_state.get() == AnimationState::Animating
    }

    fn winit_event_to_servo_event(&self, _event: glutin::WindowEvent) {
        // Not expecting any winit events.
    }
}

impl WindowMethods for Window {
    fn gl(&self) -> Rc<dyn gl::Gl> {
        self.gl.clone()
    }

    fn get_coordinates(&self) -> EmbedderCoordinates {
        let dpr = self.servo_hidpi_factor();
        let size =
            (Size2D::new(self.context.width, self.context.height).to_f32() * dpr).to_i32();
        let viewport = DeviceIntRect::new(Point2D::zero(), size);
        let framebuffer = DeviceIntSize::from_untyped(size.to_untyped());
        EmbedderCoordinates {
            viewport,
            framebuffer,
            window: (size, Point2D::zero()),
            screen: size,
            screen_avail: size,
            hidpi_factor: dpr,
        }
    }

    fn present(&self) {}

    fn set_animation_state(&self, state: AnimationState) {
        self.animation_state.set(state);
    }

    #[cfg(any(target_os = "linux", target_os = "macos"))]
    fn prepare_for_composite(&self) {
        unsafe {
            let mut buffer = self.context.buffer.borrow_mut();
            let ret = osmesa_sys::OSMesaMakeCurrent(
                self.context.context,
                buffer.as_mut_ptr() as *mut _,
                gl::UNSIGNED_BYTE,
                self.context.width as i32,
                self.context.height as i32,
            );
            assert_ne!(ret, 0);
        };
    }

    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
    fn prepare_for_composite(&self) {}

    fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
        MediaPlayerCtxt::GlContext::Unknown
    }

    fn get_native_display(&self) -> MediaPlayerCtxt::NativeDisplay {
        MediaPlayerCtxt::NativeDisplay::Unknown
    }

    fn get_gl_api(&self) -> MediaPlayerCtxt::GlApi {
        MediaPlayerCtxt::GlApi::None
    }
}

impl webxr::glwindow::GlWindow for Window {
    fn make_current(&mut self) {}
    fn swap_buffers(&mut self) {}
    fn size(&self) -> UntypedSize2D<gl::GLsizei> {
        let dpr = self.servo_hidpi_factor().get();
        Size2D::new((self.context.width as f32 * dpr) as gl::GLsizei, (self.context.height as f32 * dpr) as gl::GLsizei)
    }
    fn new_window(&self) -> Result<Box<dyn webxr::glwindow::GlWindow>, ()> {
        let width = self.context.width;
        let height = self.context.height;
        let share = Some(&self.context);
        let context = HeadlessContext::new(width, height, share);
        let gl = self.gl.clone();
        Ok(Box::new(Window {
            context,
            gl,
            animation_state: Cell::new(AnimationState::Idle),
            fullscreen: Cell::new(false),
        }))
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up_while(&mut self, v: &i32) -> Result<&mut Self, String> {}
}

fn main() {
    let mut a = Tree::new(&3);
    a.insert(&2);
    a.insert(&1);

    println!("{:?}", a);
}
<commit_msg>a bit<commit_after>#[derive(Debug)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up_while(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        }

        let next

        loop {

        }
    }
}

fn main() {
    let mut a = Tree::new(&3);
    a.insert(&2);
    a.insert(&1);

    println!("{:?}", a);
}
<|endoftext|>


<commit_before>use std::iter;
use super::stacks_and_queues::bag::{Bag, Iter};

#[derive(Clone, Debug)]
pub struct Graph {
    v: usize,
    e: usize,
    adj: Vec<Bag<usize>>
}

impl Graph {
    pub fn new(v: usize) -> Graph {
        Graph {
            v: v,
            e: 0,
            adj: iter::repeat(Bag::<usize>::new()).take(v).collect()
        }
    }

    fn validate_vertex(&self, v: usize) {
        assert!(v < self.v, "vertex is not between 0 and {}", self.v - 1)
    }

    pub fn vertices(&self) -> usize {
        self.v
    }

    pub fn edges(&self) -> usize {
        self.e
    }

    pub fn add_edge(&mut self, v: usize, w: usize) {
        self.validate_vertex(v);
        self.validate_vertex(w);

        self.e += 1;
        self.adj[v].add(w);
        self.adj[w].add(v);
    }

    // FIXME: should this be a global function
    pub fn degree(&self, v: usize) -> usize {
        self.validate_vertex(v);
        self.adj[v].len()
    }

    pub fn max_degree(&self) -> usize {
        (0 .. self.vertices()).map(|v| self.degree(v)).max().unwrap_or(0)
    }

    pub fn average_degree(&self) -> f64 {
        (0 .. self.vertices()).map(|v| self.degree(v)).sum::<usize>() as f64 / self.vertices() as f64
    }

    pub fn to_dot(&self) -> String {
        let mut dot = String::new();

        dot.push_str("graph G {\n");
        for i in 0 .. self.v {
            dot.push_str(&format!("  {};\n", i));
        }

        for (v, adj) in self.adj.iter().enumerate() {
            for w in adj.iter() {
                dot.push_str(&format!("  {} -- {};\n", v, w));
            }
        }
        dot.push_str("}\n");
        dot
    }

    pub fn adj(&self, v: usize) -> Iter<usize> {
        self.adj[v].iter()
    }
}

#[test]
fn test_graph() {
    let mut g = Graph::new(10);
    g.add_edge(0, 3);
    g.add_edge(0, 5);
    g.add_edge(4, 5);
    g.add_edge(2, 9);
    g.add_edge(2, 8);
    g.add_edge(3, 7);

    g.add_edge(1, 6);
    g.add_edge(6, 9);
    g.add_edge(5, 8);

    // println!("got => \n{}", g.to_dot());

    assert_eq!(10, g.vertices());
    assert_eq!(9, g.edges());
    assert_eq!(3, g.degree(5));

    for w in g.adj(5) {
        assert!(vec![8, 4, 0].contains(w));
    }

    assert_eq!(g.max_degree(), 3);
    assert!(g.average_degree() < 2.0);
}
<commit_msg>undirected_graphs: add basic functions for Graph<commit_after>use std::iter;
use super::stacks_and_queues::bag::{Bag, Iter};

#[derive(Clone, Debug)]
pub struct Graph {
    v: usize,
    e: usize,
    adj: Vec<Bag<usize>>
}

impl Graph {
    pub fn new(v: usize) -> Graph {
        Graph {
            v: v,
            e: 0,
            adj: iter::repeat(Bag::<usize>::new()).take(v).collect()
        }
    }

    fn validate_vertex(&self, v: usize) {
        assert!(v < self.v, "vertex is not between 0 and {}", self.v - 1)
    }

    pub fn vertices(&self) -> usize {
        self.v
    }

    pub fn edges(&self) -> usize {
        self.e
    }

    pub fn add_edge(&mut self, v: usize, w: usize) {
        self.validate_vertex(v);
        self.validate_vertex(w);

        self.e += 1;
        self.adj[v].add(w);
        self.adj[w].add(v);
    }

    // FIXME: should this be a global function
    pub fn degree(&self, v: usize) -> usize {
        self.validate_vertex(v);
        self.adj[v].len()
    }

    pub fn max_degree(&self) -> usize {
        (0 .. self.vertices()).map(|v| self.degree(v)).max().unwrap_or(0)
    }

    pub fn average_degree(&self) -> f64 {
        // (0 .. self.vertices()) .map(|v| self.degree(v)).sum::<usize>() as f64 / self.vertices() as f64
        2.0 * self.edges() as f64 / self.vertices() as f64
    }

    pub fn number_of_self_loops(&self) -> usize {
        let mut count = 0;
        for v in 0 .. self.vertices() {
            for w in self.adj(v) {
                if v == *w {
                    count += 1;
                }
            }
        }
        count / 2
    }

    pub fn to_dot(&self) -> String {
        let mut dot = String::new();

        dot.push_str("graph G {\n");
        for i in 0 .. self.v {
            dot.push_str(&format!("  {};\n", i));
        }

        for (v, adj) in self.adj.iter().enumerate() {
            for w in adj.iter() {
                dot.push_str(&format!("  {} -- {};\n", v, w));
            }
        }
        dot.push_str("}\n");
        dot
    }

    pub fn adj(&self, v: usize) -> Iter<usize> {
        self.adj[v].iter()
    }

    pub fn dfs<'a>(&'a self, s: usize) -> DepthFirstPaths<'a> {
        DepthFirstPaths {
            graph: self,
            marked: Vec::new(),
            edge_to: Vec::new(),
            s: s
        }
    }
}

pub struct DepthFirstPaths<'a> {
    graph: &'a Graph,
    marked: Vec<bool>,
    edge_to: Vec<usize>,
    s: usize
}

#[test]
fn test_graph_visit() {
    let mut g = Graph::new(13);
    g.add_edge(0, 1);
    g.add_edge(0, 2);
    g.add_edge(0, 6);
    g.add_edge(0, 5);
    g.add_edge(5, 3);
    g.add_edge(5, 4);
    g.add_edge(3, 4);
    g.add_edge(4, 6);

    g.add_edge(7, 8);

    g.add_edge(9, 10);
    g.add_edge(9, 11);
    g.add_edge(9, 12);
    g.add_edge(11, 12);

}

#[test]
fn test_graph() {
    let mut g = Graph::new(10);
    g.add_edge(0, 3);
    g.add_edge(0, 5);
    g.add_edge(4, 5);
    g.add_edge(2, 9);
    g.add_edge(2, 8);
    g.add_edge(3, 7);

    g.add_edge(1, 6);
    g.add_edge(6, 9);
    g.add_edge(5, 8);

    // println!("got => \n{}", g.to_dot());

    assert_eq!(10, g.vertices());
    assert_eq!(9, g.edges());
    assert_eq!(3, g.degree(5));

    for w in g.adj(5) {
        assert!(vec![8, 4, 0].contains(w));
    }

    assert_eq!(g.max_degree(), 3);
    assert!(g.average_degree() < 2.0);
    assert_eq!(g.number_of_self_loops(), 0);
}
<|endoftext|>


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

use eew::EEW;

const MAX_BLOCK_COUNT: usize = 32;

pub struct EEWBuffer {
	buffer: VecDeque<Vec<EEW>> // each element of buffer must have at least 1 EEW object
}

impl EEWBuffer {

	pub fn new() -> EEWBuffer
	{
		EEWBuffer { buffer: VecDeque::new() }
	}

	fn lookup(&self, eew_id: &str) -> Option<usize>
	{
		for idx in 0..(self.buffer.len()) {
			if self.buffer[idx][0].id == eew_id {
				return Some(idx);
			}
		}

		return None;
	}

	fn extend_block(&mut self, idx: usize, eew: EEW) {

		let ref mut block = self.buffer[idx];

		let to_add = {
			let last_eew = block.last().expect("block must have at least 1 element");
			last_eew.number < eew.number
		};

		if to_add {
			block.push(eew);
		}
	}

	fn create_block(&mut self, eew: EEW) {

		let block = vec! { eew };
		self.buffer.push_back(block);

		while self.buffer.len() > MAX_BLOCK_COUNT {
			self.buffer.pop_front();
		}
	}

	pub fn append(&mut self, eew: EEW) -> &[EEW]
	{
		match self.lookup(&eew.id) {

			Some(idx) => {
				self.extend_block(idx, eew);
				&self.buffer[idx]
			},
			None => {
				self.create_block(eew);
				&self.buffer.back().expect("buffer must have at least 1 block")
			}
		}
	}
}
<commit_msg>Refactor eew_buffer.rs<commit_after>use std::collections::VecDeque;

use eew::EEW;

const DEFAULT_MAX_BLOCK_COUNT: usize = 32;

pub struct EEWBuffer {
	buffer: VecDeque<Vec<EEW>>, // each element of buffer must have at least 1 EEW object
	max_block_count: usize
}

impl EEWBuffer {

	pub fn new() -> EEWBuffer
	{
		EEWBuffer { buffer: VecDeque::new(), max_block_count: DEFAULT_MAX_BLOCK_COUNT }
	}

	fn lookup(&self, eew_id: &str) -> Option<usize>
	{
		return self.buffer.iter().position(|ref b|
			b.first().map(|ref e| e.id.as_str()) == Some(eew_id));
	}

	fn extend_block(&mut self, idx: usize, eew: EEW) {

		let ref mut block = self.buffer[idx];

		let is_latest = {
			let last_eew = block.last().expect("a block must have at least 1 element");
			last_eew.number < eew.number
		};

		if is_latest {
			block.push(eew);
		}
	}

	fn create_block(&mut self, eew: EEW) {

		let block = vec! { eew };
		self.buffer.push_back(block);

		while self.buffer.len() > self.max_block_count {
			self.buffer.pop_front();
		}
	}

	pub fn append(&mut self, eew: EEW) -> &[EEW]
	{
		match self.lookup(&eew.id) {

			Some(idx) => {
				self.extend_block(idx, eew);
				&self.buffer[idx]
			},
			None => {
				self.create_block(eew);
				&self.buffer.back().expect("a buffer must have at least 1 block")
			}
		}
	}
}
<|endoftext|>


<commit_before>use bytes::BytesMut;
use fallible_iterator::FallibleIterator;
use std::collections::HashMap;

use super::*;
use crate::IsNull;

#[test]
#[allow(clippy::bool_assert_comparison)]
fn bool() {
    let mut buf = BytesMut::new();
    bool_to_sql(true, &mut buf);
    assert_eq!(bool_from_sql(&buf).unwrap(), true);

    let mut buf = BytesMut::new();
    bool_to_sql(false, &mut buf);
    assert_eq!(bool_from_sql(&buf).unwrap(), false);
}

#[test]
fn int2() {
    let mut buf = BytesMut::new();
    int2_to_sql(0x0102, &mut buf);
    assert_eq!(int2_from_sql(&buf).unwrap(), 0x0102);
}

#[test]
fn int4() {
    let mut buf = BytesMut::new();
    int4_to_sql(0x0102_0304, &mut buf);
    assert_eq!(int4_from_sql(&buf).unwrap(), 0x0102_0304);
}

#[test]
fn int8() {
    let mut buf = BytesMut::new();
    int8_to_sql(0x0102_0304_0506_0708, &mut buf);
    assert_eq!(int8_from_sql(&buf).unwrap(), 0x0102_0304_0506_0708);
}

#[test]
#[allow(clippy::float_cmp)]
fn float4() {
    let mut buf = BytesMut::new();
    float4_to_sql(10343.95, &mut buf);
    assert_eq!(float4_from_sql(&buf).unwrap(), 10343.95);
}

#[test]
#[allow(clippy::float_cmp)]
fn float8() {
    let mut buf = BytesMut::new();
    float8_to_sql(10343.95, &mut buf);
    assert_eq!(float8_from_sql(&buf).unwrap(), 10343.95);
}

#[test]
fn hstore() {
    let mut map = HashMap::new();
    map.insert("hello", Some("world"));
    map.insert("hola", None);

    let mut buf = BytesMut::new();
    hstore_to_sql(map.iter().map(|(&k, &v)| (k, v)), &mut buf).unwrap();
    assert_eq!(
        hstore_from_sql(&buf)
            .unwrap()
            .collect::<HashMap<_, _>>()
            .unwrap(),
        map
    );
}

#[test]
fn varbit() {
    let len = 12;
    let bits = [0b0010_1011, 0b0000_1111];

    let mut buf = BytesMut::new();
    varbit_to_sql(len, bits.iter().cloned(), &mut buf).unwrap();
    let out = varbit_from_sql(&buf).unwrap();
    assert_eq!(out.len(), len);
    assert_eq!(out.bytes(), bits);
}

#[test]
fn array() {
    let dimensions = [
        ArrayDimension {
            len: 1,
            lower_bound: 10,
        },
        ArrayDimension {
            len: 2,
            lower_bound: 0,
        },
    ];
    let values = [None, Some(&b"hello"[..])];

    let mut buf = BytesMut::new();
    array_to_sql(
        dimensions.iter().cloned(),
        10,
        values.iter().cloned(),
        |v, buf| match v {
            Some(v) => {
                buf.extend_from_slice(v);
                Ok(IsNull::No)
            }
            None => Ok(IsNull::Yes),
        },
        &mut buf,
    )
    .unwrap();

    let array = array_from_sql(&buf).unwrap();
    assert!(array.has_nulls());
    assert_eq!(array.element_type(), 10);
    assert_eq!(array.dimensions().collect::<Vec<_>>().unwrap(), dimensions);
    assert_eq!(array.values().collect::<Vec<_>>().unwrap(), values);
}

#[test]
fn non_null_array() {
    let dimensions = [
        ArrayDimension {
            len: 1,
            lower_bound: 10,
        },
        ArrayDimension {
            len: 2,
            lower_bound: 0,
        },
    ];
    let values = [Some(&b"hola"[..]), Some(&b"hello"[..])];

    let mut buf = BytesMut::new();
    array_to_sql(
        dimensions.iter().cloned(),
        10,
        values.iter().cloned(),
        |v, buf| match v {
            Some(v) => {
                buf.extend_from_slice(v);
                Ok(IsNull::No)
            }
            None => Ok(IsNull::Yes),
        },
        &mut buf,
    )
    .unwrap();

    let array = array_from_sql(&buf).unwrap();
    assert!(array.has_nulls());
    assert_eq!(array.element_type(), 10);
    assert_eq!(array.dimensions().collect::<Vec<_>>().unwrap(), dimensions);
    assert_eq!(array.values().collect::<Vec<_>>().unwrap(), values);
}
<commit_msg>actually fix clippy<commit_after>use bytes::BytesMut;
use fallible_iterator::FallibleIterator;
use std::collections::HashMap;

use super::*;
use crate::IsNull;

#[test]
#[allow(clippy::bool_assert_comparison)]
fn bool() {
    let mut buf = BytesMut::new();
    bool_to_sql(true, &mut buf);
    assert_eq!(bool_from_sql(&buf).unwrap(), true);

    let mut buf = BytesMut::new();
    bool_to_sql(false, &mut buf);
    assert_eq!(bool_from_sql(&buf).unwrap(), false);
}

#[test]
fn int2() {
    let mut buf = BytesMut::new();
    int2_to_sql(0x0102, &mut buf);
    assert_eq!(int2_from_sql(&buf).unwrap(), 0x0102);
}

#[test]
fn int4() {
    let mut buf = BytesMut::new();
    int4_to_sql(0x0102_0304, &mut buf);
    assert_eq!(int4_from_sql(&buf).unwrap(), 0x0102_0304);
}

#[test]
fn int8() {
    let mut buf = BytesMut::new();
    int8_to_sql(0x0102_0304_0506_0708, &mut buf);
    assert_eq!(int8_from_sql(&buf).unwrap(), 0x0102_0304_0506_0708);
}

#[test]
#[allow(clippy::float_cmp)]
fn float4() {
    let mut buf = BytesMut::new();
    float4_to_sql(10343.95, &mut buf);
    assert_eq!(float4_from_sql(&buf).unwrap(), 10343.95);
}

#[test]
#[allow(clippy::float_cmp)]
fn float8() {
    let mut buf = BytesMut::new();
    float8_to_sql(10343.95, &mut buf);
    assert_eq!(float8_from_sql(&buf).unwrap(), 10343.95);
}

#[test]
fn hstore() {
    let mut map = HashMap::new();
    map.insert("hello", Some("world"));
    map.insert("hola", None);

    let mut buf = BytesMut::new();
    hstore_to_sql(map.iter().map(|(&k, &v)| (k, v)), &mut buf).unwrap();
    assert_eq!(
        hstore_from_sql(&buf)
            .unwrap()
            .collect::<HashMap<_, _>>()
            .unwrap(),
        map
    );
}

#[test]
fn varbit() {
    let len = 12;
    let bits = [0b0010_1011, 0b0000_1111];

    let mut buf = BytesMut::new();
    varbit_to_sql(len, bits.iter().cloned(), &mut buf).unwrap();
    let out = varbit_from_sql(&buf).unwrap();
    assert_eq!(out.len(), len);
    assert_eq!(out.bytes(), bits);
}

#[test]
fn array() {
    let dimensions = [
        ArrayDimension {
            len: 1,
            lower_bound: 10,
        },
        ArrayDimension {
            len: 2,
            lower_bound: 0,
        },
    ];
    let values = [None, Some(&b"hello"[..])];

    let mut buf = BytesMut::new();
    array_to_sql(
        dimensions.iter().cloned(),
        10,
        values.iter().cloned(),
        |v, buf| match v {
            Some(v) => {
                buf.extend_from_slice(v);
                Ok(IsNull::No)
            }
            None => Ok(IsNull::Yes),
        },
        &mut buf,
    )
    .unwrap();

    let array = array_from_sql(&buf).unwrap();
    assert!(array.has_nulls());
    assert_eq!(array.element_type(), 10);
    assert_eq!(array.dimensions().collect::<Vec<_>>().unwrap(), dimensions);
    assert_eq!(array.values().collect::<Vec<_>>().unwrap(), values);
}

#[test]
fn non_null_array() {
    let dimensions = [
        ArrayDimension {
            len: 1,
            lower_bound: 10,
        },
        ArrayDimension {
            len: 2,
            lower_bound: 0,
        },
    ];
    let values = [Some(&b"hola"[..]), Some(&b"hello"[..])];

    let mut buf = BytesMut::new();
    array_to_sql(
        dimensions.iter().cloned(),
        10,
        values.iter().cloned(),
        |v, buf| match v {
            Some(v) => {
                buf.extend_from_slice(v);
                Ok(IsNull::No)
            }
            None => Ok(IsNull::Yes),
        },
        &mut buf,
    )
    .unwrap();

    let array = array_from_sql(&buf).unwrap();
    assert!(!array.has_nulls());
    assert_eq!(array.element_type(), 10);
    assert_eq!(array.dimensions().collect::<Vec<_>>().unwrap(), dimensions);
    assert_eq!(array.values().collect::<Vec<_>>().unwrap(), values);
}
<|endoftext|>


<commit_before>// run-pass
#![allow(dead_code)]
#![allow(non_upper_case_globals)]

enum A { A1, A2 }
enum B { B1=0, B2=2 }

pub fn main () {
    static c1: isize = A::A2 as isize;
    static c2: isize = B::B2 as isize;
    let a1 = A::A2 as isize;
    let a2 = B::B2 as isize;
    assert_eq!(c1, 1);
    assert_eq!(c2, 2);
    assert_eq!(a1, 1);
    assert_eq!(a2, 2);
}
<commit_msg>test more variants of enum-int-casting<commit_after>// run-pass
#![allow(non_upper_case_globals)]

enum A { A1, A2 }
enum B { B1=4, B2=2 }

pub fn main () {
    static c1: isize = A::A2 as isize;
    static c2: isize = B::B2 as isize;
    let a1 = A::A2 as isize;
    let a2 = B::B2 as isize;
    assert_eq!(c1, 1);
    assert_eq!(c2, 2);
    assert_eq!(a1, 1);
    assert_eq!(a2, 2);

    // Turns out that adding a let-binding generates totally different MIR.
    static c1_2: isize = { let v = A::A1; v as isize };
    static c2_2: isize = { let v = B::B1; v as isize };
    let a1_2 = { let v = A::A1; v as isize };
    let a2_2 = { let v = B::B1; v as isize };
    assert_eq!(c1_2, 0);
    assert_eq!(c2_2, 4);
    assert_eq!(a1_2, 0);
    assert_eq!(a2_2, 4);
}
<|endoftext|>