<commit_before>use std::collections::HashMap;
use std::fmt;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Metadata {
  /// Marks whether the current metadata block is the last.
  is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  length: u32,
  /// Block data containing one of the eight different types of metadata.
  pub data: Data,
}

/// An enum that represents a metadata block type.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
  /// Represents the current block is stream information.
  StreamInfo,
  /// Represents the current block is padding.
  Padding,
  /// Represents the current block is application data.
  Application,
  /// Represents the current block is a seek table.
  SeekTable,
  /// Represents the current block is a vorbis comment.
  VorbisComment,
  /// Represents the current block is a cue sheet.
  CueSheet,
  /// Represents the current block is a picture.
  Picture,
  /// Represents the current block is unknow.
  Unknown,
}

macro_rules! is_block_type (
  ($name: ident, $block_type: ident) => (
    #[inline]
    pub fn $name(&self) -> bool {
      self.data_type() == Type::$block_type
    }
  );
);

impl Metadata {
  /// Constructs a new `Metadata` struct based on the arguments passed in.
  pub fn new(is_last: bool, length: u32, data: Data) -> Self {
    Metadata {
      is_last: is_last,
      length: length,
      data: data,
    }
  }

  /// Returns whether the current metadata block is the last.
  #[inline]
  pub fn is_last(&self) -> bool {
    self.is_last
  }

  /// Returns the metadata block's type.
  pub fn data_type(&self) -> Type {
    match self.data {
      Data::StreamInfo(_)    => Type::StreamInfo,
      Data::Padding(_)       => Type::Padding,
      Data::Application(_)   => Type::Application,
      Data::SeekTable(_)     => Type::SeekTable,
      Data::VorbisComment(_) => Type::VorbisComment,
      Data::CueSheet(_)      => Type::CueSheet,
      Data::Picture(_)       => Type::Picture,
      Data::Unknown(_)       => Type::Unknown,
    }
  }

  is_block_type!(is_stream_info, StreamInfo);
  is_block_type!(is_padding, Padding);
  is_block_type!(is_application, Application);
  is_block_type!(is_seek_table, SeekTable);
  is_block_type!(is_vorbis_comment, VorbisComment);
  is_block_type!(is_cue_sheet, CueSheet);
  is_block_type!(is_picture, Picture);
  is_block_type!(is_unknown, Unknown);
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StreamInfo {
  /// Minimum block size, in samples, used in the stream.
  pub min_block_size: u16,
  /// Maximum block size, in samples, used in the stream.
  pub max_block_size: u16,
  /// Minimum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub min_frame_size: u32,
  /// Maximum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub max_frame_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels. FLAC supports one to eight channel.
  pub channels: u8,
  /// Bits per sample. FLAC supports four to thirty-two bits per sample.
  pub bits_per_sample: u8,
  /// Total samples in the stream. A value of zero means the number is
  /// unknown.
  pub total_samples: u64,
  /// MD5 signature of the unencoded audio data.
  pub md5_sum: [u8; 16],
}

impl StreamInfo {
  /// Constructs a zeroed out `StreamInfo` struct.
  pub fn new() -> StreamInfo {
    StreamInfo {
      min_block_size: 0,
      max_block_size: 0,
      min_frame_size: 0,
      max_frame_size: 0,
      sample_rate: 0,
      channels: 0,
      bits_per_sample: 0,
      total_samples: 0,
      md5_sum: [0; 16],
    }
  }

  /// Returns true if `min_block_size` and `max_block_size` are different,
  /// otherwise false.
  #[inline]
  pub fn is_varied_block_size(&self) -> bool {
    self.min_block_size != self.max_block_size
  }

  /// Returns true if `min_block_size` and `max_block_size` are equal,
  /// otherwise false.
  #[inline]
  pub fn is_fixed_block_size(&self) -> bool {
    self.min_block_size == self.max_block_size
  }
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  /// Registered application ID.
  pub id: String,
  /// Data used by the third-party application.
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  /// Sample number of the first sample in the target frame.
  pub sample_number: u64,
  /// Byte offset of the target frame's header.
  pub stream_offset: u64,
  /// Number of samples in the target frame.
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  /// Vendor name.
  pub vendor_string: String,
  /// Comments associated with a name, or category, followed by it's
  /// contents.
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  /// Media catalog number.
  pub media_catalog_number: String,
  /// Number of lead-in samples.
  pub lead_in: u64,
  /// Whether or not this `CueSheet` corresponds to a Compact Disc.
  pub is_cd: bool,
  /// One or more tracks.
  pub tracks: Vec<CueSheetTrack>,
}

/// Track information inside a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  /// Track offset, in samples, relative to the beginning of the FLAC audio
  /// stream.
  pub offset: u64,
  /// Track number.
  pub number: u8,
  /// Twelve digit alphanumeric code.
  pub isrc: String,
  /// Whether the cue sheet track is audio.
  pub is_audio: bool,
  /// Whether the cue sheet track is pre-emphasis.
  pub is_pre_emphasis: bool,
  /// For all tracks except the lead-out track.
  pub indices: Vec<CueSheetTrackIndex>,
}

/// An index point within a track, inside of a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  /// Offset, in samples, relative to the track offset of the index point.
  pub offset: u64,
  /// Index point number.
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  /// Picture type, based on the ID3v2 APIC frame.
  pub picture_type: PictureType,
  /// Multipurpose Internet Mail Extensions (MIME) type.
  pub mime_type: String,
  /// A string describing the picture.
  pub description: String,
  /// Width of the picture in pixels.
  pub width: u32,
  /// Height of the picture in pixels.
  pub height: u32,
  /// Color depth of the picture in bits-per-pixel.
  pub depth: u32,
  /// Number of colors used.
  pub colors: u32,
  /// Binary picture data.
  pub data: Vec<u8>,
}

/// The picture type according to the ID3v2 attached picture frame.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  /// Other picture type not categorized in this enum.
  Other,
  /// 32x32 pixels 'file icon'.
  FileIconStandard,
  /// Other, or non-standard, file icon.
  FileIcon,
  /// Cover (front).
  FrontCover,
  /// Cover (back).
  BackCover,
  /// Leaflet page.
  LeafletPage,
  /// Media, like label side of a CD.
  Media,
  /// Lead artist, lead performer, or soloist.
  LeadArtist,
  /// Artist or performer.
  Artist,
  /// Conductor.
  Conductor,
  /// Band or orchestra.
  Band,
  /// Composer.
  Composer,
  /// Lyricist or text writer.
  Lyricist,
  /// Recording location.
  RecordingLocation,
  /// During recording.
  DuringRecording,
  /// During performance.
  DuringPerformace,
  /// Movie, or video, screen capture.
  VideoScreenCapture,
  /// A bright colored fish.
  Fish,
  /// Illustration.
  Illustration,
  /// Band, or artist, logotype.
  BandLogo,
  /// Publisher, or studio, logotype.
  PublisherLogo,
}

impl fmt::Display for PictureType {
  fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
    write!(formatter, "{}", match *self {
      PictureType::Other              => "Other",
      PictureType::FileIconStandard   => "File Icon (standard)",
      PictureType::FileIcon           => "File Icon",
      PictureType::FrontCover         => "Cover (front)",
      PictureType::BackCover          => "Cover (back)",
      PictureType::LeafletPage        => "Leaflet Page",
      PictureType::Media              => "Media",
      PictureType::LeadArtist         => "Lead Artist",
      PictureType::Artist             => "Arist",
      PictureType::Conductor          => "Conductor",
      PictureType::Band               => "Band",
      PictureType::Composer           => "Composer",
      PictureType::Lyricist           => "Lyricist",
      PictureType::RecordingLocation  => "Recoding Location",
      PictureType::DuringRecording    => "During Recording",
      PictureType::DuringPerformace   => "During Performace",
      PictureType::VideoScreenCapture => "Video Screen Capture",
      PictureType::Fish               => "Fish",
      PictureType::Illustration       => "Illustration",
      PictureType::BandLogo           => "Band Logo",
      PictureType::PublisherLogo      => "Publisher Logo",
    })
  }
}

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

  #[test]
  fn test_is_varied_block_size() {
    let mut info = StreamInfo::new();

    info.min_block_size = 512;
    info.max_block_size = 1024;

    assert!(info.is_varied_block_size());

    info.min_block_size = 2048;
    info.max_block_size = 2048;

    assert!(!info.is_varied_block_size());
  }

  #[test]
  fn test_is_fixed_block_size() {
    let mut info = StreamInfo::new();

    info.min_block_size = 512;
    info.max_block_size = 512;

    assert!(info.is_fixed_block_size());

    info.min_block_size = 1024;
    info.max_block_size = 2048;

    assert!(!info.is_fixed_block_size());
  }
}
<commit_msg>Fix missing "n" in `DuringPerformance`<commit_after>use std::collections::HashMap;
use std::fmt;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Metadata {
  /// Marks whether the current metadata block is the last.
  is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  length: u32,
  /// Block data containing one of the eight different types of metadata.
  pub data: Data,
}

/// An enum that represents a metadata block type.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
  /// Represents the current block is stream information.
  StreamInfo,
  /// Represents the current block is padding.
  Padding,
  /// Represents the current block is application data.
  Application,
  /// Represents the current block is a seek table.
  SeekTable,
  /// Represents the current block is a vorbis comment.
  VorbisComment,
  /// Represents the current block is a cue sheet.
  CueSheet,
  /// Represents the current block is a picture.
  Picture,
  /// Represents the current block is unknow.
  Unknown,
}

macro_rules! is_block_type (
  ($name: ident, $block_type: ident) => (
    #[inline]
    pub fn $name(&self) -> bool {
      self.data_type() == Type::$block_type
    }
  );
);

impl Metadata {
  /// Constructs a new `Metadata` struct based on the arguments passed in.
  pub fn new(is_last: bool, length: u32, data: Data) -> Self {
    Metadata {
      is_last: is_last,
      length: length,
      data: data,
    }
  }

  /// Returns whether the current metadata block is the last.
  #[inline]
  pub fn is_last(&self) -> bool {
    self.is_last
  }

  /// Returns the metadata block's type.
  pub fn data_type(&self) -> Type {
    match self.data {
      Data::StreamInfo(_)    => Type::StreamInfo,
      Data::Padding(_)       => Type::Padding,
      Data::Application(_)   => Type::Application,
      Data::SeekTable(_)     => Type::SeekTable,
      Data::VorbisComment(_) => Type::VorbisComment,
      Data::CueSheet(_)      => Type::CueSheet,
      Data::Picture(_)       => Type::Picture,
      Data::Unknown(_)       => Type::Unknown,
    }
  }

  is_block_type!(is_stream_info, StreamInfo);
  is_block_type!(is_padding, Padding);
  is_block_type!(is_application, Application);
  is_block_type!(is_seek_table, SeekTable);
  is_block_type!(is_vorbis_comment, VorbisComment);
  is_block_type!(is_cue_sheet, CueSheet);
  is_block_type!(is_picture, Picture);
  is_block_type!(is_unknown, Unknown);
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StreamInfo {
  /// Minimum block size, in samples, used in the stream.
  pub min_block_size: u16,
  /// Maximum block size, in samples, used in the stream.
  pub max_block_size: u16,
  /// Minimum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub min_frame_size: u32,
  /// Maximum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub max_frame_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels. FLAC supports one to eight channel.
  pub channels: u8,
  /// Bits per sample. FLAC supports four to thirty-two bits per sample.
  pub bits_per_sample: u8,
  /// Total samples in the stream. A value of zero means the number is
  /// unknown.
  pub total_samples: u64,
  /// MD5 signature of the unencoded audio data.
  pub md5_sum: [u8; 16],
}

impl StreamInfo {
  /// Constructs a zeroed out `StreamInfo` struct.
  pub fn new() -> StreamInfo {
    StreamInfo {
      min_block_size: 0,
      max_block_size: 0,
      min_frame_size: 0,
      max_frame_size: 0,
      sample_rate: 0,
      channels: 0,
      bits_per_sample: 0,
      total_samples: 0,
      md5_sum: [0; 16],
    }
  }

  /// Returns true if `min_block_size` and `max_block_size` are different,
  /// otherwise false.
  #[inline]
  pub fn is_varied_block_size(&self) -> bool {
    self.min_block_size != self.max_block_size
  }

  /// Returns true if `min_block_size` and `max_block_size` are equal,
  /// otherwise false.
  #[inline]
  pub fn is_fixed_block_size(&self) -> bool {
    self.min_block_size == self.max_block_size
  }
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  /// Registered application ID.
  pub id: String,
  /// Data used by the third-party application.
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  /// Sample number of the first sample in the target frame.
  pub sample_number: u64,
  /// Byte offset of the target frame's header.
  pub stream_offset: u64,
  /// Number of samples in the target frame.
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  /// Vendor name.
  pub vendor_string: String,
  /// Comments associated with a name, or category, followed by it's
  /// contents.
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  /// Media catalog number.
  pub media_catalog_number: String,
  /// Number of lead-in samples.
  pub lead_in: u64,
  /// Whether or not this `CueSheet` corresponds to a Compact Disc.
  pub is_cd: bool,
  /// One or more tracks.
  pub tracks: Vec<CueSheetTrack>,
}

/// Track information inside a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  /// Track offset, in samples, relative to the beginning of the FLAC audio
  /// stream.
  pub offset: u64,
  /// Track number.
  pub number: u8,
  /// Twelve digit alphanumeric code.
  pub isrc: String,
  /// Whether the cue sheet track is audio.
  pub is_audio: bool,
  /// Whether the cue sheet track is pre-emphasis.
  pub is_pre_emphasis: bool,
  /// For all tracks except the lead-out track.
  pub indices: Vec<CueSheetTrackIndex>,
}

/// An index point within a track, inside of a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  /// Offset, in samples, relative to the track offset of the index point.
  pub offset: u64,
  /// Index point number.
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  /// Picture type, based on the ID3v2 APIC frame.
  pub picture_type: PictureType,
  /// Multipurpose Internet Mail Extensions (MIME) type.
  pub mime_type: String,
  /// A string describing the picture.
  pub description: String,
  /// Width of the picture in pixels.
  pub width: u32,
  /// Height of the picture in pixels.
  pub height: u32,
  /// Color depth of the picture in bits-per-pixel.
  pub depth: u32,
  /// Number of colors used.
  pub colors: u32,
  /// Binary picture data.
  pub data: Vec<u8>,
}

/// The picture type according to the ID3v2 attached picture frame.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  /// Other picture type not categorized in this enum.
  Other,
  /// 32x32 pixels 'file icon'.
  FileIconStandard,
  /// Other, or non-standard, file icon.
  FileIcon,
  /// Cover (front).
  FrontCover,
  /// Cover (back).
  BackCover,
  /// Leaflet page.
  LeafletPage,
  /// Media, like label side of a CD.
  Media,
  /// Lead artist, lead performer, or soloist.
  LeadArtist,
  /// Artist or performer.
  Artist,
  /// Conductor.
  Conductor,
  /// Band or orchestra.
  Band,
  /// Composer.
  Composer,
  /// Lyricist or text writer.
  Lyricist,
  /// Recording location.
  RecordingLocation,
  /// During recording.
  DuringRecording,
  /// During performance.
  DuringPerformance,
  /// Movie, or video, screen capture.
  VideoScreenCapture,
  /// A bright colored fish.
  Fish,
  /// Illustration.
  Illustration,
  /// Band, or artist, logotype.
  BandLogo,
  /// Publisher, or studio, logotype.
  PublisherLogo,
}

impl fmt::Display for PictureType {
  fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
    write!(formatter, "{}", match *self {
      PictureType::Other              => "Other",
      PictureType::FileIconStandard   => "File Icon (standard)",
      PictureType::FileIcon           => "File Icon",
      PictureType::FrontCover         => "Cover (front)",
      PictureType::BackCover          => "Cover (back)",
      PictureType::LeafletPage        => "Leaflet Page",
      PictureType::Media              => "Media",
      PictureType::LeadArtist         => "Lead Artist",
      PictureType::Artist             => "Arist",
      PictureType::Conductor          => "Conductor",
      PictureType::Band               => "Band",
      PictureType::Composer           => "Composer",
      PictureType::Lyricist           => "Lyricist",
      PictureType::RecordingLocation  => "Recoding Location",
      PictureType::DuringRecording    => "During Recording",
      PictureType::DuringPerformace   => "During Performace",
      PictureType::VideoScreenCapture => "Video Screen Capture",
      PictureType::Fish               => "Fish",
      PictureType::Illustration       => "Illustration",
      PictureType::BandLogo           => "Band Logo",
      PictureType::PublisherLogo      => "Publisher Logo",
    })
  }
}

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

  #[test]
  fn test_is_varied_block_size() {
    let mut info = StreamInfo::new();

    info.min_block_size = 512;
    info.max_block_size = 1024;

    assert!(info.is_varied_block_size());

    info.min_block_size = 2048;
    info.max_block_size = 2048;

    assert!(!info.is_varied_block_size());
  }

  #[test]
  fn test_is_fixed_block_size() {
    let mut info = StreamInfo::new();

    info.min_block_size = 512;
    info.max_block_size = 512;

    assert!(info.is_fixed_block_size());

    info.min_block_size = 1024;
    info.max_block_size = 2048;

    assert!(!info.is_fixed_block_size());
  }
}
<|endoftext|>


<commit_before>use std::result::Result;

use clap::ArgMatches;

use runtime::Runtime;
use super::ModuleError;
use storage::backend::{StorageBackend, StorageBackendError};

pub type CommandError = Result<ModuleError, StorageBackendError>;
pub type CommandResult = Result<(), Result<ModuleError, CommandError>>;

pub trait ExecutableCommand {
    fn get_callname() -> &'static str;
    fn exec(&self,
            rt: &Runtime,
            matches: &ArgMatches<'a, 'a>,
            s: StorageBackend) -> CommandResult;
}
<commit_msg>Add struct for passing environment of command to command execute function<commit_after>use std::result::Result;

use clap::ArgMatches;

use runtime::Runtime;
use super::ModuleError;
use storage::backend::{StorageBackend, StorageBackendError};

pub type CommandError = Result<ModuleError, StorageBackendError>;
pub type CommandResult = Result<(), Result<ModuleError, CommandError>>;

pub struct CommandEnv<'a> {
    pub rt: &'a Runtime<'a>,
    pub matches: &'a ArgMatches<'a, 'a>,
    pub backend: StorageBackend
}

pub trait ExecutableCommand {
    fn get_callname() -> &'static str;
    fn exec(&self, env: CommandEnv) -> CommandResult;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::{mem, ptr};
use ffi;
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PythonObjectDowncastError};
use objects::PyType;
use err::PyResult;

/// Represents a reference to a Python object.
///
/// Python objects are reference counted.
/// Calling `clone_ref()` on a `PyObject` will return a new reference to the same object
/// (thus incrementing the reference count).
/// The `Drop` implementation will automatically decrement the reference count.
/// You can also call `release_ref()` to explicitly decrement the reference count.
/// This is slightly faster than relying on automatic drop, because `release_ref`
/// does not need to check whether the GIL needs to be acquired.
///
/// `PyObject` can be used with all Python objects, since all python types
/// derive from `object`. This crate also contains other, more specific types
/// that serve as references to Python objects (e.g. `PyTuple` for Python tuples, etc.).
///
/// You can convert from any Python object to `PyObject` by calling `as_object()` or `into_object()`
/// from the [PythonObject trait](trait.PythonObject.html).
/// In the other direction, you can call `cast_as()` or `cast_into()`
/// on `PyObject` to convert to more specific object types.
///
/// Most of the interesting methods are provided by the [ObjectProtocol trait](trait.ObjectProtocol.html).
#[repr(C)]
pub struct PyObject {
    // PyObject owns one reference to the *PyObject
    // ptr is not null
    #[cfg(feature="nightly")]
    ptr: ptr::Shared<ffi::PyObject>,
    #[cfg(not(feature="nightly"))]
    ptr: *mut ffi::PyObject,
}

// PyObject is thread-safe, because all operations on it require a Python<'p> token.
unsafe impl Send for PyObject {}
unsafe impl Sync for PyObject {}

/// Dropping a `PyObject` decrements the reference count on the object by 1.
impl Drop for PyObject {
    fn drop(&mut self) {
        let _gil_guard = Python::acquire_gil();
        unsafe { ffi::Py_DECREF(unpack_shared(self.ptr)); }
    }
}

#[inline]
#[cfg(feature="nightly")]
unsafe fn make_shared(ptr: *mut ffi::PyObject) -> ptr::Shared<ffi::PyObject> {
    ptr::Shared::new(ptr)
}

#[inline]
#[cfg(not(feature="nightly"))]
unsafe fn make_shared(ptr: *mut ffi::PyObject) -> *mut ffi::PyObject {
    ptr
}

#[inline]
#[cfg(feature="nightly")]
fn unpack_shared(ptr: ptr::Shared<ffi::PyObject>) -> *mut ffi::PyObject {
    *ptr as *mut ffi::PyObject
}

#[inline]
#[cfg(not(feature="nightly"))]
fn unpack_shared(ptr: *mut ffi::PyObject) -> *mut ffi::PyObject {
    ptr
}

impl PythonObject for PyObject {
    #[inline]
    fn as_object(&self) -> &PyObject {
        self
    }

    #[inline]
    fn into_object(self) -> PyObject {
        self
    }

    #[inline]
    unsafe fn unchecked_downcast_from(o: PyObject) -> PyObject {
        o
    }

    #[inline]
    unsafe fn unchecked_downcast_borrow_from(o: &PyObject) -> &PyObject {
        o
    }
}

impl PythonObjectWithCheckedDowncast for PyObject {
    #[inline]
    fn downcast_from<'p>(_py: Python<'p>, obj: PyObject) -> Result<PyObject, PythonObjectDowncastError<'p>> {
        Ok(obj)
    }

    #[inline]
    fn downcast_borrow_from<'a, 'p>(_py: Python<'p>, obj: &'a PyObject) -> Result<&'a PyObject, PythonObjectDowncastError<'p>> {
        Ok(obj)
    }
}

impl PythonObjectWithTypeObject for PyObject {
    #[inline]
    fn type_object(py: Python) -> PyType {
        unsafe { PyType::from_type_ptr(py, &mut ffi::PyBaseObject_Type) }
    }
}

impl PyObject {
    /// Creates a PyObject instance for the given FFI pointer.
    /// This moves ownership over the pointer into the PyObject.
    /// Undefined behavior if the pointer is NULL or invalid.
    #[inline]
    pub unsafe fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
        debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
        PyObject { ptr: make_shared(ptr) }
    }

    /// Creates a PyObject instance for the given FFI pointer.
    /// Calls Py_INCREF() on the ptr.
    /// Undefined behavior if the pointer is NULL or invalid.
    #[inline]
    pub unsafe fn from_borrowed_ptr(_py : Python, ptr : *mut ffi::PyObject) -> PyObject {
        debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
        ffi::Py_INCREF(ptr);
        PyObject { ptr: make_shared(ptr) }
    }

    /// Creates a PyObject instance for the given FFI pointer.
    /// This moves ownership over the pointer into the PyObject.
    /// Returns None for null pointers; undefined behavior if the pointer is invalid.
    #[inline]
    pub unsafe fn from_owned_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
        if ptr.is_null() {
            None
        } else {
            Some(PyObject::from_owned_ptr(py, ptr))
        }
    }

    /// Returns None for null pointers; undefined behavior if the pointer is invalid.
    #[inline]
    pub unsafe fn from_borrowed_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
        if ptr.is_null() {
            None
        } else {
            Some(PyObject::from_borrowed_ptr(py, ptr))
        }
    }

    /// Gets the underlying FFI pointer.
    /// Returns a borrowed pointer.
    #[inline]
    pub fn as_ptr(&self) -> *mut ffi::PyObject {
        unpack_shared(self.ptr)
    }

    /// Gets the underlying FFI pointer.
    /// Consumes `self` without calling `Py_DECREF()`, thus returning an owned pointer.
    #[inline]
    #[must_use]
    pub fn steal_ptr(self) -> *mut ffi::PyObject {
        let ptr = self.as_ptr();
        mem::forget(self);
        ptr
    }

    /// Transmutes an FFI pointer to `&PyObject`.
    /// Undefined behavior if the pointer is NULL or invalid.
    #[inline]
    pub unsafe fn borrow_from_ptr<'a>(ptr : &'a *mut ffi::PyObject) -> &'a PyObject {
        debug_assert!(!ptr.is_null());
        mem::transmute(ptr)
    }

    /// Transmutes a slice of owned FFI pointers to `&[PyObject]`.
    /// Undefined behavior if any pointer in the slice is NULL or invalid.
    #[inline]
    pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr : &'a [*mut ffi::PyObject]) -> &'a [PyObject] {
        mem::transmute(ptr)
    }

    /// Gets the reference count of this Python object.
    #[inline]
    pub fn get_refcnt(&self, _py: Python) -> usize {
        unsafe { ffi::Py_REFCNT(self.as_ptr()) as usize }
    }

    /// Gets the Python type object for this object's type.
    pub fn get_type(&self, py: Python) -> PyType {
        unsafe {
            PyType::from_type_ptr(py, (*self.as_ptr()).ob_type)
        }
    }

    /// Casts the PyObject to a concrete Python object type.
    /// Causes undefined behavior if the object is not of the expected type.
    /// This is a wrapper function around `PythonObject::unchecked_downcast_from()`.
    #[inline]
    pub unsafe fn unchecked_cast_into<T>(self) -> T
        where T: PythonObject
    {
        PythonObject::unchecked_downcast_from(self)
    }

    /// Casts the PyObject to a concrete Python object type.
    /// Fails with `PythonObjectDowncastError` if the object is not of the expected type.
    /// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_from()`.
    #[inline]
    pub fn cast_into<'p, T>(self, py: Python<'p>) -> Result<T, PythonObjectDowncastError<'p>>
        where T: PythonObjectWithCheckedDowncast
    {
        PythonObjectWithCheckedDowncast::downcast_from(py, self)
    }

    /// Casts the PyObject to a concrete Python object type.
    /// Causes undefined behavior if the object is not of the expected type.
    /// This is a wrapper function around `PythonObject::unchecked_downcast_borrow_from()`.
    #[inline]
    pub unsafe fn unchecked_cast_as<'s, T>(&'s self) -> &'s T
        where T: PythonObject
    {
        PythonObject::unchecked_downcast_borrow_from(self)
    }

    /// Casts the PyObject to a concrete Python object type.
    /// Fails with `PythonObjectDowncastError` if the object is not of the expected type.
    /// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_borrow_from()`.
    #[inline]
    pub fn cast_as<'s, 'p, T>(&'s self, py: Python<'p>) -> Result<&'s T, PythonObjectDowncastError<'p>>
        where T: PythonObjectWithCheckedDowncast
    {
        PythonObjectWithCheckedDowncast::downcast_borrow_from(py, self)
    }

    /// Extracts some type from the Python object.
    /// This is a wrapper function around `FromPyObject::from_py_object()`.
    #[inline]
    pub fn extract<'a, T>(&'a self, py: Python) -> PyResult<T>
        where T: ::conversion::FromPyObject<'a>
    {
        ::conversion::FromPyObject::extract(py, self)
    }
}

/// PyObject implements the `==` operator using reference equality:
/// `obj1 == obj2` in rust is equivalent to `obj1 is obj2` in Python.
impl PartialEq for PyObject {
    #[inline]
    fn eq(&self, o : &PyObject) -> bool {
        self.as_ptr() == o.as_ptr()
    }
}

/// PyObject implements the `==` operator using reference equality:
/// `obj1 == obj2` in rust is equivalent to `obj1 is obj2` in Python.
impl Eq for PyObject { }

#[test]
fn test_sizeof() {
    // should be a static_assert, but size_of is not a compile-time const
    // these are necessary for the transmutes in this module
    assert_eq!(mem::size_of::<PyObject>(), mem::size_of::<*mut ffi::PyObject>());
    assert_eq!(mem::size_of::<PyType>(), mem::size_of::<*mut ffi::PyTypeObject>());
}

<commit_msg>Adjust to std::ptr::Shared API change.<commit_after>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::{mem, ptr};
use ffi;
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PythonObjectDowncastError};
use objects::PyType;
use err::PyResult;

/// Represents a reference to a Python object.
///
/// Python objects are reference counted.
/// Calling `clone_ref()` on a `PyObject` will return a new reference to the same object
/// (thus incrementing the reference count).
/// The `Drop` implementation will automatically decrement the reference count.
/// You can also call `release_ref()` to explicitly decrement the reference count.
/// This is slightly faster than relying on automatic drop, because `release_ref`
/// does not need to check whether the GIL needs to be acquired.
///
/// `PyObject` can be used with all Python objects, since all python types
/// derive from `object`. This crate also contains other, more specific types
/// that serve as references to Python objects (e.g. `PyTuple` for Python tuples, etc.).
///
/// You can convert from any Python object to `PyObject` by calling `as_object()` or `into_object()`
/// from the [PythonObject trait](trait.PythonObject.html).
/// In the other direction, you can call `cast_as()` or `cast_into()`
/// on `PyObject` to convert to more specific object types.
///
/// Most of the interesting methods are provided by the [ObjectProtocol trait](trait.ObjectProtocol.html).
#[repr(C)]
pub struct PyObject {
    // PyObject owns one reference to the *PyObject
    // ptr is not null
    #[cfg(feature="nightly")]
    ptr: ptr::Shared<ffi::PyObject>,
    #[cfg(not(feature="nightly"))]
    ptr: *mut ffi::PyObject,
}

// PyObject is thread-safe, because all operations on it require a Python<'p> token.
unsafe impl Send for PyObject {}
unsafe impl Sync for PyObject {}

/// Dropping a `PyObject` decrements the reference count on the object by 1.
impl Drop for PyObject {
    fn drop(&mut self) {
        let _gil_guard = Python::acquire_gil();
        unsafe { ffi::Py_DECREF(unpack_shared(self.ptr)); }
    }
}

#[inline]
#[cfg(feature="nightly")]
unsafe fn make_shared(ptr: *mut ffi::PyObject) -> ptr::Shared<ffi::PyObject> {
    ptr::Shared::new(ptr)
}

#[inline]
#[cfg(not(feature="nightly"))]
unsafe fn make_shared(ptr: *mut ffi::PyObject) -> *mut ffi::PyObject {
    ptr
}

#[inline]
#[cfg(feature="nightly")]
fn unpack_shared(ptr: ptr::Shared<ffi::PyObject>) -> *mut ffi::PyObject {
    ptr.as_ptr()
}

#[inline]
#[cfg(not(feature="nightly"))]
fn unpack_shared(ptr: *mut ffi::PyObject) -> *mut ffi::PyObject {
    ptr
}

impl PythonObject for PyObject {
    #[inline]
    fn as_object(&self) -> &PyObject {
        self
    }

    #[inline]
    fn into_object(self) -> PyObject {
        self
    }

    #[inline]
    unsafe fn unchecked_downcast_from(o: PyObject) -> PyObject {
        o
    }

    #[inline]
    unsafe fn unchecked_downcast_borrow_from(o: &PyObject) -> &PyObject {
        o
    }
}

impl PythonObjectWithCheckedDowncast for PyObject {
    #[inline]
    fn downcast_from<'p>(_py: Python<'p>, obj: PyObject) -> Result<PyObject, PythonObjectDowncastError<'p>> {
        Ok(obj)
    }

    #[inline]
    fn downcast_borrow_from<'a, 'p>(_py: Python<'p>, obj: &'a PyObject) -> Result<&'a PyObject, PythonObjectDowncastError<'p>> {
        Ok(obj)
    }
}

impl PythonObjectWithTypeObject for PyObject {
    #[inline]
    fn type_object(py: Python) -> PyType {
        unsafe { PyType::from_type_ptr(py, &mut ffi::PyBaseObject_Type) }
    }
}

impl PyObject {
    /// Creates a PyObject instance for the given FFI pointer.
    /// This moves ownership over the pointer into the PyObject.
    /// Undefined behavior if the pointer is NULL or invalid.
    #[inline]
    pub unsafe fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
        debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
        PyObject { ptr: make_shared(ptr) }
    }

    /// Creates a PyObject instance for the given FFI pointer.
    /// Calls Py_INCREF() on the ptr.
    /// Undefined behavior if the pointer is NULL or invalid.
    #[inline]
    pub unsafe fn from_borrowed_ptr(_py : Python, ptr : *mut ffi::PyObject) -> PyObject {
        debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
        ffi::Py_INCREF(ptr);
        PyObject { ptr: make_shared(ptr) }
    }

    /// Creates a PyObject instance for the given FFI pointer.
    /// This moves ownership over the pointer into the PyObject.
    /// Returns None for null pointers; undefined behavior if the pointer is invalid.
    #[inline]
    pub unsafe fn from_owned_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
        if ptr.is_null() {
            None
        } else {
            Some(PyObject::from_owned_ptr(py, ptr))
        }
    }

    /// Returns None for null pointers; undefined behavior if the pointer is invalid.
    #[inline]
    pub unsafe fn from_borrowed_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
        if ptr.is_null() {
            None
        } else {
            Some(PyObject::from_borrowed_ptr(py, ptr))
        }
    }

    /// Gets the underlying FFI pointer.
    /// Returns a borrowed pointer.
    #[inline]
    pub fn as_ptr(&self) -> *mut ffi::PyObject {
        unpack_shared(self.ptr)
    }

    /// Gets the underlying FFI pointer.
    /// Consumes `self` without calling `Py_DECREF()`, thus returning an owned pointer.
    #[inline]
    #[must_use]
    pub fn steal_ptr(self) -> *mut ffi::PyObject {
        let ptr = self.as_ptr();
        mem::forget(self);
        ptr
    }

    /// Transmutes an FFI pointer to `&PyObject`.
    /// Undefined behavior if the pointer is NULL or invalid.
    #[inline]
    pub unsafe fn borrow_from_ptr<'a>(ptr : &'a *mut ffi::PyObject) -> &'a PyObject {
        debug_assert!(!ptr.is_null());
        mem::transmute(ptr)
    }

    /// Transmutes a slice of owned FFI pointers to `&[PyObject]`.
    /// Undefined behavior if any pointer in the slice is NULL or invalid.
    #[inline]
    pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr : &'a [*mut ffi::PyObject]) -> &'a [PyObject] {
        mem::transmute(ptr)
    }

    /// Gets the reference count of this Python object.
    #[inline]
    pub fn get_refcnt(&self, _py: Python) -> usize {
        unsafe { ffi::Py_REFCNT(self.as_ptr()) as usize }
    }

    /// Gets the Python type object for this object's type.
    pub fn get_type(&self, py: Python) -> PyType {
        unsafe {
            PyType::from_type_ptr(py, (*self.as_ptr()).ob_type)
        }
    }

    /// Casts the PyObject to a concrete Python object type.
    /// Causes undefined behavior if the object is not of the expected type.
    /// This is a wrapper function around `PythonObject::unchecked_downcast_from()`.
    #[inline]
    pub unsafe fn unchecked_cast_into<T>(self) -> T
        where T: PythonObject
    {
        PythonObject::unchecked_downcast_from(self)
    }

    /// Casts the PyObject to a concrete Python object type.
    /// Fails with `PythonObjectDowncastError` if the object is not of the expected type.
    /// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_from()`.
    #[inline]
    pub fn cast_into<'p, T>(self, py: Python<'p>) -> Result<T, PythonObjectDowncastError<'p>>
        where T: PythonObjectWithCheckedDowncast
    {
        PythonObjectWithCheckedDowncast::downcast_from(py, self)
    }

    /// Casts the PyObject to a concrete Python object type.
    /// Causes undefined behavior if the object is not of the expected type.
    /// This is a wrapper function around `PythonObject::unchecked_downcast_borrow_from()`.
    #[inline]
    pub unsafe fn unchecked_cast_as<'s, T>(&'s self) -> &'s T
        where T: PythonObject
    {
        PythonObject::unchecked_downcast_borrow_from(self)
    }

    /// Casts the PyObject to a concrete Python object type.
    /// Fails with `PythonObjectDowncastError` if the object is not of the expected type.
    /// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_borrow_from()`.
    #[inline]
    pub fn cast_as<'s, 'p, T>(&'s self, py: Python<'p>) -> Result<&'s T, PythonObjectDowncastError<'p>>
        where T: PythonObjectWithCheckedDowncast
    {
        PythonObjectWithCheckedDowncast::downcast_borrow_from(py, self)
    }

    /// Extracts some type from the Python object.
    /// This is a wrapper function around `FromPyObject::from_py_object()`.
    #[inline]
    pub fn extract<'a, T>(&'a self, py: Python) -> PyResult<T>
        where T: ::conversion::FromPyObject<'a>
    {
        ::conversion::FromPyObject::extract(py, self)
    }
}

/// PyObject implements the `==` operator using reference equality:
/// `obj1 == obj2` in rust is equivalent to `obj1 is obj2` in Python.
impl PartialEq for PyObject {
    #[inline]
    fn eq(&self, o : &PyObject) -> bool {
        self.as_ptr() == o.as_ptr()
    }
}

/// PyObject implements the `==` operator using reference equality:
/// `obj1 == obj2` in rust is equivalent to `obj1 is obj2` in Python.
impl Eq for PyObject { }

#[test]
fn test_sizeof() {
    // should be a static_assert, but size_of is not a compile-time const
    // these are necessary for the transmutes in this module
    assert_eq!(mem::size_of::<PyObject>(), mem::size_of::<*mut ffi::PyObject>());
    assert_eq!(mem::size_of::<PyType>(), mem::size_of::<*mut ffi::PyTypeObject>());
}

<|endoftext|>


<commit_before>#![allow(unused_variables, dead_code)]

use std::ffi::{OsStr, OsString};

pub type ShortArg = u8;
pub type LongArg = &'static str;

#[derive(PartialEq, Debug)]
pub enum Flag {
    Short(ShortArg),
    Long(LongArg),
}

#[derive(PartialEq, Debug)]
pub enum Strictness {
    ComplainAboutRedundantArguments,
    UseLastArguments,
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum TakesValue {
    Necessary,
    Forbidden,
}

#[derive(PartialEq, Debug)]
pub struct Arg {
    short: Option<ShortArg>,
    long: LongArg,
    takes_value: TakesValue,
}

#[derive(PartialEq, Debug)]
pub struct Args(&'static [Arg]);

impl Args {
    fn lookup_short<'a>(&self, short: ShortArg) -> Result<&Arg, ParseError<'a>> {
        match self.0.into_iter().find(|arg| arg.short == Some(short)) {
            Some(arg)  => Ok(arg),
            None       => Err(ParseError::UnknownShortArgument { attempt: short })
        }
    }

    fn lookup_long<'a>(&self, long: &'a OsStr) -> Result<&Arg, ParseError<'a>> {
        match self.0.into_iter().find(|arg| arg.long == long) {
            Some(arg)  => Ok(arg),
            None       => Err(ParseError::UnknownArgument { attempt: long })
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct Matches<'a> {
    /// Long and short arguments need to be kept in the same vector, because
    /// we usually want the one nearest the end to count.
    flags: Vec<(Flag, Option<&'a OsStr>)>,
    frees: Vec<&'a OsStr>,
}

#[derive(PartialEq, Debug)]
pub enum ParseError<'a> {
    NeedsValue { flag: Flag },
    ForbiddenValue { flag: Flag },
    UnknownShortArgument { attempt: ShortArg },
    UnknownArgument { attempt: &'a OsStr },
}

fn parse<'a>(args: Args, inputs: &'a [OsString]) -> Result<Matches<'a>, ParseError<'a>> {
    use std::os::unix::ffi::OsStrExt;
    use self::TakesValue::*;

    let mut parsing = true;

    let mut results = Matches {
        flags: Vec::new(),
        frees: Vec::new(),
    };

    let mut iter = inputs.iter();
    while let Some(arg) = iter.next() {
        let bytes = arg.as_bytes();

        if !parsing {
            results.frees.push(arg)
        }
        else if arg == "--" {
            parsing = false;
        }
        else if bytes.starts_with(b"--") {
            let long_arg_name = OsStr::from_bytes(&bytes[2..]);

            if let Some((before, after)) = split_on_equals(long_arg_name) {
                let arg = args.lookup_long(before)?;
                let flag = Flag::Long(arg.long);
                match arg.takes_value {
                    Necessary  => results.flags.push((flag, Some(after))),
                    Forbidden  => return Err(ParseError::ForbiddenValue { flag })
                }
            }
            else {
                let arg = args.lookup_long(long_arg_name)?;
                let flag = Flag::Long(arg.long);
                match arg.takes_value {
                    Forbidden  => results.flags.push((flag, None)),
                    Necessary  => {
                        if let Some(next_arg) = iter.next() {
                            results.flags.push((flag, Some(next_arg)));
                        }
                        else {
                            return Err(ParseError::NeedsValue { flag })
                        }
                    }
                }
            }
        }
        else if bytes.starts_with(b"-") && arg != "-" {
            let short_arg = OsStr::from_bytes(&bytes[1..]);
            if let Some((before, after)) = split_on_equals(short_arg) {
                // TODO: remember to deal with the other bytes!
                let arg = args.lookup_short(*before.as_bytes().last().unwrap())?;
                let flag = Flag::Short(arg.short.unwrap());
                match arg.takes_value {
                    Necessary  => results.flags.push((flag, Some(after))),
                    Forbidden  => return Err(ParseError::ForbiddenValue { flag })
                }
            }
            else {
                for byte in &bytes[1..] {
                    // TODO: gotta check that these don't take arguments
                    // like -c4
                    let arg = args.lookup_short(*byte)?;
                    let flag = Flag::Short(*byte);
                    match arg.takes_value {
                        Forbidden  => results.flags.push((flag, None)),
                        Necessary  => {
                            if let Some(next_arg) = iter.next() {
                                results.flags.push((flag, Some(next_arg)));
                            }
                            else {
                                return Err(ParseError::NeedsValue { flag })
                            }
                        }
                    }
                }
            }
        }
        else {
            results.frees.push(arg)
        }
    }

    Ok(results)
}

/// Splits a string on its `=` character, returning the two substrings on
/// either side. Returns `None` if there’s no equals or a string is missing.
fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> {
    use std::os::unix::ffi::OsStrExt;

    if let Some(index) = input.as_bytes().iter().position(|elem| *elem == b'=') {
        let (before, after) = input.as_bytes().split_at(index);

        // The after string contains the = that we need to remove.
        if before.len() >= 1 && after.len() >= 2 {
            return Some((OsStr::from_bytes(before),
                         OsStr::from_bytes(&after[1..])))
        }
    }

    None
}

/// Creates an `OSString` (used in tests)
#[cfg(test)]
fn os(input: &'static str) -> OsString {
    let mut os = OsString::new();
    os.push(input);
    os
}

#[cfg(test)]
mod split_test {
    use super::{split_on_equals, os};

    macro_rules! test_split {
        ($name:ident: $input:expr => None) => {
            #[test]
            fn $name() {
                assert_eq!(split_on_equals(&os($input)),
                           None);
            }
        };

        ($name:ident: $input:expr => $before:expr, $after:expr) => {
            #[test]
            fn $name() {
                assert_eq!(split_on_equals(&os($input)),
                           Some((&*os($before), &*os($after))));
            }
        };
    }

    test_split!(empty:   ""   => None);
    test_split!(letter:  "a"  => None);

    test_split!(just:      "="    => None);
    test_split!(intro:     "=bbb" => None);
    test_split!(denou:  "aaa="    => None);
    test_split!(equals: "aaa=bbb" => "aaa", "bbb");

    test_split!(sort: "--sort=size"     => "--sort", "size");
    test_split!(more: "this=that=other" => "this",   "that=other");
}

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

    static TEST_ARGS: &'static [Arg] = &[
        Arg { short: Some(b'l'), long: "long",  takes_value: TakesValue::Forbidden },
        Arg { short: Some(b'c'), long: "count", takes_value: TakesValue::Necessary }
    ];

    #[test]
    fn empty() {
        let bits = [ ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![] }))
    }

    #[test]
    fn filename() {
        let bits = [ os("exa") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![ os("exa").as_os_str() ], flags: vec![] }))
    }

    #[test]
    fn the_dashes_do_nothing() {
        let bits = [ os("--") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![] }))
    }

    #[test]
    fn but_just_one_does() {
        let bits = [ os("-") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![ os("-").as_os_str() ], flags: vec![] }))
    }

    // ----- long args --------

    #[test]
    fn as_filename() {
        let bits = [ os("--"), os("--long") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![os("--long").as_os_str() ], flags: vec![] }))
    }

    #[test]
    fn long() {
        let bits = [ os("--long") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("long"), None) ] }))
    }

    #[test]
    fn long_equals() {
        let bits = [ os("--long=equals") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Err(ParseError::ForbiddenValue { flag: Flag::Long("long") }))
    }

    #[test]
    fn no_arg_separate() {
        let bits = [ os("--long"), os("4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![ os("4").as_os_str() ], flags: vec![ (Flag::Long("long"), None) ] }))
    }

    #[test]
    fn no_arg_given() {
        let bits = [ os("--count") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Err(ParseError::NeedsValue { flag: Flag::Long("count") }))
    }

    #[test]
    fn arg_equals() {
        let bits = [ os("--count=4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(os("4").as_os_str())) ] }))
    }

    #[test]
    fn arg_separate() {
        let bits = [ os("--count"), os("4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(os("4").as_os_str())) ] }))
    }

    // ----- short args --------

    #[test]
    fn short_as_filename() {
        let bits = [ os("--"), os("-l") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![os("-l").as_os_str() ], flags: vec![] }))
    }

    #[test]
    fn short_long() {
        let bits = [ os("-l") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None) ] }))
    }

    #[test]
    fn short_long_equals() {
        let bits = [ os("-l=equals") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Err(ParseError::ForbiddenValue { flag: Flag::Short(b'l') }))
    }

    #[test]
    fn short_no_arg_separate() {
        let bits = [ os("-l"), os("4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![ os("4").as_os_str() ], flags: vec![ (Flag::Short(b'l'), None) ] }))
    }

    #[test]
    fn short_no_arg_given() {
        let bits = [ os("-c") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Err(ParseError::NeedsValue { flag: Flag::Short(b'c') }))
    }

    #[test]
    fn short_arg_equals() {
        let bits = [ os("-c=4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(os("4").as_os_str())) ] }))
    }

    #[test]
    fn short_arg_separate() {
        let bits = [ os("-c"), os("4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(os("4").as_os_str())) ] }))
    }

}
<commit_msg>Add missing short arg functionality<commit_after>#![allow(unused_variables, dead_code)]

use std::ffi::{OsStr, OsString};

pub type ShortArg = u8;
pub type LongArg = &'static str;

#[derive(PartialEq, Debug)]
pub enum Flag {
    Short(ShortArg),
    Long(LongArg),
}

#[derive(PartialEq, Debug)]
pub enum Strictness {
    ComplainAboutRedundantArguments,
    UseLastArguments,
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum TakesValue {
    Necessary,
    Forbidden,
}

#[derive(PartialEq, Debug)]
pub struct Arg {
    short: Option<ShortArg>,
    long: LongArg,
    takes_value: TakesValue,
}

#[derive(PartialEq, Debug)]
pub struct Args(&'static [Arg]);

impl Args {
    fn lookup_short<'a>(&self, short: ShortArg) -> Result<&Arg, ParseError<'a>> {
        match self.0.into_iter().find(|arg| arg.short == Some(short)) {
            Some(arg)  => Ok(arg),
            None       => Err(ParseError::UnknownShortArgument { attempt: short })
        }
    }

    fn lookup_long<'a>(&self, long: &'a OsStr) -> Result<&Arg, ParseError<'a>> {
        match self.0.into_iter().find(|arg| arg.long == long) {
            Some(arg)  => Ok(arg),
            None       => Err(ParseError::UnknownArgument { attempt: long })
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct Matches<'a> {
    /// Long and short arguments need to be kept in the same vector, because
    /// we usually want the one nearest the end to count.
    flags: Vec<(Flag, Option<&'a OsStr>)>,
    frees: Vec<&'a OsStr>,
}

#[derive(PartialEq, Debug)]
pub enum ParseError<'a> {
    NeedsValue { flag: Flag },
    ForbiddenValue { flag: Flag },
    UnknownShortArgument { attempt: ShortArg },
    UnknownArgument { attempt: &'a OsStr },
}

fn parse<'a>(args: Args, inputs: &'a [OsString]) -> Result<Matches<'a>, ParseError<'a>> {
    use std::os::unix::ffi::OsStrExt;
    use self::TakesValue::*;

    let mut parsing = true;

    let mut results = Matches {
        flags: Vec::new(),
        frees: Vec::new(),
    };

    let mut iter = inputs.iter();
    while let Some(arg) = iter.next() {
        let bytes = arg.as_bytes();

        if !parsing {
            results.frees.push(arg)
        }
        else if arg == "--" {
            parsing = false;
        }
        else if bytes.starts_with(b"--") {
            let long_arg_name = OsStr::from_bytes(&bytes[2..]);

            if let Some((before, after)) = split_on_equals(long_arg_name) {
                let arg = args.lookup_long(before)?;
                let flag = Flag::Long(arg.long);
                match arg.takes_value {
                    Necessary  => results.flags.push((flag, Some(after))),
                    Forbidden  => return Err(ParseError::ForbiddenValue { flag })
                }
            }
            else {
                let arg = args.lookup_long(long_arg_name)?;
                let flag = Flag::Long(arg.long);
                match arg.takes_value {
                    Forbidden  => results.flags.push((flag, None)),
                    Necessary  => {
                        if let Some(next_arg) = iter.next() {
                            results.flags.push((flag, Some(next_arg)));
                        }
                        else {
                            return Err(ParseError::NeedsValue { flag })
                        }
                    }
                }
            }
        }
        else if bytes.starts_with(b"-") && arg != "-" {
            let short_arg = OsStr::from_bytes(&bytes[1..]);
            if let Some((before, after)) = split_on_equals(short_arg) {
                let (arg_with_value, other_args) = before.as_bytes().split_last().unwrap();

                for byte in other_args {
                    let arg = args.lookup_short(*byte)?;
                    let flag = Flag::Short(*byte);
                    match arg.takes_value {
                        Forbidden  => results.flags.push((flag, None)),
                        Necessary  => return Err(ParseError::NeedsValue { flag })
                    }
                }

                let arg = args.lookup_short(*before.as_bytes().last().unwrap())?;
                let flag = Flag::Short(arg.short.unwrap());
                match arg.takes_value {
                    Necessary  => results.flags.push((flag, Some(after))),
                    Forbidden  => return Err(ParseError::ForbiddenValue { flag })
                }
            }
            else {
                for (index, byte) in bytes.into_iter().enumerate().skip(1) {
                    let arg = args.lookup_short(*byte)?;
                    let flag = Flag::Short(*byte);
                    match arg.takes_value {
                        Forbidden  => results.flags.push((flag, None)),
                        Necessary  => {
                            if index < bytes.len() - 1 {
                                let remnants = &bytes[index+1 ..];
                                results.flags.push((flag, Some(OsStr::from_bytes(remnants))));
                                break;
                            }
                            else if let Some(next_arg) = iter.next() {
                                results.flags.push((flag, Some(next_arg)));
                            }
                            else {
                                return Err(ParseError::NeedsValue { flag })
                            }
                        }
                    }
                }
            }
        }
        else {
            results.frees.push(arg)
        }
    }

    Ok(results)
}

/// Splits a string on its `=` character, returning the two substrings on
/// either side. Returns `None` if there’s no equals or a string is missing.
fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> {
    use std::os::unix::ffi::OsStrExt;

    if let Some(index) = input.as_bytes().iter().position(|elem| *elem == b'=') {
        let (before, after) = input.as_bytes().split_at(index);

        // The after string contains the = that we need to remove.
        if before.len() >= 1 && after.len() >= 2 {
            return Some((OsStr::from_bytes(before),
                         OsStr::from_bytes(&after[1..])))
        }
    }

    None
}

/// Creates an `OSString` (used in tests)
#[cfg(test)]
fn os(input: &'static str) -> OsString {
    let mut os = OsString::new();
    os.push(input);
    os
}

#[cfg(test)]
mod split_test {
    use super::{split_on_equals, os};

    macro_rules! test_split {
        ($name:ident: $input:expr => None) => {
            #[test]
            fn $name() {
                assert_eq!(split_on_equals(&os($input)),
                           None);
            }
        };

        ($name:ident: $input:expr => $before:expr, $after:expr) => {
            #[test]
            fn $name() {
                assert_eq!(split_on_equals(&os($input)),
                           Some((&*os($before), &*os($after))));
            }
        };
    }

    test_split!(empty:   ""   => None);
    test_split!(letter:  "a"  => None);

    test_split!(just:      "="    => None);
    test_split!(intro:     "=bbb" => None);
    test_split!(denou:  "aaa="    => None);
    test_split!(equals: "aaa=bbb" => "aaa", "bbb");

    test_split!(sort: "--sort=size"     => "--sort", "size");
    test_split!(more: "this=that=other" => "this",   "that=other");
}

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

    static TEST_ARGS: &'static [Arg] = &[
        Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden },
        Arg { short: Some(b'v'), long: "verbose",  takes_value: TakesValue::Forbidden },
        Arg { short: Some(b'c'), long: "count",    takes_value: TakesValue::Necessary }
    ];

    #[test]
    fn empty() {
        let bits = [ ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![] }))
    }

    #[test]
    fn filename() {
        let bits = [ os("exa") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![ os("exa").as_os_str() ], flags: vec![] }))
    }

    #[test]
    fn the_dashes_do_nothing() {
        let bits = [ os("--") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![] }))
    }

    #[test]
    fn but_just_one_does() {
        let bits = [ os("-") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![ os("-").as_os_str() ], flags: vec![] }))
    }

    // ----- long args --------

    #[test]
    fn as_filename() {
        let bits = [ os("--"), os("--long") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![os("--long").as_os_str() ], flags: vec![] }))
    }

    #[test]
    fn long() {
        let bits = [ os("--long") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("long"), None) ] }))
    }

    #[test]
    fn long_equals() {
        let bits = [ os("--long=equals") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Err(ParseError::ForbiddenValue { flag: Flag::Long("long") }))
    }

    #[test]
    fn no_arg_separate() {
        let bits = [ os("--long"), os("4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![ os("4").as_os_str() ], flags: vec![ (Flag::Long("long"), None) ] }))
    }

    #[test]
    fn two_long_flags() {
        let bits = [ os("--long"), os("--verbose") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("long"), None), (Flag::Long("verbose"), None) ] }))
    }

    #[test]
    fn no_arg_given() {
        let bits = [ os("--count") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Err(ParseError::NeedsValue { flag: Flag::Long("count") }))
    }

    #[test]
    fn arg_equals() {
        let bits = [ os("--count=4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(os("4").as_os_str())) ] }))
    }

    #[test]
    fn arg_separate() {
        let bits = [ os("--count"), os("4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(os("4").as_os_str())) ] }))
    }

    // ----- short args --------

    #[test]
    fn short_as_filename() {
        let bits = [ os("--"), os("-l") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![os("-l").as_os_str() ], flags: vec![] }))
    }

    #[test]
    fn short_long() {
        let bits = [ os("-l") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None) ] }))
    }

    #[test]
    fn short_long_equals() {
        let bits = [ os("-l=equals") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Err(ParseError::ForbiddenValue { flag: Flag::Short(b'l') }))
    }

    #[test]
    fn short_no_arg_separate() {
        let bits = [ os("-l"), os("4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![ os("4").as_os_str() ], flags: vec![ (Flag::Short(b'l'), None) ] }))
    }

    #[test]
    fn short_no_arg_given() {
        let bits = [ os("-c") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Err(ParseError::NeedsValue { flag: Flag::Short(b'c') }))
    }

    #[test]
    fn short_arg_equals() {
        let bits = [ os("-c=4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(os("4").as_os_str())) ] }))
    }

    #[test]
    fn short_arg_separate() {
        let bits = [ os("-c"), os("4") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(os("4").as_os_str())) ] }))
    }

    #[test]
    fn two_short_flags() {
        let bits = [ os("-lv") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'v'), None) ] }))
    }

    #[test]
    fn two_short_flags_nothing() {
        let bits = [ os("-lctwo") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }))
    }

    #[test]
    fn two_short_flags_equals() {
        let bits = [ os("-lc=two") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }))
    }

    #[test]
    fn two_short_flags_next() {
        let bits = [ os("-lc"), os("two") ];
        let results = parse(Args(TEST_ARGS), &bits);
        assert_eq!(results, Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(os("two").as_os_str())) ] }))
    }
}
<|endoftext|>


<commit_before>use std::{mem, slice, thread};
use std::fs::File;
use std::io::Read;
use std::os::unix::io::{AsRawFd, RawFd};

use super::syscall;

use color::Color;
use event::Event;
use renderer::Renderer;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// True if the window should not wait for events
    async: bool,
    /// The input scheme
    file: File,
    /// Window data
    data: &'static mut [Color],
}

impl Renderer for Window {
    /// Get width
    fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    fn height(&self) -> u32 {
        self.h
    }

    /// Access pixel buffer
    fn data(&self) -> &[Color] {
        &self.data
    }

    /// Access pixel buffer mutably
    fn data_mut(&mut self) -> &mut [Color] {
        &mut self.data
    }

    /// Flip the buffer
    fn sync(&mut self) -> bool {
        self.file.sync_data().is_ok()
    }
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
        Window::new_flags(x, y, w, h, title, false)
    }

    /// Create a new window with flags
    pub fn new_flags(x: i32, y: i32, w: u32, h: u32, title: &str, async: bool) -> Option<Self> {
        if let Ok(file) = File::open(&format!("orbital:{}/{}/{}/{}/{}/{}", if async { "a" } else { "" }, x, y, w, h, title)) {
            if let Ok(address) = unsafe { syscall::fmap(file.as_raw_fd(), 0, (w * h * 4) as usize) } {
                Some(Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    async: async,
                    file: file,
                    data: unsafe { slice::from_raw_parts_mut(address as *mut Color, (w * h) as usize) },
                })
            } else {
                None
            }
        } else {
            None
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        let mut buf: [u8; 4096] = [0; 4096];
        if let Ok(count) = syscall::fpath(self.file.as_raw_fd() as usize, &mut buf) {
            let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
            // orbital:/x/y/w/h/t
            let mut parts = path.split('/').skip(1);
            if let Some(x) = parts.next() {
                self.x = x.parse::<i32>().unwrap_or(0);
            }
            if let Some(y) = parts.next() {
                self.y = y.parse::<i32>().unwrap_or(0);
            }
            if let Some(w) = parts.next() {
                self.w = w.parse::<u32>().unwrap_or(0);
            }
            if let Some(h) = parts.next() {
                self.h = h.parse::<u32>().unwrap_or(0);
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    /// Blocking iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            events: [Event::new(); 128],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            //Should it be cleared? iter.events = [Event::new(); 128];
            match self.file.read(unsafe {
                slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
            }){
                Ok(0) => if ! self.async {
                    thread::yield_now();
                } else {
                    break 'blocking;
                },
                Ok(count) => {
                    iter.count = count/mem::size_of::<Event>();
                    break 'blocking;
                },
                Err(_) => break 'blocking,
            }
        }

        iter
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        let _ = unsafe { syscall::funmap(self.data.as_ptr() as usize) };
    }
}

impl AsRawFd for Window {
    fn as_raw_fd(&self) -> RawFd {
        self.file.as_raw_fd()
    }
}

/// Event iterator
pub struct EventIter {
    events: [Event; 128],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        if self.i < self.count {
            if let Some(event) = self.events.get(self.i) {
                self.i += 1;
                Some(*event)
            } else {
                None
            }
        } else {
            None
        }
    }
}
<commit_msg>Allow set_title in orbital<commit_after>use std::{mem, slice, thread};
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, RawFd};

use super::syscall;

use color::Color;
use event::Event;
use renderer::Renderer;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// True if the window should not wait for events
    async: bool,
    /// The input scheme
    file: File,
    /// Window data
    data: &'static mut [Color],
}

impl Renderer for Window {
    /// Get width
    fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    fn height(&self) -> u32 {
        self.h
    }

    /// Access pixel buffer
    fn data(&self) -> &[Color] {
        &self.data
    }

    /// Access pixel buffer mutably
    fn data_mut(&mut self) -> &mut [Color] {
        &mut self.data
    }

    /// Flip the buffer
    fn sync(&mut self) -> bool {
        self.file.sync_data().is_ok()
    }
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
        Window::new_flags(x, y, w, h, title, false)
    }

    /// Create a new window with flags
    pub fn new_flags(x: i32, y: i32, w: u32, h: u32, title: &str, async: bool) -> Option<Self> {
        if let Ok(file) = File::open(&format!("orbital:{}/{}/{}/{}/{}/{}", if async { "a" } else { "" }, x, y, w, h, title)) {
            if let Ok(address) = unsafe { syscall::fmap(file.as_raw_fd(), 0, (w * h * 4) as usize) } {
                Some(Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    async: async,
                    file: file,
                    data: unsafe { slice::from_raw_parts_mut(address as *mut Color, (w * h) as usize) },
                })
            } else {
                None
            }
        } else {
            None
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        let mut buf: [u8; 4096] = [0; 4096];
        if let Ok(count) = syscall::fpath(self.file.as_raw_fd() as usize, &mut buf) {
            let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
            // orbital:/x/y/w/h/t
            let mut parts = path.split('/').skip(1);
            if let Some(x) = parts.next() {
                self.x = x.parse::<i32>().unwrap_or(0);
            }
            if let Some(y) = parts.next() {
                self.y = y.parse::<i32>().unwrap_or(0);
            }
            if let Some(w) = parts.next() {
                self.w = w.parse::<u32>().unwrap_or(0);
            }
            if let Some(h) = parts.next() {
                self.h = h.parse::<u32>().unwrap_or(0);
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, title: &str) {
        let _ = self.file.write(title.as_bytes());
        self.sync_path();
    }

    /// Blocking iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            events: [Event::new(); 128],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            //Should it be cleared? iter.events = [Event::new(); 128];
            match self.file.read(unsafe {
                slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
            }){
                Ok(0) => if ! self.async {
                    thread::yield_now();
                } else {
                    break 'blocking;
                },
                Ok(count) => {
                    iter.count = count/mem::size_of::<Event>();
                    break 'blocking;
                },
                Err(_) => break 'blocking,
            }
        }

        iter
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        let _ = unsafe { syscall::funmap(self.data.as_ptr() as usize) };
    }
}

impl AsRawFd for Window {
    fn as_raw_fd(&self) -> RawFd {
        self.file.as_raw_fd()
    }
}

/// Event iterator
pub struct EventIter {
    events: [Event; 128],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        if self.i < self.count {
            if let Some(event) = self.events.get(self.i) {
                self.i += 1;
                Some(*event)
            } else {
                None
            }
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>#![crate_type = "dylib"]
#![feature(plugin_registrar, managed_boxes, quote, globs)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItem, DummyResult};
use syntax::parse;
use syntax::parse::token;
use rustc::plugin::Registry;
use std::io::fs::File;
use std::str;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(box syntax::ext::base::BasicIdentMacroExpander {
                expander: expand_peg_str,
                span: None,
            }, None));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(box syntax::ext::base::BasicIdentMacroExpander {
                expander: expand_peg_file,
                span: None,
            }, None));
}

fn expand_peg_str(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult> {
    let source = match parse_arg(cx, tts.as_slice()) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg_file(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult> {
    let fname = match parse_arg(cx, tts.as_slice()) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(cx.codemap().span_to_filename(sp)).dir_path().join(fname);

    let source_utf8 = match File::open(&path).read_to_end() {
      Ok(source_utf8) => source_utf8,
      Err(e) => {
        cx.span_err(sp, e.to_string().as_slice());
        return DummyResult::any(sp)
      }
    };

    let source = str::from_utf8(source_utf8.as_slice()).unwrap();

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, msg.as_slice());
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case_functions, unused_variable)]
    let attr = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec!(
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case_functions")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused_variable")),
    )));

    MacItem::new(cx.item_mod(sp, sp, ident, vec!(attr), ast.view_items.clone(), ast.items.clone()))
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                Vec::from_slice(tts));
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expand_expr(parser.parse_expr());
    match arg.node {
        ast::ExprLit(spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::EOF) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.get().to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(arg));
    cx.span_err(parser.span, err.as_slice());
    None
}
<commit_msg>rust: auto-borrow<commit_after>#![crate_type = "dylib"]
#![feature(plugin_registrar, managed_boxes, quote, globs)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItem, DummyResult};
use syntax::parse;
use syntax::parse::token;
use rustc::plugin::Registry;
use std::io::fs::File;
use std::str;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(box syntax::ext::base::BasicIdentMacroExpander {
                expander: expand_peg_str,
                span: None,
            }, None));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(box syntax::ext::base::BasicIdentMacroExpander {
                expander: expand_peg_file,
                span: None,
            }, None));
}

fn expand_peg_str(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult> {
    let source = match parse_arg(cx, tts.as_slice()) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg_file(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult> {
    let fname = match parse_arg(cx, tts.as_slice()) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(cx.codemap().span_to_filename(sp)).dir_path().join(fname);

    let source_utf8 = match File::open(&path).read_to_end() {
      Ok(source_utf8) => source_utf8,
      Err(e) => {
        cx.span_err(sp, e.to_string().as_slice());
        return DummyResult::any(sp)
      }
    };

    let source = str::from_utf8(source_utf8.as_slice()).unwrap();

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, msg.as_slice());
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case_functions, unused_variable)]
    let attr = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec!(
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case_functions")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused_variable")),
    )));

    MacItem::new(cx.item_mod(sp, sp, ident, vec!(attr), ast.view_items.clone(), ast.items.clone()))
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                Vec::from_slice(tts));
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expand_expr(parser.parse_expr());
    match arg.node {
        ast::ExprLit(spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::EOF) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.get().to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, err.as_slice());
    None
}
<|endoftext|>


<commit_before>use super::{ NewPerson, Person };
use std::sync::Arc;
use connection::Connection;
use schema::person::dsl::*;
use schema::person;
use diesel::prelude::*;
use diesel;
use diesel::types;
use diesel::result;

pub struct PersonService {
    connection: Arc<Connection>
}

impl PersonService {
	pub fn new (connection: Arc<Connection>) -> Self {
		PersonService {
			connection
		}
	}

	pub fn get_persons(&self) -> Result<Vec<Person>, result::Error> {
        let conn = self.connection.lock().unwrap();

	    person
	        .get_results::<Person>(&*conn)
    }

    pub fn get_person_by_id(&self, req_id: i32) -> Result<Person, result::Error> {
        let conn = self.connection.lock().unwrap();

	    person
	        .find(req_id)
	        .get_result::<Person>(&*conn)
    }

    pub fn create_person(&self, new_person: &NewPerson) -> Result<i32, result::Error> {
    	let conn = self.connection.lock().unwrap();

	    diesel::insert(new_person)
		    .into(person::table)
	        .execute(&*conn)
	        .expect("Error saving new person");

        no_arg_sql_function!(LAST_INSERT_ROWID, types::Integer);

        diesel::select(LAST_INSERT_ROWID).first(&*conn)
    }

    pub fn delete_person(&self, del_id: i32) -> Result<usize, result::Error> {
    	let conn = self.connection.lock().unwrap();

    	diesel::delete(person.filter(id.eq(del_id))).execute(&*conn)
    }
}

unsafe impl Sync for PersonService {}<commit_msg>[FIX] Remove unnessesery Sync impl<commit_after>use super::{ NewPerson, Person };
use std::sync::Arc;
use connection::Connection;
use schema::person::dsl::*;
use schema::person;
use diesel::prelude::*;
use diesel;
use diesel::types;
use diesel::result;

pub struct PersonService {
    connection: Arc<Connection>
}

impl PersonService {
	pub fn new (connection: Arc<Connection>) -> Self {
		PersonService {
			connection
		}
	}

	pub fn get_persons(&self) -> Result<Vec<Person>, result::Error> {
        let conn = self.connection.lock().unwrap();

	    person
	        .get_results::<Person>(&*conn)
    }

    pub fn get_person_by_id(&self, req_id: i32) -> Result<Person, result::Error> {
        let conn = self.connection.lock().unwrap();

	    person
	        .find(req_id)
	        .get_result::<Person>(&*conn)
    }

    pub fn create_person(&self, new_person: &NewPerson) -> Result<i32, result::Error> {
    	let conn = self.connection.lock().unwrap();

	    diesel::insert(new_person)
		    .into(person::table)
	        .execute(&*conn)
	        .expect("Error saving new person");

        no_arg_sql_function!(LAST_INSERT_ROWID, types::Integer);

        diesel::select(LAST_INSERT_ROWID).first(&*conn)
    }

    pub fn delete_person(&self, del_id: i32) -> Result<usize, result::Error> {
    	let conn = self.connection.lock().unwrap();

    	diesel::delete(person.filter(id.eq(del_id))).execute(&*conn)
    }
}<|endoftext|>