<commit_before>#![allow(dead_code)]

use std::io::{IoError, IoErrorKind, Reader};

struct Frame;

// TODO: there should be a way to signal IO error.
// This will be handled by the error reform RFCs, I think.
// For now, use IO error to indicate any failure.
pub type Error = IoError;

fn mk_err() -> Error {
    IoError {
        kind: IoErrorKind::OtherIoError,
        desc: "FLAC decoding error",
        detail: None
    }
}

struct FlacStream {
    streaminfo: StreamInfo,
    metadata_blocks: Vec<MetadataBlock>
}

// TODO: this should be private, but it must be public for the test for now.
pub fn read_stream_header(input: &mut Reader) -> Result<(), Error> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const HEADER: u32 = 0x66_4c_61_43;
    let header = try!(input.read_be_u32());
    if header != HEADER { return Err(mk_err()); } // TODO: provide more error info.
    Ok(())
}

#[deriving(Copy)]
pub struct StreamInfo {
    pub min_block_size: u16,
    pub max_block_size: u16,
    pub min_frame_size: Option<u32>,
    pub max_frame_size: Option<u32>,
    pub sample_rate: u32,
    pub n_channels: u8,
    pub bits_per_sample: u8,
    pub n_samples: Option<u64>,
    pub md5sum: [u8, ..16]
}

// TODO: should this be private?
#[deriving(Copy)]
pub struct SeekPoint {
    pub sample: u64,
    pub offset: u64,
    pub n_samples: u16
}

// TODO: should this be private?
pub struct SeekTable {
    seekpoints: Vec<SeekPoint>
}

pub enum MetadataBlock {
    StreamInfo(StreamInfo),
    Padding { length: u32 },
    Application { id: u32, data: Vec<u8> },
    SeekTable(SeekTable),
    VorbisComment, // TODO
    CueSheet, // TODO
    Picture // TODO
}

// TODO: this should be private.
#[deriving(Copy)]
pub struct MetadataBlockHeader {
    is_last: bool,
    block_type: u8,
    length: u32
}

// TODO: this should be private, but it must be public for the test for now.
pub fn read_metadata_block_header(input: &mut Reader) -> Result<MetadataBlockHeader, Error> {
    let byte = try!(input.read_u8());

    // The first bit specifies whether this is the last block, the next 7 bits
    // specify the type of the metadata block to follow.
    let is_last = (byte & 1) == 1;
    let block_type = byte >> 1;

    // The length field is 24 bits, or 3 bytes.
    let length = try!(input.read_be_uint_n(3)) as u32;

    let header = MetadataBlockHeader {
        is_last: is_last,
        block_type: block_type,
        length: length
    };
    Ok(header)
}

fn read_metadata_block(input: &mut Reader, block_type: u8, length: u32)
                       -> Result<MetadataBlock, Error> {
    match block_type {
        0 => {
            let streaminfo = try!(read_streaminfo_block(input));
            Ok(MetadataBlock::StreamInfo(streaminfo))
        },
        1 => {
            try!(read_padding_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        2 => {
            let (id, data) = try!(read_application_block(input, length));
            Ok(MetadataBlock::Application { id: id, data: data })
        },
        3 => {
            // TODO: implement seektable reading. For now, pretend it is padding.
            try!(skip_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        4 => {
            // TODO: implement Vorbis comment reading. For now, pretend it is padding.
            try!(skip_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        5 => {
            // TODO: implement CUE sheet reading. For now, pretend it is padding.
            try!(skip_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        6 => {
            // TODO: implement picture reading. For now, pretend it is padding.
            try!(skip_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        127 => Err(mk_err()), // TODO: "invalid, to avoid confusion with a frame sync code"
        _ => Err(mk_err()) // TODO: "reserved", is that an error or do we ignore it?
    }
}

// TODO: this should be private, but it must be public for the test for now.
pub fn read_streaminfo_block(input: &mut Reader) -> Result<StreamInfo, Error> {
    let min_block_size = try!(input.read_be_u16());
    let max_block_size = try!(input.read_be_u16());

    // The frame size fields are 24 bits, or 3 bytes.
    let min_frame_size = try!(input.read_be_uint_n(3)) as u32;
    let max_frame_size = try!(input.read_be_uint_n(3)) as u32;

    // Next up are 20 bits that determine the sample rate.
    let sample_rate_msb = try!(input.read_be_u16());
    let sample_rate_lsb = try!(input.read_byte());

    // Stitch together the value from the first 16 bits,
    // and then the 4 most significant bits of the next byte.
    let sample_rate = sample_rate_msb as u32 << 4 | sample_rate_lsb as u32 >> 4;

    // Next three bits are the number of channels - 1. Mask them out and add 1.
    let n_channels_bps = sample_rate_lsb;
    let n_channels = ((n_channels_bps >> 1) & 0x7) + 1;

    // The final bit is the most significant of bits per sample - 1. Bits per
    // sample - 1 is 5 bits in total.
    let bps_msb = n_channels_bps & 1;
    let bps_lsb_n_samples = try!(input.read_byte());

    // Stitch together these values, add 1 because # - 1 is stored.
    let bits_per_sample = (bps_msb << 4 | (bps_lsb_n_samples >> 4)) + 1;

    // Number of samples in 36 bits, we have 4 already, 32 to go.
    let n_samples_msb = bps_lsb_n_samples & 0xf;
    let n_samples_lsb = try!(input.read_be_u32());
    let n_samples = n_samples_msb as u64 << 32 | n_samples_lsb as u64;

    let mut md5sum = [0u8, ..16];
    try!(input.read_at_least(16, &mut md5sum));

    let stream_info = StreamInfo {
        min_block_size: min_block_size,
        max_block_size: max_block_size,
        min_frame_size: if min_frame_size == 0 { None } else { Some(min_frame_size) },
        max_frame_size: if max_frame_size == 0 { None } else { Some(max_frame_size) },
        sample_rate: sample_rate,
        n_channels: n_channels,
        bits_per_sample: bits_per_sample,
        n_samples: if n_samples == 0 { None } else { Some(n_samples) },
        md5sum: md5sum
    };

    Ok(stream_info)
}

fn read_padding_block(input: &mut Reader, length: u32) -> Result<(), Error> {
    // The specification dictates that all bits of the padding block must be 0.
    for _ in range(0, length) {
        if try!(input.read_byte()) != 0 {
            return Err(mk_err()); // TODO: error, nonzero bit in padding block.
        }
    }
    Ok(())
}

fn skip_block(input: &mut Reader, length: u32) -> Result<(), Error> {
    // Skip all the padding bytes.
    for _ in range(0, length) { try!(input.read_byte()); }
    Ok(())
}

fn read_application_block(input: &mut Reader, length: u32) -> Result<(u32, Vec<u8>), Error> {
    let id = try!(input.read_be_u32());

    // Four bytes of the block have been used for the ID, the rest is payload.
    let data = try!(input.read_exact((length - 4) as uint));

    Ok((id, data))
}

/// Reads metadata blocks from a stream and exposes them as an iterator.
///
/// It is assumed that the next byte that the reader will read, is the first
/// byte of a metadata block header. This means that the iterator will yield at
/// least a single value. If the iterator ever yields an error, then no more
/// data will be read thereafter, and the next value will be `None`.
struct MetadataBlockReader<'r, R> where R: 'r {
    input: &'r mut R,
    done: bool
}

type MetadataBlockResult = Result<MetadataBlock, Error>;

impl<'r, R> MetadataBlockReader<'r, R> where R: Reader {
    pub fn new(input: &'r mut R) -> MetadataBlockReader<'r, R> {
        MetadataBlockReader { input: input, done: false }
    }

    fn read_next(&mut self) -> MetadataBlockResult {
        let header = try!(read_metadata_block_header(self.input));
        let block = try!(read_metadata_block(self.input, header.block_type,
                                                         header.length));
        self.done = header.is_last;
        Ok(block)
    }
}

impl<'r, R> Iterator<MetadataBlockResult>
    for MetadataBlockReader<'r, R>
    where R: Reader {

    fn next(&mut self) -> Option<MetadataBlockResult> {
        if self.done {
            None
        } else {
            let block = self.read_next();

            // After a failure, no more attempts to read will be made,
            // because we don't know where we are in the stream.
            if !block.is_ok() { self.done = true; }

            Some(block)
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        if self.done { (0, Some(0)) } else { (1, None) }
    }
}

impl FlacStream {
    pub fn new<R>(input: &mut R) -> Result<FlacStream, Error>
        where R: Reader {
        // A flac stream first of all starts with a stream header.
        try!(read_stream_header(input));

        // Next are one or more metadata blocks. The flac specification
        // dictates that the streaminfo block is the first block. The metadata
        // block reader will yield at least one element, so the unwrap is safe.
        let mut metadata_iter = MetadataBlockReader::new(input);
        let streaminfo_block = try!(metadata_iter.next().unwrap());
        let streaminfo = match streaminfo_block {
            MetadataBlock::StreamInfo(info) => info,
            _ => return Err(mk_err()) // TODO: Error: streaminfo block must be the first block.
        };

        // There might be more metadata blocks, read and store them.
        let mut metadata_blocks = Vec::new();
        for block_result in metadata_iter {
            match block_result {
                Err(error) => return Err(error),
                Ok(block) => metadata_blocks.push(block)
            }
        }

        // Read frames

        let flac_stream = FlacStream {
            streaminfo: streaminfo,
            metadata_blocks: metadata_blocks
        };

        Ok(flac_stream)
    }
}

#[test]
fn test_open_stream() {
    use std::io::File;
    let mut input = File::open(&Path::new("foo.flac")).unwrap();
    let flac_stream = FlacStream::new(&mut input).unwrap();
}
<commit_msg>improve error reporting and streaminfo validation<commit_after>#![allow(dead_code)]

use std::error::FromError;
use std::io::IoError;

struct Frame;

#[deriving(Show)]
pub enum FlacError {
    /// Not a decoding error, but a problem with the underlying IO.
    IoError(IoError),

    /// The stream header does not equal 'fLaC'.
    InvalidStreamHeader,

    /// Metadata block type 127 is invalid, to avoid confusion with a frame sync code.
    InvalidMetadataBlockType,
    /// This version of the library cannot handle this kind of metadata block,
    /// it was reserved at the time of writing.
    ReservedMetadataBlockType,

    /// A lower bound was encountered that was bigger than an upper bound.
    InconsistentBounds,
    /// The minimum block size must be larger than 15.
    InvalidBlockSize,
    /// The sample rate must be positive and no larger than 6553550 Hz.
    InvalidSampleRate,

    /// The streaminfo block must be the very first metadata block.
    MissingStreamInfoBlock,
}

pub type FlacResult<T> = Result<T, FlacError>;

// TODO: implement the Error trait for FlacError.

impl FromError<IoError> for FlacError {
    fn from_error(err: IoError) -> FlacError {
        FlacError::IoError(err)
    }
}

struct FlacStream {
    streaminfo: StreamInfo,
    metadata_blocks: Vec<MetadataBlock>
}

// TODO: this should be private, but it must be public for the test for now.
pub fn read_stream_header(input: &mut Reader) -> FlacResult<()> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const HEADER: u32 = 0x66_4c_61_43;
    let header = try!(input.read_be_u32());
    if header != HEADER { return Err(FlacError::InvalidStreamHeader); }
    Ok(())
}

#[deriving(Copy)]
pub struct StreamInfo {
    pub min_block_size: u16,
    pub max_block_size: u16,
    pub min_frame_size: Option<u32>,
    pub max_frame_size: Option<u32>,
    pub sample_rate: u32,
    pub n_channels: u8,
    pub bits_per_sample: u8,
    pub n_samples: Option<u64>,
    pub md5sum: [u8, ..16]
}

// TODO: should this be private?
#[deriving(Copy)]
pub struct SeekPoint {
    pub sample: u64,
    pub offset: u64,
    pub n_samples: u16
}

// TODO: should this be private?
pub struct SeekTable {
    seekpoints: Vec<SeekPoint>
}

pub enum MetadataBlock {
    StreamInfo(StreamInfo),
    Padding { length: u32 },
    Application { id: u32, data: Vec<u8> },
    SeekTable(SeekTable),
    VorbisComment, // TODO
    CueSheet, // TODO
    Picture // TODO
}

// TODO: this should be private.
#[deriving(Copy)]
pub struct MetadataBlockHeader {
    is_last: bool,
    block_type: u8,
    length: u32
}

// TODO: this should be private, but it must be public for the test for now.
pub fn read_metadata_block_header(input: &mut Reader) -> FlacResult<MetadataBlockHeader> {
    let byte = try!(input.read_u8());

    // The first bit specifies whether this is the last block, the next 7 bits
    // specify the type of the metadata block to follow.
    let is_last = (byte & 1) == 1;
    let block_type = byte >> 1;

    // The length field is 24 bits, or 3 bytes.
    let length = try!(input.read_be_uint_n(3)) as u32;

    let header = MetadataBlockHeader {
        is_last: is_last,
        block_type: block_type,
        length: length
    };
    Ok(header)
}

fn read_metadata_block(input: &mut Reader, block_type: u8, length: u32)
                       -> FlacResult<MetadataBlock> {
    match block_type {
        0 => {
            let streaminfo = try!(read_streaminfo_block(input));
            Ok(MetadataBlock::StreamInfo(streaminfo))
        },
        1 => {
            try!(read_padding_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        2 => {
            let (id, data) = try!(read_application_block(input, length));
            Ok(MetadataBlock::Application { id: id, data: data })
        },
        3 => {
            // TODO: implement seektable reading. For now, pretend it is padding.
            try!(skip_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        4 => {
            // TODO: implement Vorbis comment reading. For now, pretend it is padding.
            try!(skip_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        5 => {
            // TODO: implement CUE sheet reading. For now, pretend it is padding.
            try!(skip_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        6 => {
            // TODO: implement picture reading. For now, pretend it is padding.
            try!(skip_block(input, length));
            Ok(MetadataBlock::Padding { length: length })
        },
        127 => Err(FlacError::InvalidMetadataBlockType),

        // Other values of the block type are reserved at the moment of writing.
        // When we do encounter such a value, it means that this library will
        // be unable to handle it. We could ignore the block, but there would
        // be no way to tell that we did so for users of the library. I think
        // it is better to be explicit, and make this an error.
        _ => Err(FlacError::ReservedMetadataBlockType)
    }
}

// TODO: this should be private, but it must be public for the test for now.
pub fn read_streaminfo_block(input: &mut Reader) -> FlacResult<StreamInfo> {
    let min_block_size = try!(input.read_be_u16());
    let max_block_size = try!(input.read_be_u16());

    // The frame size fields are 24 bits, or 3 bytes.
    let min_frame_size = try!(input.read_be_uint_n(3)) as u32;
    let max_frame_size = try!(input.read_be_uint_n(3)) as u32;

    // Next up are 20 bits that determine the sample rate.
    let sample_rate_msb = try!(input.read_be_u16());
    let sample_rate_lsb = try!(input.read_byte());

    // Stitch together the value from the first 16 bits,
    // and then the 4 most significant bits of the next byte.
    let sample_rate = sample_rate_msb as u32 << 4 | sample_rate_lsb as u32 >> 4;

    // Next three bits are the number of channels - 1. Mask them out and add 1.
    let n_channels_bps = sample_rate_lsb;
    let n_channels = ((n_channels_bps >> 1) & 0x7) + 1;

    // The final bit is the most significant of bits per sample - 1. Bits per
    // sample - 1 is 5 bits in total.
    let bps_msb = n_channels_bps & 1;
    let bps_lsb_n_samples = try!(input.read_byte());

    // Stitch together these values, add 1 because # - 1 is stored.
    let bits_per_sample = (bps_msb << 4 | (bps_lsb_n_samples >> 4)) + 1;

    // Number of samples in 36 bits, we have 4 already, 32 to go.
    let n_samples_msb = bps_lsb_n_samples & 0xf;
    let n_samples_lsb = try!(input.read_be_u32());
    let n_samples = n_samples_msb as u64 << 32 | n_samples_lsb as u64;

    let mut md5sum = [0u8, ..16];
    try!(input.read_at_least(16, &mut md5sum));

    // Lower bounds can never be larger than upper bounds. Note that 0 indicates
    // unknown for the frame size. Also, the block size must be at least 16.
    if min_block_size > max_block_size {
        return Err(FlacError::InconsistentBounds);
    }
    if min_block_size < 16 {
        return Err(FlacError::InvalidBlockSize);
    }
    if min_frame_size > max_frame_size && max_frame_size != 0 {
        return Err(FlacError::InconsistentBounds);
    }

    // A sample rate of 0 is invalid, and the maximum sample rate is limited by
    // the structure of the frame headers to 655350 Hz.
    if sample_rate == 0 || sample_rate > 655350 {
        return Err(FlacError::InvalidSampleRate);
    }

    let stream_info = StreamInfo {
        min_block_size: min_block_size,
        max_block_size: max_block_size,
        min_frame_size: if min_frame_size == 0 { None } else { Some(min_frame_size) },
        max_frame_size: if max_frame_size == 0 { None } else { Some(max_frame_size) },
        sample_rate: sample_rate,
        n_channels: n_channels,
        bits_per_sample: bits_per_sample,
        n_samples: if n_samples == 0 { None } else { Some(n_samples) },
        md5sum: md5sum
    };
    Ok(stream_info)
}

fn read_padding_block(input: &mut Reader, length: u32) -> FlacResult<()> {
    // The specification dictates that all bits of the padding block must be 0.
    // However, the reference implementation does not issue an error when this
    // is not the case, and frankly, when you are going to skip over these
    // bytes and do nothing with them whatsoever, why waste all those CPU
    // cycles checking that the padding is valid?
    skip_block(input, length)
}

fn skip_block(input: &mut Reader, length: u32) -> FlacResult<()> {
    // Skip all the padding bytes.
    for _ in range(0, length) { try!(input.read_byte()); }
    Ok(())
}

fn read_application_block(input: &mut Reader, length: u32) -> FlacResult<(u32, Vec<u8>)> {
    let id = try!(input.read_be_u32());

    // Four bytes of the block have been used for the ID, the rest is payload.
    let data = try!(input.read_exact((length - 4) as uint));

    Ok((id, data))
}

/// Reads metadata blocks from a stream and exposes them as an iterator.
///
/// It is assumed that the next byte that the reader will read, is the first
/// byte of a metadata block header. This means that the iterator will yield at
/// least a single value. If the iterator ever yields an error, then no more
/// data will be read thereafter, and the next value will be `None`.
struct MetadataBlockReader<'r, R> where R: 'r {
    input: &'r mut R,
    done: bool
}

type MetadataBlockResult = FlacResult<MetadataBlock>;

impl<'r, R> MetadataBlockReader<'r, R> where R: Reader {
    pub fn new(input: &'r mut R) -> MetadataBlockReader<'r, R> {
        MetadataBlockReader { input: input, done: false }
    }

    fn read_next(&mut self) -> MetadataBlockResult {
        let header = try!(read_metadata_block_header(self.input));
        let block = try!(read_metadata_block(self.input, header.block_type,
                                                         header.length));
        self.done = header.is_last;
        Ok(block)
    }
}

impl<'r, R> Iterator<MetadataBlockResult>
    for MetadataBlockReader<'r, R>
    where R: Reader {

    fn next(&mut self) -> Option<MetadataBlockResult> {
        if self.done {
            None
        } else {
            let block = self.read_next();

            // After a failure, no more attempts to read will be made,
            // because we don't know where we are in the stream.
            if !block.is_ok() { self.done = true; }

            Some(block)
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        if self.done { (0, Some(0)) } else { (1, None) }
    }
}

impl FlacStream {
    pub fn new<R>(input: &mut R) -> FlacResult<FlacStream>
        where R: Reader {
        // A flac stream first of all starts with a stream header.
        try!(read_stream_header(input));

        // Next are one or more metadata blocks. The flac specification
        // dictates that the streaminfo block is the first block. The metadata
        // block reader will yield at least one element, so the unwrap is safe.
        let mut metadata_iter = MetadataBlockReader::new(input);
        let streaminfo_block = try!(metadata_iter.next().unwrap());
        let streaminfo = match streaminfo_block {
            MetadataBlock::StreamInfo(info) => info,
            _ => return Err(FlacError::MissingStreamInfoBlock)
        };

        // There might be more metadata blocks, read and store them.
        let mut metadata_blocks = Vec::new();
        for block_result in metadata_iter {
            match block_result {
                Err(error) => return Err(error),
                Ok(block) => metadata_blocks.push(block)
            }
        }

        // Read frames

        let flac_stream = FlacStream {
            streaminfo: streaminfo,
            metadata_blocks: metadata_blocks
        };

        Ok(flac_stream)
    }
}

#[test]
fn test_open_stream() {
    use std::io::File;
    let mut input = File::open(&Path::new("foo.flac")).unwrap();
    let flac_stream = FlacStream::new(&mut input).unwrap();
}
<|endoftext|>


<commit_before>//! Contains various utility types and macros useful for testing hyper clients.
//!
//! # Macros
//! The `mock_connector!` and `mock_connector_in_order!` macros can be used to
//! feed a client with preset data. That way you can control exactly what it will
//! see, confining the test-case to its own sandbox that way.
//!
//! All types they define are public to allow them to be used in other unit-tests.
//! Please note that integration tests cannot share their mock types anyway, as each
//! integration test goes into its own binary.
//!
//! # Usage
//!
//! Set it up for use in tests in `Cargo.toml`
//!
//! ```toml
//! [dev-dependencies]
//! yup-hyper-mock = "*"
//! log = "*"  # log macros are used within yup-hyper-mock
//! ```
//!
//! Link it into your `src/(lib.rs|main.rs)`
//!
//! ```Rust
//! #[cfg(test)] #[macro_use]
//! extern crate "yup-hyper-mock" as hyper_mock
//! ```

extern crate hyper;

#[macro_use]
extern crate log;

use std::fmt;
use std::net::SocketAddr;
use std::io::{self, Read, Write, Cursor};

use hyper::net::{NetworkStream, NetworkConnector};

/// A `NetworkStream` compatible stream that writes into memory, and reads from memory.
pub struct MockStream {
    pub read: Cursor<Vec<u8>>,
    pub write: Vec<u8>,
}

/// A `NetworkStream` compatible stream which contains another `NetworkStream`,
/// whose traffic will be written to another stream.
/// Currently that stream will always be standard error.
pub struct TeeStream<T> {
    pub read_write: T,
    pub copy_to: io::Stderr,
}

impl<T> Clone for TeeStream<T>
    where T: Clone {
    fn clone(&self) -> TeeStream<T> {
        TeeStream {
            read_write: self.read_write.clone(),
            copy_to: io::stderr(),
        }
    }
}

impl<T> Read for TeeStream<T>
    where T: Read {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.read_write.read(buf);
        match res {
            Ok(s) => {
                self.copy_to.write(&buf[..s]).ok();
            }
            _ => {}
        };
        res
    }
}

impl<T> Write for TeeStream<T>
    where T: Write {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        self.copy_to.write(msg).ok();
        self.read_write.write(msg)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.copy_to.flush().ok();
        self.read_write.flush()
    }
}

impl<T> NetworkStream for TeeStream<T>
    where T: NetworkStream + Send + Clone {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        self.read_write.peer_addr()
    }
}
impl Clone for MockStream {
    fn clone(&self) -> MockStream {
        MockStream {
            read: Cursor::new(self.read.get_ref().clone()),
            write: self.write.clone()
        }
    }
}

impl fmt::Debug for MockStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MockStream {{ read: {:?}, write: {:?} }}", self.read.get_ref(), self.write)
    }
}

impl PartialEq for MockStream {
    fn eq(&self, other: &MockStream) -> bool {
        self.read.get_ref() == other.read.get_ref() && self.write == other.write
    }
}

impl MockStream {
    pub fn new() -> MockStream {
        MockStream {
            read: Cursor::new(vec![]),
            write: vec![],
        }
    }

    pub fn with_input(input: &[u8]) -> MockStream {
        MockStream {
            read: Cursor::new(input.to_vec()),
            write: vec![]
        }
    }
}

impl Read for MockStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.read.read(buf)
    }
}

impl Write for MockStream {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        Write::write(&mut self.write, msg)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl NetworkStream for MockStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        Ok("127.0.0.1:1337".parse().unwrap())
    }
}

/// A `NetworkConnector` which creates `MockStream` instances exclusively.
/// It may be useful to intercept writes.
pub struct MockConnector;

impl NetworkConnector for MockConnector {
    type Stream = MockStream;

    fn connect(&self, _host: &str, _port: u16, _scheme: &str) -> hyper::Result<MockStream> {
        Ok(MockStream::new())
    }

    fn set_ssl_verifier(&mut self, _: hyper::net::ContextVerifier) {}
}

/// A `NetworkConnector` embedding another `NetworkConnector` instance,
/// and sets it up to write all reads and writes to standard error as well.
///
/// > **NOTE** It was originally intended to allow arbitrary streams to copy data to,
/// > but I couldn't get passt the compiler with that as normal streams, like files,
/// > are not normally clonable. Maybe an Arc+Mutex would have helped ... .
pub struct TeeConnector<C>
    where C: NetworkConnector {
    pub connector: C,
}

impl<C, S> NetworkConnector for TeeConnector<C>
    where C: NetworkConnector<Stream=S>,
          S: NetworkStream + Send + Clone {
    type Stream = TeeStream<<C as NetworkConnector>::Stream>;

    fn connect(&self, _host: &str, _port: u16, _scheme: &str)
        -> hyper::Result<TeeStream<<C as NetworkConnector>::Stream>> {
        match self.connector.connect(_host, _port, _scheme) {
            Ok(s) => {
                Ok(TeeStream {
                        read_write: s,
                        copy_to: io::stderr(),
                    }
                )
            },
            Err(err) => Err(err),
        }
    }

    fn set_ssl_verifier(&mut self, _: hyper::net::ContextVerifier) {}
}

/// This macro maps host URLs to a respective reply, which is given in plain-text.
/// It ignores, but stores, everything that is written to it. However, the stored
/// values are not accessible just yet.
#[macro_export]
macro_rules! mock_connector (
    ($name:ident {
        $($url:expr => $res:expr)*
    }) => (

        pub struct $name;

        impl hyper::net::NetworkConnector for $name {
            type Stream = $crate::MockStream;
            fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::hyper::Result<$crate::MockStream> {
                use std::collections::HashMap;
                use std::io::Cursor;
                debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
                let mut map = HashMap::new();
                $(map.insert($url, $res);)*

                let key = format!("{}://{}", scheme, host);
                // ignore port for now
                match map.get(&*key) {
                    Some(res) => Ok($crate::MockStream {
                        write: vec![],
                        read: Cursor::new(res.to_string().into_bytes()),
                    }),
                    None => panic!("{:?} doesn't know url {}", stringify!($name), key)
                }
            }
        }
    )
);

/// This macro yields all given server replies in the order they are given.
/// The destination host URL doesn't matter at all.
#[macro_export]
macro_rules! mock_connector_in_order (
    ($name:ident {
        $( $res:expr )*
    }) => (

        #[derive(Default)]
        pub struct $name {
            streamers: Vec<String>,
            current: usize,
        }

        impl hyper::net::NetworkConnector for $name {
            type Stream = $crate::MockStream;
            fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::hyper::Result<$crate::MockStream> {
                use std::io::Cursor;
                debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);

                if self.streamers.len() == 0 {
                    let mut v = Vec::new();
                    $(v.push($res.to_string());)*
                    self.streamers = v;
                    self.current = 0;
                }
                assert!(self.streamers.len() != 0, "Not a single streamer return value specified");

                let r = Ok($crate::MockStream {
                        write: vec![],
                        read: Cursor::new(self.streamers[self.current].clone().into_bytes())
                });
                self.current += 1;
                r
            }
        }
    )
);

<commit_msg>fix(macros): adjust to changed hyper signatures<commit_after>//! Contains various utility types and macros useful for testing hyper clients.
//!
//! # Macros
//! The `mock_connector!` and `mock_connector_in_order!` macros can be used to
//! feed a client with preset data. That way you can control exactly what it will
//! see, confining the test-case to its own sandbox that way.
//!
//! All types they define are public to allow them to be used in other unit-tests.
//! Please note that integration tests cannot share their mock types anyway, as each
//! integration test goes into its own binary.
//!
//! # Usage
//!
//! Set it up for use in tests in `Cargo.toml`
//!
//! ```toml
//! [dev-dependencies]
//! yup-hyper-mock = "*"
//! log = "*"  # log macros are used within yup-hyper-mock
//! ```
//!
//! Link it into your `src/(lib.rs|main.rs)`
//!
//! ```Rust
//! #[cfg(test)] #[macro_use]
//! extern crate "yup-hyper-mock" as hyper_mock
//! ```

extern crate hyper;

#[macro_use]
extern crate log;

use std::fmt;
use std::net::SocketAddr;
use std::io::{self, Read, Write, Cursor};

use hyper::net::{NetworkStream, NetworkConnector};

/// A `NetworkStream` compatible stream that writes into memory, and reads from memory.
pub struct MockStream {
    pub read: Cursor<Vec<u8>>,
    pub write: Vec<u8>,
}

/// A `NetworkStream` compatible stream which contains another `NetworkStream`,
/// whose traffic will be written to another stream.
/// Currently that stream will always be standard error.
pub struct TeeStream<T> {
    pub read_write: T,
    pub copy_to: io::Stderr,
}

impl<T> Clone for TeeStream<T>
    where T: Clone {
    fn clone(&self) -> TeeStream<T> {
        TeeStream {
            read_write: self.read_write.clone(),
            copy_to: io::stderr(),
        }
    }
}

impl<T> Read for TeeStream<T>
    where T: Read {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.read_write.read(buf);
        match res {
            Ok(s) => {
                self.copy_to.write(&buf[..s]).ok();
            }
            _ => {}
        };
        res
    }
}

impl<T> Write for TeeStream<T>
    where T: Write {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        self.copy_to.write(msg).ok();
        self.read_write.write(msg)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.copy_to.flush().ok();
        self.read_write.flush()
    }
}

impl<T> NetworkStream for TeeStream<T>
    where T: NetworkStream + Send + Clone {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        self.read_write.peer_addr()
    }
}
impl Clone for MockStream {
    fn clone(&self) -> MockStream {
        MockStream {
            read: Cursor::new(self.read.get_ref().clone()),
            write: self.write.clone()
        }
    }
}

impl fmt::Debug for MockStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MockStream {{ read: {:?}, write: {:?} }}", self.read.get_ref(), self.write)
    }
}

impl PartialEq for MockStream {
    fn eq(&self, other: &MockStream) -> bool {
        self.read.get_ref() == other.read.get_ref() && self.write == other.write
    }
}

impl MockStream {
    pub fn new() -> MockStream {
        MockStream {
            read: Cursor::new(vec![]),
            write: vec![],
        }
    }

    pub fn with_input(input: &[u8]) -> MockStream {
        MockStream {
            read: Cursor::new(input.to_vec()),
            write: vec![]
        }
    }
}

impl Read for MockStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.read.read(buf)
    }
}

impl Write for MockStream {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        Write::write(&mut self.write, msg)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl NetworkStream for MockStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        Ok("127.0.0.1:1337".parse().unwrap())
    }
}

/// A `NetworkConnector` which creates `MockStream` instances exclusively.
/// It may be useful to intercept writes.
pub struct MockConnector;

impl NetworkConnector for MockConnector {
    type Stream = MockStream;

    fn connect(&self, _host: &str, _port: u16, _scheme: &str) -> hyper::Result<MockStream> {
        Ok(MockStream::new())
    }

    fn set_ssl_verifier(&mut self, _: hyper::net::ContextVerifier) {}
}

/// A `NetworkConnector` embedding another `NetworkConnector` instance,
/// and sets it up to write all reads and writes to standard error as well.
///
/// > **NOTE** It was originally intended to allow arbitrary streams to copy data to,
/// > but I couldn't get passt the compiler with that as normal streams, like files,
/// > are not normally clonable. Maybe an Arc+Mutex would have helped ... .
pub struct TeeConnector<C>
    where C: NetworkConnector {
    pub connector: C,
}

impl<C, S> NetworkConnector for TeeConnector<C>
    where C: NetworkConnector<Stream=S>,
          S: NetworkStream + Send + Clone {
    type Stream = TeeStream<<C as NetworkConnector>::Stream>;

    fn connect(&self, _host: &str, _port: u16, _scheme: &str)
        -> hyper::Result<TeeStream<<C as NetworkConnector>::Stream>> {
        match self.connector.connect(_host, _port, _scheme) {
            Ok(s) => {
                Ok(TeeStream {
                        read_write: s,
                        copy_to: io::stderr(),
                    }
                )
            },
            Err(err) => Err(err),
        }
    }

    fn set_ssl_verifier(&mut self, _: hyper::net::ContextVerifier) {}
}

/// This macro maps host URLs to a respective reply, which is given in plain-text.
/// It ignores, but stores, everything that is written to it. However, the stored
/// values are not accessible just yet.
#[macro_export]
macro_rules! mock_connector (
    ($name:ident {
        $($url:expr => $res:expr)*
    }) => (

        pub struct $name;

        impl hyper::net::NetworkConnector for $name {
            type Stream = $crate::MockStream;
            fn connect(&self, host: &str, port: u16, scheme: &str) -> ::hyper::Result<$crate::MockStream> {
                use std::collections::HashMap;
                use std::io::Cursor;
                debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
                let mut map = HashMap::new();
                $(map.insert($url, $res);)*

                let key = format!("{}://{}", scheme, host);
                // ignore port for now
                match map.get(&*key) {
                    Some(res) => Ok($crate::MockStream {
                        write: vec![],
                        read: Cursor::new(res.to_string().into_bytes()),
                    }),
                    None => panic!("{:?} doesn't know url {}", stringify!($name), key)
                }
            }

            fn set_ssl_verifier(&mut self, _: hyper::net::ContextVerifier) {}
        }
    )
);

/// This macro yields all given server replies in the order they are given.
/// The destination host URL doesn't matter at all.
#[macro_export]
macro_rules! mock_connector_in_order (
    ($name:ident {
        $( $res:expr )*
    }) => (
        use std::cell::{Cell, RefCell};

        #[derive(Default)]
        pub struct $name {
            streamers: RefCell<Vec<String>>,
            current: Cell<usize>,
        }

        impl hyper::net::NetworkConnector for $name {
            type Stream = $crate::MockStream;
            fn connect(&self, host: &str, port: u16, scheme: &str) -> ::hyper::Result<$crate::MockStream> {
                use std::io::Cursor;
                debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);

                if self.streamers.borrow().len() == 0 {
                    let mut v = Vec::new();
                    $(v.push($res.to_string());)*
                    self.streamers.borrow_mut().extend(v.into_iter());
                    self.current.set(0);
                }
                assert!(self.streamers.borrow().len() != 0, "Not a single streamer return value specified");

                let r = Ok($crate::MockStream {
                        write: vec![],
                        read: Cursor::new(self.streamers.borrow()[self.current.get()]
                                                                 .clone().into_bytes())
                });
                self.current.set(self.current.get() + 1);
                r
            }

            fn set_ssl_verifier(&mut self, _: hyper::net::ContextVerifier) {}
        }
    )
);

<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_name = "gst"]
#![feature(libc,core,alloc,unsafe_destructor)]

extern crate libc;

pub use self::appsink::AppSink;
pub use self::appsrc::AppSrc;
pub use self::sample::Sample;
pub use self::caps::Caps;
pub use self::buffer::Buffer;
pub use self::mapinfo::MapInfo;
pub use self::mapinfo::Map;
pub use self::element::Element;
pub use self::element::ElementT;
pub use self::bus::Bus;
pub use self::bin::Bin;
pub use self::bin::BinT;
pub use self::pipeline::Pipeline;
pub use self::pipeline::PipelineT;
pub use self::playbin::PlayBin;
pub use self::message::Message;
pub use self::mainloop::MainLoop;
pub use self::error::Error;
pub use self::error::Result;
pub use self::videoframe::VideoFrame;
pub use self::videoframe::VideoPlane;
pub use self::videoframe::VideoComponent;
pub use self::videoinfo::VideoInfo;
pub use self::buffer_pool::BufferPool;

pub use ffi::*;
use std::ptr;
use std::mem;
use std::ffi::CString;
use std::str;
use std::ffi::CStr;

#[macro_use] mod util;
pub mod ffi;
pub mod appsink;
pub mod appsrc;
mod sample;
mod caps;
mod buffer;
mod element;
pub mod bus;
mod bin;
mod pipeline;
mod playbin;
mod message;
pub mod mainloop;
mod error;
mod videoframe;
mod videoinfo;
mod mapinfo;
mod buffer_pool;
#[cfg(target_os="linux")]
mod link_linux;
#[cfg(target_os="macos")]
mod link_osx;
#[cfg(target_os="windows")]
mod link_windows;

pub fn init(){
	unsafe{
		gst_init(ptr::null::<i32>() as *mut i32, ptr::null_mut::<i8>() as *mut *mut *mut i8);
	}
}

pub fn filename_to_uri(filename: &str) -> Result<String>{
	unsafe{
		if gst_uri_is_valid(to_c_str!(filename))==1{
			return Ok(filename.to_string())
		}
		let err: *mut GError = ptr::null_mut();
		let c_uri = gst_filename_to_uri(to_c_str!(filename),mem::transmute(&err));
		if err != ptr::null_mut(){
			Err(Error::new(0, 0, from_c_str!(mem::transmute((*err).message))))
		}else{
			let uri = from_c_str!(mem::transmute(c_uri)).to_string();
			g_free(mem::transmute(c_uri));
			Ok(uri)
		}
	}
}

pub fn uri_get_protocol(uri: &str) -> Result<String>{
	unsafe{
		if gst_uri_is_valid(to_c_str!(uri))==1{
			Ok(from_c_str!(mem::transmute(gst_uri_get_protocol(to_c_str!(uri)))).to_string())
		}else{
			Err(Error::new(0,0,"not a valid URI"))
		}
	}
}

pub trait Transfer<PtrType=GstElement>{
    /// Consumes the current object and transfers ownership of the raw pointer
    /// Used to transfer ownership to ffi functions, should be used when an ffi
    /// function expects full transfer of an object to avoid the original object
    /// to be unreferenced in the process
    unsafe fn transfer(self) -> *mut PtrType;
}
<commit_msg>remove unused unsafe destructors feature<commit_after>#![crate_type = "lib"]
#![crate_name = "gst"]
#![feature(libc,core,alloc)]

extern crate libc;

pub use self::appsink::AppSink;
pub use self::appsrc::AppSrc;
pub use self::sample::Sample;
pub use self::caps::Caps;
pub use self::buffer::Buffer;
pub use self::mapinfo::MapInfo;
pub use self::mapinfo::Map;
pub use self::element::Element;
pub use self::element::ElementT;
pub use self::bus::Bus;
pub use self::bin::Bin;
pub use self::bin::BinT;
pub use self::pipeline::Pipeline;
pub use self::pipeline::PipelineT;
pub use self::playbin::PlayBin;
pub use self::message::Message;
pub use self::mainloop::MainLoop;
pub use self::error::Error;
pub use self::error::Result;
pub use self::videoframe::VideoFrame;
pub use self::videoframe::VideoPlane;
pub use self::videoframe::VideoComponent;
pub use self::videoinfo::VideoInfo;
pub use self::buffer_pool::BufferPool;

pub use ffi::*;
use std::ptr;
use std::mem;
use std::ffi::CString;
use std::str;
use std::ffi::CStr;

#[macro_use] mod util;
pub mod ffi;
pub mod appsink;
pub mod appsrc;
mod sample;
mod caps;
mod buffer;
mod element;
pub mod bus;
mod bin;
mod pipeline;
mod playbin;
mod message;
pub mod mainloop;
mod error;
mod videoframe;
mod videoinfo;
mod mapinfo;
mod buffer_pool;
#[cfg(target_os="linux")]
mod link_linux;
#[cfg(target_os="macos")]
mod link_osx;
#[cfg(target_os="windows")]
mod link_windows;

pub fn init(){
	unsafe{
		gst_init(ptr::null::<i32>() as *mut i32, ptr::null_mut::<i8>() as *mut *mut *mut i8);
	}
}

pub fn filename_to_uri(filename: &str) -> Result<String>{
	unsafe{
		if gst_uri_is_valid(to_c_str!(filename))==1{
			return Ok(filename.to_string())
		}
		let err: *mut GError = ptr::null_mut();
		let c_uri = gst_filename_to_uri(to_c_str!(filename),mem::transmute(&err));
		if err != ptr::null_mut(){
			Err(Error::new(0, 0, from_c_str!(mem::transmute((*err).message))))
		}else{
			let uri = from_c_str!(mem::transmute(c_uri)).to_string();
			g_free(mem::transmute(c_uri));
			Ok(uri)
		}
	}
}

pub fn uri_get_protocol(uri: &str) -> Result<String>{
	unsafe{
		if gst_uri_is_valid(to_c_str!(uri))==1{
			Ok(from_c_str!(mem::transmute(gst_uri_get_protocol(to_c_str!(uri)))).to_string())
		}else{
			Err(Error::new(0,0,"not a valid URI"))
		}
	}
}

pub trait Transfer<PtrType=GstElement>{
    /// Consumes the current object and transfers ownership of the raw pointer
    /// Used to transfer ownership to ffi functions, should be used when an ffi
    /// function expects full transfer of an object to avoid the original object
    /// to be unreferenced in the process
    unsafe fn transfer(self) -> *mut PtrType;
}
<|endoftext|>


<commit_before>mod token;

pub fn compile(sass: String, style: &str) -> String {
    let mut sp = SassParser::new(sass); // SassTokenizer::new(sass);
    let parsed = sp.parse();
    match style {
        "nested"     => nested(parsed),
        "compressed" => compressed(parsed),
        "expanded"   => expanded(parsed),
        "compact"    => compact(parsed),
        _            => panic!("Unknown style: {}. Please specify one of nested, compressed, expanded, or compact.", style),
    }
}

fn nested(sass: String) -> String {
    sass
}

fn compressed(sass: String) -> String {
    sass.replace(" ", "").replace("\n", "")
}

fn expanded(sass: String) -> String {
    sass
}

fn compact(sass: String) -> String {
    sass
}

#[derive(Debug)]
struct SassRuleSet {
    pub rules: Vec<SassRule>,
}

#[derive(Debug)]
struct SassRule {
    pub selectors: Vec<token::Range>,
    pub props_and_values: Vec<PropertyValueSet>,
}

#[derive(Debug)]
struct PropertyValueSet {
    pub property: token::Range,
    pub value: token::Range,
}

#[derive(Debug)]
struct SassParser {
    pub token: token::Range,
    pub last_token: token::Range,
    pub tokenizer: SassTokenizer,
}

impl SassParser {
    pub fn new(str: String) -> SassParser {
        let mut tokenizer = SassTokenizer::new(str);
        let initial_token = tokenizer.real_token();
        SassParser {
            token: initial_token.clone(),
            last_token: initial_token.clone(),
            tokenizer: tokenizer,
        }
    }

    pub fn bump(&mut self) {
        self.last_token = self.token.clone();
        self.token = self.tokenizer.real_token();
    }

    pub fn parse(&mut self) -> String {
        println!("{:?}", self.parse_rules());
        self.tokenizer.sass.clone()
    }

    fn parse_rules(&mut self) -> Result<SassRuleSet, &'static str> {
        let mut rules = vec![];
        while let Some(rule) = try!(self.parse_rule()) {
            rules.push(rule);
        }
        Ok(SassRuleSet { rules: rules })
    }

    fn parse_rule(&mut self) -> Result<Option<SassRule>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        let mut selectors = vec![];
        while let Some(selector) = try!(self.parse_selector()) {
            selectors.push(selector);
        }
        if selectors.len() == 0 {
            panic!("Empty selector!")
        }

        let mut props_and_values = vec![];
        while let Some(property_value_set) = try!(self.parse_property_value_set()) {
            props_and_values.push(property_value_set);
        }

        // A rule without properties and values isn't *wrong*, per se...
        Ok(Some(SassRule { selectors: selectors, props_and_values: props_and_values }))
    }

    fn parse_selector(&mut self) -> Result<Option<token::Range>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        if self.token.token == token::Text {
            self.bump();
            return Ok(Some(self.last_token.clone()))
        }

        match &self.token.token {
            &token::Eof => Ok(None),
            &token::OpenDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            &token::Comma => {
                self.bump();
                self.parse_selector()
            },
            &token::Whitespace => { // wrong but temporarily so
                self.bump();
                self.parse_selector()
            },
            _ => Err("Unexpected token where we expected selectors"),
        }
    }

    fn parse_property_value_set(&mut self) -> Result<Option<PropertyValueSet>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        if self.token.token == token::CloseDelim(token::Brace) {
            self.bump();
            return Ok(None)
        }

        let p = self.token.clone();

        match p.token {
            token::Text => {
                self.bump(); // should be colon
                self.bump(); // optional whitespace required for now

                let v = self.token.clone();

                if v.token == token::Text {
                    self.bump(); // semicolon
                    self.bump(); // whitespace
                    return Ok(Some(PropertyValueSet { property: p, value: v }))
                } else {
                    panic!("Expected a value here, instead got who knows what!");
                }
            },
            token::CloseDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            token::Whitespace => {
                self.bump();
                self.parse_property_value_set()
            },
            _ => Err("Unexpected token where we expected properties and values"),
        }
    }
}

#[derive(Debug)]
struct SassTokenizer {
    pub pos: u32,
    pub last_pos: u32,
    pub curr: Option<char>,
    pub peek_range: token::Range,
    sass: String,
}

impl SassTokenizer {
    pub fn new(str: String) -> SassTokenizer {
        let mut sr = SassTokenizer {
            pos: 0,
            last_pos: 0,
            curr: Some('\n'),
            peek_range: token::Range { start_pos: 0, end_pos: 0, token: token::Eof },
            sass: str,
        };
        sr.bump();
        sr.advance_token();
        sr
    }

    pub fn bump(&mut self) {
        self.last_pos = self.pos;
        let current_pos = self.pos as usize;
        if current_pos < self.sass.len() {
            let ch = char_at(&self.sass, current_pos);

            self.pos = self.pos + (ch.len_utf8() as u32);
            self.curr = Some(ch);
        } else {
            self.curr = None;
        }
    }

    fn advance_token(&mut self) {
        match self.scan_whitespace() {
            Some(whitespace) => {
                self.peek_range = whitespace;
            },
            None => {
                if self.is_eof() {
                    self.peek_range = token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof };
                } else {
                    self.peek_range = self.next_token_inner();
                }
            },
        }
    }

    fn next_token(&mut self) -> token::Range {
        let retval = self.peek_range.clone();
        self.advance_token();
        retval
    }

    fn next_token_inner(&mut self) -> token::Range {
        let c = match self.curr {
            Some(c) => c,
            None => return token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof },
        };

        if c >= 'a' && c <= 'z' {
            let start = self.last_pos;
            while !self.curr.is_none() && self.curr.unwrap() >= 'a' && self.curr.unwrap() <= 'z' {
                self.bump();
            }
            return token::Range { start_pos: start, end_pos: self.last_pos, token: token::Text }
        }

        match c {
            ';' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Semi }; },
            ':' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Colon }; },
            ',' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Comma }; },
            '{' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::OpenDelim(token::Brace) }; },
            '}' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::CloseDelim(token::Brace) }; },
            _   => { return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Unknown} },
        }
    }

    fn real_token(&mut self) -> token::Range {
        let mut t = self.next_token();
        loop {
            match t.token {
                token::Whitespace => {
                    t = self.next_token();
                },
                _ => break,
            }
        }
        t
    }

    fn scan_whitespace(&mut self) -> Option<token::Range> {
        match self.curr.unwrap_or('\0') {
            c if is_whitespace(Some(c)) => {
                let start = self.last_pos;
                while is_whitespace(self.curr) { self.bump(); }
                Some(token::Range { start_pos: start, end_pos: self.last_pos, token: token::Whitespace })
            },
            _ => None
        }
    }

    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }
}

pub fn char_at(s: &str, byte: usize) -> char {
    s[byte..].chars().next().unwrap()
}

pub fn is_whitespace(c: Option<char>) -> bool {
    match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace
        ' ' | '\n' | '\t' | '\r' => true,
        _ => false
    }
}
<commit_msg>Remove unnecessary cases<commit_after>mod token;

pub fn compile(sass: String, style: &str) -> String {
    let mut sp = SassParser::new(sass); // SassTokenizer::new(sass);
    let parsed = sp.parse();
    match style {
        "nested"     => nested(parsed),
        "compressed" => compressed(parsed),
        "expanded"   => expanded(parsed),
        "compact"    => compact(parsed),
        _            => panic!("Unknown style: {}. Please specify one of nested, compressed, expanded, or compact.", style),
    }
}

fn nested(sass: String) -> String {
    sass
}

fn compressed(sass: String) -> String {
    sass.replace(" ", "").replace("\n", "")
}

fn expanded(sass: String) -> String {
    sass
}

fn compact(sass: String) -> String {
    sass
}

#[derive(Debug)]
struct SassRuleSet {
    pub rules: Vec<SassRule>,
}

#[derive(Debug)]
struct SassRule {
    pub selectors: Vec<token::Range>,
    pub props_and_values: Vec<PropertyValueSet>,
}

#[derive(Debug)]
struct PropertyValueSet {
    pub property: token::Range,
    pub value: token::Range,
}

#[derive(Debug)]
struct SassParser {
    pub token: token::Range,
    pub last_token: token::Range,
    pub tokenizer: SassTokenizer,
}

impl SassParser {
    pub fn new(str: String) -> SassParser {
        let mut tokenizer = SassTokenizer::new(str);
        let initial_token = tokenizer.real_token();
        SassParser {
            token: initial_token.clone(),
            last_token: initial_token.clone(),
            tokenizer: tokenizer,
        }
    }

    pub fn bump(&mut self) {
        self.last_token = self.token.clone();
        self.token = self.tokenizer.real_token();
    }

    pub fn parse(&mut self) -> String {
        println!("{:?}", self.parse_rules());
        self.tokenizer.sass.clone()
    }

    fn parse_rules(&mut self) -> Result<SassRuleSet, &'static str> {
        let mut rules = vec![];
        while let Some(rule) = try!(self.parse_rule()) {
            rules.push(rule);
        }
        Ok(SassRuleSet { rules: rules })
    }

    fn parse_rule(&mut self) -> Result<Option<SassRule>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        let mut selectors = vec![];
        while let Some(selector) = try!(self.parse_selector()) {
            selectors.push(selector);
        }
        if selectors.len() == 0 {
            panic!("Empty selector!")
        }

        let mut props_and_values = vec![];
        while let Some(property_value_set) = try!(self.parse_property_value_set()) {
            props_and_values.push(property_value_set);
        }

        // A rule without properties and values isn't *wrong*, per se...
        Ok(Some(SassRule { selectors: selectors, props_and_values: props_and_values }))
    }

    fn parse_selector(&mut self) -> Result<Option<token::Range>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        if self.token.token == token::Text {
            self.bump();
            return Ok(Some(self.last_token.clone()))
        }

        match &self.token.token {
            &token::OpenDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            &token::Comma => {
                self.bump();
                self.parse_selector()
            },
            _ => Err("Unexpected token where we expected selectors"),
        }
    }

    fn parse_property_value_set(&mut self) -> Result<Option<PropertyValueSet>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        if self.token.token == token::CloseDelim(token::Brace) {
            self.bump();
            return Ok(None)
        }

        let p = self.token.clone();

        match p.token {
            token::Text => {
                self.bump(); // should be colon
                self.bump(); // optional whitespace required for now

                let v = self.token.clone();

                if v.token == token::Text {
                    self.bump(); // semicolon
                    self.bump(); // whitespace
                    return Ok(Some(PropertyValueSet { property: p, value: v }))
                } else {
                    panic!("Expected a value here, instead got who knows what!");
                }
            },
            token::CloseDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            _ => Err("Unexpected token where we expected properties and values"),
        }
    }
}

#[derive(Debug)]
struct SassTokenizer {
    pub pos: u32,
    pub last_pos: u32,
    pub curr: Option<char>,
    pub peek_range: token::Range,
    sass: String,
}

impl SassTokenizer {
    pub fn new(str: String) -> SassTokenizer {
        let mut sr = SassTokenizer {
            pos: 0,
            last_pos: 0,
            curr: Some('\n'),
            peek_range: token::Range { start_pos: 0, end_pos: 0, token: token::Eof },
            sass: str,
        };
        sr.bump();
        sr.advance_token();
        sr
    }

    pub fn bump(&mut self) {
        self.last_pos = self.pos;
        let current_pos = self.pos as usize;
        if current_pos < self.sass.len() {
            let ch = char_at(&self.sass, current_pos);

            self.pos = self.pos + (ch.len_utf8() as u32);
            self.curr = Some(ch);
        } else {
            self.curr = None;
        }
    }

    fn advance_token(&mut self) {
        match self.scan_whitespace() {
            Some(whitespace) => {
                self.peek_range = whitespace;
            },
            None => {
                if self.is_eof() {
                    self.peek_range = token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof };
                } else {
                    self.peek_range = self.next_token_inner();
                }
            },
        }
    }

    fn next_token(&mut self) -> token::Range {
        let retval = self.peek_range.clone();
        self.advance_token();
        retval
    }

    fn next_token_inner(&mut self) -> token::Range {
        let c = match self.curr {
            Some(c) => c,
            None => return token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof },
        };

        if c >= 'a' && c <= 'z' {
            let start = self.last_pos;
            while !self.curr.is_none() && self.curr.unwrap() >= 'a' && self.curr.unwrap() <= 'z' {
                self.bump();
            }
            return token::Range { start_pos: start, end_pos: self.last_pos, token: token::Text }
        }

        match c {
            ';' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Semi }; },
            ':' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Colon }; },
            ',' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Comma }; },
            '{' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::OpenDelim(token::Brace) }; },
            '}' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::CloseDelim(token::Brace) }; },
            _   => { return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Unknown} },
        }
    }

    fn real_token(&mut self) -> token::Range {
        let mut t = self.next_token();
        loop {
            match t.token {
                token::Whitespace => {
                    t = self.next_token();
                },
                _ => break,
            }
        }
        t
    }

    fn scan_whitespace(&mut self) -> Option<token::Range> {
        match self.curr.unwrap_or('\0') {
            c if is_whitespace(Some(c)) => {
                let start = self.last_pos;
                while is_whitespace(self.curr) { self.bump(); }
                Some(token::Range { start_pos: start, end_pos: self.last_pos, token: token::Whitespace })
            },
            _ => None
        }
    }

    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }
}

pub fn char_at(s: &str, byte: usize) -> char {
    s[byte..].chars().next().unwrap()
}

pub fn is_whitespace(c: Option<char>) -> bool {
    match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace
        ' ' | '\n' | '\t' | '\r' => true,
        _ => false
    }
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]
#![feature(cfg_target_feature)]
//! Basic digital signal processing (DSP) operations
//!
//! Digital signal processing based on real or complex vectors in time or frequency domain. Vectors are expected to typically have a size which is at least in the order
//! of magnitude of a couple of thousand elements. This crate tries to balance between a clear API and performance in terms of processing speed.
//! This project started as small pet project to learn more about DSP, CPU architecture and Rust. Since learning
//! involves making mistakes, don't expect things to be flawless or even close to flawless.
//!
//! This library isn't suited - from my point of view - for game programming. If you are looking for vector types to do
//! 2D or 3D graphics calculations then you unfortunately have to continue with your search. However there seem to be
//! a lot of suitable crates on `crates.io` for you.
//!
//! The vector types don't distinguish between 1xN or Nx1. This is a difference to other conventions such as in MATLAB or GNU Octave.
//! The reason for this decision is that it seems to be more practical to ignore the shape of the vector.
//!
//! Right now the library uses pretty aggressive parallelization. So this means that it will keep all CPU cores busy
//! even if the performance gain is minimal e.g. because the multi core overhead is nearly as large as the performance boost
//! of multiple cores. In future there will be likely an option which tells the library how it should balance between processing time
//! and CPU utilization. The library also avoids to allocate and free memory and it allocates memory for temporary allocation.
//! so the library is likely not suitable for devices which are tight on memory. On normal desktop computers there is usually plenty of
//! memory available so that the optimization focus is on decreasing the processing time for every (common) operation and to spent little time with memory allocations.

/// Like `try!` but for operations returning a vector.
///
/// Operations which return a vector on success even return an error reason
/// together with a vector on failure. So even if the operation has failed the
/// vector can still be reused and thus memory allocation can be avoided. If
/// this is undesired then this macro can be used instead of `try!` to just
/// return the error reason.
#[macro_export]
macro_rules! try_vec {
    ( $ expr : expr ) => {
        match $expr {
            Ok(vec) => vec,
            Err((reason, _)) => return Err(reason)
        };
    };
}

extern crate simd;
extern crate num_cpus;
extern crate crossbeam;
extern crate num;
extern crate rustfft;
mod vector_types;
mod multicore_support;
mod simd_extensions;
pub mod window_functions;
pub mod conv_types;
pub mod interop_facade;
pub mod combined_ops;
pub use vector_types::
    {
        DataVectorDomain,
        DataVector,
        VecResult,
        VoidResult,
        ErrorReason,
        GenericVectorOps,
        RealVectorOps,
        ComplexVectorOps,
        TimeDomainOperations,
        FrequencyDomainOperations,
        SymmetricFrequencyDomainOperations,
        SymmetricTimeDomainOperations,
        GenericDataVector,
        ComplexFreqVector,
        ComplexTimeVector,
        RealTimeVector,
        RealFreqVector,
        DataVector32,
        RealTimeVector32,
        ComplexTimeVector32,
        RealFreqVector32,
        ComplexFreqVector32,
        DataVector64,
        RealTimeVector64,
        ComplexTimeVector64,
        RealFreqVector64,
        ComplexFreqVector64,
        Statistics,
        RededicateVector,
        ScaleOps,
        OffsetOps,
        DotProductOps,
        StatisticsOps,
        Convolution,
        VectorConvolution,
        FrequencyMultiplication,
        CrossCorrelation,
        Interpolation,
        RealInterpolation,
        PaddingOption,
        VectorIter
    };
 pub use multicore_support::MultiCoreSettings;
 use num::traits::Float;

 /// A real floating pointer number intended to abstract over `f32` and `f64`.
 pub trait RealNumber : Float + Copy + Clone + Send + Sync { }
 impl<T> RealNumber for T
  where T: Float + Copy + Clone + Send + Sync {}

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

    fn void_try_method() -> Result<i32, ErrorReason> {
        let array = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
        let vector = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let mut dest = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let _ = try!(vector.get_magnitude(&mut dest));
        Ok(0)
    }

    fn scalar_try_method() -> Result<i32, ErrorReason> {
        let array = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
        let vector = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let dest = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let _ = try!(vector.complex_dot_product(&dest));
        Ok(0)
    }

    fn vec_try_method() -> Result<i32, ErrorReason> {
        let array = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
        let vector = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let array = [1.0, 2.0, 3.0, 4.0];
        let dest = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let _ = try_vec!(vector.add_vector(&dest));
        Ok(0)
    }

    /// This test should make sure that there are convenient error handling
    /// methods available.
    #[test]
    fn construct_real_time_vector_32_test()
    {
        let res = void_try_method();
        assert!(res.is_err());
        let res = scalar_try_method();
        assert!(res.is_err());
        let res = vec_try_method();
        assert!(res.is_err());
    }
}<commit_msg>Clarified a doc section<commit_after>#![feature(box_syntax)]
#![feature(cfg_target_feature)]
//! Basic digital signal processing (DSP) operations
//!
//! Digital signal processing based on real or complex vectors in time or frequency domain. Vectors are expected to typically have a size which is at least in the order
//! of magnitude of a couple of thousand elements. This crate tries to balance between a clear API and performance in terms of processing speed.
//! This project started as small pet project to learn more about DSP, CPU architecture and Rust. Since learning
//! involves making mistakes, don't expect things to be flawless or even close to flawless.
//!
//! This library isn't suited - from my point of view - for game programming. If you are looking for vector types to do
//! 2D or 3D graphics calculations then you unfortunately have to continue with your search. However there seem to be
//! a lot of suitable crates on `crates.io` for you.
//!
//! The vector types don't distinguish between 1xN or Nx1. This is a difference to other conventions such as in MATLAB or GNU Octave.
//! The reason for this decision is that it seems to be more practical to ignore the shape of the vector.
//!
//! Right now the library uses pretty aggressive parallelization. So this means that it will keep all CPU cores busy
//! even if the performance gain is minimal e.g. because the multi core overhead is nearly as large as the performance boost
//! of multiple cores. In future there will be likely an option which tells the library how it should balance between processing time
//! and CPU utilization. The library also avoids to allocate and free memory so it allocates all of the required temporary memory when a new vector
//! is constructed. Therefore the library is likely not suitable for devices which are tight on memory. On normal desktop computers there is usually plenty of
//! memory available so that the optimization focus is on decreasing the processing time for every (common) operation and to spent little time with memory allocations.

/// Like `try!` but for operations returning a vector.
///
/// Operations which return a vector on success even return an error reason
/// together with a vector on failure. So even if the operation has failed the
/// vector can still be reused and thus memory allocation can be avoided. If
/// this is undesired then this macro can be used instead of `try!` to just
/// return the error reason.
#[macro_export]
macro_rules! try_vec {
    ( $ expr : expr ) => {
        match $expr {
            Ok(vec) => vec,
            Err((reason, _)) => return Err(reason)
        };
    };
}

extern crate simd;
extern crate num_cpus;
extern crate crossbeam;
extern crate num;
extern crate rustfft;
mod vector_types;
mod multicore_support;
mod simd_extensions;
pub mod window_functions;
pub mod conv_types;
pub mod interop_facade;
pub mod combined_ops;
pub use vector_types::
    {
        DataVectorDomain,
        DataVector,
        VecResult,
        VoidResult,
        ErrorReason,
        GenericVectorOps,
        RealVectorOps,
        ComplexVectorOps,
        TimeDomainOperations,
        FrequencyDomainOperations,
        SymmetricFrequencyDomainOperations,
        SymmetricTimeDomainOperations,
        GenericDataVector,
        ComplexFreqVector,
        ComplexTimeVector,
        RealTimeVector,
        RealFreqVector,
        DataVector32,
        RealTimeVector32,
        ComplexTimeVector32,
        RealFreqVector32,
        ComplexFreqVector32,
        DataVector64,
        RealTimeVector64,
        ComplexTimeVector64,
        RealFreqVector64,
        ComplexFreqVector64,
        Statistics,
        RededicateVector,
        ScaleOps,
        OffsetOps,
        DotProductOps,
        StatisticsOps,
        Convolution,
        VectorConvolution,
        FrequencyMultiplication,
        CrossCorrelation,
        Interpolation,
        RealInterpolation,
        PaddingOption,
        VectorIter
    };
 pub use multicore_support::MultiCoreSettings;
 use num::traits::Float;

 /// A real floating pointer number intended to abstract over `f32` and `f64`.
 pub trait RealNumber : Float + Copy + Clone + Send + Sync { }
 impl<T> RealNumber for T
  where T: Float + Copy + Clone + Send + Sync {}

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

    fn void_try_method() -> Result<i32, ErrorReason> {
        let array = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
        let vector = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let mut dest = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let _ = try!(vector.get_magnitude(&mut dest));
        Ok(0)
    }

    fn scalar_try_method() -> Result<i32, ErrorReason> {
        let array = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
        let vector = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let dest = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let _ = try!(vector.complex_dot_product(&dest));
        Ok(0)
    }

    fn vec_try_method() -> Result<i32, ErrorReason> {
        let array = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
        let vector = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let array = [1.0, 2.0, 3.0, 4.0];
        let dest = DataVector32::from_array(false, DataVectorDomain::Time, &array);
        let _ = try_vec!(vector.add_vector(&dest));
        Ok(0)
    }

    /// This test should make sure that there are convenient error handling
    /// methods available.
    #[test]
    fn construct_real_time_vector_32_test()
    {
        let res = void_try_method();
        assert!(res.is_err());
        let res = scalar_try_method();
        assert!(res.is_err());
        let res = vec_try_method();
        assert!(res.is_err());
    }
}<|endoftext|>


<commit_before>
extern crate core;
extern crate libc;

pub mod ffi;
pub mod ffi_type;

use ffi::bindgen;
use std::mem;

#[derive(Debug)]
pub struct Cif(bindgen::ffi_cif);

#[derive(Debug)]
pub struct Arg(*mut ::std::os::raw::c_void);

#[derive(Copy, Clone, Debug)]
pub enum Type {
    Void,
    UInt8,
    SInt8,
    UInt16,
    SInt16,
    UInt32,
    SInt32,
    UInt64,
    SInt64,
    Float,
    Double,
    Pointer,
    LongDouble,
    ComplexFloat,
    ComplexDouble,
    ComplexLongDouble,
}

impl Type {
    fn as_ffi_type(self) -> *mut bindgen::ffi_type {
        use Type::*;
        unsafe {
            match self {
                Void => &mut bindgen::ffi_type_void,
                UInt8 => &mut bindgen::ffi_type_uint8,
                SInt8 => &mut bindgen::ffi_type_sint8,
                UInt16 => &mut bindgen::ffi_type_uint16,
                SInt16 => &mut bindgen::ffi_type_sint16,
                UInt32 => &mut bindgen::ffi_type_uint32,
                SInt32 => &mut bindgen::ffi_type_sint32,
                UInt64 => &mut bindgen::ffi_type_uint64,
                SInt64 => &mut bindgen::ffi_type_sint64,
                Float => &mut bindgen::ffi_type_float,
                Double => &mut bindgen::ffi_type_double,
                Pointer => &mut bindgen::ffi_type_pointer,
                LongDouble => &mut bindgen::ffi_type_longdouble,
                ComplexFloat => &mut bindgen::ffi_type_complex_float,
                ComplexDouble => &mut bindgen::ffi_type_complex_double,
                ComplexLongDouble => &mut bindgen::ffi_type_complex_double,
            }
        }
    }
}

pub fn arg<T>(r: &T) -> Arg {
    Arg(unsafe { mem::transmute(r as *const T) })
}

impl Cif {
    pub fn new(args: &[Type], result: Type) -> Self {
        let mut cif: bindgen::ffi_cif = Default::default();
        let mut real_args: Vec<_> =
            args.iter().map(|t| t.as_ffi_type()).collect();

        let result = unsafe {
            bindgen::ffi_prep_cif(&mut cif,
                                  bindgen::FFI_DEFAULT_ABI,
                                  args.len() as u32,
                                  result.as_ffi_type(),
                                  real_args.as_mut_ptr())
        };

        match result {
            bindgen::ffi_status::FFI_OK
                => (),
            bindgen::ffi_status::FFI_BAD_TYPEDEF
                => panic!("FFI_BAD_TYPEDEF"),
            bindgen::ffi_status::FFI_BAD_ABI
                => panic!("FFI_BAD_ABI"),
        }

        Cif(cif)
    }

    pub unsafe fn call<R>(&self, f: usize, values: &[Arg]) -> R {
        use std::mem;

        assert!(self.0.nargs as usize == values.len());

        let mut result: R = mem::zeroed();

        bindgen::ffi_call(
            mem::transmute(&self.0),
            mem::transmute(f),
            mem::transmute(&mut result),
            mem::transmute(values.as_ptr()));

        return result;
    }
}

pub struct Closure {
    alloc: *mut ::std::os::raw::c_void,
    _code:  *mut ::std::os::raw::c_void,
}

impl Drop for Closure {
    fn drop(&mut self) {
        unsafe {
            bindgen::ffi_closure_free(self.alloc);
        }
    }
}

impl Closure {
    pub fn new() -> Self {
        let mut code: *mut ::std::os::raw::c_void =
            unsafe { mem::zeroed() };

        let alloc = unsafe {
            bindgen::ffi_closure_alloc(
                mem::size_of::<bindgen::ffi_closure>(),
                &mut code)
        };

        assert!(alloc as usize != 0);

        Closure {
            alloc: alloc,
            _code:  code,
        }
    }
}

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

    #[test]
    fn ffi_call() {
        let cif = Cif::new(&[Type::SInt64, Type::SInt64], Type::SInt64);
        let f   = |m: i64, n: i64| -> i64 {
            unsafe { cif.call(add_it as usize, &[arg(&m), arg(&n)]) }
        };

        assert_eq!(12, f(5, 7));
        assert_eq!(13, f(6, 7));
        assert_eq!(15, f(8, 7));
    }

    extern "C" fn add_it(n: i64, m: i64) -> i64 {
        return n + m;
    }
}
<commit_msg>removed unused extern crate item<commit_after>extern crate libc;

pub mod ffi;
pub mod ffi_type;

use ffi::bindgen;
use std::mem;

#[derive(Debug)]
pub struct Cif(bindgen::ffi_cif);

#[derive(Debug)]
pub struct Arg(*mut ::std::os::raw::c_void);

#[derive(Copy, Clone, Debug)]
pub enum Type {
    Void,
    UInt8,
    SInt8,
    UInt16,
    SInt16,
    UInt32,
    SInt32,
    UInt64,
    SInt64,
    Float,
    Double,
    Pointer,
    LongDouble,
    ComplexFloat,
    ComplexDouble,
    ComplexLongDouble,
}

impl Type {
    fn as_ffi_type(self) -> *mut bindgen::ffi_type {
        use Type::*;
        unsafe {
            match self {
                Void => &mut bindgen::ffi_type_void,
                UInt8 => &mut bindgen::ffi_type_uint8,
                SInt8 => &mut bindgen::ffi_type_sint8,
                UInt16 => &mut bindgen::ffi_type_uint16,
                SInt16 => &mut bindgen::ffi_type_sint16,
                UInt32 => &mut bindgen::ffi_type_uint32,
                SInt32 => &mut bindgen::ffi_type_sint32,
                UInt64 => &mut bindgen::ffi_type_uint64,
                SInt64 => &mut bindgen::ffi_type_sint64,
                Float => &mut bindgen::ffi_type_float,
                Double => &mut bindgen::ffi_type_double,
                Pointer => &mut bindgen::ffi_type_pointer,
                LongDouble => &mut bindgen::ffi_type_longdouble,
                ComplexFloat => &mut bindgen::ffi_type_complex_float,
                ComplexDouble => &mut bindgen::ffi_type_complex_double,
                ComplexLongDouble => &mut bindgen::ffi_type_complex_double,
            }
        }
    }
}

pub fn arg<T>(r: &T) -> Arg {
    Arg(unsafe { mem::transmute(r as *const T) })
}

impl Cif {
    pub fn new(args: &[Type], result: Type) -> Self {
        let mut cif: bindgen::ffi_cif = Default::default();
        let mut real_args: Vec<_> =
            args.iter().map(|t| t.as_ffi_type()).collect();

        let result = unsafe {
            bindgen::ffi_prep_cif(&mut cif,
                                  bindgen::FFI_DEFAULT_ABI,
                                  args.len() as u32,
                                  result.as_ffi_type(),
                                  real_args.as_mut_ptr())
        };

        match result {
            bindgen::ffi_status::FFI_OK
                => (),
            bindgen::ffi_status::FFI_BAD_TYPEDEF
                => panic!("FFI_BAD_TYPEDEF"),
            bindgen::ffi_status::FFI_BAD_ABI
                => panic!("FFI_BAD_ABI"),
        }

        Cif(cif)
    }

    pub unsafe fn call<R>(&self, f: usize, values: &[Arg]) -> R {
        use std::mem;

        assert!(self.0.nargs as usize == values.len());

        let mut result: R = mem::zeroed();

        bindgen::ffi_call(
            mem::transmute(&self.0),
            mem::transmute(f),
            mem::transmute(&mut result),
            mem::transmute(values.as_ptr()));

        return result;
    }
}

pub struct Closure {
    alloc: *mut ::std::os::raw::c_void,
    _code:  *mut ::std::os::raw::c_void,
}

impl Drop for Closure {
    fn drop(&mut self) {
        unsafe {
            bindgen::ffi_closure_free(self.alloc);
        }
    }
}

impl Closure {
    pub fn new() -> Self {
        let mut code: *mut ::std::os::raw::c_void =
            unsafe { mem::zeroed() };

        let alloc = unsafe {
            bindgen::ffi_closure_alloc(
                mem::size_of::<bindgen::ffi_closure>(),
                &mut code)
        };

        assert!(alloc as usize != 0);

        Closure {
            alloc: alloc,
            _code:  code,
        }
    }
}

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

    #[test]
    fn ffi_call() {
        let cif = Cif::new(&[Type::SInt64, Type::SInt64], Type::SInt64);
        let f   = |m: i64, n: i64| -> i64 {
            unsafe { cif.call(add_it as usize, &[arg(&m), arg(&n)]) }
        };

        assert_eq!(12, f(5, 7));
        assert_eq!(13, f(6, 7));
        assert_eq!(15, f(8, 7));
    }

    extern "C" fn add_it(n: i64, m: i64) -> i64 {
        return n + m;
    }
}
<|endoftext|>


<commit_before>//! A pure-Rust LDAP library using the Tokio stack.
//!
//! ## Usage
//!
//! In `Cargo.toml`:
//!
//! ```toml
//! [dependencies.ldap3]
//! version = "0.5"
//! ```
//!
//! In the crate root (`src/lib.rs` or `src/main.rs`):
//!
//! ```
//! extern crate ldap3;
//! ```
//! ## Summary
//!
//! The library provides both synchronous and asynchronous interfaces. The [`LdapConn`]
//! (struct.LdapConn.html) structure is the starting point for all synchronous operations.
//! [`LdapConnAsync`](struct.LdapConnAsync) is its asynchronous analogue, and [`Ldap`](struct.Ldap) is
//! the low-level asynchronous connection handle used by both.
//!
//! In the [struct list](#structs), async-related structs have an asterisk (__*__) after
//! the short description.
//!
//! Since the library is still in development, none of the interfaces should be considered
//! stable. If a breaking change of some component is planned, it will be noted in the
//! documentation with a bolded __Note__, and a link to the GitHub issue discussing the
//! change, if applicable. General, crate-level issues with the documentation can be
//! discussed [here](https://github.com/inejge/ldap3/issues/3).
//!
//! The documentation is written for readers familiar with LDAP concepts and terminology,
//! which it won't attempt to explain.
//!
//! ## Examples
//!
//! The following two examples perform exactly the same operation and should produce identical
//! results. They should be run against the example server in the `data` subdirectory of the crate source.
//! Other sample programs expecting the same server setup can be found in the `examples` subdirectory.
//!
//! ### Synchronous search
//!
//! ```rust,no_run
//! extern crate ldap3;
//!
//! use std::error::Error;
//!
//! use ldap3::{LdapConn, Scope, SearchEntry};
//!
//! fn main() {
//!     match do_search() {
//!         Ok(_) => (),
//!         Err(e) => println!("{}", e),
//!     }
//! }
//!
//! fn do_search() -> Result<(), Box<Error>> {
//!     let ldap = LdapConn::new("ldap://localhost:2389")?;
//!     let (rs, _res) = ldap.search(
//!         "ou=Places,dc=example,dc=org",
//!         Scope::Subtree,
//!         "(&(objectClass=locality)(l=ma*))",
//!         vec!["l"]
//!     )?.success()?;
//!     for entry in rs {
//!         println!("{:?}", SearchEntry::construct(entry));
//!     }
//!     Ok(())
//! }
//! ```
//!
//! ### Asynchronous search
//!
//! ```rust,no_run
//! extern crate futures;
//! extern crate ldap3;
//! extern crate tokio_core;
//!
//! use std::error::Error;
//!
//! use futures::Future;
//! use ldap3::{LdapConnAsync, Scope, SearchEntry};
//! use tokio_core::reactor::Core;
//!
//! fn main() {
//!     match do_search() {
//!         Ok(_) => (),
//!         Err(e) => println!("{}", e),
//!     }
//! }
//!
//! fn do_search() -> Result<(), Box<Error>> {
//!     let mut core = Core::new()?;
//!     let handle = core.handle();
//!     let ldap = LdapConnAsync::new("ldap://localhost:2389", &handle)?;
//!     let srch = ldap.and_then(|ldap|
//!         ldap.search(
//!             "ou=Places,dc=example,dc=org",
//!             Scope::Subtree,
//!             "(&(objectClass=locality)(l=ma*))",
//!             vec!["l"]
//!         ))
//!         .and_then(|response| response.success())
//!         .and_then(|(rs, _res)| Ok(rs));
//!     let rs = core.run(srch)?;
//!     for entry in rs {
//!         println!("{:?}", SearchEntry::construct(entry));
//!     }
//!     Ok(())
//! }
//! ```

extern crate bytes;
extern crate byteorder;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate lazy_static;
extern crate lber;
#[macro_use]
extern crate log;
#[cfg(feature = "tls")]
extern crate native_tls;
#[macro_use]
extern crate nom;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_proto;
extern crate tokio_service;
#[cfg(feature = "tls")]
extern crate tokio_tls;
#[cfg(all(unix, not(feature = "minimal")))]
extern crate tokio_uds;
#[cfg(all(unix, not(feature = "minimal")))]
extern crate tokio_uds_proto;
extern crate url;

mod abandon;
mod add;
mod bind;
mod compare;
mod conn;
pub mod controls {
    //! Control construction and parsing.
    //!
    //! A control can be associated with a request or a response. Several common
    //! controls, such as [`PagedResults`](struct.PagedResults.html), are implemented
    //! directly by this library. If an implemented control has the same form for
    //! the request and the response, there will be a single structure for both.
    //! (This is the case for `PagedResults`.) If the response control is different,
    //! its name will consist of the request control name with the `Resp` suffix.
    //!
    //! A request control can be created by instantiating its structure and converting
    //! it to ASN.1 with `into()` when passing the instance or constructing the request
    //! control vector in the call to [`with_controls()`](../struct.LdapConn.html#method.with_controls).
    //! A third-party control must implement the conversion from an instance
    //! of itself to [`RawControl`](struct.RawControl.html), a general form of control.
    //!
    //! `RawControl`, together with an optional instance of [`ControlType`]
    //! (types/index.html), forms the type [`Control`](struct.Control.html); a vector
    //! of `Control`s is part of the result of all LDAP operation which return one.
    //!
    //! The first element of `Control` will have a value if the parser recognizes
    //! the control's OID as one that is implemented by the library itself. Since the
    //! list of implemented controls is expected to grow, matching those values must
    //! be done through reexported types in the [`types`](types/index.html) module,
    //! and cannot be exhaustive.
    //!
    //! A recognized response control can be parsed by calling [`parse()`]
    //! (struct.RawControl.html#method.parse) on the instance of `RawControl` representing it.
    //! A third-party control must implement the [`ControlParser`](trait.ControlParser.html)
    //! trait to support this interface.
    pub use controls_impl::{Control, ControlParser, CriticalControl, MakeCritical, RawControl};
    pub use controls_impl::{Assertion, PagedResults, ProxyAuth, RelaxRules};
    pub use controls_impl::{PostRead, PostReadResp, PreRead, PreReadResp, ReadEntryResp};
    pub use controls_impl::types;
}
mod controls_impl;
mod delete;
mod extended;
mod exop_impl;
pub mod exop {
    //! Extended operation construction and parsing.
    //!
    //! A generic exop is represented by [`Exop`](struct.Exop.html). If a particular
    //! exop is implemented by this library, it may have one or two associated structs;
    //! one for constructing requests, and another for parsing responses. If request and
    //! response are the same, there is only the request struct; if they are different,
    //! the response struct's name will consist of the request struct name with the
    //! `Resp` suffix.
    //!
    //! A request struct must implement the `From` conversion of itself into `Exop`.
    //! A response struct must implement the [`ExopParser`](trait.ExopParser.html)
    //! trait.
    pub use exop_impl::{Exop, ExopParser, StartTLS, WhoAmI, WhoAmIResp};
}
mod filter;
mod ldap;
mod modify;
mod modifydn;
mod protocol;
pub mod result;
mod search;
mod unbind;
mod util;

pub use conn::{EntryStream, LdapConn, LdapConnAsync, LdapConnBuilder};
pub use filter::parse as parse_filter;
pub use ldap::Ldap;
pub use modify::Mod;
pub use result::LdapResult;
pub use search::{DerefAliases, ResultEntry, Scope, SearchEntry, SearchOptions, SearchStream};
pub use util::{dn_escape, ldap_escape};

pub mod asn1 {
    //! ASN.1 structure construction and parsing.
    //!
    //! This section is deliberately under-documented; it's expected that the ASN.1 subsystem will
    //! be extensively overhauled in the future. If you need examples of using the present interface
    //! for, e.g., implementing a new extended operation or a control, consult the source of existing
    //! exops/controls.
    pub use lber::IResult;
    pub use lber::common::TagClass;
    pub use lber::structure::{PL, StructureTag};
    pub use lber::structures::{ASNTag, Boolean, Enumerated, ExplicitTag, Integer, Null, OctetString, Sequence, Set, Tag};
    pub use lber::parse::{parse_tag, parse_uint};
    pub use lber::write;
}
<commit_msg>Hide StartTLS exop from public API<commit_after>//! A pure-Rust LDAP library using the Tokio stack.
//!
//! ## Usage
//!
//! In `Cargo.toml`:
//!
//! ```toml
//! [dependencies.ldap3]
//! version = "0.5"
//! ```
//!
//! In the crate root (`src/lib.rs` or `src/main.rs`):
//!
//! ```
//! extern crate ldap3;
//! ```
//! ## Summary
//!
//! The library provides both synchronous and asynchronous interfaces. The [`LdapConn`]
//! (struct.LdapConn.html) structure is the starting point for all synchronous operations.
//! [`LdapConnAsync`](struct.LdapConnAsync) is its asynchronous analogue, and [`Ldap`](struct.Ldap) is
//! the low-level asynchronous connection handle used by both.
//!
//! In the [struct list](#structs), async-related structs have an asterisk (__*__) after
//! the short description.
//!
//! Since the library is still in development, none of the interfaces should be considered
//! stable. If a breaking change of some component is planned, it will be noted in the
//! documentation with a bolded __Note__, and a link to the GitHub issue discussing the
//! change, if applicable. General, crate-level issues with the documentation can be
//! discussed [here](https://github.com/inejge/ldap3/issues/3).
//!
//! The documentation is written for readers familiar with LDAP concepts and terminology,
//! which it won't attempt to explain.
//!
//! ## Examples
//!
//! The following two examples perform exactly the same operation and should produce identical
//! results. They should be run against the example server in the `data` subdirectory of the crate source.
//! Other sample programs expecting the same server setup can be found in the `examples` subdirectory.
//!
//! ### Synchronous search
//!
//! ```rust,no_run
//! extern crate ldap3;
//!
//! use std::error::Error;
//!
//! use ldap3::{LdapConn, Scope, SearchEntry};
//!
//! fn main() {
//!     match do_search() {
//!         Ok(_) => (),
//!         Err(e) => println!("{}", e),
//!     }
//! }
//!
//! fn do_search() -> Result<(), Box<Error>> {
//!     let ldap = LdapConn::new("ldap://localhost:2389")?;
//!     let (rs, _res) = ldap.search(
//!         "ou=Places,dc=example,dc=org",
//!         Scope::Subtree,
//!         "(&(objectClass=locality)(l=ma*))",
//!         vec!["l"]
//!     )?.success()?;
//!     for entry in rs {
//!         println!("{:?}", SearchEntry::construct(entry));
//!     }
//!     Ok(())
//! }
//! ```
//!
//! ### Asynchronous search
//!
//! ```rust,no_run
//! extern crate futures;
//! extern crate ldap3;
//! extern crate tokio_core;
//!
//! use std::error::Error;
//!
//! use futures::Future;
//! use ldap3::{LdapConnAsync, Scope, SearchEntry};
//! use tokio_core::reactor::Core;
//!
//! fn main() {
//!     match do_search() {
//!         Ok(_) => (),
//!         Err(e) => println!("{}", e),
//!     }
//! }
//!
//! fn do_search() -> Result<(), Box<Error>> {
//!     let mut core = Core::new()?;
//!     let handle = core.handle();
//!     let ldap = LdapConnAsync::new("ldap://localhost:2389", &handle)?;
//!     let srch = ldap.and_then(|ldap|
//!         ldap.search(
//!             "ou=Places,dc=example,dc=org",
//!             Scope::Subtree,
//!             "(&(objectClass=locality)(l=ma*))",
//!             vec!["l"]
//!         ))
//!         .and_then(|response| response.success())
//!         .and_then(|(rs, _res)| Ok(rs));
//!     let rs = core.run(srch)?;
//!     for entry in rs {
//!         println!("{:?}", SearchEntry::construct(entry));
//!     }
//!     Ok(())
//! }
//! ```

extern crate bytes;
extern crate byteorder;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate lazy_static;
extern crate lber;
#[macro_use]
extern crate log;
#[cfg(feature = "tls")]
extern crate native_tls;
#[macro_use]
extern crate nom;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_proto;
extern crate tokio_service;
#[cfg(feature = "tls")]
extern crate tokio_tls;
#[cfg(all(unix, not(feature = "minimal")))]
extern crate tokio_uds;
#[cfg(all(unix, not(feature = "minimal")))]
extern crate tokio_uds_proto;
extern crate url;

mod abandon;
mod add;
mod bind;
mod compare;
mod conn;
pub mod controls {
    //! Control construction and parsing.
    //!
    //! A control can be associated with a request or a response. Several common
    //! controls, such as [`PagedResults`](struct.PagedResults.html), are implemented
    //! directly by this library. If an implemented control has the same form for
    //! the request and the response, there will be a single structure for both.
    //! (This is the case for `PagedResults`.) If the response control is different,
    //! its name will consist of the request control name with the `Resp` suffix.
    //!
    //! A request control can be created by instantiating its structure and converting
    //! it to ASN.1 with `into()` when passing the instance or constructing the request
    //! control vector in the call to [`with_controls()`](../struct.LdapConn.html#method.with_controls).
    //! A third-party control must implement the conversion from an instance
    //! of itself to [`RawControl`](struct.RawControl.html), a general form of control.
    //!
    //! `RawControl`, together with an optional instance of [`ControlType`]
    //! (types/index.html), forms the type [`Control`](struct.Control.html); a vector
    //! of `Control`s is part of the result of all LDAP operation which return one.
    //!
    //! The first element of `Control` will have a value if the parser recognizes
    //! the control's OID as one that is implemented by the library itself. Since the
    //! list of implemented controls is expected to grow, matching those values must
    //! be done through reexported types in the [`types`](types/index.html) module,
    //! and cannot be exhaustive.
    //!
    //! A recognized response control can be parsed by calling [`parse()`]
    //! (struct.RawControl.html#method.parse) on the instance of `RawControl` representing it.
    //! A third-party control must implement the [`ControlParser`](trait.ControlParser.html)
    //! trait to support this interface.
    pub use controls_impl::{Control, ControlParser, CriticalControl, MakeCritical, RawControl};
    pub use controls_impl::{Assertion, PagedResults, ProxyAuth, RelaxRules};
    pub use controls_impl::{PostRead, PostReadResp, PreRead, PreReadResp, ReadEntryResp};
    pub use controls_impl::types;
}
mod controls_impl;
mod delete;
mod extended;
mod exop_impl;
pub mod exop {
    //! Extended operation construction and parsing.
    //!
    //! A generic exop is represented by [`Exop`](struct.Exop.html). If a particular
    //! exop is implemented by this library, it may have one or two associated structs;
    //! one for constructing requests, and another for parsing responses. If request and
    //! response are the same, there is only the request struct; if they are different,
    //! the response struct's name will consist of the request struct name with the
    //! `Resp` suffix.
    //!
    //! A request struct must implement the `From` conversion of itself into `Exop`.
    //! A response struct must implement the [`ExopParser`](trait.ExopParser.html)
    //! trait.
    pub use exop_impl::{Exop, ExopParser, WhoAmI, WhoAmIResp};
}
mod filter;
mod ldap;
mod modify;
mod modifydn;
mod protocol;
pub mod result;
mod search;
mod unbind;
mod util;

pub use conn::{EntryStream, LdapConn, LdapConnAsync, LdapConnBuilder};
pub use filter::parse as parse_filter;
pub use ldap::Ldap;
pub use modify::Mod;
pub use result::LdapResult;
pub use search::{DerefAliases, ResultEntry, Scope, SearchEntry, SearchOptions, SearchStream};
pub use util::{dn_escape, ldap_escape};

pub mod asn1 {
    //! ASN.1 structure construction and parsing.
    //!
    //! This section is deliberately under-documented; it's expected that the ASN.1 subsystem will
    //! be extensively overhauled in the future. If you need examples of using the present interface
    //! for, e.g., implementing a new extended operation or a control, consult the source of existing
    //! exops/controls.
    pub use lber::IResult;
    pub use lber::common::TagClass;
    pub use lber::structure::{PL, StructureTag};
    pub use lber::structures::{ASNTag, Boolean, Enumerated, ExplicitTag, Integer, Null, OctetString, Sequence, Set, Tag};
    pub use lber::parse::{parse_tag, parse_uint};
    pub use lber::write;
}
<|endoftext|>