<commit_before>use std::collections::{HashMap, hash_map};
use tensor::Tensor;
use autograd::Variable;
use nn;

// placeholder
struct TorchBackend {}

pub trait ModuleStruct {
    fn init_module(self) -> Self;
}

pub struct Module<T: Copy> {
    pub _name: String,
    pub training: bool,
    _backend: TorchBackend,

    _buffers: HashMap<String, Tensor<T>>,
    //	_backward_hooks:
    //	_forward_hooks:
    _params: HashMap<String, *mut nn::Parameter<T>>,
    _modules: HashMap<String, *mut Module<T>>,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, String, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, String, *mut T>,
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a String, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &**t as &T }))
        } else {
            None
        }
    }
}

impl<T: Copy> Module<T> {
    pub fn new() -> Module<T> {
        Module {
            _name: String::from(""),
            _backend: TorchBackend {},
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<T> {
        self as *mut Module<T>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<T>) {
        let m = module.delegate();
        self._modules.insert(m._name.clone(), m.as_mut_ptr());

    }
    pub fn add_param(&mut self, name: &str, param: &mut nn::Parameter<T>) {
        let s = String::from(name);
        self._params.insert(s, param.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<T>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<T>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<nn::Parameter<T>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &str, tensor: &mut Tensor<T>) {
        self._buffers.insert(String::from(name), tensor.clone());
    }
    fn _apply(&mut self, callback: fn(&mut Tensor<T>)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for (_, param) in self.params_iter_mut() {
            param.apply(callback)
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name);
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModDelegate<T: Copy> {
    fn delegate(&mut self) -> &mut Module<T>;
}

pub trait ModIntf<T: Copy>: ModDelegate<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T>;
    fn f(&mut self, input: &mut Variable<T>) -> Variable<T> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forward(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn train(&mut self) {
        self.delegate().train(true)
    }
    fn eval(&mut self) {
        self.delegate().train(false)
    }
}

pub trait ModIntfV<T: Copy>: ModDelegate<T> {
    fn forwardv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn fv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forwardv(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
}
<commit_msg>implement parameters<commit_after>use std::collections::{HashMap, hash_map};
use tensor::Tensor;
use autograd::Variable;
use std::vec::IntoIter;
use nn;

// placeholder
struct TorchBackend {}

pub trait ModuleStruct {
    fn init_module(self) -> Self;
}

pub struct Module<T: Copy> {
    pub _name: String,
    pub training: bool,
    _backend: TorchBackend,

    _buffers: HashMap<String, Tensor<T>>,
    //	_backward_hooks:
    //	_forward_hooks:
    _params: HashMap<String, *mut nn::Parameter<T>>,
    _modules: HashMap<String, *mut Module<T>>,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, String, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, String, *mut T>,
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &**t as &T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a String, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

pub struct ModIter<'a, T: 'a + Copy> {
    pub modules: IntoIter<*mut Module<T>>,
    pub iter: PtrIterMut<'a, nn::Parameter<T>>,
}
fn mod_accum<TMod: Copy>(module: &mut Module<TMod>, arg: &mut Vec<*mut Module<TMod>>) {
    arg.push((module));
}
impl<'a, TMod: 'a + Copy> ModIter<'a, TMod> {
    pub fn new(root: &'a mut Module<TMod>) -> Self {
        let mut mods = Vec::new();
        root.apply_arg(&mut mods, mod_accum);
        // XXX assert is root
        mods.pop();
        ModIter {
            modules: mods.into_iter(),
            iter: root.params_iter_mut(),
        }
    }
}

impl<'a, T: Copy> Iterator for ModIter<'a, T> {
    type Item = &'a mut nn::Parameter<T>;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.iter.next() {
            Some(t)
        } else if let Some(modulep) = self.modules.next() {
            let mut module = unsafe { &mut *modulep as &mut Module<T> };
            self.iter = module.params_iter_mut();
            self.next()
        } else {
            None
        }
    }
}

impl<T: Copy> Module<T> {
    pub fn new() -> Module<T> {
        Module {
            _name: String::from(""),
            _backend: TorchBackend {},
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<T> {
        self as *mut Module<T>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<T>) {
        let m = module.delegate();
        self._modules.insert(m._name.clone(), m.as_mut_ptr());

    }
    pub fn add_param(&mut self, name: &str, param: &mut nn::Parameter<T>) {
        let s = String::from(name);
        self._params.insert(s, param.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<T>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<T>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<nn::Parameter<T>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &str, tensor: &mut Tensor<T>) {
        self._buffers.insert(String::from(name), tensor.clone());
    }
    pub fn parameters(&mut self) -> ModIter<T> {
        ModIter::new(self)
    }
    fn _apply(&mut self, callback: fn(&mut Tensor<T>)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for (_, param) in self.params_iter_mut() {
            param.apply(callback)
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    pub fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    fn apply_arg<Ta>(&mut self, arg: &mut Ta, callback: fn(&mut Self, &mut Ta)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply_arg(arg, callback)
        }
        callback(self, arg)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name);
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModDelegate<T: Copy> {
    fn delegate(&mut self) -> &mut Module<T>;
}

pub trait ModIntf<T: Copy>: ModDelegate<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T>;
    fn f(&mut self, input: &mut Variable<T>) -> Variable<T> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forward(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn train(&mut self) {
        self.delegate().train(true)
    }
    fn eval(&mut self) {
        self.delegate().train(false)
    }
}

pub trait ModIntfV<T: Copy>: ModDelegate<T> {
    fn forwardv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn fv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forwardv(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
}
<|endoftext|>


<commit_before><commit_msg>Enable grouping for benchmarking<commit_after><|endoftext|>


<commit_before>use frontend::input::AxisValue;
use core::clock::{SpeedFactor, SecondsValue};
use std::f32::consts;

pub const FRAME_SMOOTH_COUNT: usize = 120;
pub const DEAD_ZONE: AxisValue = 0.3f32;
pub const TURN_SPEED: f32 = consts::PI * 200.;
pub const DEBUG_DRAW_BRAKE_SCALE: f32 = 0.05;
pub const DEBUG_DRAW_MOVE_SCALE: f32 = 0.05;
pub const MIN_FRAME_LENGTH: SecondsValue = (1.0 / 1000.0) as SecondsValue;
pub const MAX_FRAME_LENGTH: SecondsValue = (1.0 / 15.0) as SecondsValue;
pub const THRUST_POWER: f32 = 1500.;
pub const POWER_BOOST: f32 = 100.;
pub const DRAG_COEFFICIENT: f32 = 0.00001;
pub const COMPASS_SPRING_POWER: f32 = 1000.0;
pub const JOINT_UPPER_ANGLE: f32 = consts::PI / 6.;
pub const JOINT_LOWER_ANGLE: f32 = -consts::PI / 6.;
pub const JOINT_FREQUENCY: f32 = 5.0;
pub const JOINT_DAMPING_RATIO: f32 = 0.9;
pub const LINEAR_DAMPING: f32 = 0.8;
pub const ANGULAR_DAMPING: f32 = 0.9;
pub const PICK_EPS: f32 = 0.001f32;
pub const DEFAULT_RESOURCE_CHARGE: f32 = 0.8;
pub const DEFAULT_SPORE_CHARGE: f32 = 0.8;
pub const DEFAULT_MINION_CHARGE: f32 = 0.3;
pub const INITIAL_SPAWN_RADIUS_RATIO: f32 = 0.25;
pub const INITIAL_SPAWN_RADIUS_SLICES: f32 = 16.;
pub const WORLD_RADIUS: f32 = 80.;
pub const EMITTER_DISTANCE: f32 = 20.;
pub const EMITTER_PERIOD: SecondsValue = 0.4;
pub const EMITTER_SPREAD_ANGLE: f32 = consts::PI / 12.;
pub const BULLET_SPEED_SCALE: f32 = 100.;
pub const BULLET_FIRE_RATE_SCALE: SecondsValue = 0.5;
pub const BULLET_FULL_CHARGE: SecondsValue = 1.0;
pub const BULLET_FIRE_RATE: SecondsValue = 45.0;
pub const DEFAULT_MINION_GENE_POOL: &'static [&'static str] = &[
	"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
	"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
	"GzB2lQVwM00tTAm5gwajjf4wc0a5GzB2lQVwM00tTAm5gwajjf4wc0a5",
	"GzB2lQdwM10vQEu5zwaPgDhfq2v8GzB2lQdwM10vQEu5zwaPgDhfq2v8",
];

pub const DEFAULT_RESOURCE_GENE_POOL: &'static [&'static str] = &[
	"GyA21QoQ",
	"M00sWS0M"
];

pub const DUMP_FILE_PATTERN: &'static str = "resources/%Y%m%d_%H%M%S.csv";

pub const AMBIENT_LIGHTS: &'static [[f32; 4]] = &[
	[1.0, 1.0, 1.0, 1.0],
	[3.1, 3.1, 3.1, 1.0],
	[10.0, 10.0, 10.0, 1.0],
	[31.0, 31.0, 31.0, 1.0],
	[100.0, 100.0, 100.0, 1.0],
	[0.001, 0.001, 0.001, 1.0],
	[0.01, 0.01, 0.01, 1.0],
	[0.1, 0.1, 0.1, 1.0],
	[0.31, 0.31, 0.31, 0.5],
];

pub const SPEED_FACTORS: &'static [SpeedFactor] = &[
	1.0,
	0.5,
	0.2,
	0.1,
	1.0,
	2.0,
	5.0,
	10.0,
];

pub const BACKGROUNDS: &'static [[f32; 4]] = &[
	[0.05, 0.07, 0.1, 1.0],
	[0.5, 0.5, 0.5, 0.5],
	[1.0, 1.0, 1.0, 1.0],
	[3.1, 3.1, 3.1, 1.0],
	[10.0, 10.0, 10.0, 1.0],
	[0., 0., 0., 1.0],
	[0.01, 0.01, 0.01, 1.0],
];<commit_msg>Reduced drag<commit_after>use frontend::input::AxisValue;
use core::clock::{SpeedFactor, SecondsValue};
use std::f32::consts;

pub const FRAME_SMOOTH_COUNT: usize = 120;
pub const DEAD_ZONE: AxisValue = 0.3f32;
pub const TURN_SPEED: f32 = consts::PI * 200.;
pub const DEBUG_DRAW_BRAKE_SCALE: f32 = 0.05;
pub const DEBUG_DRAW_MOVE_SCALE: f32 = 0.05;
pub const MIN_FRAME_LENGTH: SecondsValue = (1.0 / 1000.0) as SecondsValue;
pub const MAX_FRAME_LENGTH: SecondsValue = (1.0 / 15.0) as SecondsValue;
pub const THRUST_POWER: f32 = 10000.;
pub const POWER_BOOST: f32 = 100.;
pub const DRAG_COEFFICIENT: f32 = 0.000001;
pub const COMPASS_SPRING_POWER: f32 = 1000.0;
pub const JOINT_UPPER_ANGLE: f32 = consts::PI / 6.;
pub const JOINT_LOWER_ANGLE: f32 = -consts::PI / 6.;
pub const JOINT_FREQUENCY: f32 = 5.0;
pub const JOINT_DAMPING_RATIO: f32 = 0.9;
pub const LINEAR_DAMPING: f32 = 0.8;
pub const ANGULAR_DAMPING: f32 = 0.9;
pub const PICK_EPS: f32 = 0.001f32;
pub const DEFAULT_RESOURCE_CHARGE: f32 = 0.8;
pub const DEFAULT_SPORE_CHARGE: f32 = 0.8;
pub const DEFAULT_MINION_CHARGE: f32 = 0.3;
pub const INITIAL_SPAWN_RADIUS_RATIO: f32 = 0.25;
pub const INITIAL_SPAWN_RADIUS_SLICES: f32 = 16.;
pub const WORLD_RADIUS: f32 = 80.;
pub const EMITTER_DISTANCE: f32 = 20.;
pub const EMITTER_PERIOD: SecondsValue = 0.4;
pub const EMITTER_SPREAD_ANGLE: f32 = consts::PI / 12.;
pub const BULLET_SPEED_SCALE: f32 = 100.;
pub const BULLET_FIRE_RATE_SCALE: SecondsValue = 0.5;
pub const BULLET_FULL_CHARGE: SecondsValue = 1.0;
pub const BULLET_FIRE_RATE: SecondsValue = 45.0;
pub const DEFAULT_MINION_GENE_POOL: &'static [&'static str] = &[
	"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
	"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
	"GzB2lQVwM00tTAm5gwajjf4wc0a5GzB2lQVwM00tTAm5gwajjf4wc0a5",
	"GzB2lQdwM10vQEu5zwaPgDhfq2v8GzB2lQdwM10vQEu5zwaPgDhfq2v8",
];

pub const DEFAULT_RESOURCE_GENE_POOL: &'static [&'static str] = &[
	"GyA21QoQ",
	"M00sWS0M"
];

pub const DUMP_FILE_PATTERN: &'static str = "resources/%Y%m%d_%H%M%S.csv";

pub const AMBIENT_LIGHTS: &'static [[f32; 4]] = &[
	[1.0, 1.0, 1.0, 1.0],
	[3.1, 3.1, 3.1, 1.0],
	[10.0, 10.0, 10.0, 1.0],
	[31.0, 31.0, 31.0, 1.0],
	[100.0, 100.0, 100.0, 1.0],
	[0.001, 0.001, 0.001, 1.0],
	[0.01, 0.01, 0.01, 1.0],
	[0.1, 0.1, 0.1, 1.0],
	[0.31, 0.31, 0.31, 0.5],
];

pub const SPEED_FACTORS: &'static [SpeedFactor] = &[
	1.0,
	0.5,
	0.2,
	0.1,
	1.0,
	2.0,
	5.0,
	10.0,
];

pub const BACKGROUNDS: &'static [[f32; 4]] = &[
	[0.05, 0.07, 0.1, 1.0],
	[0.5, 0.5, 0.5, 0.5],
	[1.0, 1.0, 1.0, 1.0],
	[3.1, 3.1, 3.1, 1.0],
	[10.0, 10.0, 10.0, 1.0],
	[0., 0., 0., 1.0],
	[0.01, 0.01, 0.01, 1.0],
];<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader, BufWriter, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::string;

use mktemp::Temp;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        UnableToCreateTempDir(err: io::Error) {
            description("unable to create temporary directory")
            display("Unable to create temporary directory: {}", err)
            cause(err)
        }
        UnableToCreateSourceFile(err: io::Error) {
            description("unable to create source file")
            display("Unable to create source file: {}", err)
            cause(err)
        }
        UnableToExecuteCompiler(err: io::Error) {
            description("unable to execute the compiler")
            display("Unable to execute the compiler: {}", err)
            cause(err)
        }
        UnableToReadOutput(err: io::Error) {
            description("unable to read output file")
            display("Unable to read output file: {}", err)
            cause(err)
        }
        OutputNotUtf8(err: string::FromUtf8Error) {
            description("output was not valid UTF-8")
            display("Output was not valid UTF-8: {}", err)
            cause(err)
        }
        OutputMissing {
            description("output was missing")
            display("Output was missing")
        }
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub struct Sandbox {
    scratch_dir: Temp,
}

fn vec_to_str(v: Vec<u8>) -> Result<String> {
    String::from_utf8(v).map_err(Error::OutputNotUtf8)
}

impl Sandbox {
    pub fn new() -> Result<Self> {
        Ok(Sandbox {
            scratch_dir: try!(Temp::new_dir().map_err(Error::UnableToCreateTempDir)),
        })
    }

    pub fn compile(&self, req: &CompileRequest) -> Result<CompileResponse> {
        try!(self.write_source_code(&req.code));

        let mut output_path = self.scratch_dir.as_ref().to_path_buf();
        output_path.push("compiler-output");
        let mut command = self.compile_command(req.target, req.channel, req.mode, req.tests);

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(CompileResponse {
            success: output.status.success(),
            code: try!(read(&output_path)).unwrap_or_else(String::new),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    pub fn execute(&self, req: &ExecuteRequest) -> Result<ExecuteResponse> {
        try!(self.write_source_code(&req.code));
        let mut command = self.execute_command(req.channel, req.mode, req.tests);

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(ExecuteResponse {
            success: output.status.success(),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    pub fn format(&self, req: &FormatRequest) -> Result<FormatResponse> {
        let path = try!(self.write_source_code(&req.code));
        let mut command = self.format_command();

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(FormatResponse {
            success: output.status.success(),
            code: try!(try!(read(path.as_path())).ok_or(Error::OutputMissing)),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    fn write_source_code(&self, code: &str) -> Result<PathBuf> {
        let data = code.as_bytes();

        let path = {
            let mut p = self.scratch_dir.to_path_buf();
            p.push("main.rs");
            p
        };

        let file = try!(File::create(&path).map_err(Error::UnableToCreateSourceFile));
        let mut file = BufWriter::new(file);

        try!(file.write_all(data).map_err(Error::UnableToCreateSourceFile));

        debug!("Wrote {} bytes of source to {}", data.len(), path.display());
        Ok(path)
    }

    fn compile_command(&self, target: CompileTarget, channel: Channel, mode: Mode, tests: bool) -> Command {
        let mut cmd = self.docker_command();

        let execution_cmd = build_execution_command(Some((target, "compiler-output")), mode, tests, "main.rs");

        cmd.arg(&channel.container_name()).args(&["bash", "-c", &execution_cmd]);

        debug!("Compilation command is {:?}", cmd);

        cmd
    }

    fn execute_command(&self, channel: Channel, mode: Mode, tests: bool) -> Command {
        let mut cmd = self.docker_command();

        let mut execution_cmd = build_execution_command(None, mode, tests, "main.rs");
        execution_cmd.push_str(" && ./main");

        cmd.arg(&channel.container_name()).args(&["bash", "-c", &execution_cmd]);

        debug!("Execution command is {:?}", cmd);

        cmd
    }

    fn format_command(&self) -> Command {
        let mut cmd = self.docker_command();

        cmd.arg("rustfmt").args(&["main.rs"]);

        debug!("Formatting command is {:?}", cmd);

        cmd
    }

    fn docker_command(&self) -> Command {
        const DIR_INSIDE_CONTAINER: &'static str = "/source";

        let mut mount_source_volume = self.scratch_dir.as_ref().as_os_str().to_os_string();
        mount_source_volume.push(":");
        mount_source_volume.push(DIR_INSIDE_CONTAINER);

        let mut cmd = Command::new("docker");

        cmd
            .arg("run")
            .arg("--volume").arg(&mount_source_volume)
            .args(&["--workdir", DIR_INSIDE_CONTAINER])
            .args(&["--net", "none"])
            .args(&["--memory", "256m"])
            .args(&["--memory-swap", "320m"])
            .args(&["--env", "PLAYGROUND_TIMEOUT=10"]);

        cmd
    }
}

fn build_execution_command(target: Option<(CompileTarget, &str)>, mode: Mode, tests: bool, source_file: &str) -> String {
    use self::CompileTarget::*;
    use self::Mode::*;

    let mut s = String::from("rustc");

    match mode {
        Debug => s.push_str(" -g"),
        Release => s.push_str(" -C opt-level=3"),
    }

    if tests {
        s.push_str(" --test");
    }

    if let Some((target, filename)) = target {
        match target {
            Assembly => s.push_str(" --emit asm"),
            LlvmIr => s.push_str(" --emit llvm-ir"),
        }
        s.push_str(" -o ");
        s.push_str(filename);
    }

    s.push_str(" ");
    s.push_str(source_file);

    s
}

fn read(path: &Path) -> Result<Option<String>> {
    let f = match File::open(path) {
        Ok(f) => f,
        Err(ref e) if e.kind() == ErrorKind::NotFound => return Ok(None),
        Err(e) => return Err(Error::UnableToReadOutput(e)),
    };
    let mut f = BufReader::new(f);

    let mut s = String::new();
    try!(f.read_to_string(&mut s).map_err(Error::UnableToReadOutput));
    Ok(Some(s))
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CompileTarget {
    Assembly,
    LlvmIr,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Channel {
    Stable,
    Beta,
    Nightly,
}

impl Channel {
    fn container_name(&self) -> &'static str {
        use self::Channel::*;

        match *self {
            Stable => "rust-stable",
            Beta => "rust-beta",
            Nightly => "rust-nightly",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Debug,
    Release,
}

#[derive(Debug, Clone)]
pub struct CompileRequest {
    pub target: CompileTarget,
    pub channel: Channel,
    pub mode: Mode,
    pub tests: bool,
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct CompileResponse {
    pub success: bool,
    pub code: String,
    pub stdout: String,
    pub stderr: String,
}

#[derive(Debug, Clone)]
pub struct ExecuteRequest {
    pub channel: Channel,
    pub mode: Mode,
    pub tests: bool,
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct ExecuteResponse {
    pub success: bool,
    pub stdout: String,
    pub stderr: String,
}

#[derive(Debug, Clone)]
pub struct FormatRequest {
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct FormatResponse {
    pub success: bool,
    pub code: String,
    pub stdout: String,
    pub stderr: String,
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn network_connections_are_disabled() {
        let code = r#"
            fn main() {
                match ::std::net::TcpStream::connect("google.com:80") {
                    Ok(_) => println!("Able to connect to the outside world"),
                    Err(e) => println!("Failed to connect {}, {:?}", e, e),
                }
            }
        "#;

        let req = ExecuteRequest {
            channel: Channel::Stable,
            mode: Mode::Debug,
            tests: false,
            code: code.to_string(),
        };

        let sb = Sandbox::new().expect("Unable to create sandbox");
        let resp = sb.execute(&req).expect("Unable to execute code");

        assert!(resp.stdout.contains("Failed to connect"));
    }

    #[test]
    fn memory_usage_is_limited() {
        let code = r#"
            fn main() {
                let megabyte = 1024 * 1024;
                let mut big = vec![0u8; 384 * megabyte];
                *big.last_mut().unwrap() += 1;
            }
        "#;

        let req = ExecuteRequest {
            channel: Channel::Stable,
            mode: Mode::Debug,
            tests: false,
            code: code.to_string(),
        };

        let sb = Sandbox::new().expect("Unable to create sandbox");
        let resp = sb.execute(&req).expect("Unable to execute code");

        println!("{:?}", resp);
        assert!(resp.stderr.contains("Killed"));
    }

    #[test]
    fn wallclock_time_is_limited() {
        let code = r#"
            fn main() {
                let a_long_time = std::time::Duration::from_secs(20);
                std::thread::sleep(a_long_time);
            }
        "#;

        let req = ExecuteRequest {
            channel: Channel::Stable,
            mode: Mode::Debug,
            tests: false,
            code: code.to_string(),
        };

        let sb = Sandbox::new().expect("Unable to create sandbox");
        let resp = sb.execute(&req).expect("Unable to execute code");

        println!("{:?}", resp);
        assert!(resp.stderr.contains("Killed"));
    }
}
<commit_msg>Clean up created containers<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader, BufWriter, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::string;

use mktemp::Temp;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        UnableToCreateTempDir(err: io::Error) {
            description("unable to create temporary directory")
            display("Unable to create temporary directory: {}", err)
            cause(err)
        }
        UnableToCreateSourceFile(err: io::Error) {
            description("unable to create source file")
            display("Unable to create source file: {}", err)
            cause(err)
        }
        UnableToExecuteCompiler(err: io::Error) {
            description("unable to execute the compiler")
            display("Unable to execute the compiler: {}", err)
            cause(err)
        }
        UnableToReadOutput(err: io::Error) {
            description("unable to read output file")
            display("Unable to read output file: {}", err)
            cause(err)
        }
        OutputNotUtf8(err: string::FromUtf8Error) {
            description("output was not valid UTF-8")
            display("Output was not valid UTF-8: {}", err)
            cause(err)
        }
        OutputMissing {
            description("output was missing")
            display("Output was missing")
        }
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub struct Sandbox {
    scratch_dir: Temp,
}

fn vec_to_str(v: Vec<u8>) -> Result<String> {
    String::from_utf8(v).map_err(Error::OutputNotUtf8)
}

impl Sandbox {
    pub fn new() -> Result<Self> {
        Ok(Sandbox {
            scratch_dir: try!(Temp::new_dir().map_err(Error::UnableToCreateTempDir)),
        })
    }

    pub fn compile(&self, req: &CompileRequest) -> Result<CompileResponse> {
        try!(self.write_source_code(&req.code));

        let mut output_path = self.scratch_dir.as_ref().to_path_buf();
        output_path.push("compiler-output");
        let mut command = self.compile_command(req.target, req.channel, req.mode, req.tests);

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(CompileResponse {
            success: output.status.success(),
            code: try!(read(&output_path)).unwrap_or_else(String::new),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    pub fn execute(&self, req: &ExecuteRequest) -> Result<ExecuteResponse> {
        try!(self.write_source_code(&req.code));
        let mut command = self.execute_command(req.channel, req.mode, req.tests);

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(ExecuteResponse {
            success: output.status.success(),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    pub fn format(&self, req: &FormatRequest) -> Result<FormatResponse> {
        let path = try!(self.write_source_code(&req.code));
        let mut command = self.format_command();

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(FormatResponse {
            success: output.status.success(),
            code: try!(try!(read(path.as_path())).ok_or(Error::OutputMissing)),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    fn write_source_code(&self, code: &str) -> Result<PathBuf> {
        let data = code.as_bytes();

        let path = {
            let mut p = self.scratch_dir.to_path_buf();
            p.push("main.rs");
            p
        };

        let file = try!(File::create(&path).map_err(Error::UnableToCreateSourceFile));
        let mut file = BufWriter::new(file);

        try!(file.write_all(data).map_err(Error::UnableToCreateSourceFile));

        debug!("Wrote {} bytes of source to {}", data.len(), path.display());
        Ok(path)
    }

    fn compile_command(&self, target: CompileTarget, channel: Channel, mode: Mode, tests: bool) -> Command {
        let mut cmd = self.docker_command();

        let execution_cmd = build_execution_command(Some((target, "compiler-output")), mode, tests, "main.rs");

        cmd.arg(&channel.container_name()).args(&["bash", "-c", &execution_cmd]);

        debug!("Compilation command is {:?}", cmd);

        cmd
    }

    fn execute_command(&self, channel: Channel, mode: Mode, tests: bool) -> Command {
        let mut cmd = self.docker_command();

        let mut execution_cmd = build_execution_command(None, mode, tests, "main.rs");
        execution_cmd.push_str(" && ./main");

        cmd.arg(&channel.container_name()).args(&["bash", "-c", &execution_cmd]);

        debug!("Execution command is {:?}", cmd);

        cmd
    }

    fn format_command(&self) -> Command {
        let mut cmd = self.docker_command();

        cmd.arg("rustfmt").args(&["main.rs"]);

        debug!("Formatting command is {:?}", cmd);

        cmd
    }

    fn docker_command(&self) -> Command {
        const DIR_INSIDE_CONTAINER: &'static str = "/source";

        let mut mount_source_volume = self.scratch_dir.as_ref().as_os_str().to_os_string();
        mount_source_volume.push(":");
        mount_source_volume.push(DIR_INSIDE_CONTAINER);

        let mut cmd = Command::new("docker");

        cmd
            .arg("run")
            .arg("--rm")
            .arg("--volume").arg(&mount_source_volume)
            .args(&["--workdir", DIR_INSIDE_CONTAINER])
            .args(&["--net", "none"])
            .args(&["--memory", "256m"])
            .args(&["--memory-swap", "320m"])
            .args(&["--env", "PLAYGROUND_TIMEOUT=10"]);

        cmd
    }
}

fn build_execution_command(target: Option<(CompileTarget, &str)>, mode: Mode, tests: bool, source_file: &str) -> String {
    use self::CompileTarget::*;
    use self::Mode::*;

    let mut s = String::from("rustc");

    match mode {
        Debug => s.push_str(" -g"),
        Release => s.push_str(" -C opt-level=3"),
    }

    if tests {
        s.push_str(" --test");
    }

    if let Some((target, filename)) = target {
        match target {
            Assembly => s.push_str(" --emit asm"),
            LlvmIr => s.push_str(" --emit llvm-ir"),
        }
        s.push_str(" -o ");
        s.push_str(filename);
    }

    s.push_str(" ");
    s.push_str(source_file);

    s
}

fn read(path: &Path) -> Result<Option<String>> {
    let f = match File::open(path) {
        Ok(f) => f,
        Err(ref e) if e.kind() == ErrorKind::NotFound => return Ok(None),
        Err(e) => return Err(Error::UnableToReadOutput(e)),
    };
    let mut f = BufReader::new(f);

    let mut s = String::new();
    try!(f.read_to_string(&mut s).map_err(Error::UnableToReadOutput));
    Ok(Some(s))
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CompileTarget {
    Assembly,
    LlvmIr,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Channel {
    Stable,
    Beta,
    Nightly,
}

impl Channel {
    fn container_name(&self) -> &'static str {
        use self::Channel::*;

        match *self {
            Stable => "rust-stable",
            Beta => "rust-beta",
            Nightly => "rust-nightly",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Debug,
    Release,
}

#[derive(Debug, Clone)]
pub struct CompileRequest {
    pub target: CompileTarget,
    pub channel: Channel,
    pub mode: Mode,
    pub tests: bool,
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct CompileResponse {
    pub success: bool,
    pub code: String,
    pub stdout: String,
    pub stderr: String,
}

#[derive(Debug, Clone)]
pub struct ExecuteRequest {
    pub channel: Channel,
    pub mode: Mode,
    pub tests: bool,
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct ExecuteResponse {
    pub success: bool,
    pub stdout: String,
    pub stderr: String,
}

#[derive(Debug, Clone)]
pub struct FormatRequest {
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct FormatResponse {
    pub success: bool,
    pub code: String,
    pub stdout: String,
    pub stderr: String,
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn network_connections_are_disabled() {
        let code = r#"
            fn main() {
                match ::std::net::TcpStream::connect("google.com:80") {
                    Ok(_) => println!("Able to connect to the outside world"),
                    Err(e) => println!("Failed to connect {}, {:?}", e, e),
                }
            }
        "#;

        let req = ExecuteRequest {
            channel: Channel::Stable,
            mode: Mode::Debug,
            tests: false,
            code: code.to_string(),
        };

        let sb = Sandbox::new().expect("Unable to create sandbox");
        let resp = sb.execute(&req).expect("Unable to execute code");

        assert!(resp.stdout.contains("Failed to connect"));
    }

    #[test]
    fn memory_usage_is_limited() {
        let code = r#"
            fn main() {
                let megabyte = 1024 * 1024;
                let mut big = vec![0u8; 384 * megabyte];
                *big.last_mut().unwrap() += 1;
            }
        "#;

        let req = ExecuteRequest {
            channel: Channel::Stable,
            mode: Mode::Debug,
            tests: false,
            code: code.to_string(),
        };

        let sb = Sandbox::new().expect("Unable to create sandbox");
        let resp = sb.execute(&req).expect("Unable to execute code");

        println!("{:?}", resp);
        assert!(resp.stderr.contains("Killed"));
    }

    #[test]
    fn wallclock_time_is_limited() {
        let code = r#"
            fn main() {
                let a_long_time = std::time::Duration::from_secs(20);
                std::thread::sleep(a_long_time);
            }
        "#;

        let req = ExecuteRequest {
            channel: Channel::Stable,
            mode: Mode::Debug,
            tests: false,
            code: code.to_string(),
        };

        let sb = Sandbox::new().expect("Unable to create sandbox");
        let resp = sb.execute(&req).expect("Unable to execute code");

        println!("{:?}", resp);
        assert!(resp.stderr.contains("Killed"));
    }
}
<|endoftext|>


<commit_before>use alto;
use alto::{Context, StaticSource, StreamingSource, Buffer, SourceTrait};
use alto::{Mono, Stereo};

use std::sync::Arc;
use std::path::{PathBuf};

use super::load::load_ogg;

use std::fs::File;
use lewton::inside_ogg::OggStreamReader;

use Vec3f;
use HashMap;
use JamResult;
use JamError;
use cgmath::Zero;

pub type SoundName = String;

pub type SoundEventId = u64;

pub type Gain = f32;

pub type DistanceModel = alto::DistanceModel;

pub struct SoundContext<'a> {
    pub context: &'a Context<'a>,
    pub path: String,
    pub extension: String,
    pub sources: Vec<SoundSource<'a>>,
    pub streaming_sources: Vec<StreamingSoundSource<'a>>,
    pub buffers: HashMap<SoundName, SoundBuffer<'a>>,
    pub stream_above_file_size: u64,
    pub next_event : SoundEventId,
    pub master_gain : Gain,
    pub distance_model : DistanceModel,
    pub listener : Listener,
}

pub struct SoundBuffer<'a> {
    pub inner : Arc<Buffer<'a, 'a>>,
    pub gain: Gain,
    pub duration: f32, // we could track last used .... could be interesting if nothing else
}

pub struct SoundSource<'a> {
    static_source: StaticSource<'a, 'a>,
    pub current_binding: Option<SoundBinding>,
}

#[derive(Debug)]
pub struct SoundBinding {
    pub event_id: SoundEventId,
    pub sound_event: SoundEvent,
}

pub enum CombinedSource<'a> {
    Normal(&'a mut SoundSource<'a>),
    Streaming(&'a mut StreamingSoundSource<'a>),
}

// an index to a source + binding
#[derive(Debug, Clone, Copy)]
pub struct SoundSourceLoan {
    pub source_id: usize,
    pub event_id: SoundEventId,
    pub streaming: bool,
}

pub struct StreamingSoundSource<'a> {
    streaming_source: StreamingSource<'a, 'a>,
    pub current_binding: Option<StreamingSoundBinding>,
}

pub struct StreamingSoundBinding {
    pub event_id: SoundEventId,
    pub sound_event: SoundEvent,
    pub stream_reader : OggStreamReader<File>,
    // details about how streaming is going? .. sound_event.name gives us all we need to loop this thing
}

#[derive(Clone, Debug)]
pub struct SoundEvent {
    pub name: String,
    pub position: Vec3f,
    pub gain: f32,
    pub pitch: f32,
    pub attenuation: f32,
    pub loop_sound: bool,
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Listener {
    pub position: Vec3f,
    pub velocity: Vec3f,
    pub orientation_up: Vec3f,
    pub orientation_forward: Vec3f,
}

impl Listener {
    pub fn default() -> Listener {
        Listener {
            position: Vec3f::zero(),
            velocity: Vec3f::zero(),
            orientation_up: Vec3f::new(0.0, 1.0, 0.0),
            orientation_forward: Vec3f::new(0.0, 0.0, -1.0),
        }
    }
}

pub fn create_sound_context<'a>(context: &'a Context<'a>, path:&str, extension: &str, stream_above_file_size: u64) -> SoundContext<'a> {
    // we should probably create our sources here
    SoundContext {
        context: context,
        path: String::from(path),
        extension: String::from(extension),
        sources: Vec::new(),
        streaming_sources: Vec::new(),
        buffers: HashMap::default(),
        stream_above_file_size: stream_above_file_size,
        next_event: 0,
        master_gain: 1.0,
        distance_model: alto::DistanceModel::None,
        listener: Listener::default() ,
    }
}

impl<'a> SoundContext<'a> {
    pub fn set_gain(&mut self, gain: Gain) -> JamResult<()> {
        try!(self.context.set_gain(gain));
        self.master_gain = gain;
        Ok(())
    }

    pub fn set_listener(&mut self, listener: Listener) -> JamResult<()> {
        try!(self.context.set_position(listener.position));
        try!(self.context.set_velocity(listener.velocity));
        try!(self.context.set_orientation::<[f32; 3]>((listener.orientation_forward.into(), listener.orientation_up.into())));

        self.listener = listener;

        Ok(())
    }

    pub fn create_sources(&mut self, static_sources: usize, streaming_sources: usize) -> JamResult<()> {
        for _ in 0..static_sources {
            let source = try!(self.context.new_static_source());
            self.sources.push(SoundSource { static_source: source, current_binding: None});
        }

        for _ in 0..streaming_sources {
            let source = try!(self.context.new_streaming_source());
            self.streaming_sources.push(StreamingSoundSource { streaming_source: source, current_binding: None });
        }

        Ok(())
    }

    pub fn purge(&mut self) -> JamResult<()> {
        for source in self.sources.iter_mut() {
            if source.current_binding.is_some() {
                try!(source.static_source.stop());
                source.current_binding = None;
            }
        }
        for source in self.streaming_sources.iter_mut() {
            if source.current_binding.is_some() {
                try!(source.streaming_source.stop());
                source.current_binding = None;
            }
        }
        self.buffers.clear();
        Ok(())
    }

    pub fn full_path(&self, name: &str) -> PathBuf {
        PathBuf::from(format!("{}/{}.{}", &self.path, name, &self.extension))
    }

    pub fn load_sound(&mut self, name: &str, gain: f32) -> JamResult<()> {
        let full_path = self.full_path(name);
        if full_path.exists() {
            let sound = try!(load_ogg(&full_path));
            let mut buffer = try!(self.context.new_buffer());

            let duration = sound.duration();
            if sound.channels == 1 {
                try!(buffer.set_data::<Mono<i16>, _>(sound.data, sound.sample_rate as i32));
            } else if sound.channels == 2 {
                try!(buffer.set_data::<Stereo<i16>, _>(sound.data, sound.sample_rate as i32));
            } else {
                return Err(JamError::TooManyChannels);
            }

            let arc_buffer = Arc::new(buffer);

            self.buffers.insert(name.into(), SoundBuffer{ inner: arc_buffer, gain: gain, duration: duration });

            Ok(())
        } else {
            Err(JamError::FileDoesntExist(full_path))
        }
    }

    pub fn next_event_id(&mut self) -> SoundEventId {
        self.next_event += 1;
        self.next_event
    }

    pub fn clean_sources(&mut self) -> JamResult<(u32, u32)> {
        use alto::SourceState::*;

        let mut available_sources = 0;
        let mut available_streaming_sources = 0;

        for source in self.sources.iter_mut() {
            if source.current_binding.is_some() {
                let state = try!(source.static_source.state());
                match state {
                    Initial | Playing | Paused => (),
                    Stopped => {
                        source.current_binding = None;
                        available_sources += 1;
                    },
                };
            } else {
                available_sources += 1;
            }
        }
        for streaming_source in self.streaming_sources.iter_mut() {
            if streaming_source.current_binding.is_some() {
                let state = try!(streaming_source.streaming_source.state());
                match state {
                    Initial | Playing | Paused => (),
                    Stopped => {
                        streaming_source.current_binding = None;
                        available_streaming_sources += 1;
                    },
                };
            } else {
                available_streaming_sources += 1;
            }
        }

        Ok((available_sources, available_streaming_sources))
    }

    pub fn set_distace_model(&mut self, distance_model: DistanceModel) -> JamResult<()> {
        try!(self.context.set_distance_model(distance_model));
        self.distance_model = distance_model;
        Ok(())
    }

    pub fn loan_valid(&self, loan:SoundSourceLoan) -> bool {
        if loan.streaming {
            self.streaming_sources[loan.source_id].current_binding.iter().any(|ss| ss.event_id == loan.event_id )
        } else {
            self.sources[loan.source_id].current_binding.iter().any(|ss| ss.event_id == loan.event_id )
        }
    }

    pub fn loan_valid_ok(&'a mut self, loan:SoundSourceLoan) -> Option<CombinedSource<'a>> {
        if loan.streaming {
            let mut source : &mut StreamingSoundSource<'a> = &mut self.streaming_sources[loan.source_id];
            let valid = source.current_binding.iter().any(|ss| ss.event_id == loan.event_id );
            if valid {
                Some(CombinedSource::Streaming(source))
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn stop_loan(&mut self, loan:SoundSourceLoan) -> JamResult<()> {
        if self.loan_valid(loan) {
            if loan.streaming {
                let source = &mut self.streaming_sources[loan.source_id];
                try!(source.streaming_source.stop());
            } else {
                let source = &mut self.sources[loan.source_id];
                try!(source.static_source.stop());
                try!(source.static_source.clear_buffer());
            }
        }
        Ok(())
    }

    pub fn play_event(&mut self, sound_event: SoundEvent, loan: Option<SoundSourceLoan>) -> JamResult<SoundSourceLoan> {
        // check loan first ... if it's a loan, it's simple
        if let Some(l) = loan {
            if self.loan_valid(l) {
                if l.streaming {
                    let source = &mut self.streaming_sources[l.source_id];
                    try!(assign_event(&mut source.streaming_source, &sound_event));
                } else {
                    let source = &mut self.sources[l.source_id];
                    try!(assign_event(&mut source.static_source, &sound_event));
                }
                return Ok(l)
            }
        }

        if !self.buffers.contains_key(&sound_event.name) {
            try!(self.load_sound(&sound_event.name, sound_event.gain));
        }
        let event_id = self.next_event_id();
        if let Some(buffer) = self.buffers.get(&sound_event.name) {
            if let Some(source) = self.sources.iter_mut().filter(|src| src.current_binding.is_none()).next() {
                // fn set_buffer(&mut self, buf: Arc<Buffer<'d, 'c>
                try!(source.static_source.set_buffer(buffer.inner.clone()));
                try!(source.static_source.play());

                // try!(source.static_source.set_looping(sound_event.loop_sound));
                try!(assign_event(&mut source.static_source, &sound_event));
                source.current_binding = Some(SoundBinding {
                    event_id: event_id,
                    sound_event: sound_event,
                });
                Ok(SoundSourceLoan {
                    source_id : 0,
                    event_id : event_id,
                    streaming: false,
                })
            } else {
                Err(JamError::NoFreeSource)
            }
        } else {
            Err(JamError::NoSound(sound_event.name))
        }
    }
}

fn assign_event<'c, 'd: 'c, ST : SourceTrait<'d,'c>>(source: &mut ST, sound_event:&SoundEvent) -> JamResult<()> {
    try!(source.set_pitch(sound_event.pitch));
    try!(source.set_position(sound_event.position));
    try!(source.set_gain(sound_event.gain));
    Ok(())
}

/*
pub position: Vec3f,
    pub gain: f32,
    pub pitch: f32,
    pub attenuation: f32,
    pub loop_sound: bool,*/<commit_msg>Sound simplification WIP<commit_after>use alto;
use alto::{Context, StaticSource, StreamingSource, Buffer, SourceTrait};
use alto::{Mono, Stereo};

use std::sync::Arc;
use std::path::{PathBuf};

use super::load::load_ogg;

use std::fs::File;
use lewton::inside_ogg::OggStreamReader;

use Vec3f;
use HashMap;
use JamResult;
use JamError;
use cgmath::Zero;

pub type SoundName = String;

pub type SoundEventId = u64;

pub type Gain = f32;

pub type DistanceModel = alto::DistanceModel;

pub struct SoundContext<'a> {
    pub context: &'a Context<'a>,
    pub path: String,
    pub extension: String,
    pub sources: Vec<SoundSource<'a>>,
    pub streaming_sources: Vec<StreamingSoundSource<'a>>,
    pub buffers: HashMap<SoundName, SoundBuffer<'a>>,
    pub stream_above_file_size: u64,
    pub next_event : SoundEventId,
    pub master_gain : Gain,
    pub distance_model : DistanceModel,
    pub listener : Listener,
}

pub struct SoundBuffer<'a> {
    pub inner : Arc<Buffer<'a, 'a>>,
    pub gain: Gain,
    pub duration: f32, // we could track last used .... could be interesting if nothing else
}

pub enum CombinedSource<'a> {
    Normal(&'a mut SoundSource<'a>),
    Streaming(&'a mut StreamingSoundSource<'a>),
}

pub struct SoundSource<'a> {
    inner: StaticSource<'a, 'a>,
    pub current_binding: Option<SoundBinding>,
}

#[derive(Debug)]
pub struct SoundBinding {
    pub event_id: SoundEventId,
    pub sound_event: SoundEvent,
}

// an index to a source + binding
#[derive(Debug, Clone, Copy)]
pub struct SoundSourceLoan {
    pub source_id: usize,
    pub event_id: SoundEventId,
    pub streaming: bool,
}

pub struct StreamingSoundSource<'a> {
    inner: StreamingSource<'a, 'a>,
    pub current_binding: Option<StreamingSoundBinding>,
}

pub struct StreamingSoundBinding {
    pub event_id: SoundEventId,
    pub sound_event: SoundEvent,
    pub stream_reader : OggStreamReader<File>,
    // details about how streaming is going? .. sound_event.name gives us all we need to loop this thing
}

#[derive(Clone, Debug)]
pub struct SoundEvent {
    pub name: String,
    pub position: Vec3f,
    pub gain: f32,
    pub pitch: f32,
    pub attenuation: f32,
    pub loop_sound: bool,
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Listener {
    pub position: Vec3f,
    pub velocity: Vec3f,
    pub orientation_up: Vec3f,
    pub orientation_forward: Vec3f,
}

impl Listener {
    pub fn default() -> Listener {
        Listener {
            position: Vec3f::zero(),
            velocity: Vec3f::zero(),
            orientation_up: Vec3f::new(0.0, 1.0, 0.0),
            orientation_forward: Vec3f::new(0.0, 0.0, -1.0),
        }
    }
}

pub fn create_sound_context<'a>(context: &'a Context<'a>, path:&str, extension: &str, stream_above_file_size: u64) -> SoundContext<'a> {
    // we should probably create our sources here
    SoundContext {
        context: context,
        path: String::from(path),
        extension: String::from(extension),
        sources: Vec::new(),
        streaming_sources: Vec::new(),
        buffers: HashMap::default(),
        stream_above_file_size: stream_above_file_size,
        next_event: 0,
        master_gain: 1.0,
        distance_model: alto::DistanceModel::None,
        listener: Listener::default() ,
    }
}

impl<'a> SoundContext<'a> {
    pub fn set_gain(&mut self, gain: Gain) -> JamResult<()> {
        try!(self.context.set_gain(gain));
        self.master_gain = gain;
        Ok(())
    }

    pub fn set_listener(&mut self, listener: Listener) -> JamResult<()> {
        try!(self.context.set_position(listener.position));
        try!(self.context.set_velocity(listener.velocity));
        try!(self.context.set_orientation::<[f32; 3]>((listener.orientation_forward.into(), listener.orientation_up.into())));

        self.listener = listener;

        Ok(())
    }

    pub fn create_sources(&mut self, static_sources: usize, streaming_sources: usize) -> JamResult<()> {
        for _ in 0..static_sources {
            let source = try!(self.context.new_static_source());
            self.sources.push(SoundSource { inner: source, current_binding: None});
        }

        for _ in 0..streaming_sources {
            let source = try!(self.context.new_streaming_source());
            self.streaming_sources.push(StreamingSoundSource { inner: source, current_binding: None });
        }

        Ok(())
    }

    pub fn purge(&mut self) -> JamResult<()> {
        for source in self.sources.iter_mut() {
            if source.current_binding.is_some() {
                try!(source.inner.stop());
                source.current_binding = None;
            }
        }
        for source in self.streaming_sources.iter_mut() {
            if source.current_binding.is_some() {
                try!(source.inner.stop());
                source.current_binding = None;
            }
        }
        self.buffers.clear();
        Ok(())
    }

    pub fn full_path(&self, name: &str) -> PathBuf {
        PathBuf::from(format!("{}/{}.{}", &self.path, name, &self.extension))
    }

    pub fn load_sound(&mut self, name: &str, gain: f32) -> JamResult<()> {
        let full_path = self.full_path(name);
        if full_path.exists() {
            let sound = try!(load_ogg(&full_path));
            let mut buffer = try!(self.context.new_buffer());

            let duration = sound.duration();
            if sound.channels == 1 {
                try!(buffer.set_data::<Mono<i16>, _>(sound.data, sound.sample_rate as i32));
            } else if sound.channels == 2 {
                try!(buffer.set_data::<Stereo<i16>, _>(sound.data, sound.sample_rate as i32));
            } else {
                return Err(JamError::TooManyChannels);
            }

            let arc_buffer = Arc::new(buffer);

            self.buffers.insert(name.into(), SoundBuffer{ inner: arc_buffer, gain: gain, duration: duration });

            Ok(())
        } else {
            Err(JamError::FileDoesntExist(full_path))
        }
    }

    pub fn next_event_id(&mut self) -> SoundEventId {
        self.next_event += 1;
        self.next_event
    }

    pub fn clean_sources(&mut self) -> JamResult<(u32, u32)> {
        use alto::SourceState::*;

        let mut available_sources = 0;
        let mut available_streaming_sources = 0;

        for source in self.sources.iter_mut() {
            if source.current_binding.is_some() {
                let state = try!(source.inner.state());
                match state {
                    Initial | Playing | Paused => (),
                    Stopped => {
                        source.current_binding = None;
                        available_sources += 1;
                    },
                };
            } else {
                available_sources += 1;
            }
        }
        for streaming_source in self.streaming_sources.iter_mut() {
            if streaming_source.current_binding.is_some() {
                let state = try!(streaming_source.inner.state());
                match state {
                    Initial | Playing | Paused => (),
                    Stopped => {
                        streaming_source.current_binding = None;
                        available_streaming_sources += 1;
                    },
                };
            } else {
                available_streaming_sources += 1;
            }
        }

        Ok((available_sources, available_streaming_sources))
    }

    pub fn set_distace_model(&mut self, distance_model: DistanceModel) -> JamResult<()> {
        try!(self.context.set_distance_model(distance_model));
        self.distance_model = distance_model;
        Ok(())
    }

    pub fn loan_valid(&self, loan:SoundSourceLoan) -> bool {
        if loan.streaming {
            self.streaming_sources[loan.source_id].current_binding.iter().any(|ss| ss.event_id == loan.event_id )
        } else {
            self.sources[loan.source_id].current_binding.iter().any(|ss| ss.event_id == loan.event_id )
        }
    }

    pub fn loan_valid_ok<'b: 'a>(&'b mut self, loan:SoundSourceLoan) -> Option<CombinedSource<'b>> {
        if loan.streaming {
            let mut source : &mut StreamingSoundSource<'b> = &mut self.streaming_sources[loan.source_id];
            let valid = source.current_binding.iter().any(|ss| ss.event_id == loan.event_id );
            if valid {
                Some(CombinedSource::Streaming(source))
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn some_bullshit(&'a mut self, loan:SoundSourceLoan) -> bool {
        match self.loan_valid_ok(loan) {
            Some(CombinedSource::Normal(source)) => {
                source.inner.play().unwrap();
                true
            },
            Some(CombinedSource::Streaming(streaming)) => {
                streaming.inner.play().unwrap();
                true
            },
            None => false,
        }
    }

    pub fn stop_loan(&mut self, loan:SoundSourceLoan) -> JamResult<()> {
        if self.loan_valid(loan) {
            if loan.streaming {
                let source = &mut self.streaming_sources[loan.source_id];
                try!(source.inner.stop());
            } else {
                let source = &mut self.sources[loan.source_id];
                try!(source.inner.stop());
                try!(source.inner.clear_buffer());
            }
        }
        Ok(())
    }

    pub fn play_event(&mut self, sound_event: SoundEvent, loan: Option<SoundSourceLoan>) -> JamResult<SoundSourceLoan> {
        // check loan first ... if it's a loan, it's simple
        if let Some(l) = loan {
            if self.loan_valid(l) {
                if l.streaming {
                    let source = &mut self.streaming_sources[l.source_id];
                    try!(assign_event(&mut source.inner, &sound_event));
                } else {
                    let source = &mut self.sources[l.source_id];
                    try!(assign_event(&mut source.inner, &sound_event));
                }
                return Ok(l)
            }
        }

        if !self.buffers.contains_key(&sound_event.name) {
            try!(self.load_sound(&sound_event.name, sound_event.gain));
        }
        let event_id = self.next_event_id();
        if let Some(buffer) = self.buffers.get(&sound_event.name) {
            if let Some(source) = self.sources.iter_mut().filter(|src| src.current_binding.is_none()).next() {
                // fn set_buffer(&mut self, buf: Arc<Buffer<'d, 'c>
                try!(source.inner.set_buffer(buffer.inner.clone()));
                try!(source.inner.play());

                // try!(source.static_source.set_looping(sound_event.loop_sound));
                try!(assign_event(&mut source.inner, &sound_event));
                source.current_binding = Some(SoundBinding {
                    event_id: event_id,
                    sound_event: sound_event,
                });
                Ok(SoundSourceLoan {
                    source_id : 0,
                    event_id : event_id,
                    streaming: false,
                })
            } else {
                Err(JamError::NoFreeSource)
            }
        } else {
            Err(JamError::NoSound(sound_event.name))
        }
    }
}

fn assign_event<'c, 'd: 'c, ST : SourceTrait<'d,'c>>(source: &mut ST, sound_event:&SoundEvent) -> JamResult<()> {
    try!(source.set_pitch(sound_event.pitch));
    try!(source.set_position(sound_event.position));
    try!(source.set_gain(sound_event.gain));
    Ok(())
}

/*
pub position: Vec3f,
    pub gain: f32,
    pub pitch: f32,
    pub attenuation: f32,
    pub loop_sound: bool,*/<|endoftext|>


<commit_before>#![crate_name = "monitor"]

extern crate zmq;
use std::str;

/// Read one event off the monitor socket; return the SocketEvent value.
fn get_monitor_event(monitor: &mut zmq::Socket) -> zmq::Result<zmq::SocketEvent> {
    let mut msg = zmq::Message::new()?;
    monitor.recv(&mut msg, 0)?;
    let event = ((msg[1] as u16) << 8) | msg[0] as u16;

    assert!(
        monitor.get_rcvmore()?,
        "Monitor socket should have two messages per event"
    );

    // the address, we'll ignore it
    monitor.recv(&mut msg, 0)?;

    Ok(zmq::SocketEvent::from_raw(event))
}

/// Send a series of pings between the client and the server.
/// The messages should round trip from the client to the server
/// and back again.
fn bounce(client: &mut zmq::Socket, server: &mut zmq::Socket) {
    let data = "12345678ABCDEFGH12345678abcdefgh";

    //  Send message from client to server
    client.send(data.as_bytes(), zmq::SNDMORE).unwrap();
    client.send(data.as_bytes(), 0).unwrap();

    //  Receive message at server side
    let mut recv_data = server.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(server.get_rcvmore().unwrap());

    recv_data = server.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(!server.get_rcvmore().unwrap());

    //  Send message from client to server
    server.send(&recv_data, zmq::SNDMORE).unwrap();
    server.send(&recv_data, 0).unwrap();

    //  Receive the two parts at the client side
    recv_data = client.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(client.get_rcvmore().unwrap());

    recv_data = client.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(!client.get_rcvmore().unwrap());
}

/// Close the given socket with LINGER set to 0
fn close_zero_linger(socket: &mut zmq::Socket) {
    socket.set_linger(0).unwrap();
    drop(socket);
}

fn main() {
    let ctx = zmq::Context::new();

    let mut client = ctx.socket(zmq::DEALER).unwrap();
    let mut server = ctx.socket(zmq::DEALER).unwrap();

    let err = client
        .monitor("tcp://127.0.0.1:9999", 0)
        .expect_err("Socket monitoring only works over inproc://");
    assert_eq!(zmq::Error::EPROTONOSUPPORT, err);

    assert!(
        client
            .monitor("inproc://monitor-client", zmq::SocketEvent::ALL as i32)
            .is_ok()
    );
    assert!(
        server
            .monitor("inproc://monitor-server", zmq::SocketEvent::ALL as i32)
            .is_ok()
    );

    let mut client_mon = ctx.socket(zmq::PAIR).unwrap();
    let mut server_mon = ctx.socket(zmq::PAIR).unwrap();

    // Connect these to the inproc endpoints so they'll get events
    client_mon.connect("inproc://monitor-client").unwrap();
    server_mon.connect("inproc://monitor-server").unwrap();

    // Now do a basic ping test
    server.bind("tcp://127.0.0.1:9998").unwrap();
    client.connect("tcp://127.0.0.1:9998").unwrap();
    bounce(&mut client, &mut server);

    // Close client and server
    close_zero_linger(&mut client);
    close_zero_linger(&mut server);

    // Now collect and check events from both sockets
    let mut event = get_monitor_event(&mut client_mon).unwrap();
    println!("got client monitor event {:?}", event);
    if event == zmq::SocketEvent::CONNECT_DELAYED {
        event = get_monitor_event(&mut client_mon).unwrap();
        println!("got client monitor event {:?}", event);
    }
    assert_eq!(zmq::SocketEvent::CONNECTED, event);

    event = get_monitor_event(&mut client_mon).unwrap();
    assert_eq!(zmq::SocketEvent::MONITOR_STOPPED, event);
    println!("got client monitor event {:?}", event);

    // This is the flow of server events
    event = get_monitor_event(&mut server).unwrap();
    println!("got server monitor event {:?}", event);
    assert_eq!(zmq::SocketEvent::LISTENING, event);

    event = get_monitor_event(&mut server).unwrap();
    println!("got server monitor event {:?}", event);
    assert_eq!(zmq::SocketEvent::ACCEPTED, event);

    event = get_monitor_event(&mut server).unwrap();
    println!("got server monitor event {:?}", event);
    assert_eq!(zmq::SocketEvent::CLOSED, event);

    event = get_monitor_event(&mut server).unwrap();
    println!("got server monitor event {:?}", event);
    assert_eq!(zmq::SocketEvent::MONITOR_STOPPED, event);

    // Close down the sockets
    close_zero_linger(&mut client_mon);
    close_zero_linger(&mut server_mon);
}
<commit_msg>Fix the monitor example<commit_after>#![crate_name = "monitor"]

extern crate zmq;
use std::str;
use std::u16;

/// Read one event off the monitor socket; return the SocketEvent value.
fn get_monitor_event(monitor: &mut zmq::Socket) -> zmq::Result<zmq::SocketEvent> {
    let mut msg = zmq::Message::new()?;
    monitor.recv(&mut msg, 0)?;
    let event = (u16::from(msg[1]) << 8) | u16::from(msg[0]);

    assert!(
        monitor.get_rcvmore()?,
        "Monitor socket should have two messages per event"
    );

    // the address, we'll ignore it
    monitor.recv(&mut msg, 0)?;

    Ok(zmq::SocketEvent::from_raw(event))
}

/// Send a series of pings between the client and the server.
/// The messages should round trip from the client to the server
/// and back again.
fn bounce(client: &mut zmq::Socket, server: &mut zmq::Socket) {
    let data = "12345678ABCDEFGH12345678abcdefgh";

    //  Send message from client to server
    client.send(data.as_bytes(), zmq::SNDMORE).unwrap();
    client.send(data.as_bytes(), 0).unwrap();

    //  Receive message at server side
    let mut recv_data = server.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(server.get_rcvmore().unwrap());

    recv_data = server.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(!server.get_rcvmore().unwrap());

    //  Send message from client to server
    server.send(&recv_data, zmq::SNDMORE).unwrap();
    server.send(&recv_data, 0).unwrap();

    //  Receive the two parts at the client side
    recv_data = client.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(client.get_rcvmore().unwrap());

    recv_data = client.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(!client.get_rcvmore().unwrap());
}

/// Close the given socket with LINGER set to 0
fn close_zero_linger(socket: zmq::Socket) {
    socket.set_linger(0).unwrap();
    drop(socket);
}

fn main() {
    let ctx = zmq::Context::new();

    let mut client = ctx.socket(zmq::DEALER).unwrap();
    let mut server = ctx.socket(zmq::DEALER).unwrap();

    let err = client
        .monitor("tcp://127.0.0.1:9999", 0)
        .expect_err("Socket monitoring only works over inproc://");
    assert_eq!(zmq::Error::EPROTONOSUPPORT, err);

    assert!(
        client
            .monitor("inproc://monitor-client", zmq::SocketEvent::ALL as i32)
            .is_ok()
    );
    assert!(
        server
            .monitor("inproc://monitor-server", zmq::SocketEvent::ALL as i32)
            .is_ok()
    );

    let mut client_mon = ctx.socket(zmq::PAIR).unwrap();
    let mut server_mon = ctx.socket(zmq::PAIR).unwrap();

    // Connect these to the inproc endpoints so they'll get events
    client_mon.connect("inproc://monitor-client").unwrap();
    server_mon.connect("inproc://monitor-server").unwrap();

    // Now do a basic ping test
    server.bind("tcp://127.0.0.1:9998").unwrap();
    client.connect("tcp://127.0.0.1:9998").unwrap();
    bounce(&mut client, &mut server);

    // Close client and server
    close_zero_linger(client);
    close_zero_linger(server);

    // Now collect and check events from both sockets
    let mut event = get_monitor_event(&mut client_mon).unwrap();
    println!("got client monitor event {:?}", event);
    if event == zmq::SocketEvent::CONNECT_DELAYED {
        event = get_monitor_event(&mut client_mon).unwrap();
        println!("got client monitor event {:?}", event);
    }
    assert_eq!(zmq::SocketEvent::CONNECTED, event);

    event = get_monitor_event(&mut client_mon).unwrap();
    assert_eq!(zmq::SocketEvent::MONITOR_STOPPED, event);
    println!("got client monitor event {:?}", event);

    // This is the flow of server events
    event = get_monitor_event(&mut server_mon).unwrap();
    println!("got server monitor event {:?}", event);
    assert_eq!(zmq::SocketEvent::LISTENING, event);

    event = get_monitor_event(&mut server_mon).unwrap();
    println!("got server monitor event {:?}", event);
    assert_eq!(zmq::SocketEvent::ACCEPTED, event);

    event = get_monitor_event(&mut server_mon).unwrap();
    println!("got server monitor event {:?}", event);
    assert_eq!(zmq::SocketEvent::CLOSED, event);

    event = get_monitor_event(&mut server_mon).unwrap();
    println!("got server monitor event {:?}", event);
    assert_eq!(zmq::SocketEvent::MONITOR_STOPPED, event);

    // Close down the sockets
    close_zero_linger(client_mon);
    close_zero_linger(server_mon);
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate getopts;
extern crate serde_json as json;

use std::env;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use std::str;
use std::collections::HashSet;
use std::iter::FromIterator;

use getopts::{Matches, Options};
use json::Value;

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

fn execute() -> i32 {
    let success = 0;
    let failure = 1;

    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    if let Some(arg) = env::args()
        .skip(2)
        .take_while(|a| a != "--")
        .find(|a| !a.starts_with('-'))
    {
        print_usage(&opts, &format!("Invalid argument: `{}`.", arg));
        return failure;
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage(&opts, &e.to_string());
            return failure;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage(&opts, "quiet mode and verbose mode are not compatible");
            return failure;
        }
    };

    if matches.opt_present("h") {
        print_usage(&opts, "");
        return success;
    }

    let workspace_hitlist = WorkspaceHitlist::from_matches(&matches);

    match format_crate(verbosity, &workspace_hitlist) {
        Err(e) => {
            print_usage(&opts, &e.to_string());
            failure
        }
        Ok(status) => if status.success() {
            success
        } else {
            status.code().unwrap_or(failure)
        },
    }
}

fn print_usage(opts: &Options, reason: &str) {
    let msg = format!("{}\nusage: cargo fmt [options]", reason);
    println!(
        "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
         Arguments after `--` are passed to rustfmt.",
        opts.usage(&msg)
    );
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn format_crate(
    verbosity: Verbosity,
    workspace_hitlist: &WorkspaceHitlist,
) -> Result<ExitStatus, std::io::Error> {
    let targets = get_targets(workspace_hitlist)?;

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .filter(|t| t.kind.should_format())
        .inspect(|t| if verbosity == Verbosity::Verbose {
            println!("[{:?}] {:?}", t.kind, t.path)
        })
        .map(|t| t.path)
        .collect();

    format_files(&files, &get_fmt_args(), verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

#[derive(Debug)]
enum TargetKind {
    Lib,         // dylib, staticlib, lib
    Bin,         // bin
    Example,     // example file
    Test,        // test file
    Bench,       // bench file
    CustomBuild, // build script
    ProcMacro,   // a proc macro implementation
    Other,       // plugin,...
}

impl TargetKind {
    fn should_format(&self) -> bool {
        match *self {
            TargetKind::Lib |
            TargetKind::Bin |
            TargetKind::Example |
            TargetKind::Test |
            TargetKind::Bench |
            TargetKind::CustomBuild |
            TargetKind::ProcMacro => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct Target {
    path: PathBuf,
    kind: TargetKind,
}

#[derive(Debug, PartialEq, Eq)]
pub enum WorkspaceHitlist {
    All,
    Some(Vec<String>),
    None,
}

impl WorkspaceHitlist {
    pub fn get_some(&self) -> Option<&[String]> {
        if let WorkspaceHitlist::Some(ref hitlist) = *self {
            Some(hitlist)
        } else {
            None
        }
    }

    pub fn from_matches(matches: &Matches) -> WorkspaceHitlist {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => WorkspaceHitlist::None,
            (true, _) => WorkspaceHitlist::All,
            (false, true) => WorkspaceHitlist::Some(matches.opt_strs("p")),
        }
    }
}

// Returns a vector of all compile targets of a crate
fn get_targets(workspace_hitlist: &WorkspaceHitlist) -> Result<Vec<Target>, std::io::Error> {
    let mut targets: Vec<Target> = vec![];
    if *workspace_hitlist == WorkspaceHitlist::None {
        let output = Command::new("cargo").arg("read-manifest").output()?;
        if output.status.success() {
            // None of the unwraps should fail if output of `cargo read-manifest` is correct
            let data = &String::from_utf8(output.stdout).unwrap();
            let json: Value = json::from_str(data).unwrap();
            let json_obj = json.as_object().unwrap();
            let jtargets = json_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }

            return Ok(targets);
        }
        return Err(std::io::Error::new(
            std::io::ErrorKind::NotFound,
            str::from_utf8(&output.stderr).unwrap(),
        ));
    }
    // This happens when cargo-fmt is not used inside a crate or
    // is used inside a workspace.
    // To ensure backward compatability, we only use `cargo metadata` for workspaces.
    // TODO: Is it possible only use metadata or read-manifest
    let output = Command::new("cargo")
        .arg("metadata")
        .arg("--no-deps")
        .output()?;
    if output.status.success() {
        let data = &String::from_utf8(output.stdout).unwrap();
        let json: Value = json::from_str(data).unwrap();
        let json_obj = json.as_object().unwrap();
        let mut hitlist: HashSet<&String> = if *workspace_hitlist != WorkspaceHitlist::All {
            HashSet::from_iter(workspace_hitlist.get_some().unwrap())
        } else {
            HashSet::new() // Unused
        };
        let members: Vec<&Value> = json_obj
            .get("packages")
            .unwrap()
            .as_array()
            .unwrap()
            .into_iter()
            .filter(|member| if *workspace_hitlist == WorkspaceHitlist::All {
                true
            } else {
                let member_obj = member.as_object().unwrap();
                let member_name = member_obj.get("name").unwrap().as_str().unwrap();
                hitlist.take(&member_name.to_string()).is_some()
            })
            .collect();
        if hitlist.is_empty() {
            // Mimick cargo of only outputting one <package> spec.
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!(
                    "package `{}` is not a member of the workspace",
                    hitlist.iter().next().unwrap()
                ),
            ));
        }
        for member in members {
            let member_obj = member.as_object().unwrap();
            let jtargets = member_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }
        }
        return Ok(targets);
    }
    Err(std::io::Error::new(
        std::io::ErrorKind::NotFound,
        str::from_utf8(&output.stderr).unwrap(),
    ))
}

fn target_from_json(jtarget: &Value) -> Target {
    let jtarget = jtarget.as_object().unwrap();
    let path = PathBuf::from(jtarget.get("src_path").unwrap().as_str().unwrap());
    let kinds = jtarget.get("kind").unwrap().as_array().unwrap();
    let kind = match kinds[0].as_str().unwrap() {
        "bin" => TargetKind::Bin,
        "lib" | "dylib" | "staticlib" | "cdylib" | "rlib" => TargetKind::Lib,
        "test" => TargetKind::Test,
        "example" => TargetKind::Example,
        "bench" => TargetKind::Bench,
        "custom-build" => TargetKind::CustomBuild,
        "proc-macro" => TargetKind::ProcMacro,
        _ => TargetKind::Other,
    };

    Target {
        path: path,
        kind: kind,
    }
}

fn format_files(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, std::io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };
    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args.iter() {
            print!(" {}", a);
        }
        for f in files.iter() {
            print!(" {}", f.display());
        }
        println!("");
    }
    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            std::io::ErrorKind::NotFound => std::io::Error::new(
                std::io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;
    command.wait()
}
<commit_msg>Avoid panicking when calling 'cargo fmt --all'<commit_after>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate getopts;
extern crate serde_json as json;

use std::env;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use std::str;
use std::collections::HashSet;
use std::iter::FromIterator;

use getopts::{Matches, Options};
use json::Value;

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

fn execute() -> i32 {
    let success = 0;
    let failure = 1;

    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    if let Some(arg) = env::args()
        .skip(2)
        .take_while(|a| a != "--")
        .find(|a| !a.starts_with('-'))
    {
        print_usage(&opts, &format!("Invalid argument: `{}`.", arg));
        return failure;
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage(&opts, &e.to_string());
            return failure;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage(&opts, "quiet mode and verbose mode are not compatible");
            return failure;
        }
    };

    if matches.opt_present("h") {
        print_usage(&opts, "");
        return success;
    }

    let workspace_hitlist = WorkspaceHitlist::from_matches(&matches);

    match format_crate(verbosity, &workspace_hitlist) {
        Err(e) => {
            print_usage(&opts, &e.to_string());
            failure
        }
        Ok(status) => if status.success() {
            success
        } else {
            status.code().unwrap_or(failure)
        },
    }
}

fn print_usage(opts: &Options, reason: &str) {
    let msg = format!("{}\nusage: cargo fmt [options]", reason);
    println!(
        "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
         Arguments after `--` are passed to rustfmt.",
        opts.usage(&msg)
    );
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn format_crate(
    verbosity: Verbosity,
    workspace_hitlist: &WorkspaceHitlist,
) -> Result<ExitStatus, std::io::Error> {
    let targets = get_targets(workspace_hitlist)?;

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .filter(|t| t.kind.should_format())
        .inspect(|t| if verbosity == Verbosity::Verbose {
            println!("[{:?}] {:?}", t.kind, t.path)
        })
        .map(|t| t.path)
        .collect();

    format_files(&files, &get_fmt_args(), verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

#[derive(Debug)]
enum TargetKind {
    Lib,         // dylib, staticlib, lib
    Bin,         // bin
    Example,     // example file
    Test,        // test file
    Bench,       // bench file
    CustomBuild, // build script
    ProcMacro,   // a proc macro implementation
    Other,       // plugin,...
}

impl TargetKind {
    fn should_format(&self) -> bool {
        match *self {
            TargetKind::Lib |
            TargetKind::Bin |
            TargetKind::Example |
            TargetKind::Test |
            TargetKind::Bench |
            TargetKind::CustomBuild |
            TargetKind::ProcMacro => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct Target {
    path: PathBuf,
    kind: TargetKind,
}

#[derive(Debug, PartialEq, Eq)]
pub enum WorkspaceHitlist {
    All,
    Some(Vec<String>),
    None,
}

impl WorkspaceHitlist {
    pub fn get_some(&self) -> Option<&[String]> {
        if let WorkspaceHitlist::Some(ref hitlist) = *self {
            Some(hitlist)
        } else {
            None
        }
    }

    pub fn from_matches(matches: &Matches) -> WorkspaceHitlist {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => WorkspaceHitlist::None,
            (true, _) => WorkspaceHitlist::All,
            (false, true) => WorkspaceHitlist::Some(matches.opt_strs("p")),
        }
    }
}

// Returns a vector of all compile targets of a crate
fn get_targets(workspace_hitlist: &WorkspaceHitlist) -> Result<Vec<Target>, std::io::Error> {
    let mut targets: Vec<Target> = vec![];
    if *workspace_hitlist == WorkspaceHitlist::None {
        let output = Command::new("cargo").arg("read-manifest").output()?;
        if output.status.success() {
            // None of the unwraps should fail if output of `cargo read-manifest` is correct
            let data = &String::from_utf8(output.stdout).unwrap();
            let json: Value = json::from_str(data).unwrap();
            let json_obj = json.as_object().unwrap();
            let jtargets = json_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }

            return Ok(targets);
        }
        return Err(std::io::Error::new(
            std::io::ErrorKind::NotFound,
            str::from_utf8(&output.stderr).unwrap(),
        ));
    }
    // This happens when cargo-fmt is not used inside a crate or
    // is used inside a workspace.
    // To ensure backward compatability, we only use `cargo metadata` for workspaces.
    // TODO: Is it possible only use metadata or read-manifest
    let output = Command::new("cargo")
        .arg("metadata")
        .arg("--no-deps")
        .output()?;
    if output.status.success() {
        let data = &String::from_utf8(output.stdout).unwrap();
        let json: Value = json::from_str(data).unwrap();
        let json_obj = json.as_object().unwrap();
        let mut hitlist: HashSet<&String> = if *workspace_hitlist != WorkspaceHitlist::All {
            HashSet::from_iter(workspace_hitlist.get_some().unwrap())
        } else {
            HashSet::new() // Unused
        };
        let members: Vec<&Value> = json_obj
            .get("packages")
            .unwrap()
            .as_array()
            .unwrap()
            .into_iter()
            .filter(|member| if *workspace_hitlist == WorkspaceHitlist::All {
                true
            } else {
                let member_obj = member.as_object().unwrap();
                let member_name = member_obj.get("name").unwrap().as_str().unwrap();
                hitlist.take(&member_name.to_string()).is_some()
            })
            .collect();
        if !hitlist.is_empty() {
            // Mimick cargo of only outputting one <package> spec.
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!(
                    "package `{}` is not a member of the workspace",
                    hitlist.iter().next().unwrap()
                ),
            ));
        }
        for member in members {
            let member_obj = member.as_object().unwrap();
            let jtargets = member_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }
        }
        return Ok(targets);
    }
    Err(std::io::Error::new(
        std::io::ErrorKind::NotFound,
        str::from_utf8(&output.stderr).unwrap(),
    ))
}

fn target_from_json(jtarget: &Value) -> Target {
    let jtarget = jtarget.as_object().unwrap();
    let path = PathBuf::from(jtarget.get("src_path").unwrap().as_str().unwrap());
    let kinds = jtarget.get("kind").unwrap().as_array().unwrap();
    let kind = match kinds[0].as_str().unwrap() {
        "bin" => TargetKind::Bin,
        "lib" | "dylib" | "staticlib" | "cdylib" | "rlib" => TargetKind::Lib,
        "test" => TargetKind::Test,
        "example" => TargetKind::Example,
        "bench" => TargetKind::Bench,
        "custom-build" => TargetKind::CustomBuild,
        "proc-macro" => TargetKind::ProcMacro,
        _ => TargetKind::Other,
    };

    Target {
        path: path,
        kind: kind,
    }
}

fn format_files(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, std::io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };
    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args.iter() {
            print!(" {}", a);
        }
        for f in files.iter() {
            print!(" {}", f.display());
        }
        println!("");
    }
    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            std::io::ErrorKind::NotFound => std::io::Error::new(
                std::io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;
    command.wait()
}
<|endoftext|>