<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Data structures that represent video format information in virtio video devices.

use std::convert::{From, Into, TryFrom};
use std::io;

use base::error;
use data_model::Le32;
use enumn::N;

use crate::virtio::video::command::ReadCmdError;
use crate::virtio::video::protocol::*;
use crate::virtio::video::response::Response;
use crate::virtio::Writer;

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Profile {
    H264Baseline = VIRTIO_VIDEO_PROFILE_H264_BASELINE,
    H264Main = VIRTIO_VIDEO_PROFILE_H264_MAIN,
    H264Extended = VIRTIO_VIDEO_PROFILE_H264_EXTENDED,
    H264High = VIRTIO_VIDEO_PROFILE_H264_HIGH,
    H264High10 = VIRTIO_VIDEO_PROFILE_H264_HIGH10PROFILE,
    H264High422 = VIRTIO_VIDEO_PROFILE_H264_HIGH422PROFILE,
    H264High444PredictiveProfile = VIRTIO_VIDEO_PROFILE_H264_HIGH444PREDICTIVEPROFILE,
    H264ScalableBaseline = VIRTIO_VIDEO_PROFILE_H264_SCALABLEBASELINE,
    H264ScalableHigh = VIRTIO_VIDEO_PROFILE_H264_SCALABLEHIGH,
    H264StereoHigh = VIRTIO_VIDEO_PROFILE_H264_STEREOHIGH,
    H264MultiviewHigh = VIRTIO_VIDEO_PROFILE_H264_MULTIVIEWHIGH,
    HevcMain = VIRTIO_VIDEO_PROFILE_HEVC_MAIN,
    HevcMain10 = VIRTIO_VIDEO_PROFILE_HEVC_MAIN10,
    HevcMainStillPicture = VIRTIO_VIDEO_PROFILE_HEVC_MAIN_STILL_PICTURE,
    VP8Profile0 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE0,
    VP8Profile1 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE1,
    VP8Profile2 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE2,
    VP8Profile3 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE3,
    VP9Profile0 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE0,
    VP9Profile1 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE1,
    VP9Profile2 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE2,
    VP9Profile3 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE3,
}
impl_try_from_le32_for_enumn!(Profile, "profile");

macro_rules! impl_libvda_conversion {
    ( $( ( $x:ident, $y:ident ) ),* ) => {
        pub fn from_libvda_profile(p: libvda::Profile) -> Option<Self> {
            match p {
                $(libvda::Profile::$x => Some(Self::$y),)*
                _ => None
            }
        }

        // TODO(alexlau): Remove this after encoder CL lands.
        #[allow(dead_code)]
        pub fn to_libvda_profile(&self) -> Option<libvda::Profile> {
            match self {
                $(Self::$y => Some(libvda::Profile::$x),)*
                _ => None
            }
        }
    }
}

impl Profile {
    pub fn to_format(&self) -> Format {
        use Profile::*;
        match self {
            H264Baseline
            | H264Main
            | H264Extended
            | H264High
            | H264High10
            | H264High422
            | H264High444PredictiveProfile
            | H264ScalableBaseline
            | H264ScalableHigh
            | H264StereoHigh
            | H264MultiviewHigh => Format::H264,
            HevcMain | HevcMain10 | HevcMainStillPicture => Format::HEVC,
            VP8Profile0 | VP8Profile1 | VP8Profile2 | VP8Profile3 => Format::VP8,
            VP9Profile0 | VP9Profile1 | VP9Profile2 | VP9Profile3 => Format::VP9,
        }
    }

    impl_libvda_conversion!(
        (H264ProfileBaseline, H264Baseline),
        (H264ProfileMain, H264Main),
        (H264ProfileExtended, H264Extended),
        (H264ProfileHigh, H264High),
        (H264ProfileHigh10Profile, H264High10),
        (H264ProfileHigh422Profile, H264High422),
        (
            H264ProfileHigh444PredictiveProfile,
            H264High444PredictiveProfile
        ),
        (H264ProfileScalableBaseline, H264ScalableBaseline),
        (H264ProfileScalableHigh, H264ScalableHigh),
        (H264ProfileStereoHigh, H264StereoHigh),
        (H264ProfileMultiviewHigh, H264MultiviewHigh),
        (HevcProfileMain, HevcMain),
        (HevcProfileMain10, HevcMain10),
        (HevcProfileMainStillPicture, HevcMainStillPicture),
        (VP8, VP8Profile0),
        (VP9Profile0, VP9Profile0),
        (VP9Profile1, VP9Profile1),
        (VP9Profile2, VP9Profile2),
        (VP9Profile3, VP9Profile3)
    );
}

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Level {
    H264_1_0 = VIRTIO_VIDEO_LEVEL_H264_1_0,
}
impl_try_from_le32_for_enumn!(Level, "level");

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Format {
    // Raw formats
    NV12 = VIRTIO_VIDEO_FORMAT_NV12,
    YUV420 = VIRTIO_VIDEO_FORMAT_YUV420,

    // Bitstream formats
    H264 = VIRTIO_VIDEO_FORMAT_H264,
    HEVC = VIRTIO_VIDEO_FORMAT_HEVC,
    VP8 = VIRTIO_VIDEO_FORMAT_VP8,
    VP9 = VIRTIO_VIDEO_FORMAT_VP9,
}
impl_try_from_le32_for_enumn!(Format, "format");

#[derive(Debug, Default, Copy, Clone)]
pub struct Crop {
    pub left: u32,
    pub top: u32,
    pub width: u32,
    pub height: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_crop, Crop, left, top, width, height);

#[derive(Debug, Default, Clone, Copy)]
pub struct PlaneFormat {
    pub plane_size: u32,
    pub stride: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_plane_format, PlaneFormat, plane_size, stride);

#[derive(Debug, Default, Clone, Copy)]
pub struct FormatRange {
    pub min: u32,
    pub max: u32,
    pub step: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_format_range, FormatRange, min, max, step);

#[derive(Debug, Default, Clone)]
pub struct FrameFormat {
    pub width: FormatRange,
    pub height: FormatRange,
    pub bitrates: Vec<FormatRange>,
}

impl Response for FrameFormat {
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        w.write_obj(virtio_video_format_frame {
            width: self.width.into(),
            height: self.height.into(),
            num_rates: Le32::from(self.bitrates.len() as u32),
            ..Default::default()
        })?;
        w.write_iter(
            self.bitrates
                .iter()
                .map(|r| Into::<virtio_video_format_range>::into(*r)),
        )
    }
}

#[derive(Debug, Clone)]
pub struct FormatDesc {
    pub mask: u64,
    pub format: Format,
    pub frame_formats: Vec<FrameFormat>,
}

impl Response for FormatDesc {
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        w.write_obj(virtio_video_format_desc {
            mask: self.mask.into(),
            format: Le32::from(self.format as u32),
            // ChromeOS only supports single-buffer mode.
            planes_layout: Le32::from(VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER),
            // No alignment is required on boards that we currently support.
            plane_align: Le32::from(0),
            num_frames: Le32::from(self.frame_formats.len() as u32),
        })?;
        self.frame_formats.iter().map(|ff| ff.write(w)).collect()
    }
}
<commit_msg>devices: virtio: video: Add missing H264 levels<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Data structures that represent video format information in virtio video devices.

use std::convert::{From, Into, TryFrom};
use std::io;

use base::error;
use data_model::Le32;
use enumn::N;

use crate::virtio::video::command::ReadCmdError;
use crate::virtio::video::protocol::*;
use crate::virtio::video::response::Response;
use crate::virtio::Writer;

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Profile {
    H264Baseline = VIRTIO_VIDEO_PROFILE_H264_BASELINE,
    H264Main = VIRTIO_VIDEO_PROFILE_H264_MAIN,
    H264Extended = VIRTIO_VIDEO_PROFILE_H264_EXTENDED,
    H264High = VIRTIO_VIDEO_PROFILE_H264_HIGH,
    H264High10 = VIRTIO_VIDEO_PROFILE_H264_HIGH10PROFILE,
    H264High422 = VIRTIO_VIDEO_PROFILE_H264_HIGH422PROFILE,
    H264High444PredictiveProfile = VIRTIO_VIDEO_PROFILE_H264_HIGH444PREDICTIVEPROFILE,
    H264ScalableBaseline = VIRTIO_VIDEO_PROFILE_H264_SCALABLEBASELINE,
    H264ScalableHigh = VIRTIO_VIDEO_PROFILE_H264_SCALABLEHIGH,
    H264StereoHigh = VIRTIO_VIDEO_PROFILE_H264_STEREOHIGH,
    H264MultiviewHigh = VIRTIO_VIDEO_PROFILE_H264_MULTIVIEWHIGH,
    HevcMain = VIRTIO_VIDEO_PROFILE_HEVC_MAIN,
    HevcMain10 = VIRTIO_VIDEO_PROFILE_HEVC_MAIN10,
    HevcMainStillPicture = VIRTIO_VIDEO_PROFILE_HEVC_MAIN_STILL_PICTURE,
    VP8Profile0 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE0,
    VP8Profile1 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE1,
    VP8Profile2 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE2,
    VP8Profile3 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE3,
    VP9Profile0 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE0,
    VP9Profile1 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE1,
    VP9Profile2 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE2,
    VP9Profile3 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE3,
}
impl_try_from_le32_for_enumn!(Profile, "profile");

macro_rules! impl_libvda_conversion {
    ( $( ( $x:ident, $y:ident ) ),* ) => {
        pub fn from_libvda_profile(p: libvda::Profile) -> Option<Self> {
            match p {
                $(libvda::Profile::$x => Some(Self::$y),)*
                _ => None
            }
        }

        // TODO(alexlau): Remove this after encoder CL lands.
        #[allow(dead_code)]
        pub fn to_libvda_profile(&self) -> Option<libvda::Profile> {
            match self {
                $(Self::$y => Some(libvda::Profile::$x),)*
                _ => None
            }
        }
    }
}

impl Profile {
    pub fn to_format(&self) -> Format {
        use Profile::*;
        match self {
            H264Baseline
            | H264Main
            | H264Extended
            | H264High
            | H264High10
            | H264High422
            | H264High444PredictiveProfile
            | H264ScalableBaseline
            | H264ScalableHigh
            | H264StereoHigh
            | H264MultiviewHigh => Format::H264,
            HevcMain | HevcMain10 | HevcMainStillPicture => Format::HEVC,
            VP8Profile0 | VP8Profile1 | VP8Profile2 | VP8Profile3 => Format::VP8,
            VP9Profile0 | VP9Profile1 | VP9Profile2 | VP9Profile3 => Format::VP9,
        }
    }

    impl_libvda_conversion!(
        (H264ProfileBaseline, H264Baseline),
        (H264ProfileMain, H264Main),
        (H264ProfileExtended, H264Extended),
        (H264ProfileHigh, H264High),
        (H264ProfileHigh10Profile, H264High10),
        (H264ProfileHigh422Profile, H264High422),
        (
            H264ProfileHigh444PredictiveProfile,
            H264High444PredictiveProfile
        ),
        (H264ProfileScalableBaseline, H264ScalableBaseline),
        (H264ProfileScalableHigh, H264ScalableHigh),
        (H264ProfileStereoHigh, H264StereoHigh),
        (H264ProfileMultiviewHigh, H264MultiviewHigh),
        (HevcProfileMain, HevcMain),
        (HevcProfileMain10, HevcMain10),
        (HevcProfileMainStillPicture, HevcMainStillPicture),
        (VP8, VP8Profile0),
        (VP9Profile0, VP9Profile0),
        (VP9Profile1, VP9Profile1),
        (VP9Profile2, VP9Profile2),
        (VP9Profile3, VP9Profile3)
    );
}

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Level {
    H264_1_0 = VIRTIO_VIDEO_LEVEL_H264_1_0,
    H264_1_1 = VIRTIO_VIDEO_LEVEL_H264_1_1,
    H264_1_2 = VIRTIO_VIDEO_LEVEL_H264_1_2,
    H264_1_3 = VIRTIO_VIDEO_LEVEL_H264_1_3,
    H264_2_0 = VIRTIO_VIDEO_LEVEL_H264_2_0,
    H264_2_1 = VIRTIO_VIDEO_LEVEL_H264_2_1,
    H264_2_2 = VIRTIO_VIDEO_LEVEL_H264_2_2,
    H264_3_0 = VIRTIO_VIDEO_LEVEL_H264_3_0,
    H264_3_1 = VIRTIO_VIDEO_LEVEL_H264_3_1,
    H264_3_2 = VIRTIO_VIDEO_LEVEL_H264_3_2,
    H264_4_0 = VIRTIO_VIDEO_LEVEL_H264_4_0,
    H264_4_1 = VIRTIO_VIDEO_LEVEL_H264_4_1,
    H264_4_2 = VIRTIO_VIDEO_LEVEL_H264_4_2,
    H264_5_0 = VIRTIO_VIDEO_LEVEL_H264_5_0,
    H264_5_1 = VIRTIO_VIDEO_LEVEL_H264_5_1,
}
impl_try_from_le32_for_enumn!(Level, "level");

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Format {
    // Raw formats
    NV12 = VIRTIO_VIDEO_FORMAT_NV12,
    YUV420 = VIRTIO_VIDEO_FORMAT_YUV420,

    // Bitstream formats
    H264 = VIRTIO_VIDEO_FORMAT_H264,
    HEVC = VIRTIO_VIDEO_FORMAT_HEVC,
    VP8 = VIRTIO_VIDEO_FORMAT_VP8,
    VP9 = VIRTIO_VIDEO_FORMAT_VP9,
}
impl_try_from_le32_for_enumn!(Format, "format");

#[derive(Debug, Default, Copy, Clone)]
pub struct Crop {
    pub left: u32,
    pub top: u32,
    pub width: u32,
    pub height: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_crop, Crop, left, top, width, height);

#[derive(Debug, Default, Clone, Copy)]
pub struct PlaneFormat {
    pub plane_size: u32,
    pub stride: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_plane_format, PlaneFormat, plane_size, stride);

#[derive(Debug, Default, Clone, Copy)]
pub struct FormatRange {
    pub min: u32,
    pub max: u32,
    pub step: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_format_range, FormatRange, min, max, step);

#[derive(Debug, Default, Clone)]
pub struct FrameFormat {
    pub width: FormatRange,
    pub height: FormatRange,
    pub bitrates: Vec<FormatRange>,
}

impl Response for FrameFormat {
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        w.write_obj(virtio_video_format_frame {
            width: self.width.into(),
            height: self.height.into(),
            num_rates: Le32::from(self.bitrates.len() as u32),
            ..Default::default()
        })?;
        w.write_iter(
            self.bitrates
                .iter()
                .map(|r| Into::<virtio_video_format_range>::into(*r)),
        )
    }
}

#[derive(Debug, Clone)]
pub struct FormatDesc {
    pub mask: u64,
    pub format: Format,
    pub frame_formats: Vec<FrameFormat>,
}

impl Response for FormatDesc {
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        w.write_obj(virtio_video_format_desc {
            mask: self.mask.into(),
            format: Le32::from(self.format as u32),
            // ChromeOS only supports single-buffer mode.
            planes_layout: Le32::from(VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER),
            // No alignment is required on boards that we currently support.
            plane_align: Le32::from(0),
            num_frames: Le32::from(self.frame_formats.len() as u32),
        })?;
        self.frame_formats.iter().map(|ff| ff.write(w)).collect()
    }
}
<|endoftext|>


<commit_before>use std;

pub fn iter_dibits<T: Iterator<Item = u8>>(src: T) -> SubByteIter<DibitIterator, T> {
    SubByteIter::new(src)
}

pub fn iter_bits<T: Iterator<Item = u8>>(src: T) -> SubByteIter<BitParams, T> {
    SubByteIter::new(src)
}

pub trait IterateParams {
    type IterType;

    fn bits() -> u8;
    fn wrap(x: u8) -> Self::IterType;

    fn shift() -> u8 { Self::bits() }
    fn iterations() -> u8 { 8 / Self::bits() }

    fn validate() {
        assert!(Self::bits().is_power_of_two());
    }
}

pub struct Bit(pub u8);
pub struct BitParams;

impl IterateParams for BitParams {
    type IterType = Bit;
    fn bits() -> u8 { 1 }
    fn wrap(x: u8) -> Bit { Bit(x) }
}

pub struct Dibit(pub u8);
pub struct DibitIterator;

impl IterateParams for DibitIterator {
    type IterType = Dibit;
    fn bits() -> u8 { 2 }
    fn wrap(x: u8) -> Dibit { Dibit(x) }
}

pub struct SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// The source of bits.
    src: T,
    /// The current index into the current byte.
    idx: u8,
    /// The current byte in the source.
    byte: u8,
}

impl<P, T> SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter<T>`.
    fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            byte: 0,
            idx: 0,
        }
    }
}

impl<P, T> Iterator for SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    type Item = P::IterType;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.byte = match self.src.next() {
                Some(b) => b,
                None => return None,
            };
        }

        // Store the current byte for later.
        let byte = self.byte;

        // Strip off the MSBs for the next iteration.
        self.byte <<= P::shift();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations();

        // Yield the MSBs.
        Some(P::wrap(byte >> (8 - P::shift())))
    }
}

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

    #[test]
    fn validate_params() {
        BitParams::validate();
        DibitIterator::validate();
    }

    #[test]
    fn test_bits() {
        const BITS: &'static [u8] = &[
            0b00011011,
            0b11001100,
        ];

        {
            let mut d = iter_dibits(BITS.iter().cloned());

            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b01);
            assert!(d.next().unwrap().0 == 0b10);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().is_none());
        }

        {
            let mut b = iter_bits(BITS.iter().cloned());

            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
        }
    }
}
<commit_msg>s/DibitIterator/DibitParams/<commit_after>use std;

pub fn iter_dibits<T: Iterator<Item = u8>>(src: T) -> SubByteIter<DibitParams, T> {
    SubByteIter::new(src)
}

pub fn iter_bits<T: Iterator<Item = u8>>(src: T) -> SubByteIter<BitParams, T> {
    SubByteIter::new(src)
}

pub trait IterateParams {
    type IterType;

    fn bits() -> u8;
    fn wrap(x: u8) -> Self::IterType;

    fn shift() -> u8 { Self::bits() }
    fn iterations() -> u8 { 8 / Self::bits() }

    fn validate() {
        assert!(Self::bits().is_power_of_two());
    }
}

pub struct Bit(pub u8);
pub struct BitParams;

impl IterateParams for BitParams {
    type IterType = Bit;
    fn bits() -> u8 { 1 }
    fn wrap(x: u8) -> Bit { Bit(x) }
}

#[derive(Debug)]
pub struct Dibit(pub u8);
pub struct DibitParams;

impl IterateParams for DibitParams {
    type IterType = Dibit;
    fn bits() -> u8 { 2 }
    fn wrap(x: u8) -> Dibit { Dibit(x) }
}

pub struct SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// The source of bits.
    src: T,
    /// The current index into the current byte.
    idx: u8,
    /// The current byte in the source.
    byte: u8,
}

impl<P, T> SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter<T>`.
    fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            byte: 0,
            idx: 0,
        }
    }
}

impl<P, T> Iterator for SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    type Item = P::IterType;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.byte = match self.src.next() {
                Some(b) => b,
                None => return None,
            };
        }

        // Store the current byte for later.
        let byte = self.byte;

        // Strip off the MSBs for the next iteration.
        self.byte <<= P::shift();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations();

        // Yield the MSBs.
        Some(P::wrap(byte >> (8 - P::shift())))
    }
}

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

    #[test]
    fn validate_params() {
        BitParams::validate();
        DibitParams::validate();
    }

    #[test]
    fn test_bits() {
        const BITS: &'static [u8] = &[
            0b00011011,
            0b11001100,
        ];

        {
            let mut d = iter_dibits(BITS.iter().cloned());

            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b01);
            assert!(d.next().unwrap().0 == 0b10);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().is_none());
        }

        {
            let mut b = iter_bits(BITS.iter().cloned());

            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
        }
    }
}
<|endoftext|>


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

/// A scale and an offset that transforms xyz coordinates.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
    /// The scale.
    pub scale: f64,
    /// The offset.
    pub offset: f64,
}

impl Transform {
    /// Applies this transform to an i32, returning a float.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(3., transform.direct(1));
    /// ```
    pub fn direct(&self, n: i32) -> f64 {
        self.scale * n as f64 + self.offset
    }

    /// Applies the inverse transform, and rounds the result.
    ///
    /// Returns an error if the resultant value can't be representaed as an i32.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(1, transform.inverse(2.9).unwrap());
    /// ```
    pub fn inverse(&self, n: f64) -> Result<i32> {
        use Error;
        use std::i32;

        let n = ((n - self.offset) / self.scale).round();
        if n > i32::MAX as f64 {
            Err(Error::InverseTransform(n, *self))
        } else {
            Ok(n as i32)
        }
    }
}

impl Default for Transform {
    fn default() -> Transform {
        Transform {
            scale: 0.001,
            offset: 0.,
        }
    }
}

impl fmt::Display for Transform {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "`{} * x + {}`", self.scale, self.offset)
    }
}
<commit_msg>Fix typo in transform docs<commit_after>use Result;
use std::fmt;

/// A scale and an offset that transforms xyz coordinates.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
    /// The scale.
    pub scale: f64,
    /// The offset.
    pub offset: f64,
}

impl Transform {
    /// Applies this transform to an i32, returning a float.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(3., transform.direct(1));
    /// ```
    pub fn direct(&self, n: i32) -> f64 {
        self.scale * n as f64 + self.offset
    }

    /// Applies the inverse transform, and rounds the result.
    ///
    /// Returns an error if the resultant value can't be represented as an i32.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(1, transform.inverse(2.9).unwrap());
    /// ```
    pub fn inverse(&self, n: f64) -> Result<i32> {
        use Error;
        use std::i32;

        let n = ((n - self.offset) / self.scale).round();
        if n > i32::MAX as f64 {
            Err(Error::InverseTransform(n, *self))
        } else {
            Ok(n as i32)
        }
    }
}

impl Default for Transform {
    fn default() -> Transform {
        Transform {
            scale: 0.001,
            offset: 0.,
        }
    }
}

impl fmt::Display for Transform {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "`{} * x + {}`", self.scale, self.offset)
    }
}
<|endoftext|>


<commit_before>use nalgebra::UnitQuaternion;
use std::default::Default;

pub use luminance::linear::M44;
pub use nalgebra::{Matrix4, Vector3};

/// Class of types that can yield transformation matrices.
pub trait Transformable {
  fn transform(&self) -> M44;
}

pub type Translation = Vector3<f32>;
pub type Axis = Vector3<f32>;
pub type Position = Vector3<f32>;
pub type Orientation = UnitQuaternion<f32>;

pub const X_AXIS: Axis = Axis { x: 1., y: 0., z: 0. };
pub const Y_AXIS: Axis = Axis { x: 0., y: 1., z: 0. };
pub const Z_AXIS: Axis = Axis { x: 0., y: 0., z: 1. };

/// Arbritrary scale.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Scale {
  pub x: f32,
  pub y: f32,
  pub z: f32
}

impl Scale {
  pub fn new(x: f32, y: f32, z: f32) -> Self {
    Scale {
      x: x,
      y: y,
      z: z
    }
  }

  pub fn uni(x: f32) -> Self {
    Scale {
      x: x,
      y: x,
      z: x
    }
  }

  pub fn to_mat(&self) -> Matrix4<f32> {
    Matrix4::new(
      self.x,     0.,     0., 0.,
          0., self.y,     0., 0.,
          0.,     0., self.z, 0.,
          0.,     0.,     0., 1.
    )
  }
}

impl Default for Scale {
  fn default() -> Self { Scale::new(1., 1., 1.) }
}

impl<'a> From<&'a [f32; 3]> for Scale {
  fn from(slice: &[f32; 3]) -> Self {
    Scale {
      x: slice[0],
      y: slice[1],
      z: slice[2]
    }
  }
}

impl<'a> From<&'a Scale> for [f32; 3] {
  fn from(scale: &Scale) -> Self {
    [scale.x, scale.y, scale.z]
  }
}

pub fn translation_matrix(v: Translation) -> Matrix4<f32> {
  Matrix4::new(
    1., 0., 0., v.x,
    0., 1., 0., v.y,
    0., 0., 1., v.z,
    0., 0., 0.,  1.,
  )
}
<commit_msg>impl Transformable for M44.<commit_after>use nalgebra::UnitQuaternion;
use std::default::Default;

pub use luminance::linear::M44;
pub use nalgebra::{Matrix4, Vector3};

/// Class of types that can yield transformation matrices.
pub trait Transformable {
  fn transform(&self) -> M44;
}

impl Transformable for M44 {
  fn transform(&self) -> M44 {
    self.clone()
  }
}

pub type Translation = Vector3<f32>;
pub type Axis = Vector3<f32>;
pub type Position = Vector3<f32>;
pub type Orientation = UnitQuaternion<f32>;

pub const X_AXIS: Axis = Axis { x: 1., y: 0., z: 0. };
pub const Y_AXIS: Axis = Axis { x: 0., y: 1., z: 0. };
pub const Z_AXIS: Axis = Axis { x: 0., y: 0., z: 1. };

/// Arbritrary scale.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Scale {
  pub x: f32,
  pub y: f32,
  pub z: f32
}

impl Scale {
  pub fn new(x: f32, y: f32, z: f32) -> Self {
    Scale {
      x: x,
      y: y,
      z: z
    }
  }

  pub fn uni(x: f32) -> Self {
    Scale {
      x: x,
      y: x,
      z: x
    }
  }

  pub fn to_mat(&self) -> Matrix4<f32> {
    Matrix4::new(
      self.x,     0.,     0., 0.,
          0., self.y,     0., 0.,
          0.,     0., self.z, 0.,
          0.,     0.,     0., 1.
    )
  }
}

impl Default for Scale {
  fn default() -> Self { Scale::new(1., 1., 1.) }
}

impl<'a> From<&'a [f32; 3]> for Scale {
  fn from(slice: &[f32; 3]) -> Self {
    Scale {
      x: slice[0],
      y: slice[1],
      z: slice[2]
    }
  }
}

impl<'a> From<&'a Scale> for [f32; 3] {
  fn from(scale: &Scale) -> Self {
    [scale.x, scale.y, scale.z]
  }
}

pub fn translation_matrix(v: Translation) -> Matrix4<f32> {
  Matrix4::new(
    1., 0., 0., v.x,
    0., 1., 0., v.y,
    0., 0., 1., v.z,
    0., 0., 0.,  1.,
  )
}
<|endoftext|>


<commit_before>extern crate vec2;
extern crate vec3;

use num::Num;
use length::length_values;

#[inline(always)]
pub fn transform_mat3<T: Num>(out: &mut [T; 4], a: [T; 4], m: [T; 9]) -> &mut [T; 4] {
    out[0] = a[0] * m[0] + a[1] * m[3] + a[2] * m[6];
    out[1] = a[0] * m[1] + a[1] * m[4] + a[2] * m[7];
    out[2] = a[0] * m[2] + a[1] * m[5] + a[2] * m[8];
    out
}

#[inline(always)]
pub fn transform_mat4<T: Num>(out: &mut [T; 4], a: [T; 4], m: [T; 16]) -> &mut [T; 4] {
    out[0] = a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + a[3] * m[12];
    out[1] = a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + a[3] * m[13];
    out[2] = a[0] * m[2] + a[1] * m[6] + a[2] * m[10] + a[3] * m[14];
    out[3] = a[0] * m[3] + a[1] * m[7] + a[2] * m[11] + a[3] * m[15];
    out
}

#[inline(always)]
pub fn transform_mat4_rotation<T: Num>(out: &mut [T; 4], a: [T; 4], m: [T; 16]) -> &mut [T; 4] {
    out[0] = a[0] * m[0] + a[1] * m[4] + a[2] * m[8];
    out[1] = a[0] * m[1] + a[1] * m[5] + a[2] * m[9];
    out[2] = a[0] * m[2] + a[1] * m[6] + a[2] * m[10];
    out[3] = a[0] * m[3] + a[1] * m[7] + a[2] * m[11] + a[3] * m[15];
    out
}

#[inline(always)]
pub fn transform_projection<T: Num>(out: &mut [T; 4], a: [T; 4], m: [T; 16]) -> &mut [T; 4] {
    let mut d = a[0] * m[3] + a[1] * m[7] + a[2] * m[11] + a[3] * m[15];
    d = if d != T::zero() {T::one() / d} else {d};

    out[0] = (a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + a[3] * m[12]) * d;
    out[1] = (a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + a[3] * m[13]) * d;
    out[2] = (a[0] * m[2] + a[1] * m[6] + a[2] * m[10] + a[3] * m[14]) * d;
    out[3] = (a[0] * m[3] + a[1] * m[7] + a[2] * m[11] + a[3] * m[15]) * d;
    out
}

#[inline(always)]
pub fn position_mat32<T: Num>(out: &mut [T; 4], m: [T; 6]) -> &mut [T; 4] {
    out[0] = m[4];
    out[1] = m[5];
    out
}

#[inline(always)]
pub fn position_mat4<T: Num>(out: &mut [T; 4], m: [T; 16]) -> &mut [T; 4] {
    out[0] = m[12];
    out[1] = m[13];
    out[2] = m[14];
    out[3] = m[15];
    out
}

#[inline(always)]
pub fn scale_mat2<T: Num>(out: &mut [T; 4], m: [T; 4]) -> &mut [T; 4] {
    out[0] = vec2::length_values(m[0], m[2]);
    out[1] = vec2::length_values(m[1], m[3]);
    out[2] = T::one();
    out[3] = T::one();
    out
}

#[inline(always)]
pub fn scale_mat32<T: Num>(out: &mut [T; 4], m: [T; 6]) -> &mut [T; 4] {
    out[0] = vec3::length_values(m[0], m[2], T::zero());
    out[1] = vec3::length_values(m[1], m[3], T::zero());
    out[2] = T::one();
    out[3] = T::one();
    out
}

#[inline(always)]
pub fn scale_mat3<T: Num>(out: &mut [T; 4], m: [T; 9]) -> &mut [T; 4] {
    out[0] = vec3::length_values(m[0], m[3], m[6]);
    out[1] = vec3::length_values(m[1], m[4], m[7]);
    out[2] = vec3::length_values(m[2], m[5], m[8]);
    out[3] = T::one();
    out
}

#[inline(always)]
pub fn scale_mat4<T: Num>(out: &mut [T; 4], m: [T; 16]) -> &mut [T; 4] {
    out[0] = vec3::length_values(m[0], m[4], m[8]);
    out[1] = vec3::length_values(m[1], m[5], m[9]);
    out[2] = vec3::length_values(m[2], m[6], m[10]);
    out[3] = vec3::length_values(m[3], m[7], m[11]);
    out
}
<commit_msg>updates<commit_after>extern crate vec2;
extern crate vec3;

use num::Num;
use length::length_values;

#[inline(always)]
pub fn transform_mat3<T: Num>(out: &mut [T; 4], a: [T; 4], m: [T; 9]) -> &mut [T; 4] {
    out[0] = a[0] * m[0] + a[1] * m[3] + a[2] * m[6];
    out[1] = a[0] * m[1] + a[1] * m[4] + a[2] * m[7];
    out[2] = a[0] * m[2] + a[1] * m[5] + a[2] * m[8];
    out
}

#[inline(always)]
pub fn transform_mat4<T: Num>(out: &mut [T; 4], a: [T; 4], m: [T; 16]) -> &mut [T; 4] {
    out[0] = a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + a[3] * m[12];
    out[1] = a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + a[3] * m[13];
    out[2] = a[0] * m[2] + a[1] * m[6] + a[2] * m[10] + a[3] * m[14];
    out[3] = a[0] * m[3] + a[1] * m[7] + a[2] * m[11] + a[3] * m[15];
    out
}

#[inline(always)]
pub fn transform_mat4_rotation<T: Num>(out: &mut [T; 4], a: [T; 4], m: [T; 16]) -> &mut [T; 4] {
    out[0] = a[0] * m[0] + a[1] * m[4] + a[2] * m[8];
    out[1] = a[0] * m[1] + a[1] * m[5] + a[2] * m[9];
    out[2] = a[0] * m[2] + a[1] * m[6] + a[2] * m[10];
    out[3] = a[0] * m[3] + a[1] * m[7] + a[2] * m[11] + a[3] * m[15];
    out
}

#[inline(always)]
pub fn transform_projection<T: Num>(out: &mut [T; 4], a: [T; 4], m: [T; 16]) -> &mut [T; 4] {
    let mut d = a[0] * m[3] + a[1] * m[7] + a[2] * m[11] + a[3] * m[15];
    d = if d != T::zero() {T::one() / d} else {d};

    out[0] = (a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + a[3] * m[12]) * d;
    out[1] = (a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + a[3] * m[13]) * d;
    out[2] = (a[0] * m[2] + a[1] * m[6] + a[2] * m[10] + a[3] * m[14]) * d;
    out[3] = (a[0] * m[3] + a[1] * m[7] + a[2] * m[11] + a[3] * m[15]) * d;
    out
}

#[inline(always)]
pub fn position_mat32<T: Num>(out: &mut [T; 4], m: [T; 6]) -> &mut [T; 4] {
    out[0] = m[4];
    out[1] = m[5];
    out
}

#[inline(always)]
pub fn position_mat4<T: Num>(out: &mut [T; 4], m: [T; 16]) -> &mut [T; 4] {
    out[0] = m[12];
    out[1] = m[13];
    out[2] = m[14];
    out[3] = m[15];
    out
}

#[inline(always)]
pub fn scale_mat2<T: Num>(out: &mut [T; 4], m: [T; 4]) -> &mut [T; 4] {
    out[0] = vec2::length_values(m[0], m[2]);
    out[1] = vec2::length_values(m[1], m[3]);
    out[2] = T::one();
    out[3] = T::one();
    out
}

#[inline(always)]
pub fn scale_mat32<T: Num>(out: &mut [T; 4], m: [T; 6]) -> &mut [T; 4] {
    out[0] = vec3::length_values(m[0], m[2], T::zero());
    out[1] = vec3::length_values(m[1], m[3], T::zero());
    out[2] = T::one();
    out[3] = T::one();
    out
}

#[inline(always)]
pub fn scale_mat3<T: Num>(out: &mut [T; 4], m: [T; 9]) -> &mut [T; 4] {
    out[0] = vec3::length_values(m[0], m[3], m[6]);
    out[1] = vec3::length_values(m[1], m[4], m[7]);
    out[2] = vec3::length_values(m[2], m[5], m[8]);
    out[3] = T::one();
    out
}

#[inline(always)]
pub fn scale_mat4<T: Num>(out: &mut [T; 4], m: [T; 16]) -> &mut [T; 4] {
    out[0] = vec3::length_values(m[0], m[4], m[8]);
    out[1] = vec3::length_values(m[1], m[5], m[9]);
    out[2] = vec3::length_values(m[2], m[6], m[10]);
    out[3] = T::one();
    out
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Read, Write};
use std::net;
use std::net::TcpStream;
#[cfg(feature = "ssl")]
use openssl::ssl::{SslStream, SslConnector};

pub  trait  CDRSTransport: Sized+Read+Write+Send+Sync{

    fn try_clone(&self) -> io::Result<Self>;
    fn close(&mut self, close: net::Shutdown) -> io::Result<()>;
}

#[derive(Debug)]
pub struct TransportPlain {
    tcp: TcpStream
}

impl TransportPlain {
    pub fn new(addr: &str) -> io::Result<TransportPlain> {
        TcpStream::connect(addr).map(|socket| TransportPlain {tcp: socket})
    }

}

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

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

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

impl CDRSTransport  for TransportPlain {

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `Transport` and creates a new encrypted
    /// transport with new TCP stream under hood.
    fn try_clone(&self) -> io::Result<TransportPlain> {
        let addr = try!( self.tcp.peer_addr());
        TcpStream::connect(addr).map( | socket | TransportPlain {tcp: socket})
    }

    fn close(&mut self, close: net::Shutdown) -> io::Result<()> {
        self.tcp.shutdown(close)
    }

}

/*************************************/
/** TLS**/
/**************************************/

#[cfg(feature = "ssl")]
pub struct TransportTls {
    ssl: SslStream<TcpStream>,
    connector: SslConnector
}
#[cfg(feature = "ssl")]
impl TransportTls {

    pub fn new(addr: &str, connector: & SslConnector) -> io::Result<TransportTls> {
        let a: Vec<&str> = addr.split(':').collect();
        let res =  net::TcpStream::connect(addr)
            .map(|socket|
                     connector.connect(a[0], socket)
                         .map(|sslsocket|
                                  TransportTls {
                                      ssl: sslsocket,
                                      connector: connector.clone()
                                  }
                         )
            );

        res.and_then(|res| {
            res.map(|n: TransportTls| n ).map_err(|e| io::Error::new(io::ErrorKind::Other,e))

        })
    }

}
#[cfg(feature = "ssl")]
impl Read for TransportTls {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.ssl.read(buf)
    }
}
#[cfg(feature = "ssl")]
impl Write for TransportTls {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.ssl.write(buf)
    }

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

#[cfg(feature = "ssl")]
impl CDRSTransport for TransportTls{

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `TransportTls` and creates a new encrypted
    /// connection with a new TCP stream under hood.
    fn try_clone(&self) -> io::Result<TransportTls> {
        let addr = try!(self.ssl.get_ref().peer_addr());
        let ip_string = format!("{}", addr.ip());

        let res =  net::TcpStream::connect(addr)
            .map(|socket|
                     self.connector.connect(ip_string.as_str(), socket)
                         .map(|sslsocket| TransportTls {ssl: sslsocket, connector: self.connector.clone()}));

        res.and_then(|res| {
            res.map(|n: TransportTls| n ).map_err(|e| io::Error::new(io::ErrorKind::Other,e))
        })
    }

    fn close(&mut self, _close: net::Shutdown) -> io::Result<()> {
        self.ssl.shutdown().map_err(|e| io::Error::new(io::ErrorKind::Other,e)).and_then(|_| Ok(()))
    }
}

<commit_msg>added a single doc test<commit_after>use std::io;
use std::io::{Read, Write};
use std::net;
use std::net::TcpStream;
#[cfg(feature = "ssl")]
use openssl::ssl::{SslStream, SslConnector};

pub  trait  CDRSTransport: Sized+Read+Write+Send+Sync{

    fn try_clone(&self) -> io::Result<Self>;
    fn close(&mut self, close: net::Shutdown) -> io::Result<()>;
}

#[derive(Debug)]
pub struct TransportPlain {
    tcp: TcpStream
}

impl TransportPlain {

    /// Constructs a new `TransportPlain`.
    ///
    /// # Examples
    ///
    /// ```
    /// use cdrs::transport::TransportPlain;
    /// let addr = "127.0.0.1:9042";
    /// let tcp_transport = TransportPlain::new(addr).unwrap();
    /// ```
    pub fn new(addr: &str) -> io::Result<TransportPlain> {
        TcpStream::connect(addr).map(|socket| TransportPlain {tcp: socket})
    }

}

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

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

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

impl CDRSTransport  for TransportPlain {

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `Transport` and creates a new encrypted
    /// transport with new TCP stream under hood.
    fn try_clone(&self) -> io::Result<TransportPlain> {
        let addr = try!( self.tcp.peer_addr());
        TcpStream::connect(addr).map( | socket | TransportPlain {tcp: socket})
    }

    fn close(&mut self, close: net::Shutdown) -> io::Result<()> {
        self.tcp.shutdown(close)
    }

}

/*************************************/
/** TLS**/
/**************************************/

#[cfg(feature = "ssl")]
pub struct TransportTls {
    ssl: SslStream<TcpStream>,
    connector: SslConnector
}
#[cfg(feature = "ssl")]
impl TransportTls {

    pub fn new(addr: &str, connector: & SslConnector) -> io::Result<TransportTls> {
        let a: Vec<&str> = addr.split(':').collect();
        let res =  net::TcpStream::connect(addr)
            .map(|socket|
                     connector.connect(a[0], socket)
                         .map(|sslsocket|
                                  TransportTls {
                                      ssl: sslsocket,
                                      connector: connector.clone()
                                  }
                         )
            );

        res.and_then(|res| {
            res.map(|n: TransportTls| n ).map_err(|e| io::Error::new(io::ErrorKind::Other,e))

        })
    }

}
#[cfg(feature = "ssl")]
impl Read for TransportTls {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.ssl.read(buf)
    }
}
#[cfg(feature = "ssl")]
impl Write for TransportTls {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.ssl.write(buf)
    }

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

#[cfg(feature = "ssl")]
impl CDRSTransport for TransportTls{

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `TransportTls` and creates a new encrypted
    /// connection with a new TCP stream under hood.
    fn try_clone(&self) -> io::Result<TransportTls> {
        let addr = try!(self.ssl.get_ref().peer_addr());
        let ip_string = format!("{}", addr.ip());

        let res =  net::TcpStream::connect(addr)
            .map(|socket|
                     self.connector.connect(ip_string.as_str(), socket)
                         .map(|sslsocket| TransportTls {ssl: sslsocket, connector: self.connector.clone()}));

        res.and_then(|res| {
            res.map(|n: TransportTls| n ).map_err(|e| io::Error::new(io::ErrorKind::Other,e))
        })
    }

    fn close(&mut self, _close: net::Shutdown) -> io::Result<()> {
        self.ssl.shutdown().map_err(|e| io::Error::new(io::ErrorKind::Other,e)).and_then(|_| Ok(()))
    }
}

<|endoftext|>


<commit_before>use std::sync::atomics::AtomicBool;
use std::ptr;
use {Event, WindowBuilder};

pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};

mod event;
mod ffi;
mod init;
mod monitor;

/// The Win32 implementation of the main `Window` object.
pub struct Window {
    /// Main handle for the window.
    window: ffi::HWND,

    /// This represents a "draw context" for the surface of the window.
    hdc: ffi::HDC,

    /// OpenGL context.
    context: ffi::HGLRC,

    /// Binded to `opengl32.dll`.
    ///
    /// `wglGetProcAddress` returns null for GL 1.1 functions because they are
    ///  already defined by the system. This module contains them.
    gl_library: ffi::HMODULE,

    /// Receiver for the events dispatched by the window callback.
    events_receiver: Receiver<Event>,

    /// True if a `Closed` event has been received.
    is_closed: AtomicBool,
}

impl Window {
    /// See the docs if the crate root file.
    pub fn new(builder: WindowBuilder) -> Result<Window, String> {
        init::new_window(builder)
    }

    /// See the docs if the crate root file.
    pub fn is_closed(&self) -> bool {
        use std::sync::atomics::Relaxed;
        self.is_closed.load(Relaxed)
    }

    /// See the docs if the crate root file.
    ///
    /// Calls SetWindowText on the HWND.
    pub fn set_title(&self, text: &str) {
        unsafe {
            ffi::SetWindowTextW(self.window,
                text.utf16_units().collect::<Vec<u16>>().append_one(0).as_ptr() as ffi::LPCWSTR);
        }
    }

    /// See the docs if the crate root file.
    pub fn get_position(&self) -> Option<(int, int)> {
        use std::mem;

        let mut placement: ffi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
        placement.length = mem::size_of::<ffi::WINDOWPLACEMENT>() as ffi::UINT;

        if unsafe { ffi::GetWindowPlacement(self.window, &mut placement) } == 0 {
            return None
        }

        let ref rect = placement.rcNormalPosition;
        Some((rect.left as int, rect.top as int))
    }

    /// See the docs if the crate root file.
    pub fn set_position(&self, x: int, y: int) {
        use libc;

        unsafe {
            ffi::SetWindowPos(self.window, ptr::mut_null(), x as libc::c_int, y as libc::c_int,
                0, 0, ffi::SWP_NOZORDER | ffi::SWP_NOSIZE);
            ffi::UpdateWindow(self.window);
        }
    }

    /// See the docs if the crate root file.
    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        use std::mem;
        let mut rect: ffi::RECT = unsafe { mem::uninitialized() };

        if unsafe { ffi::GetClientRect(self.window, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as uint,
            (rect.bottom - rect.top) as uint
        ))
    }

    /// See the docs if the crate root file.
    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        use std::mem;
        let mut rect: ffi::RECT = unsafe { mem::uninitialized() };

        if unsafe { ffi::GetWindowRect(self.window, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as uint,
            (rect.bottom - rect.top) as uint
        ))
    }

    /// See the docs if the crate root file.
    pub fn set_inner_size(&self, x: uint, y: uint) {
        use libc;

        unsafe {
            ffi::SetWindowPos(self.window, ptr::mut_null(), 0, 0, x as libc::c_int,
                y as libc::c_int, ffi::SWP_NOZORDER | ffi::SWP_NOREPOSITION);
            ffi::UpdateWindow(self.window);
        }
    }

    /// See the docs if the crate root file.
    // TODO: return iterator
    pub fn poll_events(&self) -> Vec<Event> {
        let mut events = Vec::new();
        loop {
            match self.events_receiver.try_recv() {
                Ok(ev) => events.push(ev),
                Err(_) => break
            }
        }

        // if one of the received events is `Closed`, setting `is_closed` to true
        if events.iter().find(|e| match e { &&::Closed => true, _ => false }).is_some() {
            use std::sync::atomics::Relaxed;
            self.is_closed.store(true, Relaxed);
        }

        events
    }

    /// See the docs if the crate root file.
    // TODO: return iterator
    pub fn wait_events(&self) -> Vec<Event> {
        match self.events_receiver.recv_opt() {
            Ok(ev) => {
                // if the received event is `Closed`, setting `is_closed` to true
                match ev {
                    ::Closed => {
                        use std::sync::atomics::Relaxed;
                        self.is_closed.store(true, Relaxed);
                    },
                    _ => ()
                };

                // looing for other possible events in the queue
                let mut result = self.poll_events();
                result.insert(0, ev);
                result
            },

            Err(_) => {
                use std::sync::atomics::Relaxed;
                self.is_closed.store(true, Relaxed);
                vec![]
            }
        }
    }

    /// See the docs if the crate root file.
    pub unsafe fn make_current(&self) {
        ffi::wglMakeCurrent(self.hdc, self.context)
    }

    /// See the docs if the crate root file.
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        use std::c_str::ToCStr;

        unsafe {
            addr.with_c_str(|s| {
                let p = ffi::wglGetProcAddress(s) as *const ();
                if !p.is_null() { return p; }
                ffi::GetProcAddress(self.gl_library, s) as *const ()
            })
        }
    }

    /// See the docs if the crate root file.
    pub fn swap_buffers(&self) {
        unsafe {
            ffi::SwapBuffers(self.hdc);
        }
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;
        unsafe { ffi::wglMakeCurrent(ptr::mut_null(), ptr::mut_null()); }
        unsafe { ffi::wglDeleteContext(self.context); }
        unsafe { ffi::DestroyWindow(self.window); }
    }
}
<commit_msg>Add failure if SwapBuffers returns an error<commit_after>use std::sync::atomics::AtomicBool;
use std::ptr;
use {Event, WindowBuilder};

pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};

mod event;
mod ffi;
mod init;
mod monitor;

/// The Win32 implementation of the main `Window` object.
pub struct Window {
    /// Main handle for the window.
    window: ffi::HWND,

    /// This represents a "draw context" for the surface of the window.
    hdc: ffi::HDC,

    /// OpenGL context.
    context: ffi::HGLRC,

    /// Binded to `opengl32.dll`.
    ///
    /// `wglGetProcAddress` returns null for GL 1.1 functions because they are
    ///  already defined by the system. This module contains them.
    gl_library: ffi::HMODULE,

    /// Receiver for the events dispatched by the window callback.
    events_receiver: Receiver<Event>,

    /// True if a `Closed` event has been received.
    is_closed: AtomicBool,
}

impl Window {
    /// See the docs if the crate root file.
    pub fn new(builder: WindowBuilder) -> Result<Window, String> {
        init::new_window(builder)
    }

    /// See the docs if the crate root file.
    pub fn is_closed(&self) -> bool {
        use std::sync::atomics::Relaxed;
        self.is_closed.load(Relaxed)
    }

    /// See the docs if the crate root file.
    ///
    /// Calls SetWindowText on the HWND.
    pub fn set_title(&self, text: &str) {
        unsafe {
            ffi::SetWindowTextW(self.window,
                text.utf16_units().collect::<Vec<u16>>().append_one(0).as_ptr() as ffi::LPCWSTR);
        }
    }

    /// See the docs if the crate root file.
    pub fn get_position(&self) -> Option<(int, int)> {
        use std::mem;

        let mut placement: ffi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
        placement.length = mem::size_of::<ffi::WINDOWPLACEMENT>() as ffi::UINT;

        if unsafe { ffi::GetWindowPlacement(self.window, &mut placement) } == 0 {
            return None
        }

        let ref rect = placement.rcNormalPosition;
        Some((rect.left as int, rect.top as int))
    }

    /// See the docs if the crate root file.
    pub fn set_position(&self, x: int, y: int) {
        use libc;

        unsafe {
            ffi::SetWindowPos(self.window, ptr::mut_null(), x as libc::c_int, y as libc::c_int,
                0, 0, ffi::SWP_NOZORDER | ffi::SWP_NOSIZE);
            ffi::UpdateWindow(self.window);
        }
    }

    /// See the docs if the crate root file.
    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        use std::mem;
        let mut rect: ffi::RECT = unsafe { mem::uninitialized() };

        if unsafe { ffi::GetClientRect(self.window, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as uint,
            (rect.bottom - rect.top) as uint
        ))
    }

    /// See the docs if the crate root file.
    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        use std::mem;
        let mut rect: ffi::RECT = unsafe { mem::uninitialized() };

        if unsafe { ffi::GetWindowRect(self.window, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as uint,
            (rect.bottom - rect.top) as uint
        ))
    }

    /// See the docs if the crate root file.
    pub fn set_inner_size(&self, x: uint, y: uint) {
        use libc;

        unsafe {
            ffi::SetWindowPos(self.window, ptr::mut_null(), 0, 0, x as libc::c_int,
                y as libc::c_int, ffi::SWP_NOZORDER | ffi::SWP_NOREPOSITION);
            ffi::UpdateWindow(self.window);
        }
    }

    /// See the docs if the crate root file.
    // TODO: return iterator
    pub fn poll_events(&self) -> Vec<Event> {
        let mut events = Vec::new();
        loop {
            match self.events_receiver.try_recv() {
                Ok(ev) => events.push(ev),
                Err(_) => break
            }
        }

        // if one of the received events is `Closed`, setting `is_closed` to true
        if events.iter().find(|e| match e { &&::Closed => true, _ => false }).is_some() {
            use std::sync::atomics::Relaxed;
            self.is_closed.store(true, Relaxed);
        }

        events
    }

    /// See the docs if the crate root file.
    // TODO: return iterator
    pub fn wait_events(&self) -> Vec<Event> {
        match self.events_receiver.recv_opt() {
            Ok(ev) => {
                // if the received event is `Closed`, setting `is_closed` to true
                match ev {
                    ::Closed => {
                        use std::sync::atomics::Relaxed;
                        self.is_closed.store(true, Relaxed);
                    },
                    _ => ()
                };

                // looing for other possible events in the queue
                let mut result = self.poll_events();
                result.insert(0, ev);
                result
            },

            Err(_) => {
                use std::sync::atomics::Relaxed;
                self.is_closed.store(true, Relaxed);
                vec![]
            }
        }
    }

    /// See the docs if the crate root file.
    pub unsafe fn make_current(&self) {
        ffi::wglMakeCurrent(self.hdc, self.context)
    }

    /// See the docs if the crate root file.
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        use std::c_str::ToCStr;

        unsafe {
            addr.with_c_str(|s| {
                let p = ffi::wglGetProcAddress(s) as *const ();
                if !p.is_null() { return p; }
                ffi::GetProcAddress(self.gl_library, s) as *const ()
            })
        }
    }

    /// See the docs if the crate root file.
    pub fn swap_buffers(&self) {
        unsafe {
            if ffi::SwapBuffers(self.hdc) == 0 {
                use std::os;
                fail!("{}", os::error_string(os::errno()));
            }
        }
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;
        unsafe { ffi::wglMakeCurrent(ptr::mut_null(), ptr::mut_null()); }
        unsafe { ffi::wglDeleteContext(self.context); }
        unsafe { ffi::DestroyWindow(self.window); }
    }
}
<|endoftext|>


<commit_before>use failure::{Error, Fail, bail, ensure};

use super::util;
use super::loader;
use super::arch::{Arch};
use super::loader::{LoadedModule, Loader};

#[derive(Debug, Fail)]
pub enum WorkspaceError {
    #[fail(display = "The given buffer is not supported (arch/plat/file format)")]
    NotSupported,
}

pub struct Workspace<A: Arch> {
    // name or source of the file
    pub filename: String,
    // raw bytes of the file
    pub buf: Vec<u8>,

    pub loader: Box<dyn Loader<A>>,
    pub module: LoadedModule<A>,

    // analysis {
    //   flowmeta,
    //   datameta,
    //   symbols,
    //   functions,
    // }
}

impl<A: Arch + 'static> Workspace<A> {
    /// Create a workspace and load the given bytes.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::arch::*;
    /// use lancelot::workspace::Workspace;
    ///
    /// Workspace::<Arch32>::from_bytes("foo.bin", b"\xEB\xFE")
    ///   .map(|ws| {
    ///     assert_eq!(ws.loader.get_name(),       "Windows/32/Raw");
    ///     assert_eq!(ws.module.base_address,     0x0);
    ///     assert_eq!(ws.module.sections[0].name, "raw");
    ///   })
    ///   .map_err(|e| panic!(e));
    /// ```
    pub fn from_bytes(filename: &str, buf: &[u8]) -> Result<Workspace<A>, Error> {
        let buf = buf.to_vec();
        let (ldr, module) = loader::load::<A>(&buf)?;

        Ok(Workspace::<A>{
            filename: filename.to_string(),
            buf: buf,
            loader: ldr,
            module: module,
        })
    }

    pub fn from_file(filename: &str) -> Result<Workspace<A>, Error> {
        let buf = util::read_file(filename)?;
        Workspace::from_bytes(filename, &buf)
    }

    // API:
    //   get_insn
    //   get_byte/word/dword
    //   get_xrefs_to
    //   get_xrefs_from
    //   get_functions

    // elsewhere:
    //   call graph
    //   control flow graph
}
<commit_msg>workspace: add method read_bytes<commit_after>use num::{ToPrimitive};
use failure::{Error, Fail, bail, ensure};

use super::util;
use super::loader;
use super::arch;
use super::arch::{Arch};
use super::loader::{LoadedModule, Loader, Section};

#[derive(Debug, Fail)]
pub enum WorkspaceError {
    #[fail(display = "The given buffer is not supported (arch/plat/file format)")]
    NotSupported,
    #[fail(display = "The given address is not mapped")]
    InvalidAddress,
    #[fail(display = "Buffer overrun")]
    BufferOverrun,
}

pub struct Workspace<A: Arch> {
    // name or source of the file
    pub filename: String,
    // raw bytes of the file
    pub buf: Vec<u8>,

    pub loader: Box<dyn Loader<A>>,
    pub module: LoadedModule<A>,

    // analysis {
    //   flowmeta,
    //   datameta,
    //   symbols,
    //   functions,
    // }
}

impl<A: Arch + 'static> Workspace<A> {
    /// Create a workspace and load the given bytes.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::arch::*;
    /// use lancelot::workspace::Workspace;
    ///
    /// Workspace::<Arch32>::from_bytes("foo.bin", b"\xEB\xFE")
    ///   .map(|ws| {
    ///     assert_eq!(ws.loader.get_name(),       "Windows/32/Raw");
    ///     assert_eq!(ws.module.base_address,     0x0);
    ///     assert_eq!(ws.module.sections[0].name, "raw");
    ///   })
    ///   .map_err(|e| panic!(e));
    /// ```
    pub fn from_bytes(filename: &str, buf: &[u8]) -> Result<Workspace<A>, Error> {
        let buf = buf.to_vec();
        let (ldr, module) = loader::load::<A>(&buf)?;

        Ok(Workspace::<A>{
            filename: filename.to_string(),
            buf: buf,
            loader: ldr,
            module: module,
        })
    }

    // TODO: maybe use the builder pattern here,
    //  so that you can optionally specify the loader you'd like to use.
    //
    // For example:
    //
    // ```
    //  Workspace::<Arch32>::new()
    //    .with_file("foo.bin")
    //    .with_loader(loader::ShellcodeLoader::<Arch32>::new(...))
    //    .load();
    // ```
    pub fn from_file(filename: &str) -> Result<Workspace<A>, Error> {
        let buf = util::read_file(filename)?;
        Workspace::from_bytes(filename, &buf)
    }

    /// Create a workspace and load the given bytes.
    ///
    /// Errors:
    ///
    ///   - InvalidAddress - if the address is not mapped.
    ///   - BufferOverrun - if the requested region runs beyond the matching section.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::arch::*;
    /// use lancelot::workspace::Workspace;
    ///
    /// // TODO: use exactly the shellcode loader.
    ///
    /// Workspace::<Arch32>::from_bytes("foo.bin", b"\xEB\xFE")
    ///   .map(|ws| {
    ///     assert_eq!(ws.read_bytes(0x0, 0x1).unwrap().to_vec(), b"\xEB");
    ///     assert_eq!(ws.read_bytes(0x1, 0x1).unwrap().to_vec(), b"\xFE");
    ///     assert_eq!(ws.read_bytes(0x0, 0x2).unwrap().to_vec(), b"\xEB\xFE");
    ///     assert_eq!(ws.read_bytes(0x0, 0x3).is_err(), true);
    ///     assert_eq!(ws.read_bytes(0x2, 0x1).is_err(), true);
    ///   })
    ///   .map_err(|e| panic!(e));
    /// ```
    pub fn read_bytes(&self, rva: A::RVA, length: usize) -> Result<&[u8], Error> {
        self.module.sections
            .iter()
            .filter(|section| section.contains(rva))
            .nth(0)
            .ok_or(WorkspaceError::InvalidAddress.into())
            .and_then(|section| -> Result<&[u8], Error> {
                // rva is guaranteed to be within this section,
                // so we can do an unchecked subtract here.
                let offset = rva - section.addr;
                A::RVA::to_usize(&offset)
                    .ok_or(WorkspaceError::InvalidAddress.into())
                    .and_then(|offset| {
                        if offset + length > section.buf.len() {
                            Err(WorkspaceError::BufferOverrun.into())
                        } else {
                            Ok(&section.buf[offset..offset+length])
                        }
                    })
            })
    }

    // API:
    //   get_insn
    //   get_byte/word/dword
    //   get_xrefs_to
    //   get_xrefs_from
    //   get_functions

    // elsewhere:
    //   call graph
    //   control flow graph
}
<|endoftext|>


<commit_before>extern crate osmpbfreader;
use std::collections::{HashMap, HashSet};
use models::*;
use categorize::*;
use std;

// Way as represented in OpenStreetMap
struct Way {
    id: i64,
    nodes: Vec<i64>,
    properties: EdgeProperties,
}

struct Reader {
    nodes: HashMap<i64, Node>,
    ways: Vec<Way>,
    nodes_to_keep: HashSet<i64>,
}

impl Reader {
    fn new() -> Reader {
        Reader {
            nodes: HashMap::new(),
            ways: Vec::new(),
            nodes_to_keep: HashSet::new(),
        }
    }

    fn count_nodes_uses(&mut self) {
        for way in &self.ways {
            for (i, node_id) in way.nodes.iter().enumerate() {
                if let Some(node) = self.nodes.get_mut(node_id) {
                    // Count double extremities nodes
                    if i == 0 || i == way.nodes.len() - 1 {
                        node.uses += 2;
                    } else {
                        node.uses += 1;
                    }
                } else {
                    panic!("Missing node, id: {}", node_id)
                }
            }
        }
    }

    fn split_way(&self, way: &Way) -> Vec<Edge> {
        let mut result = Vec::new();

        let mut source = 0;
        let mut geometry = Vec::new();
        for (i, &node_id) in way.nodes.iter().enumerate() {
            let node = self.nodes[&node_id];
            if i == 0 {
                source = node_id;
                geometry.push(node.coord);
            } else {
                geometry.push(node.coord);

                if node.uses > 1 {
                    result.push(Edge {
                        id: way.id,
                        source: source,
                        target: node_id,
                        geometry: geometry,
                        properties: way.properties,
                    });

                    source = node_id;
                    geometry = vec![node.coord];
                }
            }
        }
        result
    }

    fn read_ways(&mut self, file: std::fs::File) {
        let mut pbf = osmpbfreader::OsmPbfReader::new(file);
        for obj in pbf.iter() {
            match obj {
                osmpbfreader::OsmObj::Way(way) => {
                    let mut properties = EdgeProperties::new();
                    for (key, val) in way.tags {
                        properties.update(key, val);
                    }
                    properties.normalize();
                    if properties.accessible() {
                        for node in &way.nodes {
                            self.nodes_to_keep.insert(node.clone());
                        }
                        self.ways.push(Way {
                            id: way.id,
                            nodes: way.nodes,
                            properties: properties,
                        });

                    }
                }
                _ => {}
            }
        }
    }

    fn read_nodes(&mut self, file: std::fs::File) {
        let mut pbf = osmpbfreader::OsmPbfReader::new(file);
        self.nodes.reserve(self.nodes_to_keep.len());
        for obj in pbf.iter() {
            match obj {
                osmpbfreader::OsmObj::Node(node) => {
                    if self.nodes_to_keep.contains(&node.id) {
                        self.nodes_to_keep.remove(&node.id);
                        let mut n = Node::new();
                        n.id = node.id;
                        n.coord = Coord {
                            lon: node.lon,
                            lat: node.lat,
                        };
                        self.nodes.insert(node.id, n);
                    }
                }
                _ => {}
            }
        }
    }

    fn nodes(self) -> Vec<Node> {
        self.nodes
            .into_iter()
            .map(|(_, node)| node)
            .filter(|node| node.uses > 1)
            .collect()
    }

    fn edges(&self) -> Vec<Edge> {
        self.ways.iter().flat_map(|way| self.split_way(way)).collect()
    }
}

// Read all the nodes and ways of the osm.pbf file
pub fn read(filename: &str) -> Result<(Vec<Node>, Vec<Edge>), String> {
    let mut r = Reader::new();
    let path = std::path::Path::new(filename);
    let file = try!(std::fs::File::open(&path).map_err(|e| e.to_string()));
    r.read_ways(file);
    let file_nodes = try!(std::fs::File::open(&path).map_err(|e| e.to_string()));
    r.read_nodes(file_nodes);
    r.count_nodes_uses();
    let edges = r.edges();
    Ok((r.nodes(), edges))
}

#[test]
fn test_real_all() {
    let (nodes, ways) = read("src/osm4routing/test_data/minimal.osm.pbf").unwrap();
    assert_eq!(2, nodes.len());
    assert_eq!(1, ways.len());
}

#[test]
fn test_count_nodes() {
    let ways = vec![Way {
                        id: 0,
                        nodes: vec![1, 2, 3],
                        properties: EdgeProperties::new(),
                    }];
    let mut nodes = HashMap::new();
    nodes.insert(1, Node::new());
    nodes.insert(2, Node::new());
    nodes.insert(3, Node::new());
    let mut r = Reader {
        ways: ways,
        nodes: nodes,
        nodes_to_keep: HashSet::new(),
    };
    r.count_nodes_uses();
    assert_eq!(2, r.nodes[&1].uses);
    assert_eq!(1, r.nodes[&2].uses);
    assert_eq!(2, r.nodes[&3].uses);

    assert_eq!(2, r.nodes().len());
}

#[test]
fn test_split() {
    let mut nodes = HashMap::new();
    nodes.insert(1, Node::new());
    nodes.insert(2, Node::new());
    nodes.insert(3, Node::new());
    nodes.insert(4, Node::new());
    nodes.insert(5, Node::new());
    let ways = vec![Way {
                        id: 0,
                        nodes: vec![1, 2, 3],
                        properties: EdgeProperties::new(),
                    },
                    Way {
                        id: 0,
                        nodes: vec![4, 5, 2],
                        properties: EdgeProperties::new(),
                    }];
    let mut r = Reader {
        nodes: nodes,
        ways: ways,
        nodes_to_keep: HashSet::new(),
    };
    r.count_nodes_uses();
    let edges = r.edges();
    assert_eq!(3, edges.len());
}

#[test]
fn test_wrong_file() {
    let r = read("i hope you have no file name like this one");
    assert!(r.is_err());
}
<commit_msg>Replace deprecated try! with ?<commit_after>extern crate osmpbfreader;
use std::collections::{HashMap, HashSet};
use models::*;
use categorize::*;
use std;

// Way as represented in OpenStreetMap
struct Way {
    id: i64,
    nodes: Vec<i64>,
    properties: EdgeProperties,
}

struct Reader {
    nodes: HashMap<i64, Node>,
    ways: Vec<Way>,
    nodes_to_keep: HashSet<i64>,
}

impl Reader {
    fn new() -> Reader {
        Reader {
            nodes: HashMap::new(),
            ways: Vec::new(),
            nodes_to_keep: HashSet::new(),
        }
    }

    fn count_nodes_uses(&mut self) {
        for way in &self.ways {
            for (i, node_id) in way.nodes.iter().enumerate() {
                if let Some(node) = self.nodes.get_mut(node_id) {
                    // Count double extremities nodes
                    if i == 0 || i == way.nodes.len() - 1 {
                        node.uses += 2;
                    } else {
                        node.uses += 1;
                    }
                } else {
                    panic!("Missing node, id: {}", node_id)
                }
            }
        }
    }

    fn split_way(&self, way: &Way) -> Vec<Edge> {
        let mut result = Vec::new();

        let mut source = 0;
        let mut geometry = Vec::new();
        for (i, &node_id) in way.nodes.iter().enumerate() {
            let node = self.nodes[&node_id];
            if i == 0 {
                source = node_id;
                geometry.push(node.coord);
            } else {
                geometry.push(node.coord);

                if node.uses > 1 {
                    result.push(Edge {
                        id: way.id,
                        source: source,
                        target: node_id,
                        geometry: geometry,
                        properties: way.properties,
                    });

                    source = node_id;
                    geometry = vec![node.coord];
                }
            }
        }
        result
    }

    fn read_ways(&mut self, file: std::fs::File) {
        let mut pbf = osmpbfreader::OsmPbfReader::new(file);
        for obj in pbf.iter() {
            match obj {
                osmpbfreader::OsmObj::Way(way) => {
                    let mut properties = EdgeProperties::new();
                    for (key, val) in way.tags {
                        properties.update(key, val);
                    }
                    properties.normalize();
                    if properties.accessible() {
                        for node in &way.nodes {
                            self.nodes_to_keep.insert(node.clone());
                        }
                        self.ways.push(Way {
                            id: way.id,
                            nodes: way.nodes,
                            properties: properties,
                        });

                    }
                }
                _ => {}
            }
        }
    }

    fn read_nodes(&mut self, file: std::fs::File) {
        let mut pbf = osmpbfreader::OsmPbfReader::new(file);
        self.nodes.reserve(self.nodes_to_keep.len());
        for obj in pbf.iter() {
            match obj {
                osmpbfreader::OsmObj::Node(node) => {
                    if self.nodes_to_keep.contains(&node.id) {
                        self.nodes_to_keep.remove(&node.id);
                        let mut n = Node::new();
                        n.id = node.id;
                        n.coord = Coord {
                            lon: node.lon,
                            lat: node.lat,
                        };
                        self.nodes.insert(node.id, n);
                    }
                }
                _ => {}
            }
        }
    }

    fn nodes(self) -> Vec<Node> {
        self.nodes
            .into_iter()
            .map(|(_, node)| node)
            .filter(|node| node.uses > 1)
            .collect()
    }

    fn edges(&self) -> Vec<Edge> {
        self.ways.iter().flat_map(|way| self.split_way(way)).collect()
    }
}

// Read all the nodes and ways of the osm.pbf file
pub fn read(filename: &str) -> Result<(Vec<Node>, Vec<Edge>), String> {
    let mut r = Reader::new();
    let path = std::path::Path::new(filename);
    let file = std::fs::File::open(&path).map_err(|e| e.to_string())?;
    r.read_ways(file);
    let file_nodes = std::fs::File::open(&path).map_err(|e| e.to_string())?;
    r.read_nodes(file_nodes);
    r.count_nodes_uses();
    let edges = r.edges();
    Ok((r.nodes(), edges))
}

#[test]
fn test_real_all() {
    let (nodes, ways) = read("src/osm4routing/test_data/minimal.osm.pbf").unwrap();
    assert_eq!(2, nodes.len());
    assert_eq!(1, ways.len());
}

#[test]
fn test_count_nodes() {
    let ways = vec![Way {
                        id: 0,
                        nodes: vec![1, 2, 3],
                        properties: EdgeProperties::new(),
                    }];
    let mut nodes = HashMap::new();
    nodes.insert(1, Node::new());
    nodes.insert(2, Node::new());
    nodes.insert(3, Node::new());
    let mut r = Reader {
        ways: ways,
        nodes: nodes,
        nodes_to_keep: HashSet::new(),
    };
    r.count_nodes_uses();
    assert_eq!(2, r.nodes[&1].uses);
    assert_eq!(1, r.nodes[&2].uses);
    assert_eq!(2, r.nodes[&3].uses);

    assert_eq!(2, r.nodes().len());
}

#[test]
fn test_split() {
    let mut nodes = HashMap::new();
    nodes.insert(1, Node::new());
    nodes.insert(2, Node::new());
    nodes.insert(3, Node::new());
    nodes.insert(4, Node::new());
    nodes.insert(5, Node::new());
    let ways = vec![Way {
                        id: 0,
                        nodes: vec![1, 2, 3],
                        properties: EdgeProperties::new(),
                    },
                    Way {
                        id: 0,
                        nodes: vec![4, 5, 2],
                        properties: EdgeProperties::new(),
                    }];
    let mut r = Reader {
        nodes: nodes,
        ways: ways,
        nodes_to_keep: HashSet::new(),
    };
    r.count_nodes_uses();
    let edges = r.edges();
    assert_eq!(3, edges.len());
}

#[test]
fn test_wrong_file() {
    let r = read("i hope you have no file name like this one");
    assert!(r.is_err());
}
<|endoftext|>


<commit_before>use super::util::{CacheKeyPath,
                  ConfigOptCacheKeyPath};
use configopt::ConfigOpt;
use structopt::StructOpt;

arg_enum! {
    #[derive(Deserialize)]
    pub enum Shell {
        Bash,
        Fish,
        Zsh,
        PowerShell,
    }
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
/// Commands relating to Habitat runtime config
pub enum Cli {
    /// Sets up the CLI with reasonable defaults
    #[structopt(no_version)]
    Setup(CacheKeyPath),
    /// Creates command-line completers for your shell
    #[structopt(no_version)]
    Completers {
        /// The name of the shell you want to generate the command-completion
        #[structopt(name = "SHELL",
                    short = "s",
                    long = "shell",
                    possible_values = &Shell::variants(),
                    case_insensitive = true)]
        shell: Shell,
    },
}
<commit_msg>[Refactor] move cli setup into its own struct<commit_after>use super::util::{CacheKeyPath,
                  ConfigOptCacheKeyPath};
use configopt::ConfigOpt;
use structopt::StructOpt;

arg_enum! {
    #[derive(Deserialize)]
    pub enum Shell {
        Bash,
        Fish,
        Zsh,
        PowerShell,
    }
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
/// Commands relating to Habitat runtime config
pub enum Cli {
    /// Sets up the CLI with reasonable defaults
    Setup(CacheKeyPath),
    /// Creates command-line completers for your shell
    #[structopt(no_version)]
    Completers {
        /// The name of the shell you want to generate the command-completion
        #[structopt(name = "SHELL",
                    short = "s",
                    long = "shell",
                    possible_values = &Shell::variants(),
                    case_insensitive = true)]
        shell: Shell,
    },
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "setup", no_version, rename_all = "screamingsnake")]
/// Sets up the CLI with reasonable defaults
pub struct CliSetup {
    #[structopt(flatten)]
    cache_key_path: CacheKeyPath
}<|endoftext|>


<commit_before>use std;
use rustc;

// -*- rust -*-
import result::{ok, err};
import std::getopts;
import io::writer_util;
import getopts::{opt_present};
import rustc::driver::driver::*;
import rustc::syntax::codemap;
import rustc::driver::diagnostic;

fn version(argv0: str) {
    let vers = "unknown version";
    let env_vers = #env["CFG_VERSION"];
    if str::len(env_vers) != 0u { vers = env_vers; }
    io::stdout().write_str(#fmt["%s %s\n", argv0, vers]);
    io::stdout().write_str(#fmt["host: %s\n", host_triple()]);
}

fn usage(argv0: str) {
    io::stdout().write_str(#fmt["Usage: %s [options] <input>\n", argv0] +
                               "
Options:

    --bin              Compile an executable crate (default)
    -c                 Compile and assemble, but do not link
    --cfg <cfgspec>    Configure the compilation environment
    --emit-llvm        Produce an LLVM bitcode file
    -g                 Produce debug info
    --gc               Garbage collect shared data (experimental/temporary)
    -h --help          Display this message
    -L <path>          Add a directory to the library search path
    --lib              Compile a library crate
    --ls               List the symbols defined by a compiled library crate
    --no-asm-comments  Do not add comments into the assembly source
    --no-lint-ctypes   Suppress warnings for possibly incorrect ctype usage
    --no-trans         Run all passes except translation; no output
    --no-verify        Suppress LLVM verification step (slight speedup)
                       (see http://llvm.org/docs/Passes.html for detail)
    -O                 Equivalent to --opt-level=2
    -o <filename>      Write output to <filename>
    --opt-level <lvl>  Optimize with possible levels 0-3
    --out-dir <dir>    Write output to compiler-chosen filename in <dir>
    --parse-only       Parse only; do not compile, assemble, or link
    --pretty [type]    Pretty-print the input instead of compiling;
                       valid types are: normal (un-annotated source),
                       expanded (crates expanded), typed (crates expanded,
                       with type annotations), or identified (fully
                       parenthesized, AST nodes and blocks with IDs)
    -S                 Compile only; do not assemble or link
    --save-temps       Write intermediate files (.bc, .opt.bc, .o)
                       in addition to normal output
    --static           Use or produce static libraries or binaries
    --stats            Print compilation statistics
    --sysroot <path>   Override the system root
    --test             Build a test harness
    --target <triple>  Target cpu-manufacturer-kernel[-os] to compile for
                       (default: host triple)
                       (see http://sources.redhat.com/autobook/autobook/
                       autobook_17.html for detail)

    --time-passes      Time the individual phases of the compiler
    --time-llvm-passes Time the individual phases of the LLVM backend
    -v --version       Print version info and exit
    --warn-unused-imports
                       Warn about unnecessary imports

");
}

fn run_compiler(args: [str], demitter: diagnostic::emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    logging::console_off();

    let args = args, binary = vec::shift(args);

    if vec::len(args) == 0u { usage(binary); ret; }

    let match =
        alt getopts::getopts(args, opts()) {
          ok(m) { m }
          err(f) {
            early_error(demitter, getopts::fail_str(f))
          }
        };
    if opt_present(match, "h") || opt_present(match, "help") {
        usage(binary);
        ret;
    }
    if opt_present(match, "v") || opt_present(match, "version") {
        version(binary);
        ret;
    }
    let ifile = alt vec::len(match.free) {
      0u { early_error(demitter, "o input filename given") }
      1u { match.free[0] }
      _ { early_error(demitter, "multiple input filenames provided") }
    };

    let sopts = build_session_options(match, demitter);
    let sess = build_session(sopts, ifile, demitter);
    let odir = getopts::opt_maybe_str(match, "out-dir");
    let ofile = getopts::opt_maybe_str(match, "o");
    let cfg = build_configuration(sess, binary, ifile);
    let pretty =
        option::map(getopts::opt_default(match, "pretty",
                                         "normal"),
                    bind parse_pretty(sess, _));
    alt pretty {
      some::<pp_mode>(ppm) { pretty_print_input(sess, cfg, ifile, ppm); ret; }
      none::<pp_mode> {/* continue */ }
    }
    let ls = opt_present(match, "ls");
    if ls {
        list_metadata(sess, ifile, io::stdout());
        ret;
    }

    compile_input(sess, cfg, ifile, odir, ofile);
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
fn monitor(f: fn~(diagnostic::emitter)) {
    enum monitor_msg {
        fatal,
        done,
    };

    let p = comm::port();
    let ch = comm::chan(p);

    alt task::try  {||

        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter = fn@(cmsp: option<(codemap::codemap, codemap::span)>,
                           msg: str, lvl: diagnostic::level) {
            if lvl == diagnostic::fatal {
                comm::send(ch, fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        resource finally(ch: comm::chan<monitor_msg>) {
            comm::send(ch, done);
        }

        let _finally = finally(ch);

        f(demitter)
    } {
        result::ok(_) { /* fallthrough */ }
        result::err(_) {
            // Task failed without emitting a fatal diagnostic
            if comm::recv(p) == done {
                diagnostic::emit(
                    none,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::error);
                let note = "The compiler hit an unexpected failure path. \
                            This is a bug. Try running with \
                            RUST_LOG=rustc=0,::rt::backtrace \
                            to get further details and report the results \
                            to github.com/mozilla/rust/issues";
                diagnostic::emit(none, note, diagnostic::note);
            }
            // Fail so the process returns a failure code
            fail;
        }
    }
}

fn main(args: [str]) {
    monitor {|demitter|
        run_compiler(args, demitter);
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>rustc: Fix typo in error message<commit_after>use std;
use rustc;

// -*- rust -*-
import result::{ok, err};
import std::getopts;
import io::writer_util;
import getopts::{opt_present};
import rustc::driver::driver::*;
import rustc::syntax::codemap;
import rustc::driver::diagnostic;

fn version(argv0: str) {
    let vers = "unknown version";
    let env_vers = #env["CFG_VERSION"];
    if str::len(env_vers) != 0u { vers = env_vers; }
    io::stdout().write_str(#fmt["%s %s\n", argv0, vers]);
    io::stdout().write_str(#fmt["host: %s\n", host_triple()]);
}

fn usage(argv0: str) {
    io::stdout().write_str(#fmt["Usage: %s [options] <input>\n", argv0] +
                               "
Options:

    --bin              Compile an executable crate (default)
    -c                 Compile and assemble, but do not link
    --cfg <cfgspec>    Configure the compilation environment
    --emit-llvm        Produce an LLVM bitcode file
    -g                 Produce debug info
    --gc               Garbage collect shared data (experimental/temporary)
    -h --help          Display this message
    -L <path>          Add a directory to the library search path
    --lib              Compile a library crate
    --ls               List the symbols defined by a compiled library crate
    --no-asm-comments  Do not add comments into the assembly source
    --no-lint-ctypes   Suppress warnings for possibly incorrect ctype usage
    --no-trans         Run all passes except translation; no output
    --no-verify        Suppress LLVM verification step (slight speedup)
                       (see http://llvm.org/docs/Passes.html for detail)
    -O                 Equivalent to --opt-level=2
    -o <filename>      Write output to <filename>
    --opt-level <lvl>  Optimize with possible levels 0-3
    --out-dir <dir>    Write output to compiler-chosen filename in <dir>
    --parse-only       Parse only; do not compile, assemble, or link
    --pretty [type]    Pretty-print the input instead of compiling;
                       valid types are: normal (un-annotated source),
                       expanded (crates expanded), typed (crates expanded,
                       with type annotations), or identified (fully
                       parenthesized, AST nodes and blocks with IDs)
    -S                 Compile only; do not assemble or link
    --save-temps       Write intermediate files (.bc, .opt.bc, .o)
                       in addition to normal output
    --static           Use or produce static libraries or binaries
    --stats            Print compilation statistics
    --sysroot <path>   Override the system root
    --test             Build a test harness
    --target <triple>  Target cpu-manufacturer-kernel[-os] to compile for
                       (default: host triple)
                       (see http://sources.redhat.com/autobook/autobook/
                       autobook_17.html for detail)

    --time-passes      Time the individual phases of the compiler
    --time-llvm-passes Time the individual phases of the LLVM backend
    -v --version       Print version info and exit
    --warn-unused-imports
                       Warn about unnecessary imports

");
}

fn run_compiler(args: [str], demitter: diagnostic::emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    logging::console_off();

    let args = args, binary = vec::shift(args);

    if vec::len(args) == 0u { usage(binary); ret; }

    let match =
        alt getopts::getopts(args, opts()) {
          ok(m) { m }
          err(f) {
            early_error(demitter, getopts::fail_str(f))
          }
        };
    if opt_present(match, "h") || opt_present(match, "help") {
        usage(binary);
        ret;
    }
    if opt_present(match, "v") || opt_present(match, "version") {
        version(binary);
        ret;
    }
    let ifile = alt vec::len(match.free) {
      0u { early_error(demitter, "no input filename given") }
      1u { match.free[0] }
      _ { early_error(demitter, "multiple input filenames provided") }
    };

    let sopts = build_session_options(match, demitter);
    let sess = build_session(sopts, ifile, demitter);
    let odir = getopts::opt_maybe_str(match, "out-dir");
    let ofile = getopts::opt_maybe_str(match, "o");
    let cfg = build_configuration(sess, binary, ifile);
    let pretty =
        option::map(getopts::opt_default(match, "pretty",
                                         "normal"),
                    bind parse_pretty(sess, _));
    alt pretty {
      some::<pp_mode>(ppm) { pretty_print_input(sess, cfg, ifile, ppm); ret; }
      none::<pp_mode> {/* continue */ }
    }
    let ls = opt_present(match, "ls");
    if ls {
        list_metadata(sess, ifile, io::stdout());
        ret;
    }

    compile_input(sess, cfg, ifile, odir, ofile);
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
fn monitor(f: fn~(diagnostic::emitter)) {
    enum monitor_msg {
        fatal,
        done,
    };

    let p = comm::port();
    let ch = comm::chan(p);

    alt task::try  {||

        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter = fn@(cmsp: option<(codemap::codemap, codemap::span)>,
                           msg: str, lvl: diagnostic::level) {
            if lvl == diagnostic::fatal {
                comm::send(ch, fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        resource finally(ch: comm::chan<monitor_msg>) {
            comm::send(ch, done);
        }

        let _finally = finally(ch);

        f(demitter)
    } {
        result::ok(_) { /* fallthrough */ }
        result::err(_) {
            // Task failed without emitting a fatal diagnostic
            if comm::recv(p) == done {
                diagnostic::emit(
                    none,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::error);
                let note = "The compiler hit an unexpected failure path. \
                            This is a bug. Try running with \
                            RUST_LOG=rustc=0,::rt::backtrace \
                            to get further details and report the results \
                            to github.com/mozilla/rust/issues";
                diagnostic::emit(none, note, diagnostic::note);
            }
            // Fail so the process returns a failure code
            fail;
        }
    }
}

fn main(args: [str]) {
    monitor {|demitter|
        run_compiler(args, demitter);
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>#[crate_id(name="dirname", vers="1.0.0", author="Derek Chiang")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{print, stderr};
use extra::getopts::groups;

static VERSION: &'static str = "1.0.0";

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("z", "zero", "separate output with NUL rather than newline"),
        groups::optflag("", "help", "display this help and exit"),
        groups::optflag("", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer,
                "Invalid options\n{}", f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };

    if matches.opt_present("help") {
        println!("dirname {:s} - strip last component from file name", VERSION);
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION] NAME...", program);
        println!("");
        print(groups::usage("Output each NAME with its last non-slash component and trailing slashes
removed; if NAME contains no  /'s,  output  '.'  (meaning  the  current
directory).", opts));
        return;
    }

    if matches.opt_present("version") {
        return println!("dirname version: {:s}", VERSION);
    }

    let separator = match matches.opt_present("zero") {
        true => "\0",
        false => "\n"
    };

    if !matches.free.is_empty() {
        for path in matches.free.iter() {
            let p = std::path::Path::new(path.clone());
            let d = std::str::from_utf8(p.dirname());
            if d.is_some() {
                print(d.unwrap());
            }
            print(separator);
        }
    } else {
        println!("{0:s}: missing operand", program);
        println!("Try '{0:s} --help' for more information.", program);
    }
}
<commit_msg>replace writing to stderr with fail<commit_after>#[crate_id(name="dirname", vers="1.0.0", author="Derek Chiang")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::print;
use extra::getopts::groups;

static VERSION: &'static str = "1.0.0";

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("z", "zero", "separate output with NUL rather than newline"),
        groups::optflag("", "help", "display this help and exit"),
        groups::optflag("", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!("Invalid options\n{}", f.to_err_msg())
    };

    if matches.opt_present("help") {
        println!("dirname {:s} - strip last component from file name", VERSION);
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION] NAME...", program);
        println!("");
        print(groups::usage("Output each NAME with its last non-slash component and trailing slashes
removed; if NAME contains no  /'s,  output  '.'  (meaning  the  current
directory).", opts));
        return;
    }

    if matches.opt_present("version") {
        return println!("dirname version: {:s}", VERSION);
    }

    let separator = match matches.opt_present("zero") {
        true => "\0",
        false => "\n"
    };

    if !matches.free.is_empty() {
        for path in matches.free.iter() {
            let p = std::path::Path::new(path.clone());
            let d = std::str::from_utf8(p.dirname());
            if d.is_some() {
                print(d.unwrap());
            }
            print(separator);
        }
    } else {
        println!("{0:s}: missing operand", program);
        println!("Try '{0:s} --help' for more information.", program);
    }
}
<|endoftext|>