<commit_before>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std::collections::BTreeMap;
use std::fmt;
use std::result;

use hab_core;
use hab_core::package::{self, Identifiable, FromArchive, PackageArchive};
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
use rustc_serialize::json::{Json, ToJson};
use protobuf;

use message::Persistable;

pub use message::depotsrv::*;

impl Decodable for OriginKeyIdent {
    fn decode<D: Decoder>(d: &mut D) -> result::Result<Self, D::Error> {
        d.read_struct("OriginKeyIdent", 3, |d| {
            let mut ident = OriginKeyIdent::new();
            ident.set_origin(try!(d.read_struct_field("origin", 0, |d| Decodable::decode(d))));
            ident.set_revision(try!(d.read_struct_field("revision", 1, |d| Decodable::decode(d))));
            ident.set_location(try!(d.read_struct_field("location", 2, |d| Decodable::decode(d))));
            Ok(ident)
        })
    }
}

impl Decodable for Package {
    fn decode<D: Decoder>(d: &mut D) -> result::Result<Self, D::Error> {
        d.read_struct("Package", 7, |d| {
            let mut package = Package::new();
            package.set_ident(try!(d.read_struct_field("ident", 0, |d| Decodable::decode(d))));
            package.set_checksum(try!(d.read_struct_field("checksum", 1, |d| Decodable::decode(d))));
            package.set_manifest(try!(d.read_struct_field("manifest", 2, |d| Decodable::decode(d))));
            let deps: Vec<PackageIdent> = try!(d.read_struct_field("deps", 3, |d| Decodable::decode(d)));
            package.set_deps(protobuf::RepeatedField::from_vec(deps));
            let tdeps: Vec<PackageIdent> = try!(d.read_struct_field("tdeps", 4, |d| Decodable::decode(d)));
            package.set_tdeps(protobuf::RepeatedField::from_vec(tdeps));
            package.set_exposes(try!(d.read_struct_field("exposes", 5, |d| Decodable::decode(d))));
            package.set_config(try!(d.read_struct_field("config", 6, |d| Decodable::decode(d))));
            Ok(package)
        })
    }
}

impl Decodable for PackageIdent {
    fn decode<D: Decoder>(d: &mut D) -> result::Result<Self, D::Error> {
        d.read_struct("PackageIdent", 4, |d| {
            let mut ident = PackageIdent::new();
            ident.set_origin(try!(d.read_struct_field("origin", 0, |d| Decodable::decode(d))));
            ident.set_name(try!(d.read_struct_field("name", 1, |d| Decodable::decode(d))));
            ident.set_version(try!(d.read_struct_field("version", 2, |d| Decodable::decode(d))));
            ident.set_release(try!(d.read_struct_field("release", 3, |d| Decodable::decode(d))));
            Ok(ident)
        })
    }
}

impl Encodable for PackageIdent {
    fn encode<S: Encoder>(&self, s: &mut S) -> result::Result<(), S::Error> {
        try!(s.emit_struct("PackageIdent", 4, |s| {
            try!(s.emit_struct_field("origin", 0, |s| self.get_origin().encode(s)));
            try!(s.emit_struct_field("name", 1, |s| self.get_name().encode(s)));
            if !self.get_version().is_empty() {
                try!(s.emit_struct_field("version", 2, |s| self.get_version().encode(s)));
            }
            if !self.get_release().is_empty() {
                try!(s.emit_struct_field("release", 3, |s| self.get_release().encode(s)));
            }
            Ok(())
        }));
        Ok(())
    }
}

impl Into<package::PackageIdent> for PackageIdent {
    fn into(self) -> package::PackageIdent {
        package::PackageIdent::new(self.get_origin(),
                                   self.get_name(),
                                   Some(self.get_version()),
                                   Some(self.get_release()))
    }
}

impl Into<package::PackageIdent> for Package {
    fn into(self) -> package::PackageIdent {
        self.get_ident().clone().into()
    }
}

impl fmt::Display for PackageIdent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if !self.get_version().is_empty() && !self.get_release().is_empty() {
            write!(f,
                   "{}/{}/{}/{}",
                   self.get_origin(),
                   self.get_name(),
                   self.get_version(),
                   self.get_release())
        } else if !self.get_version().is_empty() {
            write!(f,
                   "{}/{}/{}",
                   self.get_origin(),
                   self.get_name(),
                   self.get_version())
        } else {
            write!(f, "{}/{}", self.get_origin(), self.get_name())
        }
    }
}

impl fmt::Display for Package {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.get_ident().fmt(f)
    }
}

impl Persistable for Package {
    type Key = PackageIdent;

    fn primary_key(&self) -> Self::Key {
        self.get_ident().clone()
    }

    fn set_primary_key(&mut self, value: Self::Key) {
        self.set_ident(value);
    }
}

impl Persistable for View {
    type Key = String;

    fn primary_key(&self) -> Self::Key {
        self.get_name().to_string()
    }

    fn set_primary_key(&mut self, value: Self::Key) {
        self.set_name(value);
    }
}

impl FromArchive for Package {
    type Error = hab_core::Error;

    fn from_archive(archive: &mut PackageArchive) -> hab_core::Result<Self> {
        let ident = match archive.ident() {
            Ok(value) => PackageIdent::from(value),
            Err(e) => return Err(hab_core::Error::from(e)),
        };
        let manifest = try!(archive.manifest());
        let deps = try!(archive.deps()).into_iter().map(|d| d.into()).collect();
        let tdeps = try!(archive.tdeps()).into_iter().map(|d| d.into()).collect();
        let exposes = try!(archive.exposes()).into_iter().map(|d| d as u32).collect();
        let config = try!(archive.config());
        let checksum = try!(archive.checksum());

        let mut package = Package::new();
        package.set_ident(ident);
        package.set_manifest(manifest);
        package.set_deps(deps);
        package.set_tdeps(tdeps);
        package.set_exposes(exposes);
        if let Some(cfg) = config {
            package.set_config(cfg);
        }
        package.set_checksum(checksum);
        Ok(package)
    }
}

impl From<hab_core::package::PackageIdent> for PackageIdent {
    fn from(value: hab_core::package::PackageIdent) -> PackageIdent {
        let mut ident = PackageIdent::new();
        ident.set_origin(value.origin);
        ident.set_name(value.name);
        if let Some(ver) = value.version {
            ident.set_version(ver);
        }
        if let Some(rel) = value.release {
            ident.set_release(rel);
        }
        ident
    }
}

impl Identifiable for Package {
    fn origin(&self) -> &str {
        self.get_ident().get_origin()
    }

    fn name(&self) -> &str {
        self.get_ident().get_name()
    }

    fn version(&self) -> Option<&str> {
        let ver = self.get_ident().get_version();
        if ver.is_empty() {
            None
        } else {
            Some(ver)
        }
    }

    fn release(&self) -> Option<&str> {
        let rel = self.get_ident().get_release();
        if rel.is_empty() {
            None
        } else {
            Some(rel)
        }
    }
}

impl Identifiable for PackageIdent {
    fn origin(&self) -> &str {
        self.get_origin()
    }

    fn name(&self) -> &str {
        self.get_name()
    }

    fn version(&self) -> Option<&str> {
        let ver = self.get_version();
        if ver.is_empty() {
            None
        } else {
            Some(ver)
        }
    }

    fn release(&self) -> Option<&str> {
        let rel = self.get_release();
        if rel.is_empty() {
            None
        } else {
            Some(rel)
        }
    }
}

impl ToJson for OriginKeyIdent {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        m.insert("origin".to_string(), self.get_origin().to_json());
        m.insert("revision".to_string(), self.get_revision().to_json());
        m.insert("location".to_string(), self.get_location().to_json());
        Json::Object(m)
    }
}

impl ToJson for PackageIdent {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        let ver = self.get_version();
        let rel = self.get_release();
        m.insert("origin".to_string(), self.get_origin().to_json());
        m.insert("name".to_string(), self.get_name().to_json());
        if !ver.is_empty() {
            m.insert("version".to_string(), ver.to_json());
        }
        if !rel.is_empty() {
            m.insert("release".to_string(), rel.to_json());
        }
        Json::Object(m)
    }
}

impl ToJson for Package {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        m.insert("ident".to_string(), self.get_ident().to_string().to_json());
        m.insert("checksum".to_string(), self.get_checksum().to_json());
        m.insert("manifest".to_string(), self.get_manifest().to_json());
        m.insert("deps".to_string(), self.get_deps().to_vec().to_json());
        m.insert("tdeps".to_string(), self.get_tdeps().to_vec().to_json());
        m.insert("exposes".to_string(), self.get_exposes().to_json());
        m.insert("config".to_string(), self.get_config().to_json());
        Json::Object(m)
    }
}
<commit_msg>fix JSON encoding/decoding of Package/PackageIdent msgs<commit_after>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std::collections::BTreeMap;
use std::fmt;
use std::result;

use hab_core;
use hab_core::package::{self, Identifiable, FromArchive, PackageArchive};
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
use rustc_serialize::json::{Json, ToJson};
use protobuf;

use message::Persistable;

pub use message::depotsrv::*;

impl Decodable for OriginKeyIdent {
    fn decode<D: Decoder>(d: &mut D) -> result::Result<Self, D::Error> {
        d.read_struct("OriginKeyIdent", 3, |d| {
            let mut ident = OriginKeyIdent::new();
            ident.set_origin(try!(d.read_struct_field("origin", 0, |d| Decodable::decode(d))));
            ident.set_revision(try!(d.read_struct_field("revision", 1, |d| Decodable::decode(d))));
            ident.set_location(try!(d.read_struct_field("location", 2, |d| Decodable::decode(d))));
            Ok(ident)
        })
    }
}

impl Decodable for Package {
    fn decode<D: Decoder>(d: &mut D) -> result::Result<Self, D::Error> {
        d.read_struct("Package", 7, |d| {
            let mut package = Package::new();
            package.set_ident(try!(d.read_struct_field("ident", 0, |d| Decodable::decode(d))));
            package.set_checksum(try!(d.read_struct_field("checksum", 1, |d| Decodable::decode(d))));
            package.set_manifest(try!(d.read_struct_field("manifest", 2, |d| Decodable::decode(d))));
            let deps: Vec<PackageIdent> = try!(d.read_struct_field("deps", 3, |d| Decodable::decode(d)));
            package.set_deps(protobuf::RepeatedField::from_vec(deps));
            let tdeps: Vec<PackageIdent> = try!(d.read_struct_field("tdeps", 4, |d| Decodable::decode(d)));
            package.set_tdeps(protobuf::RepeatedField::from_vec(tdeps));
            package.set_exposes(try!(d.read_struct_field("exposes", 5, |d| Decodable::decode(d))));
            if let Some(cfg) = try!(d.read_struct_field("config", 6, |d| Ok(Decodable::decode(d).ok()))) {
                package.set_config(cfg);
            }
            Ok(package)
        })
    }
}

impl Decodable for PackageIdent {
    fn decode<D: Decoder>(d: &mut D) -> result::Result<Self, D::Error> {
        d.read_struct("PackageIdent", 4, |d| {
            let mut ident = PackageIdent::new();
            ident.set_origin(try!(d.read_struct_field("origin", 0, |d| Decodable::decode(d))));
            ident.set_name(try!(d.read_struct_field("name", 1, |d| Decodable::decode(d))));
            ident.set_version(try!(d.read_struct_field("version", 2, |d| Decodable::decode(d))));
            ident.set_release(try!(d.read_struct_field("release", 3, |d| Decodable::decode(d))));
            Ok(ident)
        })
    }
}

impl Encodable for PackageIdent {
    fn encode<S: Encoder>(&self, s: &mut S) -> result::Result<(), S::Error> {
        try!(s.emit_struct("PackageIdent", 4, |s| {
            try!(s.emit_struct_field("origin", 0, |s| self.get_origin().encode(s)));
            try!(s.emit_struct_field("name", 1, |s| self.get_name().encode(s)));
            if !self.get_version().is_empty() {
                try!(s.emit_struct_field("version", 2, |s| self.get_version().encode(s)));
            }
            if !self.get_release().is_empty() {
                try!(s.emit_struct_field("release", 3, |s| self.get_release().encode(s)));
            }
            Ok(())
        }));
        Ok(())
    }
}

impl Into<package::PackageIdent> for PackageIdent {
    fn into(self) -> package::PackageIdent {
        package::PackageIdent::new(self.get_origin(),
                                   self.get_name(),
                                   Some(self.get_version()),
                                   Some(self.get_release()))
    }
}

impl Into<package::PackageIdent> for Package {
    fn into(self) -> package::PackageIdent {
        self.get_ident().clone().into()
    }
}

impl fmt::Display for PackageIdent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if !self.get_version().is_empty() && !self.get_release().is_empty() {
            write!(f,
                   "{}/{}/{}/{}",
                   self.get_origin(),
                   self.get_name(),
                   self.get_version(),
                   self.get_release())
        } else if !self.get_version().is_empty() {
            write!(f,
                   "{}/{}/{}",
                   self.get_origin(),
                   self.get_name(),
                   self.get_version())
        } else {
            write!(f, "{}/{}", self.get_origin(), self.get_name())
        }
    }
}

impl fmt::Display for Package {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.get_ident().fmt(f)
    }
}

impl Persistable for Package {
    type Key = PackageIdent;

    fn primary_key(&self) -> Self::Key {
        self.get_ident().clone()
    }

    fn set_primary_key(&mut self, value: Self::Key) {
        self.set_ident(value);
    }
}

impl Persistable for View {
    type Key = String;

    fn primary_key(&self) -> Self::Key {
        self.get_name().to_string()
    }

    fn set_primary_key(&mut self, value: Self::Key) {
        self.set_name(value);
    }
}

impl FromArchive for Package {
    type Error = hab_core::Error;

    fn from_archive(archive: &mut PackageArchive) -> hab_core::Result<Self> {
        let ident = match archive.ident() {
            Ok(value) => PackageIdent::from(value),
            Err(e) => return Err(hab_core::Error::from(e)),
        };
        let manifest = try!(archive.manifest());
        let deps = try!(archive.deps()).into_iter().map(|d| d.into()).collect();
        let tdeps = try!(archive.tdeps()).into_iter().map(|d| d.into()).collect();
        let exposes = try!(archive.exposes()).into_iter().map(|d| d as u32).collect();
        let config = try!(archive.config());
        let checksum = try!(archive.checksum());

        let mut package = Package::new();
        package.set_ident(ident);
        package.set_manifest(manifest);
        package.set_deps(deps);
        package.set_tdeps(tdeps);
        package.set_exposes(exposes);
        if let Some(cfg) = config {
            package.set_config(cfg);
        }
        package.set_checksum(checksum);
        Ok(package)
    }
}

impl From<hab_core::package::PackageIdent> for PackageIdent {
    fn from(value: hab_core::package::PackageIdent) -> PackageIdent {
        let mut ident = PackageIdent::new();
        ident.set_origin(value.origin);
        ident.set_name(value.name);
        if let Some(ver) = value.version {
            ident.set_version(ver);
        }
        if let Some(rel) = value.release {
            ident.set_release(rel);
        }
        ident
    }
}

impl Identifiable for Package {
    fn origin(&self) -> &str {
        self.get_ident().get_origin()
    }

    fn name(&self) -> &str {
        self.get_ident().get_name()
    }

    fn version(&self) -> Option<&str> {
        let ver = self.get_ident().get_version();
        if ver.is_empty() {
            None
        } else {
            Some(ver)
        }
    }

    fn release(&self) -> Option<&str> {
        let rel = self.get_ident().get_release();
        if rel.is_empty() {
            None
        } else {
            Some(rel)
        }
    }
}

impl Identifiable for PackageIdent {
    fn origin(&self) -> &str {
        self.get_origin()
    }

    fn name(&self) -> &str {
        self.get_name()
    }

    fn version(&self) -> Option<&str> {
        let ver = self.get_version();
        if ver.is_empty() {
            None
        } else {
            Some(ver)
        }
    }

    fn release(&self) -> Option<&str> {
        let rel = self.get_release();
        if rel.is_empty() {
            None
        } else {
            Some(rel)
        }
    }
}

impl ToJson for OriginKeyIdent {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        m.insert("origin".to_string(), self.get_origin().to_json());
        m.insert("revision".to_string(), self.get_revision().to_json());
        m.insert("location".to_string(), self.get_location().to_json());
        Json::Object(m)
    }
}

impl ToJson for PackageIdent {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        let ver = self.get_version();
        let rel = self.get_release();
        m.insert("origin".to_string(), self.get_origin().to_json());
        m.insert("name".to_string(), self.get_name().to_json());
        if !ver.is_empty() {
            m.insert("version".to_string(), ver.to_json());
        }
        if !rel.is_empty() {
            m.insert("release".to_string(), rel.to_json());
        }
        Json::Object(m)
    }
}

impl ToJson for Package {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        m.insert("ident".to_string(), self.get_ident().to_json());
        m.insert("checksum".to_string(), self.get_checksum().to_json());
        m.insert("manifest".to_string(), self.get_manifest().to_json());
        m.insert("deps".to_string(), self.get_deps().to_vec().to_json());
        m.insert("tdeps".to_string(), self.get_tdeps().to_vec().to_json());
        m.insert("exposes".to_string(), self.get_exposes().to_json());
        m.insert("config".to_string(), self.get_config().to_json());
        Json::Object(m)
    }
}
<|endoftext|>


<commit_before>use dsp;
use dsp::Sample;
use dsp::Frame;
use dsp::Node;
use num;
use std::iter::Iterator;
use frontend::audio::SoundEffect;
use std::f32;

const CHANNELS: i32 = super::CHANNELS;

trait Sampling {
	fn sample(&self, position: f32, phase: f32) -> f32;
	fn pitch(&self, position: f32) -> f32;
	fn has_sample(&self, position: f32) -> bool;
}

// TODO: genericise this
struct SinWave {
	pitch: f32,
	length: f32,
	amplitude: f32,
}

struct SquareWave {
	pitch: f32,
	length: f32,
	amplitude: f32,
}

impl Sampling for SinWave {
	#[inline]
	fn sample(&self, position: f32, phase: f32) -> f32 {
		let envelope = num::clamp(1.0f32 - position / self.length, 0.0f32, 1.0f32);
		envelope * self.amplitude * (phase * f32::consts::PI * 2.0).sin()
	}
	#[inline]
	fn pitch(&self, _: f32) -> f32 {
		self.pitch
	}
	#[inline]
	fn has_sample(&self, position: f32) -> bool {
		position < self.length
	}
}

// Just to introduce a different generator
impl Sampling for SquareWave {
	#[inline]
	fn sample(&self, position: f32, phase: f32) -> f32 {
		let envelope = num::clamp(1.0f32 - position / self.length, 0.0f32, 1.0f32);
		envelope * self.amplitude * (phase * f32::consts::PI * 2.0).sin().signum() // TODO: quick and dirty and overkill. Remove sin()
	}
	#[inline]
	fn pitch(&self, _: f32) -> f32 {
		self.pitch
	}
	#[inline]
	fn has_sample(&self, position: f32) -> bool {
		position < self.length
	}
}

enum Generator {
	Sin(SinWave),
	Square(SquareWave),
	Silence,
}

impl Generator {
	fn sin(pitch: f32, length: f32, amplitude: f32) -> Generator {
		Generator::Sin(SinWave { pitch, length, amplitude })
	}
	fn square(pitch: f32, length: f32, amplitude: f32) -> Generator {
		Generator::Square(SquareWave { pitch, length, amplitude })
	}
}

impl Sampling for Generator {
	#[inline]
	fn sample(&self, position: f32, phase: f32) -> f32 {
		match self {
			&Generator::Sin(ref wave) => wave.sample(position, phase),
			&Generator::Square(ref wave) => wave.sample(position, phase),
			_ => 0.0f32,
		}
	}
	#[inline]
	fn pitch(&self, position: f32) -> f32 {
		match self {
			&Generator::Sin(ref wave) => wave.pitch(position),
			&Generator::Square(ref wave) => wave.pitch(position),
			_ => 1.0f32,
		}
	}
	#[inline]
	fn has_sample(&self, position: f32) -> bool {
		match self {
			&Generator::Sin(ref wave) => wave.has_sample(position),
			&Generator::Square(ref wave) => wave.has_sample(position),
			_ => false
		}
	}
}

enum DspNode {
	Voice {
		index: usize,
		generator: Generator,
		phase: f32,
		position: f32,
		pan: f32,
		allocated: bool,
	},
	Mixer(f32),
}

impl DspNode {
	fn new_voice(index: usize, generator: Generator) -> DspNode {
		DspNode::Voice {
			index,
			generator,
			phase: 0.0f32,
			position: 0.0f32,
			pan: 0.5f32,
			allocated: false,
		}
	}
}

pub struct Multiplexer {
	graph: dsp::Graph<[f32; CHANNELS as usize], DspNode>,
}

impl Multiplexer {
	pub fn new() -> Multiplexer {
		// Construct our dsp graph.
		let mut graph = dsp::Graph::new();

		let mixer = graph.add_node(DspNode::Mixer(0.5f32));
		const VOICES: usize = 8;
		for index in 0..VOICES {
			graph.add_input(DspNode::new_voice(index, Generator::Silence), mixer);
		}
		// graph.set_master(Some(volume));
		graph.set_master(Some(mixer));

		Multiplexer {
			graph,
		}
	}

	pub fn audio_requested(&mut self, buffer: &mut [[f32; CHANNELS as usize]], sample_hz: f64) {
		self.graph.audio_requested(buffer, sample_hz)
	}

	pub fn trigger(&mut self, effect: SoundEffect) {
		// Sweeps through completed samples
		for node in self.graph.nodes_mut() {
			match node {
				&mut DspNode::Voice { index, position, ref generator, ref mut allocated, .. } => {
					if *allocated && !generator.has_sample(position) {
						*allocated = false;
						trace!("Voice {} is available", index);
					}
				}
				_ => {}
			}
		}

		let (new_generator, new_pan) = match effect {
			SoundEffect::Click(_) => (Generator::square(880.0f32, 0.1f32, 0.1f32), 0.8f32),
			//SoundEffect::Release(_) => Some((400.0f32, 0.15f32, 0.3f32)),
			SoundEffect::UserOption => (Generator::square(1000.0f32, 0.1f32, 0.1f32), 0.6f32),
			SoundEffect::Fertilised => (Generator::sin(300.0f32, 0.3f32, 0.1f32), 0.6f32),
			SoundEffect::NewSpore => (Generator::sin(150.0f32, 0.3f32, 0.1f32), 0.3f32),
			SoundEffect::NewMinion => (Generator::sin(600.0f32, 0.5f32, 0.1f32), 0.55f32),
			SoundEffect::DieMinion => (Generator::sin(90.0f32, 1.0f32, 0.2f32), 0.1f32),
			_ => (Generator::Silence, 0.5f32)
		};
		// Finds the first available voice
		let mut free_voice = self.graph.nodes_mut().find(|n| match n {
			&&mut DspNode::Voice { allocated, .. } => !allocated,
			_ => false
		});
		// Resets the voice's phase and grabs it
		free_voice.as_mut().map(|n| {
			match n {
				&mut &mut DspNode::Voice {
					index, ref mut phase, ref mut position, ref mut pan,
					ref mut allocated, ref mut generator, ..
				} => {
					*phase = 0.0f32;
					*position = 0.0f32;
					*generator = new_generator;
					*pan = new_pan;
					*allocated = true;
					trace!("Voice {} playing", index);
				}
				_ => ()
			}
		});
	}
}

/// Our Node to be used within the Graph.
/// Implement the `Node` trait for our DspNode.
impl dsp::Node<[f32; CHANNELS as usize]> for DspNode {
	fn audio_requested(&mut self, buffer: &mut [[f32; CHANNELS as usize]], sample_hz: f64) {
		match *self {
			DspNode::Voice { ref mut phase, ref mut position, ref generator, allocated, pan, .. } => {
				dsp::slice::equilibrium(buffer);
				let c_pan: [f32; CHANNELS as usize] = [1.0f32 - pan, pan];
				if allocated {
					let dt = 1.0f32 / sample_hz as f32;
					dsp::slice::map_in_place(buffer, |_| {
						let val = generator.sample(*position, *phase);
						let dp = generator.pitch(*position) / sample_hz as f32;
						*phase += dp;
						*position += dt;
						dsp::Frame::from_fn(|channel| (val * c_pan[channel]).to_sample())
					})
				}
			}
			DspNode::Mixer(vol) => {
				dsp::slice::map_in_place(buffer, |f|
					f.map(|s| s.mul_amp(vol)))
			}
		}
	}
}
<commit_msg>Simplifying audio processing<commit_after>use dsp;
use dsp::Sample;
use dsp::Frame;
use dsp::Node;
use clock::Seconds;
use num;
use std::iter::Iterator;
use frontend::audio::SoundEffect;
use std::f32;

const CHANNELS: i32 = super::CHANNELS;

trait Sampling {
	fn sample(&self, position: f32, phase: f32) -> f32;
	fn pitch(&self, position: f32) -> f32;
	fn has_sample(&self, position: f32) -> bool;
}

struct Signal<S, F> where S: num::Float {
	sample_rate: S,
	frames: Box<[F]>,
}

// TODO: genericise this
struct SinWave {
	pitch: f32,
	length: f32,
	amplitude: f32,
}

struct SquareWave {
	pitch: f32,
	length: f32,
	amplitude: f32,
}

impl Sampling for SinWave {
	#[inline]
	fn sample(&self, position: f32, phase: f32) -> f32 {
		let envelope = num::clamp(1.0f32 - position / self.length, 0.0f32, 1.0f32);
		envelope * self.amplitude * (phase * f32::consts::PI * 2.0).sin()
	}
	#[inline]
	fn pitch(&self, _: f32) -> f32 {
		self.pitch
	}
	#[inline]
	fn has_sample(&self, position: f32) -> bool {
		position < self.length
	}
}

// Just to introduce a different generator
impl Sampling for SquareWave {
	#[inline]
	fn sample(&self, position: f32, phase: f32) -> f32 {
		let envelope = num::clamp(1.0f32 - position / self.length, 0.0f32, 1.0f32);
		envelope * self.amplitude * (phase * f32::consts::PI * 2.0).sin().signum() // TODO: quick and dirty and overkill. Remove sin()
	}
	#[inline]
	fn pitch(&self, _: f32) -> f32 {
		self.pitch
	}
	#[inline]
	fn has_sample(&self, position: f32) -> bool {
		position < self.length
	}
}

enum Generator {
	Sin(SinWave),
	Square(SquareWave),
	Silence,
}

impl Generator {
	fn sin(pitch: f32, length: f32, amplitude: f32) -> Generator {
		Generator::Sin(SinWave { pitch, length, amplitude })
	}
	fn square(pitch: f32, length: f32, amplitude: f32) -> Generator {
		Generator::Square(SquareWave { pitch, length, amplitude })
	}
}

impl Sampling for Generator {
	#[inline]
	fn sample(&self, position: f32, phase: f32) -> f32 {
		match self {
			&Generator::Sin(ref wave) => wave.sample(position, phase),
			&Generator::Square(ref wave) => wave.sample(position, phase),
			_ => 0.0f32,
		}
	}
	#[inline]
	fn pitch(&self, position: f32) -> f32 {
		match self {
			&Generator::Sin(ref wave) => wave.pitch(position),
			&Generator::Square(ref wave) => wave.pitch(position),
			_ => 1.0f32,
		}
	}
	#[inline]
	fn has_sample(&self, position: f32) -> bool {
		match self {
			&Generator::Sin(ref wave) => wave.has_sample(position),
			&Generator::Square(ref wave) => wave.has_sample(position),
			_ => false
		}
	}
}

enum DspNode {
	Voice {
		index: usize,
		generator: Generator,
		phase: f32,
		position: f32,
		pan: f32,
		allocated: bool,
	},
	Mixer(f32),
}

impl DspNode {
	fn new_voice(index: usize, generator: Generator) -> DspNode {
		DspNode::Voice {
			index,
			generator,
			phase: 0.0f32,
			position: 0.0f32,
			pan: 0.5f32,
			allocated: false,
		}
	}
}

pub struct Multiplexer {
	graph: dsp::Graph<[f32; CHANNELS as usize], DspNode>,
}

impl Multiplexer {
	pub fn new() -> Multiplexer {
		// Construct our dsp graph.
		let mut graph = dsp::Graph::new();

		let mixer = graph.add_node(DspNode::Mixer(0.5f32));
		const VOICES: usize = 8;
		for index in 0..VOICES {
			graph.add_input(DspNode::new_voice(index, Generator::Silence), mixer);
		}
		// graph.set_master(Some(volume));
		graph.set_master(Some(mixer));

		Multiplexer {
			graph,
		}
	}

	pub fn audio_requested(&mut self, buffer: &mut [[f32; CHANNELS as usize]], sample_hz: f64) {
		self.graph.audio_requested(buffer, sample_hz)
	}

	pub fn trigger(&mut self, effect: SoundEffect) {
		// Sweeps through completed samples
		for node in self.graph.nodes_mut() {
			match node {
				&mut DspNode::Voice { index, position, ref generator, ref mut allocated, .. } => {
					if *allocated && !generator.has_sample(position) {
						*allocated = false;
						trace!("Voice {} is available", index);
					}
				}
				_ => {}
			}
		}

		let (new_generator, new_pan) = match effect {
			SoundEffect::Click(_) => (Generator::square(880.0f32, 0.1f32, 0.1f32), 0.8f32),
			//SoundEffect::Release(_) => Some((400.0f32, 0.15f32, 0.3f32)),
			SoundEffect::UserOption => (Generator::square(1000.0f32, 0.1f32, 0.1f32), 0.6f32),
			SoundEffect::Fertilised => (Generator::sin(300.0f32, 0.3f32, 0.1f32), 0.6f32),
			SoundEffect::NewSpore => (Generator::sin(150.0f32, 0.3f32, 0.1f32), 0.3f32),
			SoundEffect::NewMinion => (Generator::sin(600.0f32, 0.5f32, 0.1f32), 0.55f32),
			SoundEffect::DieMinion => (Generator::sin(90.0f32, 1.0f32, 0.2f32), 0.1f32),
			_ => (Generator::Silence, 0.5f32)
		};
		// Finds the first available voice
		let mut free_voice = self.graph.nodes_mut().find(|n| match n {
			&&mut DspNode::Voice { allocated, .. } => !allocated,
			_ => false
		});
		// Resets the voice's phase and grabs it
		free_voice.as_mut().map(|n| {
			match n {
				&mut &mut DspNode::Voice {
					index, ref mut phase, ref mut position, ref mut pan,
					ref mut allocated, ref mut generator, ..
				} => {
					*phase = 0.0f32;
					*position = 0.0f32;
					*generator = new_generator;
					*pan = new_pan;
					*allocated = true;
					trace!("Voice {} playing", index);
				}
				_ => ()
			}
		});
	}
}

impl Signal<f32, f32> {
	fn new(g: Generator, sample_rate: f32, pitch: f32, duration : Seconds  ) {
		let samples = g.length / g.pitch;
		let frames = Vec::with_capacity(samples);
		for i in 0..samples {
			let sample =
			frames.push(sample)
		}
	}

	fn duration(&self) -> Seconds {
		self.sample_rate * self.frames.len()
	}
}

/// Our Node to be used within the Graph.
/// Implement the `Node` trait for our DspNode.
impl dsp::Node<[f32; CHANNELS as usize]> for DspNode {
	fn audio_requested(&mut self, buffer: &mut [[f32; CHANNELS as usize]], sample_hz: f64) {
		match *self {
			DspNode::Voice { ref mut phase, ref mut position, ref generator, allocated, pan, .. } => {
				dsp::slice::equilibrium(buffer);
				let c_pan: [f32; CHANNELS as usize] = [1.0f32 - pan, pan];
				if allocated {
					let dt = 1.0f32 / sample_hz as f32;
					dsp::slice::map_in_place(buffer, |_| {
						let val = generator.sample(*position, *phase);
						let dp = generator.pitch(*position) / sample_hz as f32;
						*phase += dp;
						*position += dt;
						dsp::Frame::from_fn(|channel| (val * c_pan[channel]).to_sample())
					})
				}
			}
			DspNode::Mixer(vol) => {
				dsp::slice::map_in_place(buffer, |f|
					f.map(|s| s.mul_amp(vol)))
			}
		}
	}
}
<|endoftext|>


<commit_before>#![deny(
    absolute_paths_not_starting_with_crate,
    ambiguous_associated_items,
    anonymous_parameters,
    arithmetic_overflow,
    array_into_iter,
    asm_sub_register,
    bad_asm_style,
    bindings_with_variant_name,
    break_with_label_and_loop,
    cenum_impl_drop_cast,
    clashing_extern_declarations,
    coherence_leak_check,
    conflicting_repr_hints,
    confusable_idents,
    const_err,
    const_evaluatable_unchecked,
    const_item_mutation,
    dead_code,
    deprecated,
    deprecated_cfg_attr_crate_type_name,
    deprecated_in_future,
    deref_into_dyn_supertrait,
    deref_nullptr,
    drop_bounds,
    duplicate_macro_attributes,
    dyn_drop,
    ellipsis_inclusive_range_patterns,
    enum_intrinsics_non_enums,
    explicit_outlives_requirements,
    exported_private_dependencies,
    forbidden_lint_groups,
    function_item_references,
    ill_formed_attribute_input,
    illegal_floating_point_literal_pattern,
    improper_ctypes,
    improper_ctypes_definitions,
    incomplete_features,
    incomplete_include,
    indirect_structural_match,
    ineffective_unstable_trait_impl,
    inline_no_sanitize,
    invalid_atomic_ordering,
    invalid_doc_attributes,
    invalid_type_param_default,
    invalid_value,
    irrefutable_let_patterns,
    keyword_idents,
    large_assignments,
    late_bound_lifetime_arguments,
    legacy_derive_helpers,
    macro_expanded_macro_exports_accessed_by_absolute_paths,
    meta_variable_misuse,
    missing_abi,
    missing_copy_implementations,
    missing_docs,
    missing_fragment_specifier,
    mixed_script_confusables,
    mutable_borrow_reservation_conflict,
    mutable_transmutes,
    named_asm_labels,
    no_mangle_const_items,
    no_mangle_generic_items,
    non_ascii_idents,
    non_camel_case_types,
    non_fmt_panics,
    non_shorthand_field_patterns,
    non_snake_case,
    non_upper_case_globals,
    nontrivial_structural_match,
    noop_method_call,
    order_dependent_trait_objects,
    overflowing_literals,
    overlapping_range_endpoints,
    path_statements,
    patterns_in_fns_without_body,
    pointer_structural_match,
    private_in_public,
    proc_macro_back_compat,
    proc_macro_derive_resolution_fallback,
    pub_use_of_private_extern_crate,
    redundant_semicolons,
    rust_2021_incompatible_closure_captures,
    rust_2021_incompatible_or_patterns,
    rust_2021_prefixes_incompatible_syntax,
    rust_2021_prelude_collisions,
    semicolon_in_expressions_from_macros,
    soft_unstable,
    stable_features,
    temporary_cstring_as_ptr,
    text_direction_codepoint_in_comment,
    text_direction_codepoint_in_literal,
    trivial_bounds,
    trivial_casts,
    trivial_numeric_casts,
    type_alias_bounds,
    tyvar_behind_raw_pointer,
    unaligned_references,
    uncommon_codepoints,
    unconditional_panic,
    unconditional_recursion,
    uninhabited_static,
    unknown_crate_types,
    unnameable_test_items,
    unreachable_code,
    unreachable_patterns,
    unreachable_pub,
    unsafe_code,
    unsafe_op_in_unsafe_fn,
    unstable_features,
    unstable_name_collisions,
    unsupported_calling_conventions,
    unsupported_naked_functions,
    unused_allocation,
    unused_assignments,
    unused_assignments,
    unused_attributes,
    unused_braces,
    unused_comparisons,
    unused_crate_dependencies,
    unused_doc_comments,
    unused_extern_crates,
    unused_features,
    unused_import_braces,
    unused_imports,
    unused_labels,
    unused_lifetimes,
    unused_macros,
    unused_must_use,
    unused_mut,
    unused_parens,
    unused_qualifications,
    unused_unsafe,
    unused_variables,
    useless_deprecated,
    where_clauses_object_safety,
    while_true
)]
#![warn(macro_use_extern_crate, unknown_lints)]
#![allow(
    bare_trait_objects,
    box_pointers,
    elided_lifetimes_in_paths,
    missing_debug_implementations,
    single_use_lifetimes,
    unused_results,
    variant_size_differences,
    warnings,
    renamed_and_removed_lints
)]

//! # cargo-make
//!
//! Rust task runner and build tool.

//! The cargo-make task runner enables to define and configure sets of tasks and run them as a flow.

//! A task is a command or a script to execute.

//! Tasks can have dependencies which are also tasks that will be executed before the task itself.

//! With a simple toml based configuration file, you can define a multi platform build script that can run build, test,
//! documentation generation, bench tests execution, security validations and more by running a single command.
//!
//! ## Installation
//! In order to install, just run the following command
//!
//! ```sh
//! cargo install cargo-make
//! ```
//!
//! This will install cargo-make in your ~/.cargo/bin.

//! Make sure to add ~/.cargo/bin directory to your PATH variable.
//!
//! # Contributing
//! See [contributing guide](https://github.com/sagiegurari/cargo-make/blob/master/.github/CONTRIBUTING.md)
//!
//! # License
//! Developed by Sagie Gur-Ari and licensed under the
//! [Apache 2](https://github.com/sagiegurari/cargo-make/blob/master/LICENSE) open source license.
//!

// Dependencies used in the binary `makers`:
#[cfg(windows)]
use ansi_term as _;

#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;

#[cfg(test)]
mod test;

// make types public for docs
pub mod types;

mod cache;
mod cli;
mod cli_commands;
mod command;
mod condition;
mod config;
mod descriptor;
mod environment;
mod execution_plan;
mod functions;
mod installer;
mod io;
mod legacy;
mod logger;
mod plugin;
mod profile;
mod proxy_task;
mod recursion_level;
mod runner;
mod scriptengine;
mod storage;
mod time_summary;
mod toolchain;
mod version;

/// Handles the command line arguments and executes the runner.
pub fn run_cli(command_name: String, sub_command: bool) {
    cli::run_cli(command_name, sub_command)
}
<commit_msg>Remove removed lint unsupported_naked_functions<commit_after>#![deny(
    absolute_paths_not_starting_with_crate,
    ambiguous_associated_items,
    anonymous_parameters,
    arithmetic_overflow,
    array_into_iter,
    asm_sub_register,
    bad_asm_style,
    bindings_with_variant_name,
    break_with_label_and_loop,
    cenum_impl_drop_cast,
    clashing_extern_declarations,
    coherence_leak_check,
    conflicting_repr_hints,
    confusable_idents,
    const_err,
    const_evaluatable_unchecked,
    const_item_mutation,
    dead_code,
    deprecated,
    deprecated_cfg_attr_crate_type_name,
    deprecated_in_future,
    deref_into_dyn_supertrait,
    deref_nullptr,
    drop_bounds,
    duplicate_macro_attributes,
    dyn_drop,
    ellipsis_inclusive_range_patterns,
    enum_intrinsics_non_enums,
    explicit_outlives_requirements,
    exported_private_dependencies,
    forbidden_lint_groups,
    function_item_references,
    ill_formed_attribute_input,
    illegal_floating_point_literal_pattern,
    improper_ctypes,
    improper_ctypes_definitions,
    incomplete_features,
    incomplete_include,
    indirect_structural_match,
    ineffective_unstable_trait_impl,
    inline_no_sanitize,
    invalid_atomic_ordering,
    invalid_doc_attributes,
    invalid_type_param_default,
    invalid_value,
    irrefutable_let_patterns,
    keyword_idents,
    large_assignments,
    late_bound_lifetime_arguments,
    legacy_derive_helpers,
    macro_expanded_macro_exports_accessed_by_absolute_paths,
    meta_variable_misuse,
    missing_abi,
    missing_copy_implementations,
    missing_docs,
    missing_fragment_specifier,
    mixed_script_confusables,
    mutable_borrow_reservation_conflict,
    mutable_transmutes,
    named_asm_labels,
    no_mangle_const_items,
    no_mangle_generic_items,
    non_ascii_idents,
    non_camel_case_types,
    non_fmt_panics,
    non_shorthand_field_patterns,
    non_snake_case,
    non_upper_case_globals,
    nontrivial_structural_match,
    noop_method_call,
    order_dependent_trait_objects,
    overflowing_literals,
    overlapping_range_endpoints,
    path_statements,
    patterns_in_fns_without_body,
    pointer_structural_match,
    private_in_public,
    proc_macro_back_compat,
    proc_macro_derive_resolution_fallback,
    pub_use_of_private_extern_crate,
    redundant_semicolons,
    rust_2021_incompatible_closure_captures,
    rust_2021_incompatible_or_patterns,
    rust_2021_prefixes_incompatible_syntax,
    rust_2021_prelude_collisions,
    semicolon_in_expressions_from_macros,
    soft_unstable,
    stable_features,
    temporary_cstring_as_ptr,
    text_direction_codepoint_in_comment,
    text_direction_codepoint_in_literal,
    trivial_bounds,
    trivial_casts,
    trivial_numeric_casts,
    type_alias_bounds,
    tyvar_behind_raw_pointer,
    unaligned_references,
    uncommon_codepoints,
    unconditional_panic,
    unconditional_recursion,
    uninhabited_static,
    unknown_crate_types,
    unnameable_test_items,
    unreachable_code,
    unreachable_patterns,
    unreachable_pub,
    unsafe_code,
    unsafe_op_in_unsafe_fn,
    unstable_features,
    unstable_name_collisions,
    unsupported_calling_conventions,
    unused_allocation,
    unused_assignments,
    unused_assignments,
    unused_attributes,
    unused_braces,
    unused_comparisons,
    unused_crate_dependencies,
    unused_doc_comments,
    unused_extern_crates,
    unused_features,
    unused_import_braces,
    unused_imports,
    unused_labels,
    unused_lifetimes,
    unused_macros,
    unused_must_use,
    unused_mut,
    unused_parens,
    unused_qualifications,
    unused_unsafe,
    unused_variables,
    useless_deprecated,
    where_clauses_object_safety,
    while_true
)]
#![warn(macro_use_extern_crate, unknown_lints)]
#![allow(
    bare_trait_objects,
    box_pointers,
    elided_lifetimes_in_paths,
    missing_debug_implementations,
    single_use_lifetimes,
    unused_results,
    variant_size_differences,
    warnings,
    renamed_and_removed_lints
)]

//! # cargo-make
//!
//! Rust task runner and build tool.

//! The cargo-make task runner enables to define and configure sets of tasks and run them as a flow.

//! A task is a command or a script to execute.

//! Tasks can have dependencies which are also tasks that will be executed before the task itself.

//! With a simple toml based configuration file, you can define a multi platform build script that can run build, test,
//! documentation generation, bench tests execution, security validations and more by running a single command.
//!
//! ## Installation
//! In order to install, just run the following command
//!
//! ```sh
//! cargo install cargo-make
//! ```
//!
//! This will install cargo-make in your ~/.cargo/bin.

//! Make sure to add ~/.cargo/bin directory to your PATH variable.
//!
//! # Contributing
//! See [contributing guide](https://github.com/sagiegurari/cargo-make/blob/master/.github/CONTRIBUTING.md)
//!
//! # License
//! Developed by Sagie Gur-Ari and licensed under the
//! [Apache 2](https://github.com/sagiegurari/cargo-make/blob/master/LICENSE) open source license.
//!

// Dependencies used in the binary `makers`:
#[cfg(windows)]
use ansi_term as _;

#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;

#[cfg(test)]
mod test;

// make types public for docs
pub mod types;

mod cache;
mod cli;
mod cli_commands;
mod command;
mod condition;
mod config;
mod descriptor;
mod environment;
mod execution_plan;
mod functions;
mod installer;
mod io;
mod legacy;
mod logger;
mod plugin;
mod profile;
mod proxy_task;
mod recursion_level;
mod runner;
mod scriptengine;
mod storage;
mod time_summary;
mod toolchain;
mod version;

/// Handles the command line arguments and executes the runner.
pub fn run_cli(command_name: String, sub_command: bool) {
    cli::run_cli(command_name, sub_command)
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Write_ppm_file
extern crate rand;

use std::fs::File;
use std::io::{BufWriter, Error, Write};
use bitmap::Image;
mod bitmap;

trait PPMWritable {
    fn write_ppm(&self, filename: &str) -> Result<(), Error>;
}

impl PPMWritable for Image {
    fn write_ppm(&self, filename: &str) -> Result<(), Error> {
        let file = try!{File::create(filename)};
        let mut writer = BufWriter::new(file);
        try!(writeln!(&mut writer, "P6"));
        try!(write!(&mut writer, "{} {} {}\n", self.width, self.height, 255));
        for color in &(self.data) {
            for channel in &[color.red, color.green, color.blue] {
                try!(write!(&mut writer, "{}", *channel as u8));
            }
        }
        Ok(())
    }
}

#[cfg(not(test))]
pub fn main() {
    use bitmap::Color;

    // write a PPM image, the left side of which is red, and the right side
    // of which is blue
    let mut image = Image::new(64, 64);
    image.fill(Color { red: 255, green: 0, blue: 0 });
    for y in 0..64 {
        for x in 32..64 {
            image[(x, y)] = Color { red: 0, green: 0, blue: 255 };
        }
    }
    image.write_ppm("./test_image.ppm").unwrap();
}

#[cfg(test)]
mod test {
    use bitmap::{Color, Image};
    use std::fs::File;
    use std::io::{BufReader, BufRead, Read};
    use rand;
    use rand::Rng;
    use std::env;

    #[test]
    fn write_ppm() {
        let mut image = Image::new(2,1);
        image[(0, 0)] = Color { red: 1, green: 2, blue: 3 };
        image[(1, 0)] = Color { red: 4, green: 5, blue: 6 };
        let fname = format!("{}/test-{}.ppm",
            env::temp_dir().to_str().unwrap(), rand::thread_rng().gen::<i32>());
        // Can't use try! macro because we want to panic, not return.
        match image.write_ppm(&fname[..]) {
            Ok(_) => {},
            Err(e) => panic!(e)
        }

        let file = File::open(&fname[..]).unwrap();
        let mut reader = BufReader::new(file);
        let mut line = String::new();
        let _ = reader.read_line(&mut line);
        assert_eq!(line, "P6\n");
        line = String::new();
        let _ = reader.read_line(&mut line);
        assert_eq!(line, "2 1 255\n");
        let mut bytes = reader.bytes();
        assert_eq!(bytes.next().unwrap(), Ok(1));
        assert_eq!(bytes.next().unwrap(), Ok(2));
        assert_eq!(bytes.next().unwrap(), Ok(3));
        assert_eq!(bytes.next().unwrap(), Ok(4));
        assert_eq!(bytes.next().unwrap(), Ok(5));
        assert_eq!(bytes.next().unwrap(), Ok(6));
        assert!(bytes.next().unwrap().is_err());
    }
}
<commit_msg>write_ppm fix<commit_after>// Implements http://rosettacode.org/wiki/Write_ppm_file
extern crate rand;

use std::fs::File;
use std::io::{BufWriter, Error, Write};
use bitmap::Image;
mod bitmap;

trait PPMWritable {
    fn write_ppm(&self, filename: &str) -> Result<(), Error>;
}

impl PPMWritable for Image {
    fn write_ppm(&self, filename: &str) -> Result<(), Error> {
        let file = try!{File::create(filename)};
        let mut writer = BufWriter::new(file);
        try!(writeln!(&mut writer, "P6"));
        try!(write!(&mut writer, "{} {} {}\n", self.width, self.height, 255));
        for color in &(self.data) {
            for channel in &[color.red, color.green, color.blue] {
                try!(writer.write(&[*channel]));
            }
        }
        Ok(())
    }
}

#[cfg(not(test))]
pub fn main() {
    use bitmap::Color;

    // write a PPM image, the left side of which is red, and the right side
    // of which is blue
    let mut image = Image::new(64, 64);
    image.fill(Color { red: 255, green: 0, blue: 0 });
    for y in 0..64 {
        for x in 32..64 {
            image[(x, y)] = Color { red: 0, green: 0, blue: 255 };
        }
    }
    image.write_ppm("./test_image.ppm").unwrap();
}

#[cfg(test)]
mod test {
    use bitmap::{Color, Image};
    use std::fs::File;
    use std::io::{BufReader, BufRead, Read};
    use rand;
    use rand::Rng;
    use std::env;

    #[test]
    fn write_ppm() {
        let mut image = Image::new(2,1);
        image[(0, 0)] = Color { red: 1, green: 2, blue: 3 };
        image[(1, 0)] = Color { red: 4, green: 5, blue: 6 };
        let fname = format!("{}/test-{}.ppm",
            env::temp_dir().to_str().unwrap(), rand::thread_rng().gen::<i32>());
        // Can't use try! macro because we want to panic, not return.
        match image.write_ppm(&fname[..]) {
            Ok(_) => {},
            Err(e) => panic!(e)
        }

        let file = File::open(&fname[..]).unwrap();
        let mut reader = BufReader::new(file);
        let mut line = String::new();
        let _ = reader.read_line(&mut line);
        assert_eq!(line, "P6\n");
        line = String::new();
        let _ = reader.read_line(&mut line);
        assert_eq!(line, "2 1 255\n");
        let mut bytes = reader.bytes();
        assert_eq!(bytes.next().unwrap(), Ok(1));
        assert_eq!(bytes.next().unwrap(), Ok(2));
        assert_eq!(bytes.next().unwrap(), Ok(3));
        assert_eq!(bytes.next().unwrap(), Ok(4));
        assert_eq!(bytes.next().unwrap(), Ok(5));
        assert_eq!(bytes.next().unwrap(), Ok(6));
        assert!(bytes.next().unwrap().is_err());
    }
}
<|endoftext|>


<commit_before>use std::process;
use std::os::unix::io::{RawFd, AsRawFd};

pub struct PersistentChild {
    pub child : process::Child,
}

impl PersistentChild {
    pub fn new(cmd: &str) -> Self {
        let child_proc = process::Command::new(cmd)
                .stdin(process::Stdio::piped())
                .stdout(process::Stdio::piped())
                .stderr(process::Stdio::piped())
                .spawn()
                .expect("failed to execute process");

        //TODO, if I want to reuse the pipes, I need to keep them open and need to write my custom
        //child spawner -_-

        println!("spawned child with pid {}", child_proc.id());
        PersistentChild{ child: child_proc }
    }

    pub fn stdin_as_mut(&mut self) -> &mut process::ChildStdin {
        self.child.stdin.as_mut().unwrap()
    }

    pub fn stdout_as_mut(&mut self) -> &mut process::ChildStdout {
        self.child.stdout.as_mut().unwrap()
    }

    pub fn stderr_as_mut(&mut self) -> &mut process::ChildStderr {
        self.child.stderr.as_mut().unwrap()
    }

    fn _unwrap_as_raw_fd<T: AsRawFd>(x: &Option<T>) -> RawFd {
        assert!(x.is_some());
        x.as_ref().unwrap().as_raw_fd()
    }

    pub fn is_stdin(&self, i: RawFd) -> bool {
        Self::_unwrap_as_raw_fd(&self.child.stdin) == i
    }

    pub fn is_stdout(&self, i: RawFd) -> bool {
        Self::_unwrap_as_raw_fd(&self.child.stdout) == i
    }

    pub fn is_stderr(&self, i: RawFd) -> bool {
        Self::_unwrap_as_raw_fd(&self.child.stderr) == i
    }
}
<commit_msg>tested pipe reuse<commit_after>use std::process;
use std::os::unix::io::{RawFd, AsRawFd};

pub struct PersistentChild {
    pub child : process::Child,
}

impl PersistentChild {
    pub fn new(cmd: &str) -> Self {
        let child_proc = process::Command::new(cmd)
                .stdin(process::Stdio::piped())
                .stdout(process::Stdio::piped())
                .stderr(process::Stdio::piped())
                .spawn()
                .expect("failed to execute process");

        //TODO, if I want to reuse the pipes, I need to keep them open and need to write my custom
        //child spawner -_-
        // If I keep both ends of the pipes open in the main process, I will not be able to read an
        // EOF if the child closes its end of the pipe. Probabaly I stick to the std library and
        //  create new pipes when a child needs to be respawned

        println!("spawned child with pid {}", child_proc.id());
        PersistentChild{ child: child_proc }
    }

    pub fn stdin_as_mut(&mut self) -> &mut process::ChildStdin {
        self.child.stdin.as_mut().unwrap()
    }

    pub fn stdout_as_mut(&mut self) -> &mut process::ChildStdout {
        self.child.stdout.as_mut().unwrap()
    }

    pub fn stderr_as_mut(&mut self) -> &mut process::ChildStderr {
        self.child.stderr.as_mut().unwrap()
    }

    fn _unwrap_as_raw_fd<T: AsRawFd>(x: &Option<T>) -> RawFd {
        assert!(x.is_some());
        x.as_ref().unwrap().as_raw_fd()
    }

    pub fn is_stdin(&self, i: RawFd) -> bool {
        Self::_unwrap_as_raw_fd(&self.child.stdin) == i
    }

    pub fn is_stdout(&self, i: RawFd) -> bool {
        Self::_unwrap_as_raw_fd(&self.child.stdout) == i
    }

    pub fn is_stderr(&self, i: RawFd) -> bool {
        Self::_unwrap_as_raw_fd(&self.child.stderr) == i
    }
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

//! Defines memory-related functions, such as allocate/deallocate/reallocate memory
//! regions.

use std::alloc::Layout;
use std::mem::align_of;

pub const ALIGNMENT: usize = 64;

pub fn allocate_aligned(size: usize) -> *mut u8 {
    unsafe {
        let layout = Layout::from_size_align_unchecked(size, ALIGNMENT);
        std::alloc::alloc(layout)
    }
}

pub fn free_aligned(p: *mut u8, size: usize) {
    unsafe {
        std::alloc::dealloc(p, Layout::from_size_align_unchecked(size, ALIGNMENT));
    }
}

pub fn reallocate(ptr: *mut u8, old_size: usize, new_size: usize) -> *mut u8 {
    unsafe {
        std::alloc::realloc(
            ptr,
            Layout::from_size_align_unchecked(old_size, ALIGNMENT),
            new_size,
        )
    }
}

pub unsafe fn memcpy(dst: *mut u8, src: *const u8, len: usize) {
    std::ptr::copy_nonoverlapping(src, dst, len)
}

extern "C" {
    pub fn memcmp(p1: *const u8, p2: *const u8, len: usize) -> i32;
}

/// Check if the pointer `p` is aligned to offset `a`.
pub fn is_aligned<T>(p: *const T, a: usize) -> bool {
    let a_minus_one = a.wrapping_sub(1);
    let pmoda = p as usize & a_minus_one;
    pmoda == 0
}

pub fn is_ptr_aligned<T>(p: *const T) -> bool {
    let alignment = align_of::<T>();
    is_aligned(p, alignment)
}

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

    #[test]
    fn test_allocate() {
        for _ in 0..10 {
            let p = allocate_aligned(1024);
            // make sure this is 64-byte aligned
            assert_eq!(0, (p as usize) % 64);
        }
    }

    #[test]
    fn test_is_aligned() {
        // allocate memory aligned to 64-byte
        let mut ptr = allocate_aligned(10);
        assert_eq!(true, is_aligned::<u8>(ptr, 1));
        assert_eq!(true, is_aligned::<u8>(ptr, 2));
        assert_eq!(true, is_aligned::<u8>(ptr, 4));

        // now make the memory aligned to 63-byte
        ptr = unsafe { ptr.offset(1) };
        assert_eq!(true, is_aligned::<u8>(ptr, 1));
        assert_eq!(false, is_aligned::<u8>(ptr, 2));
        assert_eq!(false, is_aligned::<u8>(ptr, 4));
    }
}
<commit_msg>ARROW-7836: [Rust] "allocate_aligned"/"reallocate" need to initialize memory to avoid UB<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

//! Defines memory-related functions, such as allocate/deallocate/reallocate memory
//! regions.

use std::alloc::Layout;
use std::mem::align_of;

pub const ALIGNMENT: usize = 64;

pub fn allocate_aligned(size: usize) -> *mut u8 {
    unsafe {
        let layout = Layout::from_size_align_unchecked(size, ALIGNMENT);
        std::alloc::alloc_zeroed(layout)
    }
}

pub fn free_aligned(p: *mut u8, size: usize) {
    unsafe {
        std::alloc::dealloc(p, Layout::from_size_align_unchecked(size, ALIGNMENT));
    }
}

pub fn reallocate(ptr: *mut u8, old_size: usize, new_size: usize) -> *mut u8 {
    unsafe {
        let new_ptr = std::alloc::realloc(
            ptr,
            Layout::from_size_align_unchecked(old_size, ALIGNMENT),
            new_size,
        );
        if !new_ptr.is_null() && new_size > old_size {
            new_ptr.add(old_size).write_bytes(0, new_size - old_size);
        }
        new_ptr
    }
}

pub unsafe fn memcpy(dst: *mut u8, src: *const u8, len: usize) {
    std::ptr::copy_nonoverlapping(src, dst, len)
}

extern "C" {
    pub fn memcmp(p1: *const u8, p2: *const u8, len: usize) -> i32;
}

/// Check if the pointer `p` is aligned to offset `a`.
pub fn is_aligned<T>(p: *const T, a: usize) -> bool {
    let a_minus_one = a.wrapping_sub(1);
    let pmoda = p as usize & a_minus_one;
    pmoda == 0
}

pub fn is_ptr_aligned<T>(p: *const T) -> bool {
    let alignment = align_of::<T>();
    is_aligned(p, alignment)
}

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

    #[test]
    fn test_allocate() {
        for _ in 0..10 {
            let p = allocate_aligned(1024);
            // make sure this is 64-byte aligned
            assert_eq!(0, (p as usize) % 64);
        }
    }

    #[test]
    fn test_is_aligned() {
        // allocate memory aligned to 64-byte
        let mut ptr = allocate_aligned(10);
        assert_eq!(true, is_aligned::<u8>(ptr, 1));
        assert_eq!(true, is_aligned::<u8>(ptr, 2));
        assert_eq!(true, is_aligned::<u8>(ptr, 4));

        // now make the memory aligned to 63-byte
        ptr = unsafe { ptr.offset(1) };
        assert_eq!(true, is_aligned::<u8>(ptr, 1));
        assert_eq!(false, is_aligned::<u8>(ptr, 2));
        assert_eq!(false, is_aligned::<u8>(ptr, 4));
    }
}
<|endoftext|>


<commit_before>//! Utility functions for use by parser implementations

use graph_triples::{
    relations,
    resources::{self, ResourceAutorun},
    Relation, Resource,
};
use once_cell::sync::Lazy;
use regex::Regex;
use std::path::{Path, PathBuf};

use crate::ResourceInfo;

/// Apply comment tags to a [`ResourceInfo`] object.
///
/// Parses tags from a comment and updates the supplied [`ResourceInfo`]. This pattern is
/// used because (a) the resource info may already be partially populated based on semantic
/// analysis of the code (which comments wish to override), and (b) there might be multiple
/// comments in a code resources each with (potentially overriding) tags
///
/// # Arguments
///
/// - `path`:    The path of the file.
///              Used, for example, when constructing `Symbol` resources for `@assigns` etc tags.
/// - `lang`:    The language of code that the comment is part of.
///              Used, for example, when constructing `Module` resources for `@imports` tags.
/// - `row`:     The line number of the start of the comment.
///              Used for constructing a `Range` for resources.
/// - `comment`: The comment from which to parse tags, usually a comment
/// - `kind`:    The default type for `Symbol` resources.
/// - `resource_info`: The [`ResourceInfo`] object to update
pub fn apply_tags(
    path: &Path,
    lang: &str,
    row: usize,
    comment: &str,
    kind: Option<String>,
    resource_info: &mut ResourceInfo,
) {
    static REGEX_TAGS: Lazy<Regex> = Lazy::new(|| {
        Regex::new(
            r"@(pure|impure|autorun|imports|assigns|alters|uses|reads|writes)((?:\s+).*?)?(\*/)?$",
        )
        .expect("Unable to create regex")
    });
    static REGEX_ITEMS: Lazy<Regex> =
        Lazy::new(|| Regex::new(r"\s+|(\s*,\s*)").expect("Unable to create regex"));

    let mut pairs: Vec<(Relation, Resource)> = Vec::new();
    let mut onlies: Vec<String> = Vec::new();
    for (index, line) in comment.lines().enumerate() {
        let range = (row + index, 0, row + index, line.len() - 1);
        if let Some(captures) = REGEX_TAGS.captures(line) {
            let tag = captures[1].to_string();
            let args = captures[2].trim();

            let relation = match tag.as_str() {
                "pure" | "impure" => {
                    resource_info.pure = Some(tag == "pure");
                    continue;
                }

                "autorun" => {
                    let variant = match args {
                        "always" => ResourceAutorun::Always,
                        "never" => ResourceAutorun::Never,
                        _ => ResourceAutorun::Needed,
                    };
                    resource_info.autorun = variant;
                    continue;
                }

                "imports" => relations::uses(range),
                "assigns" => relations::assigns(range),
                "alters" => relations::alters(range),
                "uses" => relations::uses(range),
                "reads" => relations::reads(range),
                "writes" => relations::writes(range),

                _ => continue,
            };

            let args: Vec<String> = REGEX_ITEMS
                .split(args)
                .map(|item| item.to_string())
                .collect();

            for arg in args {
                if arg == "only" {
                    onlies.push(tag.clone());
                    continue;
                }

                let resource = match tag.as_str() {
                    "imports" => resources::module(lang, &arg),
                    "assigns" | "alters" | "uses" => {
                        resources::symbol(path, &arg, &kind.clone().unwrap_or_default())
                    }
                    "reads" | "writes" => resources::file(&PathBuf::from(arg)),
                    _ => continue,
                };
                pairs.push((relation.clone(), resource))
            }
        }
    }

    // Remove existing pairs for relation types where the `only` keyword is present in tags
    if let Some(relations) = &mut resource_info.relations {
        for only in onlies {
            relations.retain(|(relation, _resource)| {
                !(matches!(relation, Relation::Import(..)) && only == "imports"
                    || matches!(relation, Relation::Assign(..)) && only == "assigns"
                    || matches!(relation, Relation::Alter(..)) && only == "alters"
                    || matches!(relation, Relation::Use(..)) && only == "uses"
                    || matches!(relation, Relation::Read(..)) && only == "reads"
                    || matches!(relation, Relation::Write(..)) && only == "writes")
            })
        }
    }

    // Append pairs from tags
    if !pairs.is_empty() {
        if let Some(relations) = &mut resource_info.relations {
            relations.append(&mut pairs);
        } else {
            resource_info.relations = Some(pairs)
        }
    }
}

/// Is some text quoted?
pub fn is_quoted(text: &str) -> bool {
    (text.starts_with('"') && text.ends_with('"'))
        || (text.starts_with('\'') && text.ends_with('\''))
}

/// Remove single and double quotes from text
///
/// Useful for "unquoting" captured string literals.
pub fn remove_quotes(text: &str) -> String {
    text.replace(&['\"', '\''][..], "")
}
<commit_msg>fix(Calc parser): More robust handling for regex groups<commit_after>//! Utility functions for use by parser implementations

use graph_triples::{
    relations,
    resources::{self, ResourceAutorun},
    Relation, Resource,
};
use once_cell::sync::Lazy;
use regex::Regex;
use std::path::{Path, PathBuf};

use crate::ResourceInfo;

/// Apply comment tags to a [`ResourceInfo`] object.
///
/// Parses tags from a comment and updates the supplied [`ResourceInfo`]. This pattern is
/// used because (a) the resource info may already be partially populated based on semantic
/// analysis of the code (which comments wish to override), and (b) there might be multiple
/// comments in a code resources each with (potentially overriding) tags
///
/// # Arguments
///
/// - `path`:    The path of the file.
///              Used, for example, when constructing `Symbol` resources for `@assigns` etc tags.
/// - `lang`:    The language of code that the comment is part of.
///              Used, for example, when constructing `Module` resources for `@imports` tags.
/// - `row`:     The line number of the start of the comment.
///              Used for constructing a `Range` for resources.
/// - `comment`: The comment from which to parse tags, usually a comment
/// - `kind`:    The default type for `Symbol` resources.
/// - `resource_info`: The [`ResourceInfo`] object to update
pub fn apply_tags(
    path: &Path,
    lang: &str,
    row: usize,
    comment: &str,
    kind: Option<String>,
    resource_info: &mut ResourceInfo,
) {
    static REGEX_TAGS: Lazy<Regex> = Lazy::new(|| {
        Regex::new(
            r"@(pure|impure|autorun|imports|assigns|alters|uses|reads|writes)((?:\s+).*?)?(\*/)?$",
        )
        .expect("Unable to create regex")
    });
    static REGEX_ITEMS: Lazy<Regex> =
        Lazy::new(|| Regex::new(r"\s+|(\s*,\s*)").expect("Unable to create regex"));

    let mut pairs: Vec<(Relation, Resource)> = Vec::new();
    let mut onlies: Vec<String> = Vec::new();
    for (index, line) in comment.lines().enumerate() {
        let range = (row + index, 0, row + index, line.len() - 1);
        if let Some(captures) = REGEX_TAGS.captures(line) {
            let tag = captures.get(1).map_or_else(|| "", |group| group.as_str());
            let args = captures
                .get(2)
                .map_or_else(|| "", |group| group.as_str().trim());

            let relation = match tag {
                "pure" | "impure" => {
                    resource_info.pure = Some(tag == "pure");
                    continue;
                }

                "autorun" => {
                    let variant = match args {
                        "always" => ResourceAutorun::Always,
                        "never" => ResourceAutorun::Never,
                        _ => ResourceAutorun::Needed,
                    };
                    resource_info.autorun = variant;
                    continue;
                }

                "imports" => relations::uses(range),
                "assigns" => relations::assigns(range),
                "alters" => relations::alters(range),
                "uses" => relations::uses(range),
                "reads" => relations::reads(range),
                "writes" => relations::writes(range),

                _ => continue,
            };

            let args: Vec<String> = REGEX_ITEMS
                .split(args)
                .map(|item| item.to_string())
                .collect();

            for arg in args {
                if arg == "only" {
                    onlies.push(tag.to_string());
                    continue;
                }

                let resource = match tag {
                    "imports" => resources::module(lang, &arg),
                    "assigns" | "alters" | "uses" => {
                        resources::symbol(path, &arg, &kind.clone().unwrap_or_default())
                    }
                    "reads" | "writes" => resources::file(&PathBuf::from(arg)),
                    _ => continue,
                };
                pairs.push((relation.clone(), resource))
            }
        }
    }

    // Remove existing pairs for relation types where the `only` keyword is present in tags
    if let Some(relations) = &mut resource_info.relations {
        for only in onlies {
            relations.retain(|(relation, _resource)| {
                !(matches!(relation, Relation::Import(..)) && only == "imports"
                    || matches!(relation, Relation::Assign(..)) && only == "assigns"
                    || matches!(relation, Relation::Alter(..)) && only == "alters"
                    || matches!(relation, Relation::Use(..)) && only == "uses"
                    || matches!(relation, Relation::Read(..)) && only == "reads"
                    || matches!(relation, Relation::Write(..)) && only == "writes")
            })
        }
    }

    // Append pairs from tags
    if !pairs.is_empty() {
        if let Some(relations) = &mut resource_info.relations {
            relations.append(&mut pairs);
        } else {
            resource_info.relations = Some(pairs)
        }
    }
}

/// Is some text quoted?
pub fn is_quoted(text: &str) -> bool {
    (text.starts_with('"') && text.ends_with('"'))
        || (text.starts_with('\'') && text.ends_with('\''))
}

/// Remove single and double quotes from text
///
/// Useful for "unquoting" captured string literals.
pub fn remove_quotes(text: &str) -> String {
    text.replace(&['\"', '\''][..], "")
}
<|endoftext|>


<commit_before><commit_msg>Test that opcdoe 2 works.<commit_after><|endoftext|>


<commit_before>use ffi;
use any::AnyLuaValue;

use Push;
use PushGuard;
use PushOne;
use AsMutLua;
use TuplePushError;
use LuaRead;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::Hash;
use std::iter;

#[inline]
fn push_iter<'lua, L, V, I, E>(mut lua: L, iterator: I) -> Result<PushGuard<L>, (E, L)>
    where L: AsMutLua<'lua>,
          V: for<'b> Push<&'b mut L, Err = E>,
          I: Iterator<Item = V>
{
    // creating empty table
    unsafe { ffi::lua_newtable(lua.as_mut_lua().0) };

    for (elem, index) in iterator.zip((1..)) {
        let size = match elem.push_to_lua(&mut lua) {
            Ok(pushed) => pushed.forget(),
            Err((_err, _lua)) => panic!(),     // TODO: wrong   return Err((err, lua)),      // FIXME: destroy the temporary table
        };

        match size {
            0 => continue,
            1 => {
                let index = index as u32;
                match index.push_to_lua(&mut lua) {
                    Ok(pushed) => pushed.forget(),
                    Err(_) => unreachable!(),
                };
                unsafe { ffi::lua_insert(lua.as_mut_lua().0, -2) }
                unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) }
            }
            2 => unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) },
            _ => unreachable!(),
        }
    }

    let raw_lua = lua.as_lua();
    Ok(PushGuard {
        lua: lua,
        size: 1,
        raw_lua: raw_lua,
    })
}

#[inline]
fn push_rec_iter<'lua, L, V, I, E>(mut lua: L, iterator: I) -> Result<PushGuard<L>, (E, L)>
    where L: AsMutLua<'lua>,
          V: for<'a> Push<&'a mut L, Err = E>,
          I: Iterator<Item = V>
{
    let (nrec, _) = iterator.size_hint();

    // creating empty table with pre-allocated non-array elements
    unsafe { ffi::lua_createtable(lua.as_mut_lua().0, 0, nrec as i32) };

    for elem in iterator {
        let size = match elem.push_to_lua(&mut lua) {
            Ok(pushed) => pushed.forget(),
            Err((_err, _lua)) => panic!(),     // TODO: wrong   return Err((err, lua)),      // FIXME: destroy the temporary table
        };

        match size {
            0 => continue,
            2 => unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) },
            _ => unreachable!(),
        }
    }

    let raw_lua = lua.as_lua();
    Ok(PushGuard {
        lua: lua,
        size: 1,
        raw_lua: raw_lua,
    })
}

impl<'lua, L, T, E> Push<L> for Vec<T>
    where L: AsMutLua<'lua>,
          T: for<'a> Push<&'a mut L, Err = E>
{
    type Err = E;

    #[inline]
    fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
        push_iter(lua, self.into_iter())
    }
}

impl<'lua, L, T, E> PushOne<L> for Vec<T>
    where L: AsMutLua<'lua>,
          T: for<'a> Push<&'a mut L, Err = E>
{
}

impl<'lua, L> LuaRead<L> for Vec<AnyLuaValue>
    where L: AsMutLua<'lua>
{
    fn lua_read_at_position(lua: L, index: i32) -> Result<Self, L> {
        // We need this as iteration order isn't guaranteed to match order of
        // keys, even if they're numeric
        // https://www.lua.org/manual/5.2/manual.html#pdf-next
        let mut dict: BTreeMap<i32, AnyLuaValue> = BTreeMap::new();

        let mut me = lua;
        unsafe { ffi::lua_pushnil(me.as_mut_lua().0) };
        let index = index - 1;

        loop {
            if unsafe { ffi::lua_next(me.as_mut_lua().0, index) } == 0 {
                break;
            }

            let key;

            {
                let maybe_key: Option<i32> =
                    LuaRead::lua_read_at_position(&mut me, -2).ok();
                match maybe_key {
                    None => {
                        // Cleaning up after ourselves
                        unsafe { ffi::lua_pop(me.as_mut_lua().0, 2) };
                        return Err(me)
                    }
                    Some(k) => key = k,
                }
            }

            let value: AnyLuaValue =
                LuaRead::lua_read_at_position(&mut me, -1).ok().unwrap();

            unsafe { ffi::lua_pop(me.as_mut_lua().0, 1) };

            dict.insert(key, value);
        }

        let (maximum_key, minimum_key) =
            (*dict.keys().max().unwrap_or(&1), *dict.keys().min().unwrap_or(&1));

        if minimum_key != 1 {
            // Rust doesn't support sparse arrays or arrays with negative
            // indices
            return Err(me);
        }

        let mut result =
            Vec::with_capacity(maximum_key as usize);

        // We expect to start with first element of table and have this
        // be smaller that first key by one
        let mut previous_key = 0;

        // By this point, we actually iterate the map to move values to Vec
        // and check that table represented non-sparse 1-indexed array
        for (k, v) in dict {
            if previous_key + 1 != k {
                return Err(me)
            } else {
                // We just push, thus converting Lua 1-based indexing
                // to Rust 0-based indexing
                result.push(v);
                previous_key = k;
            }
        }

        Ok(result)
    }
}

impl<'a, 'lua, L, T, E> Push<L> for &'a [T]
    where L: AsMutLua<'lua>,
          T: Clone + for<'b> Push<&'b mut L, Err = E>
{
    type Err = E;

    #[inline]
    fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
        push_iter(lua, self.iter().map(|e| e.clone()))
    }
}

impl<'a, 'lua, L, T, E> PushOne<L> for &'a [T]
    where L: AsMutLua<'lua>,
          T: Clone + for<'b> Push<&'b mut L, Err = E>
{
}

// TODO: use an enum for the error to allow different error types for K and V
impl<'lua, L, K, V, E> Push<L> for HashMap<K, V>
    where L: AsMutLua<'lua>,
          K: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E> + Eq + Hash,
          V: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E>
{
    type Err = E;

    #[inline]
    fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
        match push_rec_iter(lua, self.into_iter()) {
            Ok(g) => Ok(g),
            Err((TuplePushError::First(err), lua)) => Err((err, lua)),
            Err((TuplePushError::Other(err), lua)) => Err((err, lua)),
        }
    }
}

impl<'lua, L, K, V, E> PushOne<L> for HashMap<K, V>
    where L: AsMutLua<'lua>,
          K: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E> + Eq + Hash,
          V: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E>
{
}

impl<'lua, L, K, E> Push<L> for HashSet<K>
    where L: AsMutLua<'lua>,
          K: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E> + Eq + Hash
{
    type Err = E;

    #[inline]
    fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
        match push_rec_iter(lua, self.into_iter().zip(iter::repeat(true))) {
            Ok(g) => Ok(g),
            Err((TuplePushError::First(err), lua)) => Err((err, lua)),
            Err((TuplePushError::Other(_), _)) => unreachable!(),
        }
    }
}

impl<'lua, L, K, E> PushOne<L> for HashSet<K>
    where L: AsMutLua<'lua>,
          K: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E> + Eq + Hash
{
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::collections::HashSet;
    use Lua;
    use LuaTable;
    use AnyLuaValue;

    #[test]
    fn write() {
        let mut lua = Lua::new();

        lua.set("a", vec![9, 8, 7]);

        let mut table: LuaTable<_> = lua.get("a").unwrap();

        let values: Vec<(i32, i32)> = table.iter().filter_map(|e| e).collect();
        assert_eq!(values, vec![(1, 9), (2, 8), (3, 7)]);
    }

    #[test]
    fn write_map() {
        let mut lua = Lua::new();

        let mut map = HashMap::new();
        map.insert(5, 8);
        map.insert(13, 21);
        map.insert(34, 55);

        lua.set("a", map.clone());

        let mut table: LuaTable<_> = lua.get("a").unwrap();

        let values: HashMap<i32, i32> = table.iter().filter_map(|e| e).collect();
        assert_eq!(values, map);
    }

    #[test]
    fn write_set() {
        let mut lua = Lua::new();

        let mut set = HashSet::new();
        set.insert(5);
        set.insert(8);
        set.insert(13);
        set.insert(21);
        set.insert(34);
        set.insert(55);

        lua.set("a", set.clone());

        let mut table: LuaTable<_> = lua.get("a").unwrap();

        let values: HashSet<i32> = table.iter()
            .filter_map(|e| e)
            .map(|(elem, set): (i32, bool)| {
                assert!(set);
                elem
            })
            .collect();

        assert_eq!(values, set);
    }

    #[test]
    fn globals_table() {
        let mut lua = Lua::new();

        lua.globals_table().set("a", 12);

        let val: i32 = lua.get("a").unwrap();
        assert_eq!(val, 12);
    }

    #[test]
    fn reading_vec_works() {
        let mut lua = Lua::new();

        let orig = [1., 2., 3.];

        lua.set("v", &orig[..]);

        let read: Vec<_> = lua.get("v").unwrap();
        for (o, r) in orig.iter().zip(read.iter()) {
            if let AnyLuaValue::LuaNumber(ref n) = *r {
                assert_eq!(o, n);
            } else {
                panic!("Unexpected variant");
            }
        }
    }

    #[test]
    fn reading_vec_from_sparse_table_doesnt_work() {
        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { [-1] = -1, [2] = 2, [42] = 42 }"#).unwrap();

        let read: Option<Vec<_>> = lua.get("v");
        if read.is_some() {
            panic!("Unexpected success");
        }
    }

    #[test]
    fn reading_vec_with_empty_table_works() {
        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { }"#).unwrap();

        let read: Vec<_> = lua.get("v").unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn reading_vec_with_complex_indexes_doesnt_work() {
        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { [-1] = -1, ["foo"] = 2, [{}] = 42 }"#).unwrap();

        let read: Option<Vec<_>> = lua.get("v");
        if read.is_some() {
            panic!("Unexpected success");
        }
    }

    #[test]
    fn reading_heterogenous_vec_works() {
        let mut lua = Lua::new();

        let orig = [
            AnyLuaValue::LuaNumber(1.),
            AnyLuaValue::LuaBoolean(false),
            AnyLuaValue::LuaNumber(3.),
            // Pushing String to and reading it from makes it a number
            //AnyLuaValue::LuaString(String::from("3"))
        ];

        lua.set("v", &orig[..]);

        let read: Vec<_> = lua.get("v").unwrap();
        assert_eq!(read, orig);
    }

    #[test]
    fn reading_vec_set_from_lua_works() {
        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { 1, 2, 3 }"#).unwrap();

        let read: Vec<_> = lua.get("v").unwrap();
        assert_eq!(
            read,
            [1., 2., 3.].iter()
                .map(|x| AnyLuaValue::LuaNumber(*x)).collect::<Vec<_>>());
    }
}
<commit_msg>Simplify reading a vector a bit<commit_after>use ffi;
use any::AnyLuaValue;

use Push;
use PushGuard;
use PushOne;
use AsMutLua;
use TuplePushError;
use LuaRead;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::Hash;
use std::iter;

#[inline]
fn push_iter<'lua, L, V, I, E>(mut lua: L, iterator: I) -> Result<PushGuard<L>, (E, L)>
    where L: AsMutLua<'lua>,
          V: for<'b> Push<&'b mut L, Err = E>,
          I: Iterator<Item = V>
{
    // creating empty table
    unsafe { ffi::lua_newtable(lua.as_mut_lua().0) };

    for (elem, index) in iterator.zip((1..)) {
        let size = match elem.push_to_lua(&mut lua) {
            Ok(pushed) => pushed.forget(),
            Err((_err, _lua)) => panic!(),     // TODO: wrong   return Err((err, lua)),      // FIXME: destroy the temporary table
        };

        match size {
            0 => continue,
            1 => {
                let index = index as u32;
                match index.push_to_lua(&mut lua) {
                    Ok(pushed) => pushed.forget(),
                    Err(_) => unreachable!(),
                };
                unsafe { ffi::lua_insert(lua.as_mut_lua().0, -2) }
                unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) }
            }
            2 => unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) },
            _ => unreachable!(),
        }
    }

    let raw_lua = lua.as_lua();
    Ok(PushGuard {
        lua: lua,
        size: 1,
        raw_lua: raw_lua,
    })
}

#[inline]
fn push_rec_iter<'lua, L, V, I, E>(mut lua: L, iterator: I) -> Result<PushGuard<L>, (E, L)>
    where L: AsMutLua<'lua>,
          V: for<'a> Push<&'a mut L, Err = E>,
          I: Iterator<Item = V>
{
    let (nrec, _) = iterator.size_hint();

    // creating empty table with pre-allocated non-array elements
    unsafe { ffi::lua_createtable(lua.as_mut_lua().0, 0, nrec as i32) };

    for elem in iterator {
        let size = match elem.push_to_lua(&mut lua) {
            Ok(pushed) => pushed.forget(),
            Err((_err, _lua)) => panic!(),     // TODO: wrong   return Err((err, lua)),      // FIXME: destroy the temporary table
        };

        match size {
            0 => continue,
            2 => unsafe { ffi::lua_settable(lua.as_mut_lua().0, -3) },
            _ => unreachable!(),
        }
    }

    let raw_lua = lua.as_lua();
    Ok(PushGuard {
        lua: lua,
        size: 1,
        raw_lua: raw_lua,
    })
}

impl<'lua, L, T, E> Push<L> for Vec<T>
    where L: AsMutLua<'lua>,
          T: for<'a> Push<&'a mut L, Err = E>
{
    type Err = E;

    #[inline]
    fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
        push_iter(lua, self.into_iter())
    }
}

impl<'lua, L, T, E> PushOne<L> for Vec<T>
    where L: AsMutLua<'lua>,
          T: for<'a> Push<&'a mut L, Err = E>
{
}

impl<'lua, L> LuaRead<L> for Vec<AnyLuaValue>
    where L: AsMutLua<'lua>
{
    fn lua_read_at_position(lua: L, index: i32) -> Result<Self, L> {
        // We need this as iteration order isn't guaranteed to match order of
        // keys, even if they're numeric
        // https://www.lua.org/manual/5.2/manual.html#pdf-next
        let mut dict: BTreeMap<i32, AnyLuaValue> = BTreeMap::new();

        let mut me = lua;
        unsafe { ffi::lua_pushnil(me.as_mut_lua().0) };
        let index = index - 1;

        loop {
            if unsafe { ffi::lua_next(me.as_mut_lua().0, index) } == 0 {
                break;
            }

            let key = {
                let maybe_key: Option<i32> =
                    LuaRead::lua_read_at_position(&mut me, -2).ok();
                match maybe_key {
                    None => {
                        // Cleaning up after ourselves
                        unsafe { ffi::lua_pop(me.as_mut_lua().0, 2) };
                        return Err(me)
                    }
                    Some(k) => k,
                }
            };

            let value: AnyLuaValue =
                LuaRead::lua_read_at_position(&mut me, -1).ok().unwrap();

            unsafe { ffi::lua_pop(me.as_mut_lua().0, 1) };

            dict.insert(key, value);
        }

        let (maximum_key, minimum_key) =
            (*dict.keys().max().unwrap_or(&1), *dict.keys().min().unwrap_or(&1));

        if minimum_key != 1 {
            // Rust doesn't support sparse arrays or arrays with negative
            // indices
            return Err(me);
        }

        let mut result =
            Vec::with_capacity(maximum_key as usize);

        // We expect to start with first element of table and have this
        // be smaller that first key by one
        let mut previous_key = 0;

        // By this point, we actually iterate the map to move values to Vec
        // and check that table represented non-sparse 1-indexed array
        for (k, v) in dict {
            if previous_key + 1 != k {
                return Err(me)
            } else {
                // We just push, thus converting Lua 1-based indexing
                // to Rust 0-based indexing
                result.push(v);
                previous_key = k;
            }
        }

        Ok(result)
    }
}

impl<'a, 'lua, L, T, E> Push<L> for &'a [T]
    where L: AsMutLua<'lua>,
          T: Clone + for<'b> Push<&'b mut L, Err = E>
{
    type Err = E;

    #[inline]
    fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
        push_iter(lua, self.iter().map(|e| e.clone()))
    }
}

impl<'a, 'lua, L, T, E> PushOne<L> for &'a [T]
    where L: AsMutLua<'lua>,
          T: Clone + for<'b> Push<&'b mut L, Err = E>
{
}

// TODO: use an enum for the error to allow different error types for K and V
impl<'lua, L, K, V, E> Push<L> for HashMap<K, V>
    where L: AsMutLua<'lua>,
          K: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E> + Eq + Hash,
          V: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E>
{
    type Err = E;

    #[inline]
    fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
        match push_rec_iter(lua, self.into_iter()) {
            Ok(g) => Ok(g),
            Err((TuplePushError::First(err), lua)) => Err((err, lua)),
            Err((TuplePushError::Other(err), lua)) => Err((err, lua)),
        }
    }
}

impl<'lua, L, K, V, E> PushOne<L> for HashMap<K, V>
    where L: AsMutLua<'lua>,
          K: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E> + Eq + Hash,
          V: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E>
{
}

impl<'lua, L, K, E> Push<L> for HashSet<K>
    where L: AsMutLua<'lua>,
          K: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E> + Eq + Hash
{
    type Err = E;

    #[inline]
    fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
        match push_rec_iter(lua, self.into_iter().zip(iter::repeat(true))) {
            Ok(g) => Ok(g),
            Err((TuplePushError::First(err), lua)) => Err((err, lua)),
            Err((TuplePushError::Other(_), _)) => unreachable!(),
        }
    }
}

impl<'lua, L, K, E> PushOne<L> for HashSet<K>
    where L: AsMutLua<'lua>,
          K: for<'a, 'b> PushOne<&'a mut &'b mut L, Err = E> + Eq + Hash
{
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::collections::HashSet;
    use Lua;
    use LuaTable;
    use AnyLuaValue;

    #[test]
    fn write() {
        let mut lua = Lua::new();

        lua.set("a", vec![9, 8, 7]);

        let mut table: LuaTable<_> = lua.get("a").unwrap();

        let values: Vec<(i32, i32)> = table.iter().filter_map(|e| e).collect();
        assert_eq!(values, vec![(1, 9), (2, 8), (3, 7)]);
    }

    #[test]
    fn write_map() {
        let mut lua = Lua::new();

        let mut map = HashMap::new();
        map.insert(5, 8);
        map.insert(13, 21);
        map.insert(34, 55);

        lua.set("a", map.clone());

        let mut table: LuaTable<_> = lua.get("a").unwrap();

        let values: HashMap<i32, i32> = table.iter().filter_map(|e| e).collect();
        assert_eq!(values, map);
    }

    #[test]
    fn write_set() {
        let mut lua = Lua::new();

        let mut set = HashSet::new();
        set.insert(5);
        set.insert(8);
        set.insert(13);
        set.insert(21);
        set.insert(34);
        set.insert(55);

        lua.set("a", set.clone());

        let mut table: LuaTable<_> = lua.get("a").unwrap();

        let values: HashSet<i32> = table.iter()
            .filter_map(|e| e)
            .map(|(elem, set): (i32, bool)| {
                assert!(set);
                elem
            })
            .collect();

        assert_eq!(values, set);
    }

    #[test]
    fn globals_table() {
        let mut lua = Lua::new();

        lua.globals_table().set("a", 12);

        let val: i32 = lua.get("a").unwrap();
        assert_eq!(val, 12);
    }

    #[test]
    fn reading_vec_works() {
        let mut lua = Lua::new();

        let orig = [1., 2., 3.];

        lua.set("v", &orig[..]);

        let read: Vec<_> = lua.get("v").unwrap();
        for (o, r) in orig.iter().zip(read.iter()) {
            if let AnyLuaValue::LuaNumber(ref n) = *r {
                assert_eq!(o, n);
            } else {
                panic!("Unexpected variant");
            }
        }
    }

    #[test]
    fn reading_vec_from_sparse_table_doesnt_work() {
        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { [-1] = -1, [2] = 2, [42] = 42 }"#).unwrap();

        let read: Option<Vec<_>> = lua.get("v");
        if read.is_some() {
            panic!("Unexpected success");
        }
    }

    #[test]
    fn reading_vec_with_empty_table_works() {
        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { }"#).unwrap();

        let read: Vec<_> = lua.get("v").unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn reading_vec_with_complex_indexes_doesnt_work() {
        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { [-1] = -1, ["foo"] = 2, [{}] = 42 }"#).unwrap();

        let read: Option<Vec<_>> = lua.get("v");
        if read.is_some() {
            panic!("Unexpected success");
        }
    }

    #[test]
    fn reading_heterogenous_vec_works() {
        let mut lua = Lua::new();

        let orig = [
            AnyLuaValue::LuaNumber(1.),
            AnyLuaValue::LuaBoolean(false),
            AnyLuaValue::LuaNumber(3.),
            // Pushing String to and reading it from makes it a number
            //AnyLuaValue::LuaString(String::from("3"))
        ];

        lua.set("v", &orig[..]);

        let read: Vec<_> = lua.get("v").unwrap();
        assert_eq!(read, orig);
    }

    #[test]
    fn reading_vec_set_from_lua_works() {
        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { 1, 2, 3 }"#).unwrap();

        let read: Vec<_> = lua.get("v").unwrap();
        assert_eq!(
            read,
            [1., 2., 3.].iter()
                .map(|x| AnyLuaValue::LuaNumber(*x)).collect::<Vec<_>>());
    }
}
<|endoftext|>


<commit_before>use diesel::pg::PgValue;
use diesel::serialize::{self, IsNull, Output, ToSql};
use std::io::Write;

pub mod exports {
    pub use super::LanguageType as Language;
}

#[derive(SqlType)]
#[postgres(type_name = "Language")]
pub struct LanguageType;

#[derive(Debug, FromSqlRow, AsExpression)]
#[sql_type = "LanguageType"]
pub enum Language {
    En,
    Ru,
    De,
}

impl ToSql<LanguageType, Pg> for Language {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        match *self {
            Language::En => out.write_all(b"en")?,
            Language::Ru => out.write_all(b"ru")?,
            Language::De => out.write_all(b"de")?,
        }
        Ok(IsNull::No)
    }
}

use diesel::deserialize::{self, FromSql};
use diesel::pg::Pg;

impl FromSql<LanguageType, Pg> for Language {
    fn from_sql(bytes: Option<PgValue>) -> deserialize::Result<Self> {
        match not_none!(bytes).as_bytes() {
            b"en" => Ok(Language::En),
            b"ru" => Ok(Language::Ru),
            b"de" => Ok(Language::De),
            _ => Err("Unrecognized enum variant".into()),
        }
    }
}
<commit_msg>Fix custom types example<commit_after>use diesel::deserialize::{self, FromSql, FromSqlRow};
use diesel::expression::AsExpression;
use diesel::pg::{Pg, PgValue};
use diesel::serialize::{self, IsNull, Output, ToSql};
use diesel::sql_types::SqlType;
use std::io::Write;

pub mod exports {
    pub use super::LanguageType as Language;
}

#[derive(SqlType)]
#[postgres(type_name = "Language")]
pub struct LanguageType;

#[derive(Debug, FromSqlRow, AsExpression)]
#[sql_type = "LanguageType"]
pub enum Language {
    En,
    Ru,
    De,
}

impl ToSql<LanguageType, Pg> for Language {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        match *self {
            Language::En => out.write_all(b"en")?,
            Language::Ru => out.write_all(b"ru")?,
            Language::De => out.write_all(b"de")?,
        }
        Ok(IsNull::No)
    }
}

impl FromSql<LanguageType, Pg> for Language {
    fn from_sql(bytes: Option<PgValue>) -> deserialize::Result<Self> {
        match not_none!(bytes).as_bytes() {
            b"en" => Ok(Language::En),
            b"ru" => Ok(Language::Ru),
            b"de" => Ok(Language::De),
            _ => Err("Unrecognized enum variant".into()),
        }
    }
}
<|endoftext|>