<commit_before>use crate::modules::*;
use criterion::Criterion;
use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate};
use lucet_wasi::WasiCtxBuilder;
use lucetc::OptLevel;
use std::path::Path;
use std::sync::Arc;
use tempfile::TempDir;

/// End-to-end instance instantiation.
///
/// This is meant to simulate our startup time when we start from scratch, with no module loaded and
/// no region created at all. This would be unusual for a server application, but reflects what
/// one-shot command-line tools like `lucet-wasi` do.
///
/// To minimize the effects of filesystem cache on the `DlModule::load()`, this runs `sync` between
/// each iteration.
fn hello_load_mkregion_and_instantiate<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body<R: RegionCreate + 'static>(so_file: &Path) -> InstanceHandle {
        let module = DlModule::load(so_file).unwrap();
        let region = R::create(1, &Limits::default()).unwrap();
        region.new_instance(module).unwrap()
    }

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, OptLevel::Best);

    c.bench_function(
        &format!("hello_load_mkregion_and_instantiate ({})", R::TYPE_NAME),
        move |b| {
            b.iter_batched(
                || unsafe { nix::libc::sync() },
                |_| body::<R>(&so_file),
                criterion::BatchSize::PerIteration,
            )
        },
    );

    workdir.close().unwrap();
}

/// Instance instantiation.
///
/// This simulates a typical case for a server process like Terrarium: the region and module stay
/// initialized, but a new instance is created for each request.
fn hello_instantiate<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body<R: Region>(module: Arc<dyn Module>, region: Arc<R>) -> InstanceHandle {
        region.new_instance(module).unwrap()
    }

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, OptLevel::Best);

    let module = DlModule::load(&so_file).unwrap();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("hello_instantiate ({})", R::TYPE_NAME), move |b| {
        b.iter(|| body(module.clone(), region.clone()))
    });

    workdir.close().unwrap();
}

/// Instance instantiation with a large, dense heap.
fn instantiate_with_dense_heap<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body<R: Region>(module: Arc<dyn Module>, region: Arc<R>) -> InstanceHandle {
        region.new_instance(module).unwrap()
    }

    let limits = Limits {
        heap_memory_size: 1024 * 1024 * 1024,
        ..Limits::default()
    };

    let region = R::create(1, &limits).unwrap();

    c.bench_function_over_inputs(
        &format!("instantiate_with_dense_heap ({})", R::TYPE_NAME),
        move |b, &&heap_kb| {
            let module = large_dense_heap_mock(heap_kb);
            b.iter(|| body(module.clone(), region.clone()))
        },
        // heap sizes in KiB
        &[512, 1024, 2 * 1024, 4 * 1024],
    );
}

/// Instance instantiation with a large, sparse heap.
fn instantiate_with_sparse_heap<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body<R: Region>(module: Arc<dyn Module>, region: Arc<R>) -> InstanceHandle {
        region.new_instance(module).unwrap()
    }

    let limits = Limits {
        heap_memory_size: 1024 * 1024 * 1024,
        ..Limits::default()
    };

    let region = R::create(1, &limits).unwrap();

    c.bench_function_over_inputs(
        &format!("instantiate_with_sparse_heap ({})", R::TYPE_NAME),
        move |b, &&heap_kb| {
            // 8 means that only every eighth page has non-zero data
            let module = large_sparse_heap_mock(heap_kb, 8);
            b.iter(|| body(module.clone(), region.clone()))
        },
        // heap sizes in KiB
        &[512, 1024, 2 * 1024, 4 * 1024],
    );
}

/// Instance destruction.
///
/// Instances have some cleanup to do with memory management and freeing their slot on their region.
fn hello_drop_instance<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(_inst: InstanceHandle) {}

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, OptLevel::Best);

    let module = DlModule::load(&so_file).unwrap();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(
        &format!("hello_drop_instance ({})", R::TYPE_NAME),
        move |b| {
            b.iter_batched(
                || region.new_instance(module.clone()).unwrap(),
                |inst| body(inst),
                criterion::BatchSize::PerIteration,
            )
        },
    );

    workdir.close().unwrap();
}

/// Instance destruction with a large, dense heap.
fn drop_instance_with_dense_heap<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(_inst: InstanceHandle) {}

    let limits = Limits {
        heap_memory_size: 1024 * 1024 * 1024,
        ..Limits::default()
    };

    let region = R::create(1, &limits).unwrap();

    c.bench_function_over_inputs(
        &format!("drop_instance_with_dense_heap ({})", R::TYPE_NAME),
        move |b, &&heap_kb| {
            let module = large_dense_heap_mock(heap_kb);
            b.iter_batched(
                || region.clone().new_instance(module.clone()).unwrap(),
                |inst| body(inst),
                criterion::BatchSize::PerIteration,
            )
        },
        // heap sizes in KiB
        &[512, 1024, 2 * 1024, 4 * 1024],
    );
}

/// Instance destruction with a large, sparse heap.
fn drop_instance_with_sparse_heap<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(_inst: InstanceHandle) {}

    let limits = Limits {
        heap_memory_size: 1024 * 1024 * 1024,
        ..Limits::default()
    };

    let region = R::create(1, &limits).unwrap();

    c.bench_function_over_inputs(
        &format!("drop_instance_with_sparse_heap ({})", R::TYPE_NAME),
        move |b, &&heap_kb| {
            // 8 means that only every eighth page has non-zero data
            let module = large_sparse_heap_mock(heap_kb, 8);
            b.iter_batched(
                || region.clone().new_instance(module.clone()).unwrap(),
                |inst| body(inst),
                criterion::BatchSize::PerIteration,
            )
        },
        // heap sizes in KiB
        &[512, 1024, 2 * 1024, 4 * 1024],
    );
}

/// Run a trivial guest function.
///
/// This is primarily a measurement of the signal handler installation and removal, and the context
/// switching overhead.
fn run_null<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"f", &[]).unwrap();
    }

    let module = null_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_null ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || region.new_instance(module.clone()).unwrap(),
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Run a computation-heavy guest function from a mock module.
///
/// Since this is running code in a mock module, the cost of the computation should overwhelm the
/// cost of the Lucet runtime.
fn run_fib<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"f", &[]).unwrap();
    }

    let module = fib_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_fib ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || region.new_instance(module.clone()).unwrap(),
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Run a trivial WASI program.
fn run_hello<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"_start", &[]).unwrap();
    }

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, OptLevel::Best);

    let module = DlModule::load(&so_file).unwrap();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_hello ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || {
                let null = std::fs::File::open("/dev/null").unwrap();
                let ctx = WasiCtxBuilder::new()
                    .args(&["hello"])
                    .fd(1, null)
                    .build()
                    .unwrap();
                region
                    .new_instance_builder(module.clone())
                    .with_embed_ctx(ctx)
                    .build()
                    .unwrap()
            },
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Run a trivial guest function that takes a bunch of arguments.
///
/// This is primarily interesting as a comparison to `run_null`; the difference is the overhead of
/// installing the arguments into the guest registers and stack.
///
/// `rustfmt` hates this function.
fn run_many_args<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(
            b"f",
            &[
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
            ],
        )
        .unwrap();
    }

    let module = many_args_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_many_args ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || region.new_instance(module.clone()).unwrap(),
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

fn run_hostcall_wrapped<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"wrapped", &[]).unwrap();
    }

    let module = hostcalls_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(
        &format!("run_hostcall_wrapped ({})", R::TYPE_NAME),
        move |b| {
            b.iter_batched_ref(
                || region.new_instance(module.clone()).unwrap(),
                |inst| body(inst),
                criterion::BatchSize::PerIteration,
            )
        },
    );
}

fn run_hostcall_raw<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"raw", &[]).unwrap();
    }

    let module = hostcalls_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_hostcall_raw ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || region.new_instance(module.clone()).unwrap(),
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

pub fn seq_benches<R: RegionCreate + 'static>(c: &mut Criterion) {
    hello_load_mkregion_and_instantiate::<R>(c);
    hello_instantiate::<R>(c);
    instantiate_with_dense_heap::<R>(c);
    instantiate_with_sparse_heap::<R>(c);
    hello_drop_instance::<R>(c);
    drop_instance_with_dense_heap::<R>(c);
    drop_instance_with_sparse_heap::<R>(c);
    run_null::<R>(c);
    run_fib::<R>(c);
    run_hello::<R>(c);
    run_many_args::<R>(c);
    run_hostcall_wrapped::<R>(c);
    run_hostcall_raw::<R>(c);
}
<commit_msg>[lucet-benchmarks] run with zero-sized heaps as well<commit_after>use crate::modules::*;
use criterion::Criterion;
use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate};
use lucet_wasi::WasiCtxBuilder;
use lucetc::OptLevel;
use std::path::Path;
use std::sync::Arc;
use tempfile::TempDir;

/// End-to-end instance instantiation.
///
/// This is meant to simulate our startup time when we start from scratch, with no module loaded and
/// no region created at all. This would be unusual for a server application, but reflects what
/// one-shot command-line tools like `lucet-wasi` do.
///
/// To minimize the effects of filesystem cache on the `DlModule::load()`, this runs `sync` between
/// each iteration.
fn hello_load_mkregion_and_instantiate<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body<R: RegionCreate + 'static>(so_file: &Path) -> InstanceHandle {
        let module = DlModule::load(so_file).unwrap();
        let region = R::create(1, &Limits::default()).unwrap();
        region.new_instance(module).unwrap()
    }

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, OptLevel::Best);

    c.bench_function(
        &format!("hello_load_mkregion_and_instantiate ({})", R::TYPE_NAME),
        move |b| {
            b.iter_batched(
                || unsafe { nix::libc::sync() },
                |_| body::<R>(&so_file),
                criterion::BatchSize::PerIteration,
            )
        },
    );

    workdir.close().unwrap();
}

/// Instance instantiation.
///
/// This simulates a typical case for a server process like Terrarium: the region and module stay
/// initialized, but a new instance is created for each request.
fn hello_instantiate<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body<R: Region>(module: Arc<dyn Module>, region: Arc<R>) -> InstanceHandle {
        region.new_instance(module).unwrap()
    }

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, OptLevel::Best);

    let module = DlModule::load(&so_file).unwrap();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("hello_instantiate ({})", R::TYPE_NAME), move |b| {
        b.iter(|| body(module.clone(), region.clone()))
    });

    workdir.close().unwrap();
}

/// Instance instantiation with a large, dense heap.
fn instantiate_with_dense_heap<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body<R: Region>(module: Arc<dyn Module>, region: Arc<R>) -> InstanceHandle {
        region.new_instance(module).unwrap()
    }

    let limits = Limits {
        heap_memory_size: 1024 * 1024 * 1024,
        ..Limits::default()
    };

    let region = R::create(1, &limits).unwrap();

    c.bench_function_over_inputs(
        &format!("instantiate_with_dense_heap ({})", R::TYPE_NAME),
        move |b, &&heap_kb| {
            let module = large_dense_heap_mock(heap_kb);
            b.iter(|| body(module.clone(), region.clone()))
        },
        // heap sizes in KiB
        &[0, 512, 1024, 2 * 1024, 4 * 1024],
    );
}

/// Instance instantiation with a large, sparse heap.
fn instantiate_with_sparse_heap<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body<R: Region>(module: Arc<dyn Module>, region: Arc<R>) -> InstanceHandle {
        region.new_instance(module).unwrap()
    }

    let limits = Limits {
        heap_memory_size: 1024 * 1024 * 1024,
        ..Limits::default()
    };

    let region = R::create(1, &limits).unwrap();

    c.bench_function_over_inputs(
        &format!("instantiate_with_sparse_heap ({})", R::TYPE_NAME),
        move |b, &&heap_kb| {
            // 8 means that only every eighth page has non-zero data
            let module = large_sparse_heap_mock(heap_kb, 8);
            b.iter(|| body(module.clone(), region.clone()))
        },
        // heap sizes in KiB
        &[0, 512, 1024, 2 * 1024, 4 * 1024],
    );
}

/// Instance destruction.
///
/// Instances have some cleanup to do with memory management and freeing their slot on their region.
fn hello_drop_instance<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(_inst: InstanceHandle) {}

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, OptLevel::Best);

    let module = DlModule::load(&so_file).unwrap();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(
        &format!("hello_drop_instance ({})", R::TYPE_NAME),
        move |b| {
            b.iter_batched(
                || region.new_instance(module.clone()).unwrap(),
                |inst| body(inst),
                criterion::BatchSize::PerIteration,
            )
        },
    );

    workdir.close().unwrap();
}

/// Instance destruction with a large, dense heap.
fn drop_instance_with_dense_heap<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(_inst: InstanceHandle) {}

    let limits = Limits {
        heap_memory_size: 1024 * 1024 * 1024,
        ..Limits::default()
    };

    let region = R::create(1, &limits).unwrap();

    c.bench_function_over_inputs(
        &format!("drop_instance_with_dense_heap ({})", R::TYPE_NAME),
        move |b, &&heap_kb| {
            let module = large_dense_heap_mock(heap_kb);
            b.iter_batched(
                || region.clone().new_instance(module.clone()).unwrap(),
                |inst| body(inst),
                criterion::BatchSize::PerIteration,
            )
        },
        // heap sizes in KiB
        &[0, 512, 1024, 2 * 1024, 4 * 1024],
    );
}

/// Instance destruction with a large, sparse heap.
fn drop_instance_with_sparse_heap<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(_inst: InstanceHandle) {}

    let limits = Limits {
        heap_memory_size: 1024 * 1024 * 1024,
        ..Limits::default()
    };

    let region = R::create(1, &limits).unwrap();

    c.bench_function_over_inputs(
        &format!("drop_instance_with_sparse_heap ({})", R::TYPE_NAME),
        move |b, &&heap_kb| {
            // 8 means that only every eighth page has non-zero data
            let module = large_sparse_heap_mock(heap_kb, 8);
            b.iter_batched(
                || region.clone().new_instance(module.clone()).unwrap(),
                |inst| body(inst),
                criterion::BatchSize::PerIteration,
            )
        },
        // heap sizes in KiB
        &[0, 512, 1024, 2 * 1024, 4 * 1024],
    );
}

/// Run a trivial guest function.
///
/// This is primarily a measurement of the signal handler installation and removal, and the context
/// switching overhead.
fn run_null<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"f", &[]).unwrap();
    }

    let module = null_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_null ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || region.new_instance(module.clone()).unwrap(),
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Run a computation-heavy guest function from a mock module.
///
/// Since this is running code in a mock module, the cost of the computation should overwhelm the
/// cost of the Lucet runtime.
fn run_fib<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"f", &[]).unwrap();
    }

    let module = fib_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_fib ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || region.new_instance(module.clone()).unwrap(),
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Run a trivial WASI program.
fn run_hello<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"_start", &[]).unwrap();
    }

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, OptLevel::Best);

    let module = DlModule::load(&so_file).unwrap();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_hello ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || {
                let null = std::fs::File::open("/dev/null").unwrap();
                let ctx = WasiCtxBuilder::new()
                    .args(&["hello"])
                    .fd(1, null)
                    .build()
                    .unwrap();
                region
                    .new_instance_builder(module.clone())
                    .with_embed_ctx(ctx)
                    .build()
                    .unwrap()
            },
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Run a trivial guest function that takes a bunch of arguments.
///
/// This is primarily interesting as a comparison to `run_null`; the difference is the overhead of
/// installing the arguments into the guest registers and stack.
///
/// `rustfmt` hates this function.
fn run_many_args<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(
            b"f",
            &[
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
                0xAFu8.into(),
                0xAFu16.into(),
                0xAFu32.into(),
                0xAFu64.into(),
                175.0f32.into(),
                175.0f64.into(),
            ],
        )
        .unwrap();
    }

    let module = many_args_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_many_args ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || region.new_instance(module.clone()).unwrap(),
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

fn run_hostcall_wrapped<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"wrapped", &[]).unwrap();
    }

    let module = hostcalls_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(
        &format!("run_hostcall_wrapped ({})", R::TYPE_NAME),
        move |b| {
            b.iter_batched_ref(
                || region.new_instance(module.clone()).unwrap(),
                |inst| body(inst),
                criterion::BatchSize::PerIteration,
            )
        },
    );
}

fn run_hostcall_raw<R: RegionCreate + 'static>(c: &mut Criterion) {
    fn body(inst: &mut InstanceHandle) {
        inst.run(b"raw", &[]).unwrap();
    }

    let module = hostcalls_mock();
    let region = R::create(1, &Limits::default()).unwrap();

    c.bench_function(&format!("run_hostcall_raw ({})", R::TYPE_NAME), move |b| {
        b.iter_batched_ref(
            || region.new_instance(module.clone()).unwrap(),
            |inst| body(inst),
            criterion::BatchSize::PerIteration,
        )
    });
}

pub fn seq_benches<R: RegionCreate + 'static>(c: &mut Criterion) {
    hello_load_mkregion_and_instantiate::<R>(c);
    hello_instantiate::<R>(c);
    instantiate_with_dense_heap::<R>(c);
    instantiate_with_sparse_heap::<R>(c);
    hello_drop_instance::<R>(c);
    drop_instance_with_dense_heap::<R>(c);
    drop_instance_with_sparse_heap::<R>(c);
    run_null::<R>(c);
    run_fib::<R>(c);
    run_hello::<R>(c);
    run_many_args::<R>(c);
    run_hostcall_wrapped::<R>(c);
    run_hostcall_raw::<R>(c);
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::dsl::AsExprOf;
use crate::expression::subselect::ValidSubselect;
use crate::expression::*;
use crate::insertable::Insertable;
use crate::query_builder::distinct_clause::DistinctClause;
use crate::query_builder::group_by_clause::GroupByClause;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::limit_clause::LimitClause;
use crate::query_builder::offset_clause::OffsetClause;
use crate::query_builder::order_clause::OrderClause;
use crate::query_builder::where_clause::*;
use crate::query_builder::*;
use crate::query_dsl::methods::*;
use crate::query_dsl::*;
use crate::query_source::joins::*;
use crate::query_source::{QuerySource, Table};
use crate::result::QueryResult;
use crate::sql_types::{BigInt, Bool, NotNull, Nullable};

#[allow(missing_debug_implementations)]
pub struct BoxedSelectStatement<'a, ST, QS, DB> {
    select: Box<dyn QueryFragment<DB> + Send + 'a>,
    from: QS,
    distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
    where_clause: BoxedWhereClause<'a, DB>,
    order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
    limit: Box<dyn QueryFragment<DB> + Send + 'a>,
    offset: Box<dyn QueryFragment<DB> + Send + 'a>,
    group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    _marker: PhantomData<ST>,
}

impl<'a, ST, QS, DB> BoxedSelectStatement<'a, ST, QS, DB> {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        select: Box<dyn QueryFragment<DB> + Send + 'a>,
        from: QS,
        distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
        where_clause: BoxedWhereClause<'a, DB>,
        order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
        limit: Box<dyn QueryFragment<DB> + Send + 'a>,
        offset: Box<dyn QueryFragment<DB> + Send + 'a>,
        group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    ) -> Self {
        BoxedSelectStatement {
            select: select,
            from: from,
            distinct: distinct,
            where_clause: where_clause,
            order: order,
            limit: limit,
            offset: offset,
            group_by: group_by,
            _marker: PhantomData,
        }
    }

    pub(crate) fn build_query(
        &self,
        mut out: AstPass<DB>,
        on_no_where_clause: impl Fn(&BoxedWhereClause<'a, DB>, AstPass<DB>) -> QueryResult<()>,
    ) -> QueryResult<()>
    where
        DB: Backend,
        QS: QuerySource,
        QS::FromClause: QueryFragment<DB>,
    {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        out.push_sql(" FROM ");
        self.from.from_clause().walk_ast(out.reborrow())?;
        match &self.where_clause {
            w @ BoxedWhereClause::None => on_no_where_clause(w, out.reborrow())?,
            w => w.walk_ast(out.reborrow())?,
        }
        self.group_by.walk_ast(out.reborrow())?;

        if let Some(ref order) = self.order {
            out.push_sql(" ORDER BY ");
            order.walk_ast(out.reborrow())?;
        }

        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, QS, DB> Query for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, DB> SelectQuery for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, QS2, DB> ValidSubselect<QS2> for BoxedSelectStatement<'a, ST, QS, DB> where
    Self: Query<SqlType = ST>
{
}

impl<'a, ST, QS, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    QS: QuerySource,
    QS::FromClause: QueryFragment<DB>,
{
    fn walk_ast(&self, out: AstPass<DB>) -> QueryResult<()> {
        self.build_query(out, |where_clause, out| where_clause.walk_ast(out))
    }
}

impl<'a, ST, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, (), DB>
where
    DB: Backend,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, QS, DB> QueryId for BoxedSelectStatement<'a, ST, QS, DB> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, ST, QS, DB, Rhs, Kind, On> InternalJoinDsl<Rhs, Kind, On>
    for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>: AsQuery,
{
    type Output = BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>;

    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
        BoxedSelectStatement::new(
            self.select,
            Join::new(self.from, rhs, kind).on(on),
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB> DistinctDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    DistinctClause: QueryFragment<DB>,
{
    type Output = Self;

    fn distinct(mut self) -> Self::Output {
        self.distinct = Box::new(DistinctClause);
        self
    }
}

impl<'a, ST, QS, DB, Selection> SelectDsl<Selection> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Selection: SelectableExpression<QS> + QueryFragment<DB> + Send + 'a,
{
    type Output = BoxedSelectStatement<'a, Selection::SqlType, QS, DB>;

    fn select(self, selection: Selection) -> Self::Output {
        BoxedSelectStatement::new(
            Box::new(selection),
            self.from,
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB, Predicate> FilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.and(predicate);
        self
    }
}

impl<'a, ST, QS, DB, Predicate> OrFilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn or_filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.or(predicate);
        self
    }
}

impl<'a, ST, QS, DB> LimitDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn limit(mut self, limit: i64) -> Self::Output {
        self.limit = Box::new(LimitClause(limit.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB> OffsetDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn offset(mut self, offset: i64) -> Self::Output {
        self.offset = Box::new(OffsetClause(offset.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB, Order> OrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn order(mut self, order: Order) -> Self::Output {
        self.order = OrderClause(order).into();
        self
    }
}

impl<'a, ST, QS, DB, Order> ThenOrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend + 'a,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn then_order_by(mut self, order: Order) -> Self::Output {
        self.order = match self.order {
            Some(old) => Some(Box::new((old, order))),
            None => Some(Box::new(order)),
        };
        self
    }
}

impl<'a, ST, QS, DB, Expr> GroupByDsl<Expr> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Expr: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
    Self: Query,
{
    type Output = Self;

    fn group_by(mut self, group_by: Expr) -> Self::Output {
        self.group_by = Box::new(GroupByClause(group_by));
        self
    }
}

// FIXME: Should we disable joining when `.group_by` has been called? Are there
// any other query methods where a join no longer has the same semantics as
// joining on just the table?
impl<'a, ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedSelectStatement<'a, ST, QS, DB>
where
    QS: JoinTo<Rhs>,
{
    type FromClause = QS::FromClause;
    type OnClause = QS::OnClause;

    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
        QS::join_target(rhs)
    }
}

impl<'a, ST, QS, DB> QueryDsl for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, Conn> RunQueryDsl<Conn> for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, T> Insertable<T> for BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, 'b, ST, QS, DB, T> Insertable<T> for &'b BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, ST, QS, DB> SelectNullableDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    ST: NotNull,
{
    type Output = BoxedSelectStatement<'a, Nullable<ST>, QS, DB>;

    fn nullable(self) -> Self::Output {
        BoxedSelectStatement {
            select: self.select,
            from: self.from,
            distinct: self.distinct,
            where_clause: self.where_clause,
            order: self.order,
            limit: self.limit,
            offset: self.offset,
            group_by: self.group_by,
            _marker: PhantomData,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::backend::Backend;
    use crate::prelude::*;

    table! {
        users {
            id -> Integer,
        }
    }

    fn assert_send<T>(_: T)
    where
        T: Send,
    {
    }

    fn assert_boxed_query_send<B: Backend>() {
        assert_send(users::table.into_boxed::<B>());
        assert_send(users::table.filter(users::id.eq(10)).into_boxed::<B>());
    }

    #[test]
    fn boxed_is_send() {
        #[cfg(feature = "postgres")]
        assert_boxed_query_send::<crate::pg::Pg>();

        #[cfg(feature = "sqlite")]
        assert_boxed_query_send::<crate::sqlite::Sqlite>();

        #[cfg(feature = "mysql")]
        assert_boxed_query_send::<crate::mysql::Mysql>();
    }
}
<commit_msg>Simplify `QueryFragment` implementation of `BoxedSelectStatement`<commit_after>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::dsl::AsExprOf;
use crate::expression::subselect::ValidSubselect;
use crate::expression::*;
use crate::insertable::Insertable;
use crate::query_builder::distinct_clause::DistinctClause;
use crate::query_builder::group_by_clause::GroupByClause;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::limit_clause::LimitClause;
use crate::query_builder::offset_clause::OffsetClause;
use crate::query_builder::order_clause::OrderClause;
use crate::query_builder::where_clause::*;
use crate::query_builder::*;
use crate::query_dsl::methods::*;
use crate::query_dsl::*;
use crate::query_source::joins::*;
use crate::query_source::{QuerySource, Table};
use crate::result::QueryResult;
use crate::sql_types::{BigInt, Bool, NotNull, Nullable};

#[allow(missing_debug_implementations)]
pub struct BoxedSelectStatement<'a, ST, QS, DB> {
    select: Box<dyn QueryFragment<DB> + Send + 'a>,
    from: QS,
    distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
    where_clause: BoxedWhereClause<'a, DB>,
    order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
    limit: Box<dyn QueryFragment<DB> + Send + 'a>,
    offset: Box<dyn QueryFragment<DB> + Send + 'a>,
    group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    _marker: PhantomData<ST>,
}

impl<'a, ST, QS, DB> BoxedSelectStatement<'a, ST, QS, DB> {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        select: Box<dyn QueryFragment<DB> + Send + 'a>,
        from: QS,
        distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
        where_clause: BoxedWhereClause<'a, DB>,
        order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
        limit: Box<dyn QueryFragment<DB> + Send + 'a>,
        offset: Box<dyn QueryFragment<DB> + Send + 'a>,
        group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    ) -> Self {
        BoxedSelectStatement {
            select: select,
            from: from,
            distinct: distinct,
            where_clause: where_clause,
            order: order,
            limit: limit,
            offset: offset,
            group_by: group_by,
            _marker: PhantomData,
        }
    }

    pub(crate) fn build_query(
        &self,
        mut out: AstPass<DB>,
        where_clause_handler: impl Fn(&BoxedWhereClause<'a, DB>, AstPass<DB>) -> QueryResult<()>,
    ) -> QueryResult<()>
    where
        DB: Backend,
        QS: QuerySource,
        QS::FromClause: QueryFragment<DB>,
    {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        out.push_sql(" FROM ");
        self.from.from_clause().walk_ast(out.reborrow())?;
        where_clause_handler(&self.where_clause, out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;

        if let Some(ref order) = self.order {
            out.push_sql(" ORDER BY ");
            order.walk_ast(out.reborrow())?;
        }

        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, QS, DB> Query for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, DB> SelectQuery for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, QS2, DB> ValidSubselect<QS2> for BoxedSelectStatement<'a, ST, QS, DB> where
    Self: Query<SqlType = ST>
{
}

impl<'a, ST, QS, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    QS: QuerySource,
    QS::FromClause: QueryFragment<DB>,
{
    fn walk_ast(&self, out: AstPass<DB>) -> QueryResult<()> {
        self.build_query(out, |where_clause, out| where_clause.walk_ast(out))
    }
}

impl<'a, ST, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, (), DB>
where
    DB: Backend,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, QS, DB> QueryId for BoxedSelectStatement<'a, ST, QS, DB> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, ST, QS, DB, Rhs, Kind, On> InternalJoinDsl<Rhs, Kind, On>
    for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>: AsQuery,
{
    type Output = BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>;

    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
        BoxedSelectStatement::new(
            self.select,
            Join::new(self.from, rhs, kind).on(on),
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB> DistinctDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    DistinctClause: QueryFragment<DB>,
{
    type Output = Self;

    fn distinct(mut self) -> Self::Output {
        self.distinct = Box::new(DistinctClause);
        self
    }
}

impl<'a, ST, QS, DB, Selection> SelectDsl<Selection> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Selection: SelectableExpression<QS> + QueryFragment<DB> + Send + 'a,
{
    type Output = BoxedSelectStatement<'a, Selection::SqlType, QS, DB>;

    fn select(self, selection: Selection) -> Self::Output {
        BoxedSelectStatement::new(
            Box::new(selection),
            self.from,
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB, Predicate> FilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.and(predicate);
        self
    }
}

impl<'a, ST, QS, DB, Predicate> OrFilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn or_filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.or(predicate);
        self
    }
}

impl<'a, ST, QS, DB> LimitDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn limit(mut self, limit: i64) -> Self::Output {
        self.limit = Box::new(LimitClause(limit.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB> OffsetDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn offset(mut self, offset: i64) -> Self::Output {
        self.offset = Box::new(OffsetClause(offset.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB, Order> OrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn order(mut self, order: Order) -> Self::Output {
        self.order = OrderClause(order).into();
        self
    }
}

impl<'a, ST, QS, DB, Order> ThenOrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend + 'a,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn then_order_by(mut self, order: Order) -> Self::Output {
        self.order = match self.order {
            Some(old) => Some(Box::new((old, order))),
            None => Some(Box::new(order)),
        };
        self
    }
}

impl<'a, ST, QS, DB, Expr> GroupByDsl<Expr> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Expr: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
    Self: Query,
{
    type Output = Self;

    fn group_by(mut self, group_by: Expr) -> Self::Output {
        self.group_by = Box::new(GroupByClause(group_by));
        self
    }
}

// FIXME: Should we disable joining when `.group_by` has been called? Are there
// any other query methods where a join no longer has the same semantics as
// joining on just the table?
impl<'a, ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedSelectStatement<'a, ST, QS, DB>
where
    QS: JoinTo<Rhs>,
{
    type FromClause = QS::FromClause;
    type OnClause = QS::OnClause;

    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
        QS::join_target(rhs)
    }
}

impl<'a, ST, QS, DB> QueryDsl for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, Conn> RunQueryDsl<Conn> for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, T> Insertable<T> for BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, 'b, ST, QS, DB, T> Insertable<T> for &'b BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, ST, QS, DB> SelectNullableDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    ST: NotNull,
{
    type Output = BoxedSelectStatement<'a, Nullable<ST>, QS, DB>;

    fn nullable(self) -> Self::Output {
        BoxedSelectStatement {
            select: self.select,
            from: self.from,
            distinct: self.distinct,
            where_clause: self.where_clause,
            order: self.order,
            limit: self.limit,
            offset: self.offset,
            group_by: self.group_by,
            _marker: PhantomData,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::backend::Backend;
    use crate::prelude::*;

    table! {
        users {
            id -> Integer,
        }
    }

    fn assert_send<T>(_: T)
    where
        T: Send,
    {
    }

    fn assert_boxed_query_send<B: Backend>() {
        assert_send(users::table.into_boxed::<B>());
        assert_send(users::table.filter(users::id.eq(10)).into_boxed::<B>());
    }

    #[test]
    fn boxed_is_send() {
        #[cfg(feature = "postgres")]
        assert_boxed_query_send::<crate::pg::Pg>();

        #[cfg(feature = "sqlite")]
        assert_boxed_query_send::<crate::sqlite::Sqlite>();

        #[cfg(feature = "mysql")]
        assert_boxed_query_send::<crate::mysql::Mysql>();
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::path::PathBuf;
use std::env;
use std::process::Command;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let target = env::var("TARGET").unwrap();

    // http://doc.crates.io/build-script.html#inputs-to-the-build-script
    // "the build script’s current directory is the source directory of the build script’s package."
    let current_dir = env::current_dir().unwrap();
    let src_dir = current_dir.join("src");

    let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to ovewrite.");

    let qmake = qt_dir.join("bin").join("qmake");

    // let rcc = Path::new(&qt_dir).join("bin").join("rcc");
    // println!("rcc: {:?}", rcc);

    // let qrc_output = Path::new(&out_dir).join("qrc_gallery.cpp");
    //
    // // Run the Qt Resource Compiler (rcc)
    // // ${QTDIR}/bin/rcc -name gallery examples/gallery.qrc -o target/debug/examples/qrc_gallery.cpp
    // let output = Command::new(rcc).args(&["-name", "gallery", "src/gallery.qrc",
    //                                       "-o", qrc_output.to_str().unwrap()])
    //                               .output()
    //                               .expect("failed to execute 'rcc' process");

    // Run qmake to create a library with the reousrce file
    let output = Command::new(qmake).args(&[src_dir])
                                  .current_dir(&Path::new(&out_dir))
                                  .output()
                                  .expect("failed to execute 'qmake' process");

    // println!("output.status: {}", output.status);
    // println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    // println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success(), "failed to execute qmake process");

    // Call 'make'
    let output = Command::new("make").current_dir(&Path::new(&out_dir))
                                  .output()
                                  .expect("failed to execute 'make' process");

    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success(), "failed to execute make process");

    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=galleryresources");

    // // Initialize git submodule
    // if !Path::new("libqmlbind/.git").exists() {
    //     let _ = Command::new("git").args(&["submodule", "update", "--init"])
    //                                .status();
    // }
    //
    // Command::new("qmake").current_dir("libqmlbind").output().unwrap();
    // Command::new("make").current_dir("libqmlbind").output().unwrap();
    // Command::new("make").arg("staticlib").current_dir("libqmlbind/qmlbind").output().unwrap();
    //
    //
    // println!("cargo:rustc-flags=-L libqmlbind/qmlbind");
    // println!("cargo:rustc-link-lib=static=qmlbind");
    // // println!("cargo:rustc-link-lib=qmlbind");
    //
    //
    // // https://github.com/bitcoin/bitcoin/issues/7714
    // // println!("cargo:rustc-link-lib=Qt");
    // // HACK - missing pkgconfig files in Qt5.6
    // // QT_CFLAGS="-I${QTDIR}/include -I${QTDIR}/include/QtWidgets -I${QTDIR}/include/QtCore \
    // //            -I${QTDIR}/include/QtGui -I${QTDIR}/include/QtNetwork"
    // // QT_LIBS="-F${QTDIR}/lib -framework QtCore -framework QtNetwork -framework QtGui -framework QtWidgets" ./configure --with-gui=qt5
    // // QT_LIBS="-F${QTDIR}/lib -framework QtCore -framework QtNetwork -framework QtGui -framework QtWidgets"
    // // let qtdir = String::from("/Users/nicolas/Qt/5.6/clang_64/lib");
    // let qtdir = String::from("/Users/nicolas/Qt/5.7/clang_64/lib");
    //
    // println!("cargo:rustc-link-search=framework={}", qtdir);
    // // println!("cargo:rustc-flags=-L framework={}", qtdir);
    //
    // println!("cargo:rustc-link-lib=framework=QtCore");
    // println!("cargo:rustc-link-lib=framework=QtNetwork");
    // println!("cargo:rustc-link-lib=framework=QtGui");
    // println!("cargo:rustc-link-lib=framework=QtQml");
    // println!("cargo:rustc-link-lib=framework=QtWidgets");
    //
    // println!("cargo:rustc-flags=-l stdc++");

}
<commit_msg>Example 'gallery': Cleanup build.rs<commit_after>use std::path::Path;
use std::path::PathBuf;
use std::env;
use std::process::Command;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let target = env::var("TARGET").unwrap();

    // http://doc.crates.io/build-script.html#inputs-to-the-build-script
    // "the build script’s current directory is the source directory of the build script’s package."
    let current_dir = env::current_dir().unwrap();
    let src_dir = current_dir.join("src");

    let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to ovewrite.");

    let qmake = qt_dir.join("bin").join("qmake");

    // Run qmake to create a library with the reousrce file
    let output = Command::new(qmake).args(&[src_dir])
                                  .current_dir(&Path::new(&out_dir))
                                  .output()
                                  .expect("failed to execute 'qmake' process");

    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success(), "failed to execute qmake process");

    // Call 'make'
    let output = Command::new("make").current_dir(&Path::new(&out_dir))
                                  .output()
                                  .expect("failed to execute 'make' process");

    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success(), "failed to execute make process");

    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=galleryresources");
}
<|endoftext|>


<commit_before>use player::Next;
use db::enums;

/// The standard arena is based on the default 1v1 fight.

impl<'a> super::Arena<'a> {
    pub fn fight(&mut self) {
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Setting the switched flag in the Player structs to false and reset if a swap will be done
        ///////////////////////////////////////////////////////////////////////////////////////////
        self.get_player_one().set_switched(false);
        self.get_player_two().set_switched(false);

        ///////////////////////////////////////////////////////////////////////////////////////////
        // Handle the pursuit(ID: 228) attack
        ///////////////////////////////////////////////////////////////////////////////////////////
        match self.get_player_one()
            .get_next_move()
            .expect("Unexpected error! This field of player one shouldn`t be None at this point.") {
            Next::Move(technique, _) => {
                if technique.get_id() == 228 {
                    match self.get_player_one()
                        .get_next_move()
                        .expect("Unexpected error! This field of player one shouldn`t be None \
                                 at this point.") {
                        Next::Switch(_) => {
                            // Resolving pursuit, updating last action and last move
                            // and setting the next move to None
                            technique.resolve(self, 2);
                            // let slot =
                            //     self.get_player_one().get_attack_slot(technique.clone())
                            //         .unwrap();
                            // self.get_player_one().set_last_move(Some((technique, slot)));
                            // let old_move = self.get_player_one().get_next_move().unwrap()
                            //         .clone();
                            // self.get_player_one().set_last_action(old_move);
                            // self.get_player_one().set_next_move(None);

                        }
                        _ => {}
                    }
                }
            }
            Next::Switch(_) => {
                match self.get_player_one()
                    .get_next_move()
                    .expect("Unexpected error! This field of player one shouldn`t be None at \
                             this point.") {
                    Next::Move(technique, _) => {
                        if technique.get_id() == 228 {
                            // Resolving pursuit, updating last action and last move
                            // and setting the next move to None
                            technique.resolve(self, 1);
                            // let slot =
                            //     self.get_player_two().get_attack_slot(technique.clone())
                            //         .unwrap();
                            // self.get_player_two().set_last_move(Some((technique, slot)));
                            // let old_move = self.get_player_two().get_next_move().unwrap()
                            //         .clone();
                            // self.get_player_two().set_last_action(old_move);
                            // self.get_player_two().set_next_move(None);
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Switch Pokemon of Player One if he wants to
        ///////////////////////////////////////////////////////////////////////////////////////////
        if let Some(x) = self.get_player_one()
            .get_next_move() {
            match x {
                Next::Switch(pkmn) => {
                    // Switch of the current pokemon + setting flag
                    self.get_player_one().set_current(pkmn.get_int());
                    self.get_player_one().set_switched(true);
                    // Updating last action and setting next move to None. Last Move isnt updated
                    // because the last action wasnt a move
                    let old_move = self.get_player_one().get_next_move().unwrap().clone();
                    self.get_player_one().set_last_action(old_move);
                    self.get_player_one().set_next_move(None);
                }
                _ => {}
            }
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Switch Pokemon of Player Two if he wants to
        ///////////////////////////////////////////////////////////////////////////////////////////
        if let Some(x) = self.get_player_two()
            .get_next_move() {
            match x {
                Next::Switch(pkmn) => {
                    // Switch of the current pokemon + setting flag
                    self.get_player_two().set_current(pkmn.get_int());
                    self.get_player_two().set_switched(true);
                    // Updating last action and setting next move to None. Last Move isnt updated
                    // because the last action wasnt a move
                    let old_move = self.get_player_two().get_next_move().unwrap().clone();
                    self.get_player_two().set_last_action(old_move);
                    self.get_player_two().set_next_move(None);
                }
                _ => {}
            }
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        // If player one doesnt need to make a move anymore, only resolve attack of player two
        ///////////////////////////////////////////////////////////////////////////////////////////
        if self.get_player_one().get_next_move().is_none() &&
           self.get_player_two().get_next_move().is_some() {
            match self.get_player_two().get_next_move().unwrap() {
                Next::Move(x, _) => x.resolve(self, 2),
                _ => {}
            }
            return;
            ///////////////////////////////////////////////////////////////////////////////////////
            // If player two doesnt need to make a move anymore, only resolve attack of player one
            ///////////////////////////////////////////////////////////////////////////////////////
        } else if self.get_player_two().get_next_move().is_none() &&
                  self.get_player_one().get_next_move().is_some() {
            match self.get_player_one().get_next_move().unwrap() {
                Next::Move(x, _) => x.resolve(self, 1),
                _ => {}
            }
            return;
            ///////////////////////////////////////////////////////////////////////////////////////
            // If both player dont have a move go out of fight
            ///////////////////////////////////////////////////////////////////////////////////////
        } else if self.get_player_two().get_next_move().is_none() &&
                  self.get_player_one().get_next_move().is_some() {
            return;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////
        // If both player want to perform an attack Priority and Speed of Pokemon will be used to
        // decide which pokemon strikes first
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Variables for faster comparison. x_prio is the priority of the pokemon of player x and
        // x_speed is the attackspeed of the pokemon of player x
        let one_prio;
        let one_attack;
        match self.get_player_one().get_next_move().unwrap() {
            Next::Move(attack, _) => {
                one_prio = attack.get_priority();
                one_attack = attack.clone();
            }
            _ => unreachable!(),
        };
        let two_prio;
        let two_attack;
        match self.get_player_two().get_next_move().unwrap() {
            Next::Move(attack, _) => {
                two_prio = attack.get_priority();
                two_attack = attack.clone();
            }
            _ => unreachable!(),
        };
        let mut current = self.get_player_one().get_current();
        let one_speed = self.get_player_one().get_pokemon_list()[current]
            .get_current()
            .get_stat(&enums::Stats::Speed);
        current = self.get_player_two().get_current();
        let two_speed = self.get_player_two().get_pokemon_list()[current]
            .get_current()
            .get_stat(&enums::Stats::Speed);
        ///////////////////////////////////////////////////////////////////////////////////////////
        // The attack with the higher Priority starts
        ///////////////////////////////////////////////////////////////////////////////////////////
        if one_prio > two_prio {
            one_attack.resolve(self, 1);
            two_attack.resolve(self, 2);
        } else if one_prio < two_prio {
            two_attack.resolve(self, 2);
            one_attack.resolve(self, 1);
        } else {
            ///////////////////////////////////////////////////////////////////////////////////////
            // If the attack priority is the same the pokemon with the higher attackspeed starts
            // If the attack speed is the same, the pokemon of player one will strike first
            ///////////////////////////////////////////////////////////////////////////////////////
            if one_speed >= two_speed {
                one_attack.resolve(self, 1);
                two_attack.resolve(self, 2);
            } else {
                two_attack.resolve(self, 2);
                one_attack.resolve(self, 1);
            }
        }
    }
}
<commit_msg>added doc for fight function<commit_after>use player::Next;
use db::enums;

/// The standard arena is based on the default 1v1 fight.

impl<'a> super::Arena<'a> {
    /// Simulating a fight. This function is called on a arena and uses the next_move variables of
    /// the players to know what to do in this round.
    /// Important: All next_move variables must contain a Some() entry. If the function is called
    /// and atleast one variable is holding a None, this function will panic!
    pub fn fight(&mut self) {
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Setting the switched flag in the Player structs to false and reset if a swap will be done
        ///////////////////////////////////////////////////////////////////////////////////////////
        self.get_player_one().set_switched(false);
        self.get_player_two().set_switched(false);

        ///////////////////////////////////////////////////////////////////////////////////////////
        // Handle the pursuit(ID: 228) attack
        ///////////////////////////////////////////////////////////////////////////////////////////
        match self.get_player_one()
            .get_next_move()
            .expect("Unexpected error! This field of player one shouldn`t be None at this point.") {
            Next::Move(technique, _) => {
                if technique.get_id() == 228 {
                    match self.get_player_one()
                        .get_next_move()
                        .expect("Unexpected error! This field of player one shouldn`t be None \
                                 at this point.") {
                        Next::Switch(_) => {
                            // Resolving pursuit, updating last action and last move
                            // and setting the next move to None
                            technique.resolve(self, 2);
                            // let slot =
                            //     self.get_player_one().get_attack_slot(technique.clone())
                            //         .unwrap();
                            // self.get_player_one().set_last_move(Some((technique, slot)));
                            // let old_move = self.get_player_one().get_next_move().unwrap()
                            //         .clone();
                            // self.get_player_one().set_last_action(old_move);
                            // self.get_player_one().set_next_move(None);

                        }
                        _ => {}
                    }
                }
            }
            Next::Switch(_) => {
                match self.get_player_one()
                    .get_next_move()
                    .expect("Unexpected error! This field of player one shouldn`t be None at \
                             this point.") {
                    Next::Move(technique, _) => {
                        if technique.get_id() == 228 {
                            // Resolving pursuit, updating last action and last move
                            // and setting the next move to None
                            technique.resolve(self, 1);
                            // let slot =
                            //     self.get_player_two().get_attack_slot(technique.clone())
                            //         .unwrap();
                            // self.get_player_two().set_last_move(Some((technique, slot)));
                            // let old_move = self.get_player_two().get_next_move().unwrap()
                            //         .clone();
                            // self.get_player_two().set_last_action(old_move);
                            // self.get_player_two().set_next_move(None);
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Switch Pokemon of Player One if he wants to
        ///////////////////////////////////////////////////////////////////////////////////////////
        if let Some(x) = self.get_player_one()
            .get_next_move() {
            match x {
                Next::Switch(pkmn) => {
                    // Switch of the current pokemon + setting flag
                    self.get_player_one().set_current(pkmn.get_int());
                    self.get_player_one().set_switched(true);
                    // Updating last action and setting next move to None. Last Move isnt updated
                    // because the last action wasnt a move
                    let old_move = self.get_player_one().get_next_move().unwrap().clone();
                    self.get_player_one().set_last_action(old_move);
                    self.get_player_one().set_next_move(None);
                }
                _ => {}
            }
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Switch Pokemon of Player Two if he wants to
        ///////////////////////////////////////////////////////////////////////////////////////////
        if let Some(x) = self.get_player_two()
            .get_next_move() {
            match x {
                Next::Switch(pkmn) => {
                    // Switch of the current pokemon + setting flag
                    self.get_player_two().set_current(pkmn.get_int());
                    self.get_player_two().set_switched(true);
                    // Updating last action and setting next move to None. Last Move isnt updated
                    // because the last action wasnt a move
                    let old_move = self.get_player_two().get_next_move().unwrap().clone();
                    self.get_player_two().set_last_action(old_move);
                    self.get_player_two().set_next_move(None);
                }
                _ => {}
            }
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        // If player one doesnt need to make a move anymore, only resolve attack of player two
        ///////////////////////////////////////////////////////////////////////////////////////////
        if self.get_player_one().get_next_move().is_none() &&
           self.get_player_two().get_next_move().is_some() {
            match self.get_player_two().get_next_move().unwrap() {
                Next::Move(x, _) => x.resolve(self, 2),
                _ => {}
            }
            return;
            ///////////////////////////////////////////////////////////////////////////////////////
            // If player two doesnt need to make a move anymore, only resolve attack of player one
            ///////////////////////////////////////////////////////////////////////////////////////
        } else if self.get_player_two().get_next_move().is_none() &&
                  self.get_player_one().get_next_move().is_some() {
            match self.get_player_one().get_next_move().unwrap() {
                Next::Move(x, _) => x.resolve(self, 1),
                _ => {}
            }
            return;
            ///////////////////////////////////////////////////////////////////////////////////////
            // If both player dont have a move go out of fight
            ///////////////////////////////////////////////////////////////////////////////////////
        } else if self.get_player_two().get_next_move().is_none() &&
                  self.get_player_one().get_next_move().is_some() {
            return;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////
        // If both player want to perform an attack Priority and Speed of Pokemon will be used to
        // decide which pokemon strikes first
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Variables for faster comparison. x_prio is the priority of the pokemon of player x and
        // x_speed is the attackspeed of the pokemon of player x
        let one_prio;
        let one_attack;
        match self.get_player_one().get_next_move().unwrap() {
            Next::Move(attack, _) => {
                one_prio = attack.get_priority();
                one_attack = attack.clone();
            }
            _ => unreachable!(),
        };
        let two_prio;
        let two_attack;
        match self.get_player_two().get_next_move().unwrap() {
            Next::Move(attack, _) => {
                two_prio = attack.get_priority();
                two_attack = attack.clone();
            }
            _ => unreachable!(),
        };
        let mut current = self.get_player_one().get_current();
        let one_speed = self.get_player_one().get_pokemon_list()[current]
            .get_current()
            .get_stat(&enums::Stats::Speed);
        current = self.get_player_two().get_current();
        let two_speed = self.get_player_two().get_pokemon_list()[current]
            .get_current()
            .get_stat(&enums::Stats::Speed);
        ///////////////////////////////////////////////////////////////////////////////////////////
        // The attack with the higher Priority starts
        ///////////////////////////////////////////////////////////////////////////////////////////
        if one_prio > two_prio {
            one_attack.resolve(self, 1);
            two_attack.resolve(self, 2);
        } else if one_prio < two_prio {
            two_attack.resolve(self, 2);
            one_attack.resolve(self, 1);
        } else {
            ///////////////////////////////////////////////////////////////////////////////////////
            // If the attack priority is the same the pokemon with the higher attackspeed starts
            // If the attack speed is the same, the pokemon of player one will strike first
            ///////////////////////////////////////////////////////////////////////////////////////
            if one_speed >= two_speed {
                one_attack.resolve(self, 1);
                two_attack.resolve(self, 2);
            } else {
                two_attack.resolve(self, 2);
                one_attack.resolve(self, 1);
            }
        }
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/make-array-zero-by-subtracting-equal-amounts/
pub fn minimum_operations(nums: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!("{}", minimum_operations(vec![1, 5, 0, 3, 5])); // 3
    println!("{}", minimum_operations(vec![0])); // 0
}
<commit_msg>Update problem 2357<commit_after>// https://leetcode.com/problems/make-array-zero-by-subtracting-equal-amounts/
pub fn minimum_operations(nums: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!("{}", minimum_operations(vec![1, 5, 0, 3, 5])); // 3
    println!("{}", minimum_operations(vec![0])); //
    println!("{}", minimum_operations(vec![1, 5, 0, 3, 5, 2])); // 4
}
<|endoftext|>


<commit_before>// Thanks to Matt Godbolt for creating the amazing Compiler Explorer https://www.godbolt.org
// This aims to provide similar assembly cleanup to what Godbolt does

use regex::{Captures, Regex};
use rustc_demangle::demangle;
use std::collections::HashSet;
use petgraph::prelude::*;

pub fn demangle_asm(block: &str) -> String {
    lazy_static! {
        static ref DEMANGLE_REGEX: Regex = Regex::new(r"_[a-zA-Z0-9._$]*").unwrap();
    }

    DEMANGLE_REGEX.replace_all(block, |caps: &Captures| {
        format!("{:#}", demangle(caps.get(0).map_or("", |m| m.as_str())))
    }).to_string()
}

enum LineType<'a> {
    Opcode,
    LabelDecl(&'a str),
    Data(&'a str),
    FunctionDecl,
    Directive,
    Blank,
    Misc,
}

// Removes unused labels and directives from assembly
pub fn filter_asm(block: &str) -> String {

    use self::LineType::*;

    lazy_static! {
        // Example:    mov rax, rdx
        // Always inlude in results
        static ref OPCODE_REGEX: Regex = Regex::new(r"^\s*[a-zA-Z]+.*[^:]$").unwrap();
    }
    lazy_static! {
        // Example:.Lfunc_end7:
        // Finds label declarations
        // Include in results only if it is referenced by an opcode, or is a function
        static ref LABEL_DECL_REGEX: Regex = Regex::new(r"([a-zA-Z_.<][a-zA-Z0-9$&_.,<>\[\]{}:' ]*):$").unwrap();
    }
    lazy_static! {
        // Example:    mov lea rdi, [rip + str.0] // str.0 is the referenced label
        // Find labels used as operands for an opcode
        static ref LABEL_REF_REGEX: Regex = Regex::new(r"([a-zA-Z_.][a-zA-Z0-9$_.]*)").unwrap();
    }
    lazy_static! {
        // Example:    .string "Hello, world!"
        // Note: this is a type of directive
        // Include in results if it is part of a used label, may contain label references
        static ref DATA_REGEX: Regex = Regex::new(r"^\s*\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)").unwrap();
    }
    lazy_static! {
        // Example:    .type main,@function
        // Note: this is a type of directive
        // Never include in results, but is used to find and include functions
        static ref FUNCTION_REGEX: Regex = Regex::new(r"^\s*\.type\s*(.*),@function$").unwrap();
    }
    lazy_static! {
        // Example:    .p2align 4, 0x90
        // Note: this will also match entries found by DATA_REGEX and FUNCTION_REGEX
        // Never include in results
        static ref DIRECTIVE_REGEX: Regex = Regex::new(r"^\s*\..*[^:]$").unwrap();
    }
    lazy_static! {
        // Never include in results
        static ref BLANK_REGEX: Regex = Regex::new(r"^\s*$").unwrap();
    }

    let mut current_label = "";
    let mut line_info = Vec::new();
    let mut labels = HashSet::new();
    let mut opcode_operands = HashSet::new();
    let mut label_graph = DiGraphMap::new();

    // Note the type of data held on each line of the block
    for line in block.lines() {
        if OPCODE_REGEX.is_match(line) {
            line_info.push(Opcode);
            // Skip the opcode, just add operands
            for label_ref_cap in LABEL_REF_REGEX.captures_iter(line).skip(1).filter_map(|cap| cap.get(1)) {
                opcode_operands.insert(label_ref_cap.as_str());
            }
        } else if let Some(label_decl_cap) = LABEL_DECL_REGEX.captures(line).and_then(|cap| cap.get(1)) {
            line_info.push(LabelDecl(label_decl_cap.as_str()));
            labels.insert(label_decl_cap.as_str());
            current_label = label_decl_cap.as_str();
        } else if DATA_REGEX.is_match(line) && current_label != "" {
            line_info.push(Data(current_label));
            // These will be checked for references to other labels later on
            // Skip the data type, just capture its reference
            for label_ref_cap in LABEL_REF_REGEX.captures_iter(line).skip(1).filter_map(|cap| cap.get(1)) {
                // Create a graph of how data labels reference each other
                label_graph.add_edge(current_label, label_ref_cap.as_str(), 1);
            }
        } else if let Some(function_cap) = FUNCTION_REGEX.captures(line).and_then(|cap| cap.get(1)) {
            line_info.push(FunctionDecl);
            opcode_operands.insert(function_cap.as_str());
        // DIRECTIVE_REGEX must be checked after FUNCTION_REGEX and DATA_REGEX, matches them too
        } else if DIRECTIVE_REGEX.is_match(line) {
            line_info.push(Directive);
        } else if BLANK_REGEX.is_match(line) {
            line_info.push(Blank);
        // If no matches are found then include line in output
        } else {
            line_info.push(Misc);
        }
    }

    let mut data_labels = Vec::new();
    let mut used_labels: HashSet<_> = labels.intersection(&opcode_operands).collect();

    // We only include labels ref'd by data dirs if directly or indirectly used by an opcode
    for label in &used_labels {
        if label_graph.contains_node(label) {
            let mut label_search = Dfs::new(&label_graph, label);
            while let Some(next_label) = label_search.next(&label_graph) {
                data_labels.push(next_label);
            }
        }
    }

    used_labels.extend(&data_labels);

    let mut filtered_asm = String::new();
    for (line, line_type) in block.lines().zip(&line_info) {
        match *line_type {
            Opcode | Misc => {
                filtered_asm.push_str(line);
                filtered_asm.push('\n');
            },
            Data(data) if used_labels.contains(&data) => {
                filtered_asm.push_str(line);
                filtered_asm.push('\n');
            },
            LabelDecl(label) if used_labels.contains(&label) => {
                filtered_asm.push('\n');
                filtered_asm.push_str(line);
                filtered_asm.push('\n');
            },
            _ => (),
        }
    }

    filtered_asm
}

#[cfg(test)]
mod test {
    #[test]
    fn demangles() {
        assert_eq!(
            super::demangle_asm("_ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE"),
            "core::fmt::Arguments::new_v1");
        }

    #[test]
    fn many_demangles() {
        assert_eq!(
            super::demangle_asm(".section.text._ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE,\"ax\",@progbits\n .p2align4, 0x90\n .type_ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE,@function"),
            ".section.text.core::fmt::Arguments::new_v1,\"ax\",@progbits\n .p2align4, 0x90\n .typecore::fmt::Arguments::new_v1,@function");
        }

    #[test]
    fn demangle_pass_through() {
        assert_eq!(
            super::demangle_asm("push rbp\n mov rbp, rsp"),
            "push rbp\n mov rbp, rsp");
    }

    #[test]
    fn one_directive_removed() {
        assert_eq!(
            super::filter_asm("  .filesystem1 \"<println macros>\"\n  movq%rsp, %rbp\n"),
            "  movq%rsp, %rbp\n");
    }

    #[test]
    fn many_directives_removed() {
        assert_eq!(
            super::filter_asm(" .cfi_def_cfa_register %rbp\n subq$80, %rsp\n .text\n"),
            " subq$80, %rsp\n");
    }

    #[test]
    fn used_label_kept() {
        assert_eq!(

            super::filter_asm(".Lcfi0:\ncallq    .Lcfi0\n"),
            "\n.Lcfi0:\ncallq    .Lcfi0\n");
    }

    #[test]
    fn unused_label_removed() {
        assert_eq!(
        super::filter_asm("addq    $16, %rsp\n    popq    %rbp\n    retq\n.Lfunc_end31:\nstr.0:\n"),
        "addq    $16, %rsp\n    popq    %rbp\n    retq\n");
    }

    #[test]
    fn used_data_kept() {
        assert_eq!(super::filter_asm("ref.2:\n  .quad 1\n  jmp ref.2\n"),
        "\nref.2:\n  .quad 1\n  jmp ref.2\n")
    }

    #[test]
    fn unused_data_removed() {
        assert_eq!(super::filter_asm("str.0:\n  .ascii \"Hello, world\"\n  pop rbp\n"),
        "  pop rbp\n");
    }

    #[test]
    fn blank_lines_removed() {
        assert_eq!(super::filter_asm("  mov rbp, rsp\n  main:\n  jmp core::fmt::Arguments\n  \n"),
        "  mov rbp, rsp\n  jmp core::fmt::Arguments\n")
    }

    #[test]
    fn functions_kept() {
        assert_eq!(super::filter_asm("  .type main,@function\n  main:\n  pushq %rax\n"),
        "\n  main:\n  pushq %rax\n");
    }
    #[test]
    fn used_data_ref_label_kept() {
        assert_eq!(super::filter_asm(".Lcfi0:\n  .quad .Lcfi1\n  mov .Lcfi0\n.Lcfi1:\n  addq $16, %rsp\n"),
        "\n.Lcfi0:\n  .quad .Lcfi1\n  mov .Lcfi0\n\n.Lcfi1:\n  addq $16, %rsp\n");
    }
    #[test]
    fn unused_data_ref_label_removed() {
        assert_eq!(super::filter_asm(".Lcfi0:\n  .quad 1\n  mov .Lcfi0\n.Lcfi1:\n  addq $16, %rsp\n"),
        "\n.Lcfi0:\n  .quad 1\n  mov .Lcfi0\n  addq $16, %rsp\n");
    }
    #[test]
    fn used_data_ref_label_graph_walk() {
        assert_eq!(super::filter_asm("main:\n  .quad ref.1\n  mov main\nref.1:\n  .quad ref.2\nref.2:\n  .quad 1"),
        "\nmain:\n  .quad ref.1\n  mov main\n\nref.1:\n  .quad ref.2\n\nref.2:\n  .quad 1\n");
    }
}
<commit_msg>Fix #406, handle LLVM comments in asm filtering<commit_after>// Thanks to Matt Godbolt for creating the amazing Compiler Explorer https://www.godbolt.org
// This aims to provide similar assembly cleanup to what Godbolt does

use regex::{Captures, Regex};
use rustc_demangle::demangle;
use std::collections::HashSet;
use petgraph::prelude::*;

pub fn demangle_asm(block: &str) -> String {
    lazy_static! {
        static ref DEMANGLE_REGEX: Regex = Regex::new(r"_[a-zA-Z0-9._$]*").unwrap();
    }

    DEMANGLE_REGEX.replace_all(block, |caps: &Captures| {
        format!("{:#}", demangle(caps.get(0).map_or("", |m| m.as_str())))
    }).to_string()
}

enum LineType<'a> {
    Opcode,
    LabelDecl(&'a str),
    Data(&'a str),
    FunctionDecl,
    Directive,
    Blank,
    Misc,
}

// Removes unused labels and directives from assembly
pub fn filter_asm(block: &str) -> String {

    use self::LineType::*;

    lazy_static! {
        // Example:    mov rax, rdx
        // Always inlude in results
        static ref OPCODE_REGEX: Regex = Regex::new(r"^\s+[a-zA-Z]+.*[^:]$").unwrap();
    }
    lazy_static! {
        // Example:.Lfunc_end7:
        // Finds label declarations
        // Include in results only if it is referenced by an opcode, or is a function
        static ref LABEL_DECL_REGEX: Regex = Regex::new(r"^([a-zA-Z_.<][a-zA-Z0-9$&_.,<>\[\]{}:' ]*):(\s+#.*)?$").unwrap();
    }
    lazy_static! {
        // Example:    mov lea rdi, [rip + str.0] // str.0 is the referenced label
        // Find labels used as operands for an opcode
        static ref LABEL_REF_REGEX: Regex = Regex::new(r"([a-zA-Z_.][a-zA-Z0-9$_.]*)").unwrap();
    }
    lazy_static! {
        // Example:    .string "Hello, world!"
        // Note: this is a type of directive
        // Include in results if it is part of a used label, may contain label references
        static ref DATA_REGEX: Regex = Regex::new(r"^\s+\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)").unwrap();
    }
    lazy_static! {
        // Example:    .type main,@function
        // Note: this is a type of directive
        // Never include in results, but is used to find and include functions
        static ref FUNCTION_REGEX: Regex = Regex::new(r"^\s+\.type\s*(.*),@function$").unwrap();
    }
    lazy_static! {
        // Example:    .p2align 4, 0x90
        // Note: this will also match entries found by DATA_REGEX and FUNCTION_REGEX
        // Never include in results
        static ref DIRECTIVE_REGEX: Regex = Regex::new(r"^\s+\..*[^:]$").unwrap();
    }
    lazy_static! {
        // Never include in results
        static ref BLANK_REGEX: Regex = Regex::new(r"^\s*$").unwrap();
    }

    let mut current_label = "";
    let mut line_info = Vec::new();
    let mut labels = HashSet::new();
    let mut opcode_operands = HashSet::new();
    let mut label_graph = DiGraphMap::new();

    // Note the type of data held on each line of the block
    for line in block.lines() {
        if OPCODE_REGEX.is_match(line) {
            line_info.push(Opcode);
            // Skip the opcode, just add operands
            for label_ref_cap in LABEL_REF_REGEX.captures_iter(line).skip(1).filter_map(|cap| cap.get(1)) {
                opcode_operands.insert(label_ref_cap.as_str());
            }
        } else if let Some(label_decl_cap) = LABEL_DECL_REGEX.captures(line).and_then(|cap| cap.get(1)) {
            line_info.push(LabelDecl(label_decl_cap.as_str()));
            labels.insert(label_decl_cap.as_str());
            current_label = label_decl_cap.as_str();
        } else if DATA_REGEX.is_match(line) && current_label != "" {
            line_info.push(Data(current_label));
            // These will be checked for references to other labels later on
            // Skip the data type, just capture its reference
            for label_ref_cap in LABEL_REF_REGEX.captures_iter(line).skip(1).filter_map(|cap| cap.get(1)) {
                // Create a graph of how data labels reference each other
                label_graph.add_edge(current_label, label_ref_cap.as_str(), 1);
            }
        } else if let Some(function_cap) = FUNCTION_REGEX.captures(line).and_then(|cap| cap.get(1)) {
            line_info.push(FunctionDecl);
            opcode_operands.insert(function_cap.as_str());
        // DIRECTIVE_REGEX must be checked after FUNCTION_REGEX and DATA_REGEX, matches them too
        } else if DIRECTIVE_REGEX.is_match(line) {
            line_info.push(Directive);
        } else if BLANK_REGEX.is_match(line) {
            line_info.push(Blank);
        // If no matches are found then include line in output
        } else {
            line_info.push(Misc);
        }
    }

    let mut data_labels = Vec::new();
    let mut used_labels: HashSet<_> = labels.intersection(&opcode_operands).collect();

    // We only include labels ref'd by data dirs if directly or indirectly used by an opcode
    for label in &used_labels {
        if label_graph.contains_node(label) {
            let mut label_search = Dfs::new(&label_graph, label);
            while let Some(next_label) = label_search.next(&label_graph) {
                data_labels.push(next_label);
            }
        }
    }

    used_labels.extend(&data_labels);

    let mut filtered_asm = String::new();
    for (line, line_type) in block.lines().zip(&line_info) {
        match *line_type {
            Opcode | Misc => {
                filtered_asm.push_str(line);
                filtered_asm.push('\n');
            },
            Data(data) if used_labels.contains(&data) => {
                filtered_asm.push_str(line);
                filtered_asm.push('\n');
            },
            LabelDecl(label) if used_labels.contains(&label) => {
                filtered_asm.push('\n');
                filtered_asm.push_str(line);
                filtered_asm.push('\n');
            },
            _ => (),
        }
    }

    filtered_asm
}

#[cfg(test)]
mod test {
    #[test]
    fn demangles() {
        assert_eq!(
            super::demangle_asm("_ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE"),
            "core::fmt::Arguments::new_v1");
        }

    #[test]
    fn many_demangles() {
        assert_eq!(
            super::demangle_asm(".section.text._ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE,\"ax\",@progbits\n .p2align4, 0x90\n .type_ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE,@function"),
            ".section.text.core::fmt::Arguments::new_v1,\"ax\",@progbits\n .p2align4, 0x90\n .typecore::fmt::Arguments::new_v1,@function");
        }

    #[test]
    fn demangle_pass_through() {
        assert_eq!(
            super::demangle_asm("push rbp\n mov rbp, rsp"),
            "push rbp\n mov rbp, rsp");
    }

    #[test]
    fn one_directive_removed() {
        assert_eq!(
            super::filter_asm("  .filesystem1 \"<println macros>\"\n  movq%rsp, %rbp\n"),
            "  movq%rsp, %rbp\n");
    }

    #[test]
    fn many_directives_removed() {
        assert_eq!(
            super::filter_asm(" .cfi_def_cfa_register %rbp\n subq$80, %rsp\n .text\n"),
            " subq$80, %rsp\n");
    }

    #[test]
    fn used_label_kept() {
        assert_eq!(
            super::filter_asm(".Lcfi0:\n  callq    .Lcfi0\n"),
            "\n.Lcfi0:\n  callq    .Lcfi0\n");
    }

    #[test]
    fn unused_label_removed() {
        assert_eq!(
        super::filter_asm("addq    $16, %rsp\n    popq    %rbp\n    retq\n.Lfunc_end31:\nstr.0:\n"),
        "addq    $16, %rsp\n    popq    %rbp\n    retq\n");
    }

    #[test]
    fn used_data_kept() {
        assert_eq!(super::filter_asm("ref.2:\n  .quad 1\n  jmp ref.2\n"),
        "\nref.2:\n  .quad 1\n  jmp ref.2\n")
    }

    #[test]
    fn unused_data_removed() {
        assert_eq!(super::filter_asm("str.0:\n  .ascii \"Hello, world\"\n  pop rbp\n"),
        "  pop rbp\n");
    }

    #[test]
    fn blank_lines_removed() {
        assert_eq!(super::filter_asm("  mov rbp, rsp\nmain:\n  jmp core::fmt::Arguments\n  \n"),
        "  mov rbp, rsp\n  jmp core::fmt::Arguments\n")
    }

    #[test]
    fn functions_kept() {
        assert_eq!(super::filter_asm("  .type main,@function\nmain:\n  pushq %rax\n"),
        "\nmain:\n  pushq %rax\n");
    }
    #[test]
    fn used_data_ref_label_kept() {
        assert_eq!(super::filter_asm(".Lcfi0:\n  .quad .Lcfi1\n  mov .Lcfi0\n.Lcfi1:\n  addq $16, %rsp\n"),
        "\n.Lcfi0:\n  .quad .Lcfi1\n  mov .Lcfi0\n\n.Lcfi1:\n  addq $16, %rsp\n");
    }
    #[test]
    fn unused_data_ref_label_removed() {
        assert_eq!(super::filter_asm(".Lcfi0:\n  .quad 1\n  mov .Lcfi0\n.Lcfi1:\n  addq $16, %rsp\n"),
        "\n.Lcfi0:\n  .quad 1\n  mov .Lcfi0\n  addq $16, %rsp\n");
    }
    #[test]
    fn used_data_ref_label_graph_walk() {
        assert_eq!(super::filter_asm("main:\n  .quad ref.1\n  mov main\nref.1:\n  .quad ref.2\nref.2:\n  .quad 1"),
        "\nmain:\n  .quad ref.1\n  mov main\n\nref.1:\n  .quad ref.2\n\nref.2:\n  .quad 1\n");
    }
    #[test]
    fn label_with_comment_recognized() {
        assert_eq!(super::filter_asm(".LBB6_10:  # =>Comment\n movq %r15, %rsi\n movq %rbx, %rdx\n ja .LBB6_10\n"),
        "\n.LBB6_10:  # =>Comment\n movq %r15, %rsi\n movq %rbx, %rdx\n ja .LBB6_10\n");
    }
    #[test]
    fn comment_retained() {
        assert_eq!(super::filter_asm("# %bb.0:\n subq $24, %rsp\n"),
        "# %bb.0:\n subq $24, %rsp\n")
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix controller parsing for some rooms.<commit_after><|endoftext|>