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} {{ type Output; fn {1}(self, rhs: Rhs, mutation_count: usize, coverage: &AtomicUsize, mask: usize) -> Self::Output; }} impl {0}{2} for T where T: {0} {{ type Output = >::Output; default fn {1}(self, rhs: Rhs, _mutation_count: usize, _cov: &AtomicUsize, _mask: usize) -> Self::Output {{ {0}::{1}(self, rhs) }} }} impl {0}{2} for T where T: {0}, T: {2}, >::Output: Into<>::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 {{ fn {1}_assign(&mut self, rhs: Rhs, mutation_count: usize, coverage: &AtomicUsize, mask: usize); }} impl {0}{2}Assign for T where T: {0}Assign {{ default fn {1}_assign(&mut self, rhs: R, _mutation_count: usize, _coverage: &AtomicUsize, _mask: usize) {{ {0}Assign::{1}_assign(self, rhs); }} }} impl {0}{2}Assign for T where T: {0}Assign, T: {2}Assign {{ 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", "&", "|"], // ["BitXor", "bitxor", "BitOr", "bitor", "^"], TODO: allow multi-mutations // ["BitAnd", "bitand", "BitXor", "bitxor"], ]; 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 May{0} for T where T: {0} {{ type Output = ::Output; default fn {1}(self, _mutation_count: usize, _cov: &AtomicUsize, _mask: usize) -> Self::Output {{ {0}::{1}(self) }} }} impl May{0} for T where T: {0}, T: Into<::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 {{ fn may_clone(&self) -> bool; fn clone(&self, mutation_count: usize, coverage: &AtomicUsize, mask: usize) -> Self; }} impl MayClone for T {{ default fn may_clone(&self) -> bool {{ false }} default fn clone(&self, _mc: usize, _cov: &AtomicUsize, _mask: usize) -> Self {{ unimplemented!() }} }} impl MayClone 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(); }