use std::env;
use std::fs::File;
use std::io::{Write, BufWriter, Result};
use std::path::Path;
fn write_binop(out: &mut Write, o_trait: &str, o_fn: &str, mut_trait: &str, mut_fn: &str) ->
Result<()> {
writeln!(out, "
pub trait {0}{2}<Rhs = Self> {{
type Output;
fn {1}(self, rhs: Rhs, mutation_count: usize, coverage: &AtomicUsize, mask: usize) -> Self::Output;
}}
impl<T, Rhs> {0}{2}<Rhs> for T
where T: {0}<Rhs> {{
type Output = <T as {0}<Rhs>>::Output;
default fn {1}(self, rhs: Rhs, _mutation_count: usize, _cov: &AtomicUsize, _mask: usize) -> Self::Output {{
{0}::{1}(self, rhs)
}}
}}
impl<T, Rhs> {0}{2}<Rhs> for T
where T: {0}<Rhs>,
T: {2}<Rhs>,
<T as {2}<Rhs>>::Output: Into<<T as {0}<Rhs>>::Output> {{
fn {1}(self, rhs: Rhs, mutation_count: usize, coverage: &AtomicUsize, mask: usize) -> Self::Output {{
if now(mutation_count, coverage, mask) {{
{2}::{3}(self, rhs).into()
}} else {{
{0}::{1}(self, rhs)
}}
}}
}}
pub trait {0}{2}Assign<Rhs=Self> {{
fn {1}_assign(&mut self, rhs: Rhs, mutation_count: usize, coverage: &AtomicUsize, mask: usize);
}}
impl<T, R> {0}{2}Assign<R> for T where T: {0}Assign<R> {{
default fn {1}_assign(&mut self, rhs: R, _mutation_count: usize, _coverage: &AtomicUsize, _mask: usize) {{
{0}Assign::{1}_assign(self, rhs);
}}
}}
impl<T, R> {0}{2}Assign<R> for T
where T: {0}Assign<R>,
T: {2}Assign<R> {{
fn {1}_assign(&mut self, rhs: R, mutation_count: usize, coverage: &AtomicUsize, mask: usize) {{
if now(mutation_count, coverage, mask) {{
{2}Assign::{3}_assign(self, rhs);
}} else {{
{0}Assign::{1}_assign(self, rhs);
}}
}}
}}
", o_trait, o_fn, mut_trait, mut_fn)
}
static BINOP_PAIRS: &[[&str; 6]] = &[
["Add", "add", "Sub", "sub", "+", "-"],
["Mul", "mul", "Div", "div", "*", "/"],
["Shl", "shl", "Shr", "shr", "<<", ">>"],
["BitAnd", "bitand", "BitOr", "bitor", "&", "|"],
];
fn write_unop(out: &mut Write, op_trait: &str, op_fn: &str) -> Result<()> {
writeln!(out, "
pub trait May{0} {{
type Output;
fn {1}(self, mutation_count: usize, coverage: &AtomicUsize, mask: usize) -> Self::Output;
}}
impl<T> May{0} for T where T: {0} {{
type Output = <T as {0}>::Output;
default fn {1}(self, _mutation_count: usize, _cov: &AtomicUsize, _mask: usize) -> Self::Output {{
{0}::{1}(self)
}}
}}
impl<T> May{0} for T where T: {0}, T: Into<<T as {0}>::Output> {{
fn {1}(self, mutation_count: usize, coverage: &AtomicUsize, mask: usize) -> Self::Output {{
if now(mutation_count, coverage, mask) {{ self.into() }} else {{ {0}::{1}(self) }}
}}
}}
", op_trait, op_fn)
}
fn write_ops(out_dir: &str) -> Result<()> {
let dest = Path::new(out_dir).join("ops.rs");
let mut f = File::create(dest)?;
let mut out = BufWriter::new(&mut f);
writeln!(out, "use std::ops::*;
")?;
for names in BINOP_PAIRS.iter() {
write_binop(&mut out, names[0], names[1], names[2], names[3])?;
write_binop(&mut out, names[2], names[3], names[0], names[1])?;
}
for &(ref op_trait, ref op_fn) in [("Not", "not"), ("Neg", "neg")].iter() {
write_unop(&mut out, op_trait, op_fn)?;
}
writeln!(out, "
pub trait MayClone<T> {{
fn may_clone(&self) -> bool;
fn clone(&self, mutation_count: usize, coverage: &AtomicUsize, mask: usize) -> Self;
}}
impl<T> MayClone<T> for T {{
default fn may_clone(&self) -> bool {{ false }}
default fn clone(&self, _mc: usize, _cov: &AtomicUsize, _mask: usize) -> Self {{ unimplemented!() }}
}}
impl<T: Clone> MayClone<T> for T {{
fn may_clone(&self) -> bool {{
true
}}
fn clone(&self, mutation_count: usize, coverage: &AtomicUsize, mask: usize) -> Self {{
report_coverage(mutation_count..(mutation_count + 1), coverage, mask);
Clone::clone(&self)
}}
}}")?;
out.flush()
}
fn main() {
write_ops(&env::var("OUT_DIR").unwrap()).unwrap();
}