<commit_before>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some introductory text here.
//!
//! The following example renders a 440 Hz sine wave, and stores it as as a
//! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
//!
//! ```
//! #![feature(core)]
//!
//! use std::fs;
//! use std::f32::consts::PI;
//! use std::iter::IntoIterator;
//! use std::num;
//! use hound;
//!
//! let spec = hound::WavSpec {
//!     channels: 1,
//!     sample_rate: 44100,
//!     bits_per_sample: 16
//! };
//! // TODO: ensure that the type can be inferred.
//! let mut writer = hound::WavWriter::<fs::File>::create("sine.wav", spec);
//! let mut writer = writer.ok().unwrap();
//! for t in (0 .. 44100).into_iter().map(|x| x as f32 / 44100.0) {
//!     let sample = (t * 440.0 * 2.0 * PI).sin();
//!     let amplitude: i16 = num::Int::max_value();
//!     writer.write_sample((sample * amplitude as f32) as i16).ok().unwrap();
//! }
//! writer.finalize().ok().unwrap();
//! ```

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(convert, io)]

use std::fs;
use std::io;
use std::io::{Seek, Write};
use std::path;

/// Extends the functionality of `io::Write` with additional methods.
///
/// The methods may be used on any type that implements `io::Write`.
trait WriteExt: io::Write {
    /// Writes an unsigned 16-bit integer in little endian format.
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;

    /// Writes an unsigned 32-bit integer in little endian format.
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

/// A type that can be used to represent audio samples.
pub trait Sample {
    /// Writes the audio sample to the WAVE data section.
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self)
        // TODO: take bits into account
    }
}

impl Sample for i16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self as u16)
        // TODO: take bits into account
    }
}

/// Specifies properties of the audio data.
#[derive(Clone, Copy)]
pub struct WavSpec {
    /// The number of channels.
    pub channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    pub sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    pub bits_per_sample: u32
}

/// A writer that accepts samples and writes the WAVE format.
///
/// TODO: add example.
///
/// After all samples have been written, the file must be finalized. This can
/// be done by calling `finalize`. If `finalize` is not called, the file will
/// be finalized upon drop. However, finalization involves IO that may fail,
/// and without calling `finalize`, such a failure cannot be observed.
pub struct WavWriter<W> where W: io::Write + io::Seek {
    /// Specifies properties of the audio data.
    spec: WavSpec,

    /// The (container) bytes per sample. This is the bit rate / 8 rounded up.
    bytes_per_sample: u32,

    /// Whether the header has been written already.
    wrote_header: bool,

    /// The writer that will be written to.
    writer: io::BufWriter<W>,

    /// The number of bytes written to the data section.
    ///
    /// This is an `u32` because WAVE cannot accomodate more data.
    data_bytes_written: u32,

    /// Whether `finalize_internal` has been called.
    finalized: bool
}

impl<W> WavWriter<W> where W: io::Write + io::Seek {
    /// Creates a writer that writes the WAVE format to the underlying writer.
    ///
    /// The underlying writer is assumed to be at offset 0. `WavWriter` employs
    /// buffering internally to avoid too many `write` calls to the underlying
    /// writer.
    pub fn new(writer: W, spec: WavSpec) -> WavWriter<W> {
        WavWriter {
            spec: spec,
            bytes_per_sample: (spec.bits_per_sample as f32 / 8.0).ceil() as u32,
            wrote_header: false,
            writer: io::BufWriter::new(writer),
            data_bytes_written: 0,
            finalized: false
        }
    }

    /// Creates a writer that writes the WAVE format to a file.
    ///
    /// The file will be overwritten if it exists.
    pub fn create<P: AsRef<path::Path>>(filename: P, spec: WavSpec)
           -> io::Result<WavWriter<fs::File>> {
        let file = try!(fs::File::create(filename));
        Ok(WavWriter::new(file, spec))
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        // Useful links:
        // https://msdn.microsoft.com/en-us/library/ms713462.aspx
        // https://msdn.microsoft.com/en-us/library/ms713497.aspx

        let mut header = [0u8; 70];
        let spec = &self.spec;

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            try!(buffer.write_le_u32(0));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt ".as_bytes()));
            try!(buffer.write_le_u32(16)); // Size of the WAVE header chunk.

            // The following is based on the WAVEFORMATEXTENSIBLE struct as
            // documented on MSDN.

            // The field wFormatTag, value 1 means WAVE_FORMAT_PCM, but we use
            // the slightly more sophisticated WAVE_FORMAT_EXTENSIBLE.
            try!(buffer.write_le_u16(0xfffe));
            // The field nChannels.
            try!(buffer.write_le_u16(spec.channels));
            // The field nSamplesPerSec.
            try!(buffer.write_le_u32(spec.sample_rate));
            let bytes_per_sec = spec.sample_rate
                              * self.bytes_per_sample
                              * spec.channels as u32;
            // The field nAvgBytesPerSec;
            try!(buffer.write_le_u32(bytes_per_sec));
            // The field nBlockAlign. Block align * sample rate = bytes per sec.
            try!(buffer.write_le_u16((bytes_per_sec / spec.sample_rate) as u16));
            // The field wBitsPerSample. This is actually the size of the
            // container, so this is a multiple of 8.
            try!(buffer.write_le_u32(self.bytes_per_sample * 8));
            // The field cbSize, the number of remaining bytes in the struct.
            try!(buffer.write_le_u16(22));
            // The field wValidBitsPerSample, the real number of bits per sample.
            try!(buffer.write_le_u16(self.spec.bits_per_sample as u16));
            // The field dwChannelMask.
            // TODO: add the option to specify the channel mask. For now, write
            // the stereo mask, even though it is wrong.
            try!(buffer.write_le_u32(0x1 | 0x2));
            // The field SubFormat. We use KSDATAFORMAT_SUBTYPE_PCM. The
            // following UUIDS are defined:
            // - PCM:        00000001-0000-0010-8000-00aa00389b71
            // - IEEE_FLOAT: 00000003-0000-0010-8000-00aa00389b71
            try!(buffer.write_all(&[0x00, 0x00, 0x00, 0x01,
                                    0x00, 0x00, 0x00, 0x01,
                                    0x80, 0x00, 0x00, 0xaa,
                                    0x00, 0x38, 0x9b, 0x71]));

            // So far the "fmt " section, now comes the "data" section. We will
            // only write the header here, actual data are the samples. The
            // number of bytes that this will take is not known at this point.
            // The 0 will be overwritten later.
            try!(buffer.write_all("data".as_bytes()));
            try!(buffer.write_le_u32(0));
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    /// Writes a single sample for one channel.
    ///
    /// WAVE interleaves channel data, so the channel that this writes the
    /// sample to depends on previous writes.
    pub fn write_sample<S: Sample>(&mut self, sample: S) -> io::Result<()> {
        if !self.wrote_header {
            try!(self.write_header());
        }

        // TODO: do we need bits per sample? Is the padding at the obvious side?
        try!(sample.write(&mut self.writer, self.bytes_per_sample));
        self.data_bytes_written += self.bytes_per_sample;
        Ok(())
    }

    /// Performs finalization. After calling this, the writer should be destructed.
    fn finalize_internal(&mut self) -> io::Result<()> {
        self.finalized = true;

        // Flush remaining samples via the BufWriter.
        try!(self.writer.flush());

        // Extract the underlying writer and rewind it to the start, to update
        // the header fields of which we now know the value.
        let mut writer = self.writer.get_mut();
        try!(writer.seek(io::SeekFrom::Start(0)));

        // TODO: update size fields
        Ok(())
    }

    /// Writes the parts of the WAVE format that require knowing all samples.
    ///
    /// This method must be called after all samples have been written. If it
    /// is not called, the destructor will finalize the file, but any IO errors
    /// that occur in the process cannot be observed in that manner.
    pub fn finalize(mut self) -> io::Result<()> {
        self.finalize_internal()
    }
}

impl<W> Drop for WavWriter<W> where W: io::Write + io::Seek {
    fn drop(&mut self) {
        // `finalize_internal` must be called only once. If that is done via
        // `finalize`, then this method is a no-op. If the user did not
        // finalize explicitly, then we should do it now. This can fail, but
        // drop should not panic, so a failure is ignored silently here.
        if !self.finalized {
            let _r = self.finalize_internal();
        }
    }
}
<commit_msg>fix writing the header<commit_after>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some introductory text here.
//!
//! The following example renders a 440 Hz sine wave, and stores it as as a
//! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
//!
//! ```
//! #![feature(core)]
//!
//! use std::fs;
//! use std::f32::consts::PI;
//! use std::iter::IntoIterator;
//! use std::num;
//! use hound;
//!
//! let spec = hound::WavSpec {
//!     channels: 1,
//!     sample_rate: 44100,
//!     bits_per_sample: 16
//! };
//! // TODO: ensure that the type can be inferred.
//! let mut writer = hound::WavWriter::<fs::File>::create("sine.wav", spec);
//! let mut writer = writer.ok().unwrap();
//! for t in (0 .. 44100).into_iter().map(|x| x as f32 / 44100.0) {
//!     let sample = (t * 440.0 * 2.0 * PI).sin();
//!     let amplitude: i16 = num::Int::max_value();
//!     writer.write_sample((sample * amplitude as f32) as i16).ok().unwrap();
//! }
//! writer.finalize().ok().unwrap();
//! ```

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(convert, io)]

use std::fs;
use std::io;
use std::io::{Seek, Write};
use std::path;

/// Extends the functionality of `io::Write` with additional methods.
///
/// The methods may be used on any type that implements `io::Write`.
trait WriteExt: io::Write {
    /// Writes an unsigned 16-bit integer in little endian format.
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;

    /// Writes an unsigned 32-bit integer in little endian format.
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

/// A type that can be used to represent audio samples.
pub trait Sample {
    /// Writes the audio sample to the WAVE data section.
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self)
        // TODO: take bits into account
    }
}

impl Sample for i16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self as u16)
        // TODO: take bits into account
    }
}

/// Specifies properties of the audio data.
#[derive(Clone, Copy)]
pub struct WavSpec {
    /// The number of channels.
    pub channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    pub sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    pub bits_per_sample: u32
}

/// A writer that accepts samples and writes the WAVE format.
///
/// TODO: add example.
///
/// After all samples have been written, the file must be finalized. This can
/// be done by calling `finalize`. If `finalize` is not called, the file will
/// be finalized upon drop. However, finalization involves IO that may fail,
/// and without calling `finalize`, such a failure cannot be observed.
pub struct WavWriter<W> where W: io::Write + io::Seek {
    /// Specifies properties of the audio data.
    spec: WavSpec,

    /// The (container) bytes per sample. This is the bit rate / 8 rounded up.
    bytes_per_sample: u32,

    /// Whether the header has been written already.
    wrote_header: bool,

    /// The writer that will be written to.
    writer: io::BufWriter<W>,

    /// The number of bytes written to the data section.
    ///
    /// This is an `u32` because WAVE cannot accomodate more data.
    data_bytes_written: u32,

    /// Whether `finalize_internal` has been called.
    finalized: bool
}

impl<W> WavWriter<W> where W: io::Write + io::Seek {
    /// Creates a writer that writes the WAVE format to the underlying writer.
    ///
    /// The underlying writer is assumed to be at offset 0. `WavWriter` employs
    /// buffering internally to avoid too many `write` calls to the underlying
    /// writer.
    pub fn new(writer: W, spec: WavSpec) -> WavWriter<W> {
        WavWriter {
            spec: spec,
            bytes_per_sample: (spec.bits_per_sample as f32 / 8.0).ceil() as u32,
            wrote_header: false,
            writer: io::BufWriter::new(writer),
            data_bytes_written: 0,
            finalized: false
        }
    }

    /// Creates a writer that writes the WAVE format to a file.
    ///
    /// The file will be overwritten if it exists.
    pub fn create<P: AsRef<path::Path>>(filename: P, spec: WavSpec)
           -> io::Result<WavWriter<fs::File>> {
        let file = try!(fs::File::create(filename));
        Ok(WavWriter::new(file, spec))
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        // Useful links:
        // https://msdn.microsoft.com/en-us/library/ms713462.aspx
        // https://msdn.microsoft.com/en-us/library/ms713497.aspx

        let mut header = [0u8; 70];
        let spec = &self.spec;

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            try!(buffer.write_le_u32(0));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt ".as_bytes()));
            try!(buffer.write_le_u32(42)); // Size of the WAVE header chunk.

            // The following is based on the WAVEFORMATEXTENSIBLE struct as
            // documented on MSDN.

            // The field wFormatTag, value 1 means WAVE_FORMAT_PCM, but we use
            // the slightly more sophisticated WAVE_FORMAT_EXTENSIBLE.
            try!(buffer.write_le_u16(0xfffe));
            // The field nChannels.
            try!(buffer.write_le_u16(spec.channels));
            // The field nSamplesPerSec.
            try!(buffer.write_le_u32(spec.sample_rate));
            let bytes_per_sec = spec.sample_rate
                              * self.bytes_per_sample
                              * spec.channels as u32;
            // The field nAvgBytesPerSec;
            try!(buffer.write_le_u32(bytes_per_sec));
            // The field nBlockAlign. Block align * sample rate = bytes per sec.
            try!(buffer.write_le_u16((bytes_per_sec / spec.sample_rate) as u16));
            // The field wBitsPerSample. This is actually the size of the
            // container, so this is a multiple of 8.
            try!(buffer.write_le_u16(self.bytes_per_sample as u16 * 8));
            // The field cbSize, the number of remaining bytes in the struct.
            try!(buffer.write_le_u16(22));
            // The field wValidBitsPerSample, the real number of bits per sample.
            try!(buffer.write_le_u16(self.spec.bits_per_sample as u16));
            // The field dwChannelMask.
            // TODO: add the option to specify the channel mask. For now, write
            // the stereo mask, even though it is wrong.
            try!(buffer.write_le_u32(0x1 | 0x2));
            // The field SubFormat. We use KSDATAFORMAT_SUBTYPE_PCM. The
            // following GUIDS are defined:
            // - PCM:        00000001-0000-0010-8000-00aa00389b71
            // - IEEE_FLOAT: 00000003-0000-0010-8000-00aa00389b71
            // The byte order of a GUID is native for the first three sections,
            // which is assumed to be little endian, and big endian for the
            // last 8-byte section (which does contain a hyphen, for reasons
            // unknown to me).
            try!(buffer.write_all(&[0x01, 0x00, 0x00, 0x00,
                                    0x00, 0x00, 0x10, 0x00,
                                    0x80, 0x00, 0x00, 0xaa,
                                    0x00, 0x38, 0x9b, 0x71]));

            // So far the "fmt " section, now comes the "data" section. We will
            // only write the header here, actual data are the samples. The
            // number of bytes that this will take is not known at this point.
            // The 0 will be overwritten later.
            try!(buffer.write_all("data".as_bytes()));
            try!(buffer.write_le_u32(0));
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    /// Writes a single sample for one channel.
    ///
    /// WAVE interleaves channel data, so the channel that this writes the
    /// sample to depends on previous writes.
    pub fn write_sample<S: Sample>(&mut self, sample: S) -> io::Result<()> {
        if !self.wrote_header {
            try!(self.write_header());
            self.wrote_header = true;
        }

        // TODO: do we need bits per sample? Is the padding at the obvious side?
        try!(sample.write(&mut self.writer, self.bytes_per_sample));
        self.data_bytes_written += self.bytes_per_sample;
        Ok(())
    }

    /// Performs finalization. After calling this, the writer should be destructed.
    fn finalize_internal(&mut self) -> io::Result<()> {
        self.finalized = true;

        // Flush remaining samples via the BufWriter.
        try!(self.writer.flush());

        // Extract the underlying writer and rewind it to the start, to update
        // the header fields of which we now know the value.
        let mut writer = self.writer.get_mut();
        try!(writer.seek(io::SeekFrom::Start(0)));

        // TODO: update size fields
        Ok(())
    }

    /// Writes the parts of the WAVE format that require knowing all samples.
    ///
    /// This method must be called after all samples have been written. If it
    /// is not called, the destructor will finalize the file, but any IO errors
    /// that occur in the process cannot be observed in that manner.
    pub fn finalize(mut self) -> io::Result<()> {
        self.finalize_internal()
    }
}

impl<W> Drop for WavWriter<W> where W: io::Write + io::Seek {
    fn drop(&mut self) {
        // `finalize_internal` must be called only once. If that is done via
        // `finalize`, then this method is a no-op. If the user did not
        // finalize explicitly, then we should do it now. This can fail, but
        // drop should not panic, so a failure is ignored silently here.
        if !self.finalized {
            let _r = self.finalize_internal();
        }
    }
}
<|endoftext|>


<commit_before>//! stal-rs
//! ====
//!
//! Set algebra solver for Redis in Rust, based on
//! [Stal](https://github.com/soveran/stal).
//!
//! Description
//! -----------
//!
//! `stal-rs` provide set operations and resolves them in [Redis][redis].
//!
//! Usage
//! -----
//!
//! `stal-rs` has no dependencies. It produces a vector of Redis operations that
//! have to be run by the user.
//!
//! ```rust
//! extern crate stal;
//!
//! let foobar = stal::Set::Inter(vec![stal::Set::Key(b"foo".to_vec()), stal::Set::Key(b"bar".to_vec())]);
//! let foobar_nobaz = stal::Set::Diff(vec![foobar, stal::Set::Key(b"baz".to_vec())]);
//! let foobar_nobaz_andqux = stal::Set::Union(vec![stal::Set::Key(b"qux".to_vec()), foobar_nobaz]);
//!
//! assert_eq!(
//!    stal::Stal::new("SMEMBERS".to_string(), foobar_nobaz_andqux).solve(),
//!    (
//!     vec![
//!         vec![b"MULTI".to_vec()],
//!         vec![b"SINTERSTORE".to_vec(), b"stal:2".to_vec(), b"foo".to_vec(), b"bar".to_vec()],
//!         vec![b"SDIFFSTORE".to_vec(), b"stal:1".to_vec(), b"stal:2".to_vec(), b"baz".to_vec()],
//!         vec![b"SUNIONSTORE".to_vec(), b"stal:0".to_vec(), b"qux".to_vec(), b"stal:1".to_vec()],
//!         vec![b"SMEMBERS".to_vec(), b"stal:0".to_vec()],
//!         vec![b"DEL".to_vec(), b"stal:0".to_vec(), b"stal:1".to_vec(), b"stal:2".to_vec()],
//!         vec![b"EXEC".to_vec()],
//!     ],
//!     4
//!    ));
//! ```
//!
//! `stal-rs` translates the internal calls to  `SUNION`, `SDIFF` and
//! `SINTER` into `SDIFFSTORE`, `SINTERSTORE` and `SUNIONSTORE` to
//! perform the underlying operations, and it takes care of generating
//! and deleting any temporary keys.
//!
//! The outmost command can be any set operation, for example:
//!
//! ```rust
//! extern crate stal;
//! let myset = stal::Set::Key(b"my set".to_vec());
//! stal::Stal::new("SCARD".to_string(), myset).solve();
//! ```
//!
//! If you want to preview the commands `Stal` will send to generate
//! the results, you can use `Stal.explain`:
//!
//! ```rust
//! extern crate stal;
//!
//! assert_eq!(
//! stal::Stal::new("SMEMBERS".to_string(),
//!         stal::Set::Inter(vec![
//!             stal::Set::Union(vec![
//!                 stal::Set::Key(b"foo".to_vec()),
//!                 stal::Set::Key(b"bar".to_vec()),
//!                 ]),
//!             stal::Set::Key(b"baz".to_vec()),
//!             ])
//!         ).explain(),
//! vec![
//!     vec![b"SUNIONSTORE".to_vec(), b"stal:1".to_vec(), b"foo".to_vec(), b"bar".to_vec()],
//!     vec![b"SINTERSTORE".to_vec(), b"stal:0".to_vec(), b"stal:1".to_vec(), b"baz".to_vec()],
//!     vec![b"SMEMBERS".to_vec(), b"stal:0".to_vec()],
//! ]
//! )
//! ```
//!
//! All commands are wrapped in a `MULTI/EXEC` transaction.
//!
//! [redis]: http://redis.io

#![crate_name = "stal"]
#![crate_type = "lib"]

/// A set of values. It can be generated from a Redis key or from a set
/// operation based on other sets.
#[derive(Clone)]
pub enum Set {
    /// A key
    Key(Vec<u8>),
    /// All the elements in any of the provided sets
    Union(Vec<Set>),
    /// All the elements in all the sets
    Inter(Vec<Set>),
    /// All the elements in the first set that are not in the other sets
    Diff(Vec<Set>),
}
use Set::*;

impl Set {
    /// Gets the commands to get a list of ids for this set
    pub fn into_ids(self) -> Stal {
        let (op, sets) = match self {
            Key(_) => return Stal::from_template(vec![b"SMEMBERS".to_vec(), vec![]], vec![(self, 1)]),
            Union(sets) => ("SUNION", sets),
            Inter(sets) => ("SINTER", sets),
            Diff(sets) => ("SDIFF", sets),
        };
        let mut command = vec![op.as_bytes().to_vec()];
        command.extend(sets.iter().map(|_| vec![]).collect::<Vec<_>>());
        let mut setv = vec![];
        let mut i = 1;
        for set in sets.into_iter() {
            setv.push((set, i));
            i += 1;
        }
        Stal::from_template(command, setv)
    }

    /// Gets the commands to get a list of ids for this set
    pub fn ids(&self) -> Stal {
        let (op, sets) = match *self {
            Key(_) => return Stal::from_template(vec![b"SMEMBERS".to_vec(), vec![]], vec![(self.clone(), 1)]),
            Union(ref sets) => ("SUNION", sets),
            Inter(ref sets) => ("SINTER", sets),
            Diff(ref sets) => ("SDIFF", sets),
        };
        let mut command = vec![op.as_bytes().to_vec()];
        command.extend(sets.iter().map(|_| vec![]).collect::<Vec<_>>());
        let mut setv = vec![];
        for i in 0..sets.len() {
            setv.push((sets[i].clone(), i + 1));
        }
        Stal::from_template(command, setv)
    }

    /// Maps the operation to its Redis command name.
    fn command(&self) -> &'static str {
        match *self {
            Key(_) => unreachable!(),
            Union(_) => "SUNIONSTORE",
            Inter(_) => "SINTERSTORE",
            Diff(_) => "SDIFFSTORE",
        }
    }

    /// Appends the operation to `ops` and any temporary id created to `ids`.
    /// Returns the key representing the set.
    pub fn convert(&self, ids: &mut Vec<String>, ops: &mut Vec<Vec<Vec<u8>>>) -> Vec<u8> {
        let sets = match *self {
            Key(ref k) => return k.clone(),
            Union(ref sets) => sets,
            Inter(ref sets) => sets,
            Diff(ref sets) => sets,
        };

        let mut op = Vec::with_capacity(2 + sets.len());
        let id = format!("stal:{}", ids.len());
        let r = id.as_bytes().to_vec();
        ids.push(id);
        op.push(self.command().as_bytes().to_vec());
        op.push(r.clone());
        op.extend(sets.into_iter().map(|s| s.convert(ids, ops)));
        ops.push(op);
        r
    }
}

/// An operation to be executed on a set
pub struct Stal {
    /// A Redis command
    command: Vec<Vec<u8>>,
    /// Set in which execute the operation
    sets: Vec<(Set, usize)>,
}

impl Stal {
    pub fn new(operation: String, set: Set) -> Self {
        Stal {
            command: vec![operation.as_bytes().to_vec(), vec![]],
            sets: vec![(set, 1)],
        }
    }

    /// Takes an arbitrary command that uses one or more sets. The `command`
    /// must have placeholders where the set keys should go. Each element
    /// in `sets` specifies the position in the `command`.
    pub fn from_template(command: Vec<Vec<u8>>, sets: Vec<(Set, usize)>) -> Self {
        Stal {
            command: command,
            sets: sets,
        }
    }

    fn add_ops(&self, ids: &mut Vec<String>, ops: &mut Vec<Vec<Vec<u8>>>) {
        let mut command = self.command.clone();
        for args in self.sets.iter() {
            command.push(args.0.convert(ids, ops));
            command.swap_remove(args.1);
        }
        ops.push(command);
    }

    /// Returns a list of operations to run. For debug only.
    pub fn explain(&self) -> Vec<Vec<Vec<u8>>> {
        let mut ids = vec![];
        let mut ops = vec![];
        self.add_ops(&mut ids, &mut ops);
        ops
    }

    /// Returns a lit of operations, wrapped in a multi/exec.
    /// The last operation is always exec, and the returned `usize` indicates
    /// the return value of the `operation`.
    pub fn solve(&self) -> (Vec<Vec<Vec<u8>>>, usize) {
        let mut ids = vec![];
        let mut ops = vec![vec![b"MULTI".to_vec()]];
        self.add_ops(&mut ids, &mut ops);
        let pos = ops.len() - 1;
        if ids.len() > 0 {
            let mut del = vec![b"DEL".to_vec()];
            del.extend(ids.into_iter().map(|x| x.as_bytes().to_vec()));
            ops.push(del);
        }
        ops.push(vec![b"EXEC".to_vec()]);
        (ops, pos)
    }
}
<commit_msg>Derive debug<commit_after>//! stal-rs
//! ====
//!
//! Set algebra solver for Redis in Rust, based on
//! [Stal](https://github.com/soveran/stal).
//!
//! Description
//! -----------
//!
//! `stal-rs` provide set operations and resolves them in [Redis][redis].
//!
//! Usage
//! -----
//!
//! `stal-rs` has no dependencies. It produces a vector of Redis operations that
//! have to be run by the user.
//!
//! ```rust
//! extern crate stal;
//!
//! let foobar = stal::Set::Inter(vec![stal::Set::Key(b"foo".to_vec()), stal::Set::Key(b"bar".to_vec())]);
//! let foobar_nobaz = stal::Set::Diff(vec![foobar, stal::Set::Key(b"baz".to_vec())]);
//! let foobar_nobaz_andqux = stal::Set::Union(vec![stal::Set::Key(b"qux".to_vec()), foobar_nobaz]);
//!
//! assert_eq!(
//!    stal::Stal::new("SMEMBERS".to_string(), foobar_nobaz_andqux).solve(),
//!    (
//!     vec![
//!         vec![b"MULTI".to_vec()],
//!         vec![b"SINTERSTORE".to_vec(), b"stal:2".to_vec(), b"foo".to_vec(), b"bar".to_vec()],
//!         vec![b"SDIFFSTORE".to_vec(), b"stal:1".to_vec(), b"stal:2".to_vec(), b"baz".to_vec()],
//!         vec![b"SUNIONSTORE".to_vec(), b"stal:0".to_vec(), b"qux".to_vec(), b"stal:1".to_vec()],
//!         vec![b"SMEMBERS".to_vec(), b"stal:0".to_vec()],
//!         vec![b"DEL".to_vec(), b"stal:0".to_vec(), b"stal:1".to_vec(), b"stal:2".to_vec()],
//!         vec![b"EXEC".to_vec()],
//!     ],
//!     4
//!    ));
//! ```
//!
//! `stal-rs` translates the internal calls to  `SUNION`, `SDIFF` and
//! `SINTER` into `SDIFFSTORE`, `SINTERSTORE` and `SUNIONSTORE` to
//! perform the underlying operations, and it takes care of generating
//! and deleting any temporary keys.
//!
//! The outmost command can be any set operation, for example:
//!
//! ```rust
//! extern crate stal;
//! let myset = stal::Set::Key(b"my set".to_vec());
//! stal::Stal::new("SCARD".to_string(), myset).solve();
//! ```
//!
//! If you want to preview the commands `Stal` will send to generate
//! the results, you can use `Stal.explain`:
//!
//! ```rust
//! extern crate stal;
//!
//! assert_eq!(
//! stal::Stal::new("SMEMBERS".to_string(),
//!         stal::Set::Inter(vec![
//!             stal::Set::Union(vec![
//!                 stal::Set::Key(b"foo".to_vec()),
//!                 stal::Set::Key(b"bar".to_vec()),
//!                 ]),
//!             stal::Set::Key(b"baz".to_vec()),
//!             ])
//!         ).explain(),
//! vec![
//!     vec![b"SUNIONSTORE".to_vec(), b"stal:1".to_vec(), b"foo".to_vec(), b"bar".to_vec()],
//!     vec![b"SINTERSTORE".to_vec(), b"stal:0".to_vec(), b"stal:1".to_vec(), b"baz".to_vec()],
//!     vec![b"SMEMBERS".to_vec(), b"stal:0".to_vec()],
//! ]
//! )
//! ```
//!
//! All commands are wrapped in a `MULTI/EXEC` transaction.
//!
//! [redis]: http://redis.io

#![crate_name = "stal"]
#![crate_type = "lib"]

/// A set of values. It can be generated from a Redis key or from a set
/// operation based on other sets.
#[derive(Debug, Clone)]
pub enum Set {
    /// A key
    Key(Vec<u8>),
    /// All the elements in any of the provided sets
    Union(Vec<Set>),
    /// All the elements in all the sets
    Inter(Vec<Set>),
    /// All the elements in the first set that are not in the other sets
    Diff(Vec<Set>),
}
use Set::*;

impl Set {
    /// Gets the commands to get a list of ids for this set
    pub fn into_ids(self) -> Stal {
        let (op, sets) = match self {
            Key(_) => return Stal::from_template(vec![b"SMEMBERS".to_vec(), vec![]], vec![(self, 1)]),
            Union(sets) => ("SUNION", sets),
            Inter(sets) => ("SINTER", sets),
            Diff(sets) => ("SDIFF", sets),
        };
        let mut command = vec![op.as_bytes().to_vec()];
        command.extend(sets.iter().map(|_| vec![]).collect::<Vec<_>>());
        let mut setv = vec![];
        let mut i = 1;
        for set in sets.into_iter() {
            setv.push((set, i));
            i += 1;
        }
        Stal::from_template(command, setv)
    }

    /// Gets the commands to get a list of ids for this set
    pub fn ids(&self) -> Stal {
        let (op, sets) = match *self {
            Key(_) => return Stal::from_template(vec![b"SMEMBERS".to_vec(), vec![]], vec![(self.clone(), 1)]),
            Union(ref sets) => ("SUNION", sets),
            Inter(ref sets) => ("SINTER", sets),
            Diff(ref sets) => ("SDIFF", sets),
        };
        let mut command = vec![op.as_bytes().to_vec()];
        command.extend(sets.iter().map(|_| vec![]).collect::<Vec<_>>());
        let mut setv = vec![];
        for i in 0..sets.len() {
            setv.push((sets[i].clone(), i + 1));
        }
        Stal::from_template(command, setv)
    }

    /// Maps the operation to its Redis command name.
    fn command(&self) -> &'static str {
        match *self {
            Key(_) => unreachable!(),
            Union(_) => "SUNIONSTORE",
            Inter(_) => "SINTERSTORE",
            Diff(_) => "SDIFFSTORE",
        }
    }

    /// Appends the operation to `ops` and any temporary id created to `ids`.
    /// Returns the key representing the set.
    pub fn convert(&self, ids: &mut Vec<String>, ops: &mut Vec<Vec<Vec<u8>>>) -> Vec<u8> {
        let sets = match *self {
            Key(ref k) => return k.clone(),
            Union(ref sets) => sets,
            Inter(ref sets) => sets,
            Diff(ref sets) => sets,
        };

        let mut op = Vec::with_capacity(2 + sets.len());
        let id = format!("stal:{}", ids.len());
        let r = id.as_bytes().to_vec();
        ids.push(id);
        op.push(self.command().as_bytes().to_vec());
        op.push(r.clone());
        op.extend(sets.into_iter().map(|s| s.convert(ids, ops)));
        ops.push(op);
        r
    }
}

/// An operation to be executed on a set
#[derive(Debug)]
pub struct Stal {
    /// A Redis command
    command: Vec<Vec<u8>>,
    /// Set in which execute the operation
    sets: Vec<(Set, usize)>,
}

impl Stal {
    pub fn new(operation: String, set: Set) -> Self {
        Stal {
            command: vec![operation.as_bytes().to_vec(), vec![]],
            sets: vec![(set, 1)],
        }
    }

    /// Takes an arbitrary command that uses one or more sets. The `command`
    /// must have placeholders where the set keys should go. Each element
    /// in `sets` specifies the position in the `command`.
    pub fn from_template(command: Vec<Vec<u8>>, sets: Vec<(Set, usize)>) -> Self {
        Stal {
            command: command,
            sets: sets,
        }
    }

    fn add_ops(&self, ids: &mut Vec<String>, ops: &mut Vec<Vec<Vec<u8>>>) {
        let mut command = self.command.clone();
        for args in self.sets.iter() {
            command.push(args.0.convert(ids, ops));
            command.swap_remove(args.1);
        }
        ops.push(command);
    }

    /// Returns a list of operations to run. For debug only.
    pub fn explain(&self) -> Vec<Vec<Vec<u8>>> {
        let mut ids = vec![];
        let mut ops = vec![];
        self.add_ops(&mut ids, &mut ops);
        ops
    }

    /// Returns a lit of operations, wrapped in a multi/exec.
    /// The last operation is always exec, and the returned `usize` indicates
    /// the return value of the `operation`.
    pub fn solve(&self) -> (Vec<Vec<Vec<u8>>>, usize) {
        let mut ids = vec![];
        let mut ops = vec![vec![b"MULTI".to_vec()]];
        self.add_ops(&mut ids, &mut ops);
        let pos = ops.len() - 1;
        if ids.len() > 0 {
            let mut del = vec![b"DEL".to_vec()];
            del.extend(ids.into_iter().map(|x| x.as_bytes().to_vec()));
            ops.push(del);
        }
        ops.push(vec![b"EXEC".to_vec()]);
        (ops, pos)
    }
}
<|endoftext|>


<commit_before>#![crate_name = "tcp_simple"]
#![crate_type="lib"]

use std::thread;
use std::io::{Read, Write};
use std::sync::mpsc::channel;
use std::collections::HashMap;
use std::sync::mpsc::{Sender, Receiver};
use std::net::{TcpListener, TcpStream, Shutdown, SocketAddrV4, SocketAddr};

pub struct Message {
  pub count: usize,
  pub buf: [u8; 1400],
}

pub struct TcpCfg {
  pub address: SocketAddrV4,
  pub max_conn: usize,
}

pub struct TcpSock {
  conns: HashMap<SocketAddrV4, TcpStream>,
  listener: TcpListener,
  msg_rx: Receiver<Message>,
  conn_rx: Receiver<(SocketAddrV4, TcpStream)>,
  disc_rx: Receiver<SocketAddrV4>,
}

pub enum TcpErr {
  NotConnected,
  IoErr(std::io::Error),
}

pub enum TcpEvent {
  RecvMsg(Message),
  NewConn(SocketAddrV4),
  Disconn(SocketAddrV4),
  Nil,
}

impl TcpSock {
  pub fn new_from_cfg(cfg: TcpCfg) -> TcpSock {
    let conns = HashMap::new();
    let listener = TcpListener::bind(cfg.address).unwrap();

    let (conn_tx, conn_rx) = channel();
    let (disc_tx, disc_rx) = channel();
    let (recv_tx, recv_rx) = channel();
    let accept_listener = listener.try_clone().unwrap();
    let sock = TcpSock{
      conns: conns,
      listener: listener,
      msg_rx: recv_rx,
      conn_rx: conn_rx,
      disc_rx: disc_rx,
    };

    thread::spawn(move|| {
      TcpSock::accept_loop(conn_tx, recv_tx, disc_tx, &accept_listener);
    });

    sock
  }

  pub fn close(self) {
    drop(self.listener);
  }

  pub fn receive(&mut self) -> Option<Message> {
    match self.msg_rx.try_recv() {
      Ok(m) => Some(m),
      Err(_) => None,
    }
  }

  fn recv_loop(recv_tx: Sender<Message>, disc_tx: Sender<SocketAddrV4>, mut conn: TcpStream) {
    let mut buf = [0; 1400];
    loop {
      match conn.read(&mut buf) {
        Ok(count) if count > 0 => {
          match recv_tx.send(Message{count: count, buf: buf}) {
            Ok(_) => {},
            Err(_) => break,
          }
        },
        _ => break,
      }
    }
    let _ = conn.shutdown(Shutdown::Both);
    match conn.peer_addr().unwrap() {
        SocketAddr::V4(s) => { let _ = disc_tx.send(s); },
        _ => {},
    };
  }

  fn accept_loop(conn_tx: Sender<(SocketAddrV4, TcpStream)>,
                 recv_tx: Sender<Message>,
                 disc_tx: Sender<SocketAddrV4>,
                 listener: &TcpListener)
  {
    for stream in listener.incoming() {
      match stream {
        Ok(stream) => {
          match stream.try_clone() {
            Ok(c) => {
              let rtx = recv_tx.clone();
              let dtx = disc_tx.clone();
              thread::spawn(move|| {
                TcpSock::recv_loop(rtx, dtx, c);
              });
            },
            Err(_) => { continue; },
          }
          match stream.peer_addr().unwrap() {
            SocketAddr::V4(s) => {
              match conn_tx.send((s, stream)) {
                Ok(_) => {},
                Err(_) => return,
              }
            }
            _ => {}
          }
        },
        Err(_) => continue,
      };
    }
  }

  pub fn send(&mut self, to: &SocketAddrV4, buf: &[u8]) -> Result<usize, TcpErr> {
    match self.conns.get_mut(&to) {
      Some(conn) => match conn.write(buf) {
        Ok(s) => Ok(s),
        Err(e) => Err(TcpErr::IoErr(e)),
      },
      _ => Err(TcpErr::NotConnected)
    }
  }

  pub fn send_to_all(&mut self, buf: &[u8]) {
    for (_, conn) in self.conns.iter_mut() {
      let _ = conn.write(buf);
    }
  }

  pub fn poll(&mut self) -> TcpEvent {
    match self.conn_rx.try_recv() {
      Ok((addr, conn)) => {
        self.conns.insert(addr, conn);
        return TcpEvent::NewConn(addr);
      },
      Err(_) => {},
    };

    match self.disc_rx.try_recv() {
      Ok(addr) => {
        self.conns.remove(&addr);
        return TcpEvent::Disconn(addr);
      }
      Err(_) => {},
    }

    match self.msg_rx.try_recv() {
      Ok(msg) => return TcpEvent::RecvMsg(msg),
      Err(_) => {},
    };

    TcpEvent::Nil
  }

  pub fn disconnect(&mut self, disc: &SocketAddrV4) -> Result<(), TcpErr> {
    match self.conns.get_mut(&disc) {
      Some(conn) => match conn.shutdown(Shutdown::Both) {
        Ok(()) => {},
        Err(e) => { return Err(TcpErr::IoErr(e)); },
      },
      _ => { return Err(TcpErr::NotConnected); },
    };
    self.conns.remove(disc).unwrap();
    Ok(())
  }
}
<commit_msg>Clean up extraneous pattern matching<commit_after>#![crate_name = "tcp_simple"]
#![crate_type="lib"]

use std::thread;
use std::io::{Read, Write};
use std::sync::mpsc::channel;
use std::collections::HashMap;
use std::sync::mpsc::{Sender, Receiver};
use std::net::{TcpListener, TcpStream, Shutdown, SocketAddrV4, SocketAddr};

pub struct Message {
  pub count: usize,
  pub buf: [u8; 1400],
}

pub struct TcpCfg {
  pub address: SocketAddrV4,
  pub max_conn: usize,
}

pub struct TcpSock {
  conns: HashMap<SocketAddrV4, TcpStream>,
  listener: TcpListener,
  msg_rx: Receiver<Message>,
  conn_rx: Receiver<(SocketAddrV4, TcpStream)>,
  disc_rx: Receiver<SocketAddrV4>,
}

pub enum TcpErr {
  NotConnected,
  IoErr(std::io::Error),
}

pub enum TcpEvent {
  RecvMsg(Message),
  NewConn(SocketAddrV4),
  Disconn(SocketAddrV4),
  Nil,
}

impl TcpSock {
  pub fn new_from_cfg(cfg: TcpCfg) -> TcpSock {
    let conns = HashMap::new();
    let listener = TcpListener::bind(cfg.address).unwrap();
    let (conn_tx, conn_rx) = channel();
    let (disc_tx, disc_rx) = channel();
    let (recv_tx, recv_rx) = channel();
    let accept_listener = listener.try_clone().unwrap();

    let sock = TcpSock{
      conns: conns,
      listener: listener,
      msg_rx: recv_rx,
      conn_rx: conn_rx,
      disc_rx: disc_rx,
    };

    thread::spawn(move|| {
      TcpSock::accept_loop(conn_tx, recv_tx, disc_tx, &accept_listener);
    });

    sock
  }

  pub fn close(self) {
    drop(self.listener);
  }

  pub fn receive(&mut self) -> Option<Message> {
    match self.msg_rx.try_recv() {
      Ok(m) => Some(m),
      Err(_) => None,
    }
  }

  fn recv_loop(recv_tx: Sender<Message>, disc_tx: Sender<SocketAddrV4>, mut conn: TcpStream) {
    let mut buf = [0; 1400];
    while let Ok(count) = conn.read(&mut buf) {
      match recv_tx.send(Message{count: count, buf: buf}) {
        Ok(_) => {},
        Err(_) => break,
      }
    }
    let _ = conn.shutdown(Shutdown::Both);
    if let SocketAddr::V4(s) = conn.peer_addr().unwrap() {
      let _ = disc_tx.send(s);
    };
  }

  fn accept_loop(conn_tx: Sender<(SocketAddrV4, TcpStream)>,
                 recv_tx: Sender<Message>,
                 disc_tx: Sender<SocketAddrV4>,
                 listener: &TcpListener)
  {
    for stream in listener.incoming() {
      if let Ok(s) = stream {
        let c = s.try_clone().unwrap();
        let rtx = recv_tx.clone();
        let dtx = disc_tx.clone();
        thread::spawn(move|| {
          TcpSock::recv_loop(rtx, dtx, c);
        });

        if let SocketAddr::V4(addr) = s.peer_addr().unwrap() {
          match conn_tx.send((addr, s)) {
            Ok(_) => {},
            Err(_) => return,
          }
        };
      }
    }
  }

  pub fn send(&mut self, to: &SocketAddrV4, buf: &[u8]) -> Result<usize, TcpErr> {
    match self.conns.get_mut(&to) {
      Some(conn) => match conn.write(buf) {
        Ok(s) => Ok(s),
        Err(e) => Err(TcpErr::IoErr(e)),
      },
      _ => Err(TcpErr::NotConnected)
    }
  }

  pub fn send_to_all(&mut self, buf: &[u8]) {
    let _ = self.conns.iter_mut().map(|(_,c)| { c.write(buf) });
  }

  pub fn poll(&mut self) -> TcpEvent {
    if let Ok((addr, conn)) = self.conn_rx.try_recv() {
      self.conns.insert(addr, conn);
      return TcpEvent::NewConn(addr);
    }

    if let Ok(addr) = self.disc_rx.try_recv() {
      self.conns.remove(&addr);
      return TcpEvent::Disconn(addr);
    }

    match self.msg_rx.try_recv() {
      Ok(msg) => return TcpEvent::RecvMsg(msg),
      Err(_) => {},
    };

    TcpEvent::Nil
  }

  pub fn disconnect(&mut self, disc: &SocketAddrV4) -> Result<(), TcpErr> {
    match self.conns.get_mut(&disc) {
      Some(conn) => match conn.shutdown(Shutdown::Both) {
        Ok(()) => {},
        Err(e) => { return Err(TcpErr::IoErr(e)); },
      },
      _ => { return Err(TcpErr::NotConnected); },
    };
    self.conns.remove(disc).unwrap();
    Ok(())
  }
}
<|endoftext|>


<commit_before>//! A library for creating General Game Playing (GGP) players. This library is based off of
//! [GGP Base](https://github.com/ggp-org/ggp-base). While GGP Base allows the creation of
//! players backed by a propositional network or a logic prover, this library currently only
//! supports logic prover based players.
//!
//! # Example
//!
//! To create your own player, simply implement the `Player` trait for your struct and pass the
//! host/port you want the player to run at and the player itself to the `run` function.
//!
//! The following example implements a RandomPlayer, which plays random legal moves each turn.
//!
//! ```ignore
//! extern crate rand;
//! extern crate ggp_rs;
//!
//! use ggp_rs::{Player, Game, Move};
//! use std::net::Ipv4Addr;
//!
//! struct RandomPlayer;
//!
//! impl Player for RandomPlayer {
//!     fn get_name(&self) -> String {
//!         "RandomPlayer".to_string()
//!     }
//!
//!     fn select_move(&self, game: &Game) -> Move {
//!         let state = game.get_current_state();
//!         let role = game.get_role();
//!         let mut moves = game.get_legal_moves(state, role);
//!         let r = rand::random::<usize>() % moves.len();
//!         moves.swap_remove(r)
//!     }
//! }
//!
//! fn main() {
//!     ggp_rs::run((Ipv4Addr::new(0,0,0,0), 9147), RandomPlayer);
//! }
//! ```

#![feature(plugin)]
#![cfg_attr(all(test, feature = "unstable"), feature(test))]

extern crate time;
extern crate gdl_parser;
extern crate hyper;
extern crate regex;
extern crate unicase;

#[macro_use]
extern crate log;

#[macro_use]
extern crate lazy_static;

mod util;
mod game_manager;
mod gdl;
mod prover;

use unicase::UniCase;

use hyper::Server;
use hyper::error::HttpError::HttpIoError;
use hyper::server::{Request, Response, Handler};
use hyper::header::{ContentLength, ContentType, AccessControlAllowOrigin,
                    AccessControlAllowHeaders};
use hyper::net::Fresh;
use hyper::version::HttpVersion;

use std::net::ToSocketAddrs;
use std::io::{Read, Write};
use std::sync::Mutex;
use std::ascii::AsciiExt;

use game_manager::GameManager;

pub use game_manager::{Game, State};
pub use gdl::{constants, Move, Role, Score};

pub type MoveResult<T> = Result<T, Move>;

#[macro_export]
macro_rules! check_time {
    ($self_:ident, $game:ident) => (
        if $game.move_start_time().to(time::PreciseTime::now()) >
            time::Duration::milliseconds(
                (1000 * $game.get_start_clock() - $self_.cutoff()) as i64) {
            return $self_.out_of_time($game);
        });
}

#[macro_export]
macro_rules! check_time_result {
    ($self_:ident, $game:ident) => (
        if $game.move_start_time().to(time::PreciseTime::now()) >
            time::Duration::milliseconds(
                (1000 * $game.get_start_clock() - $self_.cutoff()) as i64) {
            return Err($self_.out_of_time($game));
        });
}

/// A GGP player
pub trait Player {
    /// Returns the name of this player
    fn get_name(&self) -> String;

    /// Called after receiving a `start` message. Used to perform any computation before the start
    /// of the game.
    fn meta_game(&mut self, _: &Game) {}

    /// Called after receiving a `play` message. Returns a `Move` for this turn.
    fn select_move(&mut self, game: &Game) -> Move;

    /// The cutoff for the remaining time for the start or play clock in milliseconds, after which
    /// `out_of_time` should be called. Note that this function does not call `out_of_time`, but is
    /// simply used by other functions when deciding whether to call it. Defaults to 500
    /// milliseconds.
    fn cutoff(&self) -> u32 { 500 }

    /// Gets a move to play when there is no more time left for computation.
    fn out_of_time(&mut self, _: &Game) -> Move { unimplemented!() }

    /// Called when a game is finished or aborted
    fn stop(&mut self, _: &Game) {}
}

/// Starts a GGP player listening at `host`
pub fn run<T: ToSocketAddrs + 'static, P: Player + Sync + Send + 'static>(host: T, player: P) {
    let handler = GameHandler::new(player);
    match Server::http(handler).listen(host) {
        Err(HttpIoError(e)) => panic!("{}", e),
        Err(e) => panic!("{}", e),
        _ => ()
    }
}

struct GameHandler<P: Player + Send> {
    pub gm: Mutex<GameManager<P>>
}

impl<P: Player + Send> GameHandler<P> {
    pub fn new(player: P) -> GameHandler<P> {
        GameHandler { gm: Mutex::new(GameManager::new(player)) }
    }
}

impl<P: Player + Sync + Send> Handler for GameHandler<P> {
    fn handle(&self, mut req: Request, mut res: Response<Fresh>) {
        let mut req_str = String::new();
        req.read_to_string(&mut req_str).unwrap();
        let req_str = req_str.to_ascii_lowercase(); // TODO: Avoid allocation
        info!("Got request: {}", req_str);

        let response = {
            let mut gm = self.gm.lock().unwrap();
            gm.handle(req_str)
        };
        let response = response.into_bytes();
        res.headers_mut().set(ContentLength(response.len() as u64));
        res.headers_mut().set(ContentType("text/acl".parse().unwrap()));
        res.headers_mut().set(AccessControlAllowOrigin::Any);
        res.headers_mut().set(AccessControlAllowHeaders(
            vec![UniCase("Content-Type".to_string())]));
        res.version = HttpVersion::Http10;
        let mut res = res.start().unwrap();
        res.write_all(&response).unwrap();
        res.end().unwrap();
    }
}
<commit_msg>Don't publicly export constants<commit_after>//! A library for creating General Game Playing (GGP) players. This library is based off of
//! [GGP Base](https://github.com/ggp-org/ggp-base). While GGP Base allows the creation of
//! players backed by a propositional network or a logic prover, this library currently only
//! supports logic prover based players.
//!
//! # Example
//!
//! To create your own player, simply implement the `Player` trait for your struct and pass the
//! host/port you want the player to run at and the player itself to the `run` function.
//!
//! The following example implements a RandomPlayer, which plays random legal moves each turn.
//!
//! ```ignore
//! extern crate rand;
//! extern crate ggp_rs;
//!
//! use ggp_rs::{Player, Game, Move};
//! use std::net::Ipv4Addr;
//!
//! struct RandomPlayer;
//!
//! impl Player for RandomPlayer {
//!     fn get_name(&self) -> String {
//!         "RandomPlayer".to_string()
//!     }
//!
//!     fn select_move(&self, game: &Game) -> Move {
//!         let state = game.get_current_state();
//!         let role = game.get_role();
//!         let mut moves = game.get_legal_moves(state, role);
//!         let r = rand::random::<usize>() % moves.len();
//!         moves.swap_remove(r)
//!     }
//! }
//!
//! fn main() {
//!     ggp_rs::run((Ipv4Addr::new(0,0,0,0), 9147), RandomPlayer);
//! }
//! ```

#![feature(plugin)]
#![cfg_attr(all(test, feature = "unstable"), feature(test))]

extern crate time;
extern crate gdl_parser;
extern crate hyper;
extern crate regex;
extern crate unicase;

#[macro_use]
extern crate log;

#[macro_use]
extern crate lazy_static;

mod util;
mod game_manager;
mod gdl;
mod prover;

use unicase::UniCase;

use hyper::Server;
use hyper::error::HttpError::HttpIoError;
use hyper::server::{Request, Response, Handler};
use hyper::header::{ContentLength, ContentType, AccessControlAllowOrigin,
                    AccessControlAllowHeaders};
use hyper::net::Fresh;
use hyper::version::HttpVersion;

use std::net::ToSocketAddrs;
use std::io::{Read, Write};
use std::sync::Mutex;
use std::ascii::AsciiExt;

use game_manager::GameManager;

pub use game_manager::{Game, State};
pub use gdl::{Move, Role, Score};

pub type MoveResult<T> = Result<T, Move>;

#[macro_export]
macro_rules! check_time {
    ($self_:ident, $game:ident) => (
        if $game.move_start_time().to(time::PreciseTime::now()) >
            time::Duration::milliseconds(
                (1000 * $game.get_start_clock() - $self_.cutoff()) as i64) {
            return $self_.out_of_time($game);
        });
}

#[macro_export]
macro_rules! check_time_result {
    ($self_:ident, $game:ident) => (
        if $game.move_start_time().to(time::PreciseTime::now()) >
            time::Duration::milliseconds(
                (1000 * $game.get_start_clock() - $self_.cutoff()) as i64) {
            return Err($self_.out_of_time($game));
        });
}

/// A GGP player
pub trait Player {
    /// Returns the name of this player
    fn get_name(&self) -> String;

    /// Called after receiving a `start` message. Used to perform any computation before the start
    /// of the game.
    fn meta_game(&mut self, _: &Game) {}

    /// Called after receiving a `play` message. Returns a `Move` for this turn.
    fn select_move(&mut self, game: &Game) -> Move;

    /// The cutoff for the remaining time for the start or play clock in milliseconds, after which
    /// `out_of_time` should be called. Note that this function does not call `out_of_time`, but is
    /// simply used by other functions when deciding whether to call it. Defaults to 500
    /// milliseconds.
    fn cutoff(&self) -> u32 { 500 }

    /// Gets a move to play when there is no more time left for computation.
    fn out_of_time(&mut self, _: &Game) -> Move { unimplemented!() }

    /// Called when a game is finished or aborted
    fn stop(&mut self, _: &Game) {}
}

/// Starts a GGP player listening at `host`
pub fn run<T: ToSocketAddrs + 'static, P: Player + Sync + Send + 'static>(host: T, player: P) {
    let handler = GameHandler::new(player);
    match Server::http(handler).listen(host) {
        Err(HttpIoError(e)) => panic!("{}", e),
        Err(e) => panic!("{}", e),
        _ => ()
    }
}

struct GameHandler<P: Player + Send> {
    pub gm: Mutex<GameManager<P>>
}

impl<P: Player + Send> GameHandler<P> {
    pub fn new(player: P) -> GameHandler<P> {
        GameHandler { gm: Mutex::new(GameManager::new(player)) }
    }
}

impl<P: Player + Sync + Send> Handler for GameHandler<P> {
    fn handle(&self, mut req: Request, mut res: Response<Fresh>) {
        let mut req_str = String::new();
        req.read_to_string(&mut req_str).unwrap();
        let req_str = req_str.to_ascii_lowercase(); // TODO: Avoid allocation
        info!("Got request: {}", req_str);

        let response = {
            let mut gm = self.gm.lock().unwrap();
            gm.handle(req_str)
        };
        let response = response.into_bytes();
        res.headers_mut().set(ContentLength(response.len() as u64));
        res.headers_mut().set(ContentType("text/acl".parse().unwrap()));
        res.headers_mut().set(AccessControlAllowOrigin::Any);
        res.headers_mut().set(AccessControlAllowHeaders(
            vec![UniCase("Content-Type".to_string())]));
        res.version = HttpVersion::Http10;
        let mut res = res.start().unwrap();
        res.write_all(&response).unwrap();
        res.end().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate lmdb;
extern crate lmdb_sys;

#[cfg(test)]
extern crate tempdir;

use std::{result, str};
use std::path::Path;
use lmdb::{Cursor, DUP_SORT, INTEGER_KEY};
use lmdb::Transaction as LmdbTransaction;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Error {
    DbCreateError,
    DbOpenError,
    DbWriteError,
    DbCorruptError,
    ParseError,
    TransactionError,
    PathError,
    NotFoundError,
}

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

pub struct LmdbAdapter {
    env: lmdb::Environment,
    nodes: lmdb::Database,
    entries: lmdb::Database,
}

pub struct RwTransaction<'a>(lmdb::RwTransaction<'a>);
pub struct RoTransaction<'a>(lmdb::RoTransaction<'a>);

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct Id(u64);

pub struct Node<'a> {
    pub id: Id,
    pub parent_id: Id,
    pub name: &'a str,
}

pub struct Entry<'a> {
    pub node: Node<'a>,
    pub objectclass: &'a str,
}

// Ids are 64-bit integers in host-native byte order
// LMDB has special optimizations for host-native integers as keys
impl Id {
    fn root() -> Id {
        Id(0)
    }

    fn from_bytes(bytes: &[u8]) -> Result<Id> {
        if bytes.len() != 8 {
            return Err(Error::ParseError);
        }

        let mut id = [0u8; 8];
        id.copy_from_slice(&bytes[0..8]);

        Ok(Id(unsafe { std::mem::transmute(id) }))
    }

    fn as_bytes(self) -> [u8; 8] {
        let Id(id) = self;
        unsafe { std::mem::transmute(id) }
    }

    fn next(self) -> Id {
        let Id(id) = self;
        Id(id + 1)
    }
}

impl<'a> Node<'a> {
    fn root() -> Node<'a> {
        Node {
            id: Id::root(),
            parent_id: Id::root(),
            name: "/",
        }
    }

    fn from_parent_id_and_bytes(parent_id: Id, bytes: &[u8]) -> Result<Node> {
        if bytes.len() < 8 {
            return Err(Error::DbCorruptError);
        }

        let id = try!(Id::from_bytes(&bytes[0..8]));
        let name = try!(std::str::from_utf8(&bytes[8..]).map_err(|_err| Error::DbCorruptError));

        Ok(Node {
            id: id,
            parent_id: parent_id,
            name: name,
        })
    }

    // TODO: since LMDB is ordered, we could e.g. perform a binary search
    fn find_child_node<T: Transaction>(&self,
                                       txn: &T,
                                       nodes: lmdb::Database,
                                       name: &str)
                                       -> Result<Node<'a>> {
        let mut cursor = try!(txn.open_ro_cursor(nodes)
                                 .map_err(|_err| Error::TransactionError));

        let mut child_node = None;

        for (id, node_bytes) in cursor.iter_from(self.id.as_bytes()) {
            if id != self.id.as_bytes() {
                return Err(Error::NotFoundError);
            }

            let node = try!(Node::from_parent_id_and_bytes(self.id, node_bytes));

            if node.name == name {
                child_node = Some(node);
                break;
            }
        }

        child_node.ok_or(Error::NotFoundError)
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(8 + self.name.len());
        bytes.extend_from_slice(&self.id.as_bytes());
        bytes.extend_from_slice(self.name.as_bytes());
        bytes
    }
}

impl LmdbAdapter {
    pub fn create_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new()
                           .set_max_dbs(8)
                           .open_with_permissions(&path, 0o600)
                           .map_err(|_err| Error::DbCreateError));

        let nodes = try!(env.create_db(Some("nodes"), INTEGER_KEY | DUP_SORT)
                            .map_err(|_err| Error::DbCreateError));

        let entries = try!(env.create_db(Some("entries"), INTEGER_KEY)
                              .map_err(|_err| Error::DbCreateError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn open_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new().open(&path).map_err(|_err| Error::DbOpenError));

        let nodes = try!(env.open_db(Some("nodes")).map_err(|_err| Error::DbOpenError));

        let entries = try!(env.open_db(Some("entries")).map_err(|_err| Error::DbOpenError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn rw_transaction(&self) -> Result<RwTransaction> {
        match self.env.begin_rw_txn() {
            Ok(txn) => Ok(RwTransaction(txn)),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn ro_transaction(&self) -> Result<RoTransaction> {
        match self.env.begin_ro_txn() {
            Ok(txn) => Ok(RoTransaction(txn)),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn next_available_id<T: Transaction>(&self, txn: &T) -> Result<Id> {
        let cursor = try!(txn.open_ro_cursor(self.nodes)
                             .map_err(|_err| Error::TransactionError));

        let last_id = match cursor.get(None, None, lmdb_sys::MDB_LAST) {
            Ok((id, _)) => Id::from_bytes(id.unwrap()).unwrap(),
            Err(_) => Id::root(),
        };

        Ok(last_id.next())
    }

    pub fn create_entry<'a>(&'a self,
                            txn: &'a mut RwTransaction,
                            id: Id,
                            parent_id: Id,
                            name: &'a str,
                            objectclass: &'a str)
                            -> Result<Entry> {
        let node = Node {
            id: id,
            parent_id: parent_id,
            name: name,
        };

        try!(txn.put(self.nodes, &parent_id.as_bytes(), &node.to_bytes())
                .map_err(|_err| Error::DbWriteError));

        try!(txn.put(self.entries, &id.as_bytes(), &objectclass.as_bytes())
                .map_err(|_err| Error::DbWriteError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    pub fn find_entry<'a, T: Transaction>(&'a self, txn: &'a T, path: &str) -> Result<Entry> {
        let node = try!(self.find_node(txn, path));

        let entry_bytes = try!(txn.get(self.entries, &node.id.as_bytes())
                                  .map_err(|_err| Error::DbCorruptError));

        let objectclass = try!(std::str::from_utf8(&entry_bytes)
                                   .map_err(|_err| Error::DbCorruptError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    fn find_node<T: Transaction>(&self, txn: &T, path: &str) -> Result<Node> {
        let all_components: Vec<&str> = path.split("/").collect();

        if all_components.is_empty() {
            return Err(Error::PathError);
        }

        let (prefix, components) = all_components.split_first().unwrap();

        // Does the path start with something other than "/"?
        if !prefix.is_empty() {
            return Err(Error::PathError);
        }

        components.iter().fold(Ok(Node::root()), |parent_node, component| {
            try!(parent_node).find_child_node(txn, self.nodes, component)
        })
    }
}

pub trait Transaction {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]>;
    fn commit(self) -> Result<()>;
    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor>;
}

impl<'a> Transaction for RwTransaction<'a> {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]> {
        self.0.get(database, &key).map_err(|_err| Error::TransactionError)
    }

    fn commit(self) -> Result<()> {
        self.0.commit().map_err(|_err| Error::TransactionError)
    }

    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor> {
        self.0.open_ro_cursor(db)
    }
}

impl<'a> Transaction for RoTransaction<'a> {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]> {
        self.0.get(database, &key).map_err(|_err| Error::TransactionError)
    }

    fn commit(self) -> Result<()> {
        self.0.commit().map_err(|_err| Error::TransactionError)
    }

    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor> {
        self.0.open_ro_cursor(db)
    }
}

impl<'a> RwTransaction<'a> {
    fn put(&mut self, database: lmdb::Database, key: &[u8], data: &[u8]) -> Result<()> {
        self.0
            .put(database, &key, &data, lmdb::WriteFlags::empty())
            .map_err(|_err| Error::TransactionError)
    }
}

#[cfg(test)]
mod tests {
    use {LmdbAdapter, Id, Transaction};
    use tempdir::TempDir;

    fn create_database() -> LmdbAdapter {
        let dir = TempDir::new("ithos-test").unwrap();
        LmdbAdapter::create_database(dir.path()).unwrap()
    }

    #[test]
    fn test_entry_lookup() {
        let adapter = create_database();

        {
            let mut txn = adapter.rw_transaction().unwrap();

            let domain_id = adapter.next_available_id(&txn).unwrap();
            adapter.create_entry(&mut txn, domain_id, Id::root(), "example.com", "domain").unwrap();

            let hosts_id = domain_id.next();
            adapter.create_entry(&mut txn, hosts_id, domain_id, "hosts", "ou").unwrap();

            let host_id = hosts_id.next();
            adapter.create_entry(&mut txn, host_id, hosts_id, "master.example.com", "host")
                   .unwrap();

            txn.commit().unwrap();
        }

        {
            let txn = adapter.ro_transaction().unwrap();

            {
                let entry = adapter.find_entry(&txn, "/example.com/hosts/master.example.com")
                                   .unwrap();

                assert_eq!(entry.node.name, "master.example.com");
                assert_eq!(entry.objectclass, "host");
            }

            txn.commit().unwrap();
        }
    }
}
<commit_msg>Return DuplicateEntryError on duplicated entries<commit_after>extern crate lmdb;
extern crate lmdb_sys;

#[cfg(test)]
extern crate tempdir;

use std::{result, str};
use std::path::Path;
use lmdb::{Cursor, DUP_SORT, INTEGER_KEY};
use lmdb::Transaction as LmdbTransaction;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Error {
    DbCreateError,
    DbOpenError,
    DbWriteError,
    DbCorruptError,
    ParseError,
    TransactionError,
    PathError,
    NotFoundError,
    DuplicateEntryError,
}

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

pub struct LmdbAdapter {
    env: lmdb::Environment,
    nodes: lmdb::Database,
    entries: lmdb::Database,
}

pub struct RwTransaction<'a>(lmdb::RwTransaction<'a>);
pub struct RoTransaction<'a>(lmdb::RoTransaction<'a>);

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct Id(u64);

#[derive(Debug, Eq, PartialEq)]
pub struct Node<'a> {
    pub id: Id,
    pub parent_id: Id,
    pub name: &'a str,
}

#[derive(Debug, Eq, PartialEq)]
pub struct Entry<'a> {
    pub node: Node<'a>,
    pub objectclass: &'a str,
}

// Ids are 64-bit integers in host-native byte order
// LMDB has special optimizations for host-native integers as keys
impl Id {
    fn root() -> Id {
        Id(0)
    }

    fn from_bytes(bytes: &[u8]) -> Result<Id> {
        if bytes.len() != 8 {
            return Err(Error::ParseError);
        }

        let mut id = [0u8; 8];
        id.copy_from_slice(&bytes[0..8]);

        Ok(Id(unsafe { std::mem::transmute(id) }))
    }

    fn as_bytes(self) -> [u8; 8] {
        let Id(id) = self;
        unsafe { std::mem::transmute(id) }
    }

    fn next(self) -> Id {
        let Id(id) = self;
        Id(id + 1)
    }
}

impl<'a> Node<'a> {
    fn root() -> Node<'a> {
        Node {
            id: Id::root(),
            parent_id: Id::root(),
            name: "/",
        }
    }

    fn from_parent_id_and_bytes(parent_id: Id, bytes: &[u8]) -> Result<Node> {
        if bytes.len() < 8 {
            return Err(Error::DbCorruptError);
        }

        let id = try!(Id::from_bytes(&bytes[0..8]));
        let name = try!(std::str::from_utf8(&bytes[8..]).map_err(|_err| Error::DbCorruptError));

        Ok(Node {
            id: id,
            parent_id: parent_id,
            name: name,
        })
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(8 + self.name.len());
        bytes.extend_from_slice(&self.id.as_bytes());
        bytes.extend_from_slice(self.name.as_bytes());
        bytes
    }
}

impl LmdbAdapter {
    pub fn create_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new()
                           .set_max_dbs(8)
                           .open_with_permissions(&path, 0o600)
                           .map_err(|_err| Error::DbCreateError));

        let nodes = try!(env.create_db(Some("nodes"), INTEGER_KEY | DUP_SORT)
                            .map_err(|_err| Error::DbCreateError));

        let entries = try!(env.create_db(Some("entries"), INTEGER_KEY)
                              .map_err(|_err| Error::DbCreateError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn open_database(path: &Path) -> Result<LmdbAdapter> {
        let env = try!(lmdb::Environment::new().open(&path).map_err(|_err| Error::DbOpenError));

        let nodes = try!(env.open_db(Some("nodes")).map_err(|_err| Error::DbOpenError));

        let entries = try!(env.open_db(Some("entries")).map_err(|_err| Error::DbOpenError));

        Ok(LmdbAdapter {
            env: env,
            nodes: nodes,
            entries: entries,
        })
    }

    pub fn rw_transaction(&self) -> Result<RwTransaction> {
        match self.env.begin_rw_txn() {
            Ok(txn) => Ok(RwTransaction(txn)),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn ro_transaction(&self) -> Result<RoTransaction> {
        match self.env.begin_ro_txn() {
            Ok(txn) => Ok(RoTransaction(txn)),
            Err(_) => Err(Error::TransactionError),
        }
    }

    pub fn next_available_id<T: Transaction>(&self, txn: &T) -> Result<Id> {
        let cursor = try!(txn.open_ro_cursor(self.nodes)
                             .map_err(|_err| Error::TransactionError));

        let last_id = match cursor.get(None, None, lmdb_sys::MDB_LAST) {
            Ok((id, _)) => Id::from_bytes(id.unwrap()).unwrap(),
            Err(_) => Id::root(),
        };

        Ok(last_id.next())
    }

    pub fn create_entry<'a>(&'a self,
                            txn: &'a mut RwTransaction,
                            id: Id,
                            parent_id: Id,
                            name: &'a str,
                            objectclass: &'a str)
                            -> Result<Entry> {
        if txn.get(self.entries, &id.as_bytes()) != Err(Error::NotFoundError) {
            return Err(Error::DuplicateEntryError);
        }

        if txn.get(self.nodes, &parent_id.as_bytes()) != Err(Error::NotFoundError) &&
           self.find_child_node(txn, parent_id, name) != Err(Error::NotFoundError) {
            return Err(Error::DuplicateEntryError);
        }

        let node = Node {
            id: id,
            parent_id: parent_id,
            name: name,
        };

        try!(txn.put(self.nodes, &parent_id.as_bytes(), &node.to_bytes())
                .map_err(|_err| Error::DbWriteError));

        try!(txn.put(self.entries, &id.as_bytes(), &objectclass.as_bytes())
                .map_err(|_err| Error::DbWriteError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    pub fn find_entry<'a, T: Transaction>(&'a self, txn: &'a T, path: &str) -> Result<Entry> {
        let node = try!(self.find_node(txn, path));

        let entry_bytes = try!(txn.get(self.entries, &node.id.as_bytes())
                                  .map_err(|_err| Error::DbCorruptError));

        let objectclass = try!(std::str::from_utf8(&entry_bytes)
                                   .map_err(|_err| Error::DbCorruptError));

        Ok(Entry {
            node: node,
            objectclass: objectclass,
        })
    }

    fn find_node<T: Transaction>(&self, txn: &T, path: &str) -> Result<Node> {
        let all_components: Vec<&str> = path.split("/").collect();

        if all_components.is_empty() {
            return Err(Error::PathError);
        }

        let (prefix, components) = all_components.split_first().unwrap();

        // Does the path start with something other than "/"?
        if !prefix.is_empty() {
            return Err(Error::PathError);
        }

        components.iter().fold(Ok(Node::root()), |parent_node, component| {
            self.find_child_node(txn, try!(parent_node).id, component)
        })
    }

    // TODO: since LMDB is ordered, we could e.g. perform a binary search
    fn find_child_node<T: Transaction>(&self, txn: &T, parent_id: Id, name: &str) -> Result<Node> {
        let mut cursor = try!(txn.open_ro_cursor(self.nodes)
                                 .map_err(|_err| Error::TransactionError));

        let mut child_node = None;

        for (id, node_bytes) in cursor.iter_from(parent_id.as_bytes()) {
            if id != parent_id.as_bytes() {
                return Err(Error::NotFoundError);
            }

            let node = try!(Node::from_parent_id_and_bytes(parent_id, node_bytes));

            if node.name == name {
                child_node = Some(node);
                break;
            }
        }

        child_node.ok_or(Error::NotFoundError)
    }
}

pub trait Transaction {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]>;
    fn commit(self) -> Result<()>;
    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor>;
}

impl<'a> Transaction for RwTransaction<'a> {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]> {
        self.0.get(database, &key).map_err(|_err| Error::NotFoundError)
    }

    fn commit(self) -> Result<()> {
        self.0.commit().map_err(|_err| Error::TransactionError)
    }

    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor> {
        self.0.open_ro_cursor(db)
    }
}

impl<'a> Transaction for RoTransaction<'a> {
    fn get(&self, database: lmdb::Database, key: &[u8]) -> Result<&[u8]> {
        self.0.get(database, &key).map_err(|_err| Error::NotFoundError)
    }

    fn commit(self) -> Result<()> {
        self.0.commit().map_err(|_err| Error::TransactionError)
    }

    fn open_ro_cursor(&self, db: lmdb::Database) -> lmdb::Result<lmdb::RoCursor> {
        self.0.open_ro_cursor(db)
    }
}

impl<'a> RwTransaction<'a> {
    fn put(&mut self, database: lmdb::Database, key: &[u8], data: &[u8]) -> Result<()> {
        self.0
            .put(database, &key, &data, lmdb::WriteFlags::empty())
            .map_err(|_err| Error::TransactionError)
    }
}

#[cfg(test)]
mod tests {
    use {LmdbAdapter, Id, Transaction, Error};
    use tempdir::TempDir;

    fn create_database() -> LmdbAdapter {
        let dir = TempDir::new("ithos-test").unwrap();
        LmdbAdapter::create_database(dir.path()).unwrap()
    }

    #[test]
    fn test_entry_lookup() {
        let adapter = create_database();

        {
            let mut txn = adapter.rw_transaction().unwrap();

            let domain_id = adapter.next_available_id(&txn).unwrap();
            adapter.create_entry(&mut txn, domain_id, Id::root(), "example.com", "domain").unwrap();

            let hosts_id = domain_id.next();
            adapter.create_entry(&mut txn, hosts_id, domain_id, "hosts", "ou").unwrap();

            let host_id = hosts_id.next();
            adapter.create_entry(&mut txn, host_id, hosts_id, "master.example.com", "host")
                   .unwrap();

            txn.commit().unwrap();
        }

        {
            let txn = adapter.ro_transaction().unwrap();

            {
                let entry = adapter.find_entry(&txn, "/example.com/hosts/master.example.com")
                                   .unwrap();

                assert_eq!(entry.node.name, "master.example.com");
                assert_eq!(entry.objectclass, "host");
            }

            txn.commit().unwrap();
        }
    }

    #[test]
    fn test_duplicate_entry_id() {
        let adapter = create_database();

        let mut txn = adapter.rw_transaction().unwrap();

        let domain_id = adapter.next_available_id(&txn).unwrap();
        adapter.create_entry(&mut txn, domain_id, Id::root(), "example.com", "domain").unwrap();

        assert_eq!(adapter.create_entry(&mut txn, domain_id, Id::root(), "another.com", "domain"),
                   Err(Error::DuplicateEntryError));
    }

    #[test]
    fn test_duplicate_entry_name() {
        let adapter = create_database();

        let mut txn = adapter.rw_transaction().unwrap();

        let domain_id = adapter.next_available_id(&txn).unwrap();
        adapter.create_entry(&mut txn, domain_id, Id::root(), "example.com", "domain").unwrap();

        assert_eq!(adapter.create_entry(&mut txn,
                                        domain_id.next(),
                                        Id::root(),
                                        "example.com",
                                        "domain"),
                   Err(Error::DuplicateEntryError));
    }
}
<|endoftext|>


<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.
//!
//! To implement your own back-end, use the BackEnd trait.
//!
//! ## Usage
//!
//! To draw to the back-end, you need a context.
//! The context contains the information necessary to perform the drawing.
//! Unlike other graphics libraries, this library is not bound to the back-end.
//! You do not have to specify which back-end to use before doing the actual drawing.
//!
//! For example, assuming we have a back-end called `back_end`:
//!
//! ```
//! Context::new().rect(x, y, w, h).rgba(r, g, b, a).fill(&mut back_end);
//! ```
//!
//! ## Important!
//!
//! Because the context is built using borrowed pointers,
//! it is not possible to do two or more steps at a time and assign it to a variable:
//!
//! ```
//! // ERROR: Borrowed value does not live long enough
//! let rect = Context::new().rect(x, y, w, h);
//! ```
//!
//! This is because the lifetime of the first step only lives inside the expression.
//! To solve this problem, break the statement into two parts, one for each step:
//!
//! ```
//! let c = Context::new();
//! let rect = c.rect(x, y, w, h);
//! ```
//!
//! This is only the case when you are assigning the context to a variable.

extern crate std;

pub use Context = context::Context;
pub use BackEnd = back_end::BackEnd;
pub use Transform2d = transform2d::Transform2d;
pub use AddColor = add_color::AddColor;
pub use AddEllipse = add_ellipse::AddEllipse;
pub use AddPolygon = add_polygon::AddPolygon;
pub use AddPolygons = add_polygons::AddPolygons;
pub use AddRectangle = add_rectangle::AddRectangle;
pub use AddRound = add_round::AddRound;
pub use AddTween = add_tween::AddTween;
pub use RelativeRectangle = relative_rectangle::RelativeRectangle;
pub use Fill = fill::Fill;
pub use Clear = clear::Clear;
pub use ColorContext = color_context::ColorContext;
pub use EllipseContext = ellipse_context::EllipseContext;
pub use EllipseColorContext = ellipse_color_context::EllipseColorContext;
pub use LineContext = line_context::LineContext;
pub use PolygonContext = polygon_context::PolygonContext;
pub use PolygonColorContext = polygon_color_context::PolygonColorContext;
pub use RectangleContext = rectangle_context::RectangleContext;
pub use RectangleColorContext = rectangle_color_context::RectangleColorContext;
pub use RoundRectangleContext = round_rectangle_context::RoundRectangleContext;
pub use RoundRectangleColorContext = round_rectangle_color_context::RoundRectangleColorContext;
pub use TweenContext = tween_context::TweenContext;
pub use TweenColorContext = tween_color_context::TweenColorContext;
pub use TweenPolygonsColorContext = tween_polygons_color_context::TweenPolygonsColorContext;

mod context;
mod back_end;
mod transform2d;
mod add_color;
mod add_ellipse;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_tween;
mod relative_rectangle;
mod fill;
mod clear;
mod color_context;
mod ellipse_context;
mod ellipse_color_context;
mod line_context;
mod polygon_context;
mod polygon_color_context;
mod rectangle_context;
mod rectangle_color_context;
mod round_rectangle_context;
mod round_rectangle_color_context;
mod tween_context;
mod tween_color_context;
mod tween_polygons_color_context;
pub mod vecmath;
pub mod triangulation;
pub mod interpolation;
pub mod modular_index;

pub type Color = [f32, ..4];
pub type Line = [f64, ..4];
pub type Ray = [f64, ..4];
pub type Matrix2d = [f64, ..6];
pub type Rectangle = [f64, ..4];
pub type RoundRectangle = [f64, ..5];
pub type Triangle = [f64, ..6];
pub type Vec2d = [f64, ..2];

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

<commit_msg>Added comments about types<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.
//!
//! To implement your own back-end, use the BackEnd trait.
//!
//! ## Usage
//!
//! To draw to the back-end, you need a context.
//! The context contains the information necessary to perform the drawing.
//! Unlike other graphics libraries, this library is not bound to the back-end.
//! You do not have to specify which back-end to use before doing the actual drawing.
//!
//! For example, assuming we have a back-end called `back_end`:
//!
//! ```
//! Context::new().rect(x, y, w, h).rgba(r, g, b, a).fill(&mut back_end);
//! ```
//!
//! ## Important!
//!
//! Because the context is built using borrowed pointers,
//! it is not possible to do two or more steps at a time and assign it to a variable:
//!
//! ```
//! // ERROR: Borrowed value does not live long enough
//! let rect = Context::new().rect(x, y, w, h);
//! ```
//!
//! This is because the lifetime of the first step only lives inside the expression.
//! To solve this problem, break the statement into two parts, one for each step:
//!
//! ```
//! let c = Context::new();
//! let rect = c.rect(x, y, w, h);
//! ```
//!
//! This is only the case when you are assigning the context to a variable.

extern crate std;

pub use Context = context::Context;
pub use BackEnd = back_end::BackEnd;
pub use Transform2d = transform2d::Transform2d;
pub use AddColor = add_color::AddColor;
pub use AddEllipse = add_ellipse::AddEllipse;
pub use AddPolygon = add_polygon::AddPolygon;
pub use AddPolygons = add_polygons::AddPolygons;
pub use AddRectangle = add_rectangle::AddRectangle;
pub use AddRound = add_round::AddRound;
pub use AddTween = add_tween::AddTween;
pub use RelativeRectangle = relative_rectangle::RelativeRectangle;
pub use Fill = fill::Fill;
pub use Clear = clear::Clear;
pub use ColorContext = color_context::ColorContext;
pub use EllipseContext = ellipse_context::EllipseContext;
pub use EllipseColorContext = ellipse_color_context::EllipseColorContext;
pub use LineContext = line_context::LineContext;
pub use PolygonContext = polygon_context::PolygonContext;
pub use PolygonColorContext = polygon_color_context::PolygonColorContext;
pub use RectangleContext = rectangle_context::RectangleContext;
pub use RectangleColorContext = rectangle_color_context::RectangleColorContext;
pub use RoundRectangleContext = round_rectangle_context::RoundRectangleContext;
pub use RoundRectangleColorContext = round_rectangle_color_context::RoundRectangleColorContext;
pub use TweenContext = tween_context::TweenContext;
pub use TweenColorContext = tween_color_context::TweenColorContext;
pub use TweenPolygonsColorContext = tween_polygons_color_context::TweenPolygonsColorContext;

mod context;
mod back_end;
mod transform2d;
mod add_color;
mod add_ellipse;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_tween;
mod relative_rectangle;
mod fill;
mod clear;
mod color_context;
mod ellipse_context;
mod ellipse_color_context;
mod line_context;
mod polygon_context;
mod polygon_color_context;
mod rectangle_context;
mod rectangle_color_context;
mod round_rectangle_context;
mod round_rectangle_color_context;
mod tween_context;
mod tween_color_context;
mod tween_polygons_color_context;
pub mod vecmath;
pub mod triangulation;
pub mod interpolation;
pub mod modular_index;

/// [red, green, blue, alpha]
pub type Color = [f32, ..4];

/// [x1, y1, x2, y2]
pub type Line = [f64, ..4];

/// [x, y, dir_x, dir_y]
pub type Ray = [f64, ..4];

/// [m00, m01, m02, m10, m11, m12]
///
/// The first 3 numbers transforms `x`,
/// the last 3 numbers transforms `y`:
///
/// ```
/// tx = m00 * x + m01 * y + m02;
/// ty = m10 * x + m11 * y + m12;
/// ```
pub type Matrix2d = [f64, ..6];

/// [x, y, w, h]
pub type Rectangle = [f64, ..4];

/// [x, y, w, h, radius]
pub type RoundRectangle = [f64, ..5];

/// [x1, y1, x2, y2, x3, y3]
pub type Triangle = [f64, ..6];

/// [x, y]
pub type Vec2d = [f64, ..2];

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

<|endoftext|>


<commit_before>pub mod core_audio_driver;
<commit_msg>Added top-level config to only compile on osx<commit_after>#![cfg(target_os = "macos")]
pub mod core_audio_driver;
<|endoftext|>