<commit_before>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate url;
#[phase(plugin, link)]
extern crate log;
extern crate http;
extern crate iron;
extern crate mount;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::{GetUrl, Serve};
use iron::middleware::{Status, Continue, Unwind};
use mount::OriginalUrl;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// This will attempt to serve static files from the given root path.
    /// The path may be relative or absolute. If `Path::new("")` is given,
    /// files will be served from the current directory.
    ///
    /// If a static file exists and can be read from, `enter` will serve it to
    /// the `Response` and `Unwind` the middleware stack with a status of `200`.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    /// If a file should have been read but cannot, due to permissions or
    /// read errors, a different `Middleware` should handle it.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }
}

impl Middleware for Static {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                // Check for requested file
                match res.serve_file(&self.root_path.join(
                    Path::new(
                        // Coerce to relative path.
                        // We include the slash to ensure that you never have a path like ".index.html"
                        // when you meant "./index.html", see http://is.gd/yz9p0B for an example.
                        "./".to_string().append(path.as_slice())))) {
                    Ok(()) => {
                        debug!("Serving static file at {}.",
                            &self.root_path.join("./".to_string().append(path.as_slice())).display());
                        return Unwind
                    },
                    Err(_) => ()
                }

                // Check for index.html
                let index_path = self.root_path.join(
                    Path::new("./".to_string().append(path.as_slice()))
                        .join("./index.html".to_string()));
                if index_path.is_file() {
                    // Avoid serving as a directory
                    match path.as_slice().char_at_reverse(path.len()) {
                        '/' => {
                            match res.serve_file(&index_path) {
                                Ok(()) => {
                                    debug!("Serving static file at {}.",
                                        &index_path.display());
                                    return Unwind
                                },
                                Err(err) => debug!("Failed while trying to serve index.html: {}", err)
                            }
                        },
                        // 303:
                        _   => {
                            let redirect_path = match alloy.find::<OriginalUrl>() {
                                Some(&OriginalUrl(ref original_url)) => original_url.clone(),
                                None => path.clone()
                            }.append("/");
                            res.headers.location = Some(::url::Url {
                                path: redirect_path.clone(),
                                scheme: "".to_string(),
                                user: None,
                                host: "".to_string(),
                                port: None,
                                query: vec![],
                                fragment: None
                            });
                            let _ = res.serve(::http::status::SeeOther,
                                format!("Redirecting to {}/", redirect_path).as_slice());
                            return Unwind
                        }
                    }
                }
            },
            None => ()
        }
        Continue
    }
}
<commit_msg>(fix) Avoid RTE with null path.<commit_after>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate url;
#[phase(plugin, link)]
extern crate log;
extern crate http;
extern crate iron;
extern crate mount;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::{GetUrl, Serve};
use iron::middleware::{Status, Continue, Unwind};
use mount::OriginalUrl;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// This will attempt to serve static files from the given root path.
    /// The path may be relative or absolute. If `Path::new("")` is given,
    /// files will be served from the current directory.
    ///
    /// If a static file exists and can be read from, `enter` will serve it to
    /// the `Response` and `Unwind` the middleware stack with a status of `200`.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    /// If a file should have been read but cannot, due to permissions or
    /// read errors, a different `Middleware` should handle it.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }
}

impl Middleware for Static {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                // Check for requested file
                match res.serve_file(&self.root_path.join(
                    Path::new(
                        // Coerce to relative path.
                        // We include the slash to ensure that you never have a path like ".index.html"
                        // when you meant "./index.html", see http://is.gd/yz9p0B for an example.
                        "./".to_string().append(path.as_slice())))) {
                    Ok(()) => {
                        debug!("Serving static file at {}.",
                            &self.root_path.join("./".to_string().append(path.as_slice())).display());
                        return Unwind
                    },
                    Err(_) => ()
                }

                // Check for index.html
                let index_path = self.root_path.join(
                    Path::new("./".to_string().append(path.as_slice()))
                        .join("./index.html".to_string()));
                if index_path.is_file() {
                    // Avoid serving as a directory
                    if path.len() > 0 {
                        match path.as_slice().char_at_reverse(path.len()) {
                            '/' => {
                                match res.serve_file(&index_path) {
                                    Ok(()) => {
                                        debug!("Serving static file at {}.",
                                            &index_path.display());
                                        return Unwind
                                    },
                                    Err(err) => {
                                        debug!("Failed while trying to serve index.html: {}", err)
                                        return Continue
                                    }
                                }
                            },
                    // 303:
                            _ => ()
                        }
                    }
                    let redirect_path = match alloy.find::<OriginalUrl>() {
                        Some(&OriginalUrl(ref original_url)) => original_url.clone(),
                        None => path.clone()
                    }.append("/");
                    res.headers.location = Some(::url::Url {
                        path: redirect_path.clone(),
                        scheme: "".to_string(),
                        user: None,
                        host: "".to_string(),
                        port: None,
                        query: vec![],
                        fragment: None
                    });
                    let _ = res.serve(::http::status::SeeOther,
                        format!("Redirecting to {}/", redirect_path).as_slice());
                    return Unwind
                }
            },
            None => ()
        }
        Continue
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod batch_iterator;
pub mod color;
pub mod data_provider;
pub mod errors;
pub mod math;
pub mod octree;
pub mod read_write;
pub mod s2_cells;

use cgmath::Vector3;
use errors::{ErrorKind, Result};
use std::collections::BTreeMap;

// Version 9 -> 10: Change in NodeId proto from level (u8) and index (u64) to high (u64) and low
// (u64). We are able to convert the proto on read, so the tools can still read version 9.
// Version 10 -> 11: Change in AxisAlignedCuboid proto from Vector3f min/max to Vector3d min/max.
// We are able to convert the proto on read, so the tools can still read version 9/10.
// Version 11 -> 12: Change in Meta names and structures, to allow both s2 and octree meta.
// We are able to convert the proto on read, so the tools can still read version 9/10/11.
pub const CURRENT_VERSION: i32 = 12;

#[derive(Debug, Clone)]
pub struct Point {
    pub position: cgmath::Vector3<f64>,
    // TODO(sirver): Make color optional, we might not always have it.
    pub color: color::Color<u8>,

    // The intensity of the point if it exists. This value is usually handed through directly by a
    // sensor and has therefore no defined range - or even meaning.
    pub intensity: Option<f32>,
}

pub fn attribute_extension(attribute: &str) -> &str {
    match attribute {
        "position" => "xyz",
        "color" => "rgb",
        _ => attribute,
    }
}

/// General field to describe point feature attributes such as color, intensity, ...
#[derive(Debug, Clone)]
pub enum AttributeData {
    U8(Vec<u8>),
    I64(Vec<i64>),
    U64(Vec<u64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    U8Vec3(Vec<Vector3<u8>>),
    F64Vec3(Vec<Vector3<f64>>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttributeDataType {
    U8,
    I64,
    U64,
    F32,
    F64,
    U8Vec3,
    F64Vec3,
}

impl AttributeDataType {
    pub fn to_proto(&self) -> proto::AttributeDataType {
        match self {
            AttributeDataType::U8 => proto::AttributeDataType::U8,
            AttributeDataType::I64 => proto::AttributeDataType::I64,
            AttributeDataType::U64 => proto::AttributeDataType::U64,
            AttributeDataType::F32 => proto::AttributeDataType::F32,
            AttributeDataType::F64 => proto::AttributeDataType::F64,
            AttributeDataType::U8Vec3 => proto::AttributeDataType::U8Vec3,
            AttributeDataType::F64Vec3 => proto::AttributeDataType::F64Vec3,
        }
    }

    pub fn from_proto(attr_proto: proto::AttributeDataType) -> Result<Self> {
        let attr = match attr_proto {
            proto::AttributeDataType::U8 => AttributeDataType::U8,
            proto::AttributeDataType::I64 => AttributeDataType::I64,
            proto::AttributeDataType::U64 => AttributeDataType::U64,
            proto::AttributeDataType::F32 => AttributeDataType::F32,
            proto::AttributeDataType::F64 => AttributeDataType::F64,
            proto::AttributeDataType::U8Vec3 => AttributeDataType::U8Vec3,
            proto::AttributeDataType::F64Vec3 => AttributeDataType::F64Vec3,
            proto::AttributeDataType::U16
            | proto::AttributeDataType::U32
            | proto::AttributeDataType::I8
            | proto::AttributeDataType::I16
            | proto::AttributeDataType::I32 => {
                return Err(ErrorKind::InvalidInput(
                    "Attribute data type not supported yet".to_string(),
                )
                .into())
            }
            proto::AttributeDataType::INVALID_DATA_TYPE => {
                return Err(
                    ErrorKind::InvalidInput("Attribute data type invalid".to_string()).into(),
                )
            }
        };
        Ok(attr)
    }

    pub fn size_of(&self) -> usize {
        match self {
            AttributeDataType::U8 => 1,
            AttributeDataType::F32 => 4,
            AttributeDataType::I64 | AttributeDataType::U64 | AttributeDataType::F64 => 8,
            AttributeDataType::U8Vec3 => 3,
            AttributeDataType::F64Vec3 => 3 * 8,
        }
    }
}

impl AttributeData {
    pub fn len(&self) -> usize {
        match self {
            AttributeData::U8(data) => data.len(),
            AttributeData::I64(data) => data.len(),
            AttributeData::U64(data) => data.len(),
            AttributeData::F32(data) => data.len(),
            AttributeData::F64(data) => data.len(),
            AttributeData::U8Vec3(data) => data.len(),
            AttributeData::F64Vec3(data) => data.len(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn dim(&self) -> usize {
        match self {
            AttributeData::U8(_)
            | AttributeData::I64(_)
            | AttributeData::U64(_)
            | AttributeData::F32(_)
            | AttributeData::F64(_) => 1,
            AttributeData::U8Vec3(_) | AttributeData::F64Vec3(_) => 3,
        }
    }

    pub fn data_type(&self) -> AttributeDataType {
        match self {
            AttributeData::U8(_) => AttributeDataType::U8,
            AttributeData::I64(_) => AttributeDataType::I64,
            AttributeData::U64(_) => AttributeDataType::U64,
            AttributeData::F32(_) => AttributeDataType::F32,
            AttributeData::F64(_) => AttributeDataType::F64,
            AttributeData::U8Vec3(_) => AttributeDataType::U8Vec3,
            AttributeData::F64Vec3(_) => AttributeDataType::F64Vec3,
        }
    }
}

/// General structure that contains points and attached feature attributes.
#[derive(Debug, Clone)]
pub struct PointsBatch {
    pub position: Vec<Vector3<f64>>,
    // BTreeMap for deterministic iteration order.
    pub attributes: BTreeMap<String, AttributeData>,
}

pub use point_viewer_proto_rust::proto;

/// size for batch
pub const NUM_POINTS_PER_BATCH: usize = 500_000;
<commit_msg>Extract data from attribute data. (#342)<commit_after>// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod batch_iterator;
pub mod color;
pub mod data_provider;
pub mod errors;
pub mod math;
pub mod octree;
pub mod read_write;
pub mod s2_cells;

use cgmath::Vector3;
use errors::{ErrorKind, Result};
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};

// Version 9 -> 10: Change in NodeId proto from level (u8) and index (u64) to high (u64) and low
// (u64). We are able to convert the proto on read, so the tools can still read version 9.
// Version 10 -> 11: Change in AxisAlignedCuboid proto from Vector3f min/max to Vector3d min/max.
// We are able to convert the proto on read, so the tools can still read version 9/10.
// Version 11 -> 12: Change in Meta names and structures, to allow both s2 and octree meta.
// We are able to convert the proto on read, so the tools can still read version 9/10/11.
pub const CURRENT_VERSION: i32 = 12;

#[derive(Debug, Clone)]
pub struct Point {
    pub position: cgmath::Vector3<f64>,
    // TODO(sirver): Make color optional, we might not always have it.
    pub color: color::Color<u8>,

    // The intensity of the point if it exists. This value is usually handed through directly by a
    // sensor and has therefore no defined range - or even meaning.
    pub intensity: Option<f32>,
}

pub fn attribute_extension(attribute: &str) -> &str {
    match attribute {
        "position" => "xyz",
        "color" => "rgb",
        _ => attribute,
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttributeDataType {
    U8,
    I64,
    U64,
    F32,
    F64,
    U8Vec3,
    F64Vec3,
}

impl AttributeDataType {
    pub fn to_proto(&self) -> proto::AttributeDataType {
        match self {
            AttributeDataType::U8 => proto::AttributeDataType::U8,
            AttributeDataType::I64 => proto::AttributeDataType::I64,
            AttributeDataType::U64 => proto::AttributeDataType::U64,
            AttributeDataType::F32 => proto::AttributeDataType::F32,
            AttributeDataType::F64 => proto::AttributeDataType::F64,
            AttributeDataType::U8Vec3 => proto::AttributeDataType::U8Vec3,
            AttributeDataType::F64Vec3 => proto::AttributeDataType::F64Vec3,
        }
    }

    pub fn from_proto(attr_proto: proto::AttributeDataType) -> Result<Self> {
        let attr = match attr_proto {
            proto::AttributeDataType::U8 => AttributeDataType::U8,
            proto::AttributeDataType::I64 => AttributeDataType::I64,
            proto::AttributeDataType::U64 => AttributeDataType::U64,
            proto::AttributeDataType::F32 => AttributeDataType::F32,
            proto::AttributeDataType::F64 => AttributeDataType::F64,
            proto::AttributeDataType::U8Vec3 => AttributeDataType::U8Vec3,
            proto::AttributeDataType::F64Vec3 => AttributeDataType::F64Vec3,
            proto::AttributeDataType::U16
            | proto::AttributeDataType::U32
            | proto::AttributeDataType::I8
            | proto::AttributeDataType::I16
            | proto::AttributeDataType::I32 => {
                return Err(ErrorKind::InvalidInput(
                    "Attribute data type not supported yet".to_string(),
                )
                .into())
            }
            proto::AttributeDataType::INVALID_DATA_TYPE => {
                return Err(
                    ErrorKind::InvalidInput("Attribute data type invalid".to_string()).into(),
                )
            }
        };
        Ok(attr)
    }

    pub fn size_of(&self) -> usize {
        match self {
            AttributeDataType::U8 => 1,
            AttributeDataType::F32 => 4,
            AttributeDataType::I64 | AttributeDataType::U64 | AttributeDataType::F64 => 8,
            AttributeDataType::U8Vec3 => 3,
            AttributeDataType::F64Vec3 => 3 * 8,
        }
    }
}

/// General field to describe point feature attributes such as color, intensity, ...
#[derive(Debug, Clone)]
pub enum AttributeData {
    U8(Vec<u8>),
    I64(Vec<i64>),
    U64(Vec<u64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    U8Vec3(Vec<Vector3<u8>>),
    F64Vec3(Vec<Vector3<f64>>),
}

impl AttributeData {
    pub fn len(&self) -> usize {
        match self {
            AttributeData::U8(data) => data.len(),
            AttributeData::I64(data) => data.len(),
            AttributeData::U64(data) => data.len(),
            AttributeData::F32(data) => data.len(),
            AttributeData::F64(data) => data.len(),
            AttributeData::U8Vec3(data) => data.len(),
            AttributeData::F64Vec3(data) => data.len(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn dim(&self) -> usize {
        match self {
            AttributeData::U8(_)
            | AttributeData::I64(_)
            | AttributeData::U64(_)
            | AttributeData::F32(_)
            | AttributeData::F64(_) => 1,
            AttributeData::U8Vec3(_) | AttributeData::F64Vec3(_) => 3,
        }
    }

    pub fn data_type(&self) -> AttributeDataType {
        match self {
            AttributeData::U8(_) => AttributeDataType::U8,
            AttributeData::I64(_) => AttributeDataType::I64,
            AttributeData::U64(_) => AttributeDataType::U64,
            AttributeData::F32(_) => AttributeDataType::F32,
            AttributeData::F64(_) => AttributeDataType::F64,
            AttributeData::U8Vec3(_) => AttributeDataType::U8Vec3,
            AttributeData::F64Vec3(_) => AttributeDataType::F64Vec3,
        }
    }
}

macro_rules! try_from_impl {
    ($data:ident, $attribute_data_type:ident, $vec_data_type:ty) => {
        match $data {
            AttributeData::$attribute_data_type(data) => Ok(data),
            _ => Err(format!(
                "Attribute data type '{:?}' is incompatible with requested type '{}'.",
                $data.data_type(),
                stringify!($vec_data_type)
            )),
        }
    };
}

macro_rules! try_from_attribute_data {
    ($attribute_data_type:ident, $vec_data_type:ty) => {
        impl TryFrom<AttributeData> for Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }

        impl<'a> TryFrom<&'a AttributeData> for &'a Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: &'a AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }

        impl<'a> TryFrom<&'a mut AttributeData> for &'a mut Vec<$vec_data_type> {
            type Error = String;

            fn try_from(data: &'a mut AttributeData) -> std::result::Result<Self, Self::Error> {
                try_from_impl!(data, $attribute_data_type, $vec_data_type)
            }
        }
    };
}
try_from_attribute_data!(U8, u8);
try_from_attribute_data!(I64, i64);
try_from_attribute_data!(U64, u64);
try_from_attribute_data!(F32, f32);
try_from_attribute_data!(F64, f64);
try_from_attribute_data!(U8Vec3, Vector3<u8>);
try_from_attribute_data!(F64Vec3, Vector3<f64>);

/// General structure that contains points and attached feature attributes.
#[derive(Debug, Clone)]
pub struct PointsBatch {
    pub position: Vec<Vector3<f64>>,
    // BTreeMap for deterministic iteration order.
    pub attributes: BTreeMap<String, AttributeData>,
}

impl PointsBatch {
    pub fn get_attribute_vec<'a, T>(
        &'a self,
        key: impl AsRef<str>,
    ) -> std::result::Result<&'a Vec<T>, String>
    where
        &'a Vec<T>: TryFrom<&'a AttributeData, Error = String>,
    {
        self.attributes
            .get(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }

    pub fn get_attribute_vec_mut<'a, T>(
        &'a mut self,
        key: impl AsRef<str>,
    ) -> std::result::Result<&'a mut Vec<T>, String>
    where
        &'a mut Vec<T>: TryFrom<&'a mut AttributeData, Error = String>,
    {
        self.attributes
            .get_mut(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }

    pub fn remove_attribute_vec<T>(
        &mut self,
        key: impl AsRef<str>,
    ) -> std::result::Result<Vec<T>, String>
    where
        Vec<T>: TryFrom<AttributeData, Error = String>,
    {
        self.attributes
            .remove(key.as_ref())
            .ok_or_else(|| format!("Attribute '{}' not found.", key.as_ref()))
            .and_then(|val| val.try_into())
    }
}

pub use point_viewer_proto_rust::proto;

/// size for batch
pub const NUM_POINTS_PER_BATCH: usize = 500_000;
<|endoftext|>


<commit_before>#![feature(test)]

#[cfg(test)]
extern crate test;

/// Makes room for up to ```max``` bytes in the Vector
/// and calls ```f``` with the extent. The number of
/// bytes appended to the Vec is returned by ```f```.
#[inline]
pub fn append_bytes_uninit<F>(vec: &mut Vec<u8>, max: usize, mut f: F)
                              where F: FnMut(&mut[u8]) -> usize {
    let orig_len = vec.len();
    vec.reserve(max);
    unsafe { vec.set_len(orig_len + max); }
    let n = f(&mut vec[orig_len..]);
    assert!(n <= max);
    unsafe { vec.set_len(orig_len + n); }
}

#[cfg(test)]
const N: usize = 1_000_000;

#[bench]
fn bench_append_bytes_using_push(b: &mut test::Bencher) {
    let mut vec = Vec::with_capacity(N);
    b.iter(|| {
        let n = test::black_box(N);
        for _ in (0..n) {
            vec.push(123);
        }
    });
}

#[bench]
fn bench_append_bytes_via_append(b: &mut test::Bencher) {
    let mut vec = Vec::with_capacity(N);
    b.iter(|| {
        append_bytes_uninit(&mut vec, test::black_box(N), |mut s| {
                for c in s.iter_mut() {
                        *c = 123;
                }
                s.len()
        });
    });
}
<commit_msg>Add a _flex variant.<commit_after>#![feature(test)]

#[cfg(test)]
extern crate test;

/// Makes room for up to ```max``` bytes in the Vector
/// and calls ```f``` with the extent. The number of
/// bytes appended to the Vec is returned by ```f```.
#[inline]
pub fn append_bytes_uninit_flex<F>(vec: &mut Vec<u8>, max: usize, mut f: F)
                              where F: FnMut(&mut[u8]) -> usize {
    let orig_len = vec.len();
    vec.reserve(max);
    unsafe { vec.set_len(orig_len + max); }
    let n = f(&mut vec[orig_len..]);
    assert!(n <= max);
    unsafe { vec.set_len(orig_len + n); }
}

/// Extends ```vec``` for ```len``` new bytes
/// and calls ```f``` with the extent.
#[inline]
pub fn append_bytes_uninit<F>(vec: &mut Vec<u8>, len: usize, mut f: F)
                              where F: FnMut(&mut[u8]) {
    let orig_len = vec.len();
    vec.reserve(len);
    unsafe { vec.set_len(orig_len + len); }
    f(&mut vec[orig_len..]);
}

#[cfg(test)]
const N: usize = 1_000_000;

#[bench]
fn bench_append_bytes_using_push(b: &mut test::Bencher) {
    let mut vec = Vec::with_capacity(N);
    b.iter(|| {
        let n = test::black_box(N);
        for _ in (0..n) {
            vec.push(123);
        }
    });
}

#[bench]
fn bench_append_bytes_via_append(b: &mut test::Bencher) {
    let mut vec = Vec::with_capacity(N);
    b.iter(|| {
        append_bytes_uninit(&mut vec, test::black_box(N), |mut s| {
                for c in s.iter_mut() {
                        *c = 123;
                }
        });
    });
}
<|endoftext|>


<commit_before>// TODO: Faire doc module + #![deny(missing_docs)]

use std::sync::{Arc, Barrier};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, Instant};

/// Test that running two operations concurrently works
///
/// When testing multi-threaded constructs, such as synchronization primitives,
/// checking that the code works when run sequentially is insufficient.
/// Concurrent interactions must also be tested, by running some operations
/// in parallel across multiple threads.
///
/// Ideally, this function would take as input a variable-size set of functors
/// to be run in parallel. Since Rust does not support variadic generics yet,
/// however, multiple versions of this function must be provided, each
/// associated with a different functor tuple size.
///
pub fn concurrent_test_2<F, G>(f1: F, f2: G)
    where F: FnOnce() + Send + 'static,
          G: FnOnce() + Send + 'static
{
    // Setup a barrier to synchronize thread startup
    let barrier1 = Arc::new(Barrier::new(2));
    let barrier2 = barrier1.clone();

    // Start the first task
    let thread1 = thread::spawn(move || {
        barrier1.wait();
        f1();
    });

    // Run the second task
    barrier2.wait();
    f2();

    // Make sure that the first task completed properly
    thread1.join().unwrap();
}

/// Test that running three operations concurrently works
///
/// This is a variant of concurrent_test_2 that works with three functors
/// instead of two. It is hoped that future evolutions of Rust will render this
/// code duplication obsolete, in favor of some variadic generic design.
///
pub fn concurrent_test_3<F, G, H>(f1: F, f2: G, f3: H)
    where F: FnOnce() + Send + 'static,
          G: FnOnce() + Send + 'static,
          H: FnOnce() + Send + 'static
{
    // Setup a barrier to synchronize thread startup
    let barrier1 = Arc::new(Barrier::new(3));
    let barrier2 = barrier1.clone();
    let barrier3 = barrier1.clone();

    // Start the first task
    let thread1 = thread::spawn(move || {
        barrier1.wait();
        f1();
    });

    // Start the second task
    let thread2 = thread::spawn(move || {
        barrier2.wait();
        f2();
    });

    // Run the third task
    barrier3.wait();
    f3();

    // Make sure that the first two tasks completed properly
    thread1.join().unwrap();
    thread2.join().unwrap();
}

/// Microbenchmark some simple operation by running it N times
///
/// This simple benchmark harness is meant as a cheap and hackish substitute for
/// cargo benchmarks in Stable Rust. It runs a user-provided operation a certain
/// number of times and measures how much time it takes.
///
/// To use it, write your benchmark as an ignored cargo test, put a call to
/// benchmark() or counting_benchmark() as the last operation, and tell your
/// user to run the benchmarks via:
///
///   $ cargo test --release -- --ignored --nocapture --test-threads=1
///
/// This is a dreadful hack. But for now, it's the best that I've thought of.
///
pub fn benchmark<F: FnMut()>(num_iterations: u32, mut iteration: F) {
    // Run the user-provided operation in a loop
    let start_time = Instant::now();
    for _ in 0..num_iterations {
        iteration()
    }
    let total_duration = start_time.elapsed();

    // Reproducible benchmarks (<10% variance) usually take between a couple of
    // seconds and a couple of minutes, so miliseconds are the right timing unit
    // for the duration of the whole benchmark.
    let total_ms = (total_duration.as_secs() as u32) * 1000 +
                   total_duration.subsec_nanos() / 1_000_000;

    // This tool is designed for microbenchmarking, so iterations are assumed
    // to last from one CPU cycle (a fraction of a nanosecond) to a fraction of
    // a second. Longer durations will require multi-resolution formatting.
    let hundred_iter_duration = total_duration * 100 / num_iterations;
    let iter_duration = hundred_iter_duration / 100;
    assert_eq!(iter_duration.as_secs(), 0);
    let iter_ns = iter_duration.subsec_nanos();
    let iter_ns_fraction = hundred_iter_duration.subsec_nanos() % 100;

    // Display the benchmark results, in a fashion that will fit in the output
    // of cargo test in nocapture mode.
    print!("{} ms ({} iters, ~{}.{} ns/iter): ",
           total_ms,
           num_iterations,
           iter_ns,
           iter_ns_fraction);
}

/// Microbenchmark some operation while another is running in a loop
///
/// For multithreaded code, benchmarking the performance of isolated operations
/// is usually only half of the story. Synchronization and memory contention can
/// also have a large impact on performance.
///
/// For this reason, it is often useful to also measure the performance of one
/// operation as another "antagonist" operation is also running in a background
/// thread. This function implements such concurrent benchmarking.
///
pub fn concurrent_benchmark<F, A>(num_iterations: u32,
                                  iteration_func: F,
                                  mut antagonist_func: A)
    where F: FnMut(),
          A: FnMut() + Send + 'static
{
    // Setup a barrier to synchronize benchmark and antagonist startup
    let barrier = Arc::new(Barrier::new(2));

    // Setup an atomic "continue" flag to shut down the antagonist at
    // the end of the benchmarking procedure
    let run_flag = Arc::new(AtomicBool::new(true));

    // Schedule the antagonist thread
    let (a_barrier, a_run_flag) = (barrier.clone(), run_flag.clone());
    let antagonist = thread::spawn(
        move || {
            a_barrier.wait();
            while a_run_flag.load(Ordering::Relaxed) {
                antagonist_func();
            }
        }
    );

    // Wait for the antagonist to be running, and give it some headstart
    barrier.wait();
    thread::sleep(Duration::from_millis(10));

    // Run the benchmark
    benchmark(num_iterations, iteration_func);

    // Stop the antagonist and check that nothing went wrong on its side
    run_flag.store(false, Ordering::Relaxed);
    antagonist.join().unwrap();
}

/// TODO: Just an usage example, should probably be improved
#[cfg(test)]
mod benchs {
    use std::time::Instant;

    #[test]
    #[ignore]
    fn it_works() {
        let initial = Instant::now();
        ::benchmark(50000000, || { assert!( Instant::now() > initial ) });
    }
}
<commit_msg>Added more documentation and examples<commit_after>//! Testing and benchmarking tools for concurrent Rust code
//!
//! This crate groups together a bunch of utilities which I've found useful when
//! testing and benchmarking Rust concurrency primitives in the triple_buffer
//! and spmc_buffer crates.
//!
//! If it proves popular, other testing and benchmarking tools may be added,
//! based on user demand.
//!
//! # Examples
//!
//! For examples of this crate at work, look at its "tests" and "benchs"
//! submodules, which showcase expected usage.

#![deny(missing_docs)]

use std::sync::{Arc, Barrier};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, Instant};

/// Test that running two operations concurrently works
///
/// When testing multi-threaded constructs, such as synchronization primitives,
/// checking that the code works when run sequentially is insufficient.
/// Concurrent interactions must also be tested, by running some operations
/// in parallel across multiple threads.
///
/// Ideally, this function would take as input a variable-size set of functors
/// to be run in parallel. Since Rust does not support variadic generics yet,
/// however, multiple versions of this function must be provided, each
/// associated with a different functor tuple size.
///
pub fn concurrent_test_2<F, G>(f1: F, f2: G)
    where F: FnOnce() + Send + 'static,
          G: FnOnce() + Send + 'static
{
    // Setup a barrier to synchronize thread startup
    let barrier1 = Arc::new(Barrier::new(2));
    let barrier2 = barrier1.clone();

    // Start the first task
    let thread1 = thread::spawn(move || {
        barrier1.wait();
        f1();
    });

    // Run the second task
    barrier2.wait();
    f2();

    // Make sure that the first task completed properly
    thread1.join().unwrap();
}

/// Test that running three operations concurrently works
///
/// This is a variant of concurrent_test_2 that works with three functors
/// instead of two. It is hoped that future evolutions of Rust will render this
/// (light) code duplication obsolete, in favor of some variadic design.
///
pub fn concurrent_test_3<F, G, H>(f1: F, f2: G, f3: H)
    where F: FnOnce() + Send + 'static,
          G: FnOnce() + Send + 'static,
          H: FnOnce() + Send + 'static
{
    // Setup a barrier to synchronize thread startup
    let barrier1 = Arc::new(Barrier::new(3));
    let barrier2 = barrier1.clone();
    let barrier3 = barrier1.clone();

    // Start the first task
    let thread1 = thread::spawn(move || {
        barrier1.wait();
        f1();
    });

    // Start the second task
    let thread2 = thread::spawn(move || {
        barrier2.wait();
        f2();
    });

    // Run the third task
    barrier3.wait();
    f3();

    // Make sure that the first two tasks completed properly
    thread1.join().unwrap();
    thread2.join().unwrap();
}

/// Microbenchmark some simple operation by running it N times
///
/// This simple benchmark harness is meant as a cheap and hackish substitute for
/// cargo benchmarks in Stable Rust. It runs a user-provided operation a certain
/// number of times and measures how much time it takes.
///
/// To use it, write your benchmark as an ignored cargo test, put a call to
/// benchmark() or counting_benchmark() as the last operation, and tell your
/// user to run the benchmarks via:
///
///   $ cargo test --release -- --ignored --nocapture --test-threads=1
///
/// This is a dreadful hack. But for now, it's the best that I've thought of.
///
pub fn benchmark<F: FnMut()>(num_iterations: u32, mut iteration: F) {
    // Run the user-provided operation in a loop
    let start_time = Instant::now();
    for _ in 0..num_iterations {
        iteration()
    }
    let total_duration = start_time.elapsed();

    // Reproducible benchmarks (<10% variance) usually take between a couple of
    // seconds and a couple of minutes, so miliseconds are the right timing unit
    // for the duration of the whole benchmark.
    let total_ms = (total_duration.as_secs() as u32) * 1000 +
                   total_duration.subsec_nanos() / 1_000_000;

    // This tool is designed for microbenchmarking, so iterations are assumed
    // to last from one CPU cycle (a fraction of a nanosecond) to a fraction of
    // a second. Longer durations will require multi-resolution formatting.
    let hundred_iter_duration = total_duration * 100 / num_iterations;
    let iter_duration = hundred_iter_duration / 100;
    assert_eq!(iter_duration.as_secs(), 0);
    let iter_ns = iter_duration.subsec_nanos();
    let iter_ns_fraction = hundred_iter_duration.subsec_nanos() % 100;

    // Display the benchmark results, in a fashion that will fit in the output
    // of cargo test in nocapture mode.
    print!("{} ms ({} iters, ~{}.{} ns/iter): ",
           total_ms,
           num_iterations,
           iter_ns,
           iter_ns_fraction);
}

/// Microbenchmark some operation while another is running in a loop
///
/// For multithreaded code, benchmarking the performance of isolated operations
/// is usually only half of the story. Synchronization and memory contention can
/// also have a large impact on performance.
///
/// For this reason, it is often useful to also measure the performance of one
/// operation as another "antagonist" operation is also running in a background
/// thread. This function implements such concurrent benchmarking.
///
pub fn concurrent_benchmark<F, A>(num_iterations: u32,
                                  iteration_func: F,
                                  mut antagonist_func: A)
    where F: FnMut(),
          A: FnMut() + Send + 'static
{
    // Setup a barrier to synchronize benchmark and antagonist startup
    let barrier = Arc::new(Barrier::new(2));

    // Setup an atomic "continue" flag to shut down the antagonist at
    // the end of the benchmarking procedure
    let run_flag = Arc::new(AtomicBool::new(true));

    // Schedule the antagonist thread
    let (a_barrier, a_run_flag) = (barrier.clone(), run_flag.clone());
    let antagonist = thread::spawn(
        move || {
            a_barrier.wait();
            while a_run_flag.load(Ordering::Relaxed) {
                antagonist_func();
            }
        }
    );

    // Wait for the antagonist to be running, and give it some headstart
    barrier.wait();
    thread::sleep(Duration::from_millis(10));

    // Run the benchmark
    benchmark(num_iterations, iteration_func);

    // Stop the antagonist and check that nothing went wrong on its side
    run_flag.store(false, Ordering::Relaxed);
    antagonist.join().unwrap();
}

/// Examples of concurrent testing code
#[cfg(test)]
mod tests {
    use std::ops::BitAnd;
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};

    // Check the behaviour of concurrent atomic swaps and fetch-adds
    #[test]
    fn swap_and_fetch_add() {
        // Amount of atomic operations to check
        const ATOMIC_OPS_COUNT: usize = 100_000_000;

        // Create a shared atomic variable
        let atom = Arc::new(AtomicUsize::new(0));
        let atom2 = atom.clone();

        // Check that concurrent atomic operations work correctly
        let mut last_value = 0;
        ::concurrent_test_2(
            move || {
                // One thread continuously increments the atomic variable...
                for _ in 1..(ATOMIC_OPS_COUNT + 1) {
                    let former_atom = atom.fetch_add(1, Ordering::Relaxed);
                    assert!((former_atom == 0) || (former_atom == last_value));
                    last_value = former_atom+1;
                }
            },
            move || {
                // ...as another continuously resets it to zero
                for _ in 1..(ATOMIC_OPS_COUNT + 1) {
                    let former_atom = atom2.swap(0, Ordering::Relaxed);
                    assert!(former_atom <= ATOMIC_OPS_COUNT);
                }
            }
        );
    }

    // Check the behaviour of concurrent fetch-and/or/xors
    #[test]
    fn fetch_and_or_xor() {
        // Amount of atomic operations to check
        const ATOMIC_OPS_COUNT: usize = 30_000_000;

        // Create a shared atomic variable. Even though this is an atomic Usize,
        // we will only use the 16 low-order bits for maximal portability.
        let atom = Arc::new(AtomicUsize::new(0));
        let atom2 = atom.clone();
        let atom3 = atom.clone();

        // Masks used by each atomic operation
        const AND_MASK: usize = 0b0000_0000_0000_0000; // Clear all bits
        const XOR_MASK: usize = 0b0000_1111_0000_1111; // Flip some bits
        const OR_MASK: usize  = 0b1111_0000_1111_0000; // Set other bits

        // Check that concurrent atomic operations work correctly by ensuring
        // that at any point in time, only the 16 low-order bits can be set, and
        // the grouped sets of bits in the masks above are either all set or
        // all cleared in any observable state.
        ::concurrent_test_3(
            move || {
                // One thread runs fetch-ands in a loop...
                for _ in 1..(ATOMIC_OPS_COUNT + 1) {
                    let old_val = atom.fetch_and(AND_MASK, Ordering::Relaxed);
                    assert_eq!(old_val.bitand(0b1111_1111_1111_1111), old_val);
                    assert!((old_val.bitand(XOR_MASK) == XOR_MASK) ||
                            (old_val.bitand(XOR_MASK) == 0));
                    assert!((old_val.bitand(OR_MASK) == OR_MASK) ||
                            (old_val.bitand(OR_MASK) == 0));
                }
            },
            move || {
                // ...another runs fetch-ors in a loop...
                for _ in 1..(ATOMIC_OPS_COUNT + 1) {
                    let old_val = atom2.fetch_or(OR_MASK, Ordering::Relaxed);
                    assert_eq!(old_val.bitand(0b1111_1111_1111_1111), old_val);
                    assert!((old_val.bitand(XOR_MASK) == XOR_MASK) ||
                            (old_val.bitand(XOR_MASK) == 0));
                    assert!((old_val.bitand(OR_MASK) == OR_MASK) ||
                            (old_val.bitand(OR_MASK) == 0));
                }
            },
            move || {
                // ...and the last one runs fetch-xors in a loop...
                for _ in 1..(ATOMIC_OPS_COUNT + 1) {
                    let old_val = atom3.fetch_xor(XOR_MASK, Ordering::Relaxed);
                    assert_eq!(old_val.bitand(0b1111_1111_1111_1111), old_val);
                    assert!((old_val.bitand(XOR_MASK) == XOR_MASK) ||
                            (old_val.bitand(XOR_MASK) == 0));
                    assert!((old_val.bitand(OR_MASK) == OR_MASK) ||
                            (old_val.bitand(OR_MASK) == 0));
                }
            }
        );
    }
}

/// Exemples of benchmarking code
///
/// As discussed before, these should be run via the following command:
///
///   $ cargo test --release -- --ignored --nocapture --test-threads=1
#[cfg(test)]
mod benchs {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};

    // Benchmark relaxed atomics in sequential code (best case)
    #[test]
    #[ignore]
    fn bench_relaxed() {
        let atom = AtomicUsize::new(0);
        ::benchmark(500_000_000, || { atom.fetch_add(1, Ordering::Relaxed); });
        assert_eq!(atom.load(Ordering::Relaxed), 500_000_000);
    }

    // Benchmark sequentially consistent atomics in concurrent code (worst case)
    #[test]
    #[ignore]
    fn bench_seqcst() {
        let atom = Arc::new(AtomicUsize::new(0));
        let atom2 = atom.clone();
        ::concurrent_benchmark(
            100_000_000,
            move || { atom.fetch_add(1, Ordering::SeqCst); },
            move || { atom2.fetch_add(1, Ordering::SeqCst); }
        );
    }
}
<|endoftext|>


<commit_before>//! Collection traits for generic programming.

#![deny(missing_docs)]
#![feature(linked_list_extras)]
#![feature(set_recovery)]

mod std_impls;

pub use collection::Collection;
pub use list::List;
pub use map::Map;
pub use seq::{Deque, Queue, Stack};
pub use set::Set;

pub mod collection {
    //! Collections.

    /// A collection.
    pub trait Collection {
        /// The type of the collection's items.
        type Item;

        /// Checks if the collection contains zero items.
        ///
        /// This is equivalent to `self.len() == 0`, but may be optimized.
        fn is_empty(&self) -> bool {
            self.len() == 0
        }

        /// Returns the number of items in the collection.
        fn len(&self) -> usize;
    }

    /// A collection that supports insertion.
    pub trait Insert: Collection {
        /// Moves all items from the given collection into the collection.
        fn append(&mut self, other: &mut Self) where Self: Sized;
    }

    /// A collection that supports removal.
    pub trait Remove: Collection {
        /// Removes all items from the collection.
        fn clear(&mut self);
    }
}

pub mod list {
    //! Lists.

    use super::*;

    /// A list.
    pub trait List: Collection {
        /// Returns a reference to the item at the given index.
        ///
        /// Returns `None` if `index >= self.len()`.
        fn get(&self, index: usize) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the given index.
        ///
        /// Returns `None` if `index >= self.len()`.
        fn get_mut(&mut self, index: usize) -> Option<&mut Self::Item>;

        /// Swaps the items at the given indices in the list.
        ///
        /// # Panics
        ///
        /// Panics if `i >= self.len() || j >= self.len()`.
        fn swap(&mut self, i: usize, j: usize);
    }

    /// A list that supports insertion.
    pub trait Insert: List {
        /// Inserts the given item into the list at the given index.
        ///
        /// All items after the given index are shifted one index to the right.
        ///
        /// # Panics
        ///
        /// Panics if `index > self.len()`.
        fn insert(&mut self, index: usize, item: Self::Item);

        /// Pushes the given item onto the back of the list.
        fn push(&mut self, item: Self::Item) {
            let len = self.len();
            self.insert(len, item);
        }
    }

    /// A list that supports removal.
    pub trait Remove: List {
        /// Removes the last item in the list.
        ///
        /// Returns `None` if the list is empty.
        fn pop(&mut self) -> Option<Self::Item> {
            if self.is_empty() {
                None
            } else {
                let len = self.len();
                self.remove(len - 1)
            }
        }

        /// Removes the item at the given index from the list and returns it.
        ///
        /// Returns `None` if `index >= self.len()`.
        fn remove(&mut self, index: usize) -> Option<Self::Item>;

        /// Splits the list in two at the given index.
        ///
        /// After this method returns, `self` contains the items `[0, index)` and the returned list
        /// contains the items `[index, len)`.
        ///
        /// # Panics
        ///
        /// Panics if `index > self.len()`.
        fn split_off(&mut self, index: usize) -> Self where Self: Sized;

        /// Removes the item at the given index from the list and returns it, replacing it with the
        /// last item in the list.
        ///
        /// Returns `None` if `index >= self.len()`.
        fn swap_remove(&mut self, index: usize) -> Option<Self::Item> {
            if index >= self.len() {
                None
            } else {
                let len = self.len();
                self.swap(index, len - 1);
                self.pop()
            }
        }
    }
}

pub mod map {
    //! Maps.

    use super::*;

    /// A map.
    ///
    /// A map is a collection that associates keys with values, where the keys are distinguished
    /// according to some uniqueness criteria.
    pub trait Map: Collection<Item = (<Self as Map>::Key, <Self as Map>::Value)> {
        /// The type of the map's keys.
        type Key;

        /// The type of the map's values.
        type Value;

        /// Returns the entry in the map corresponding to the given key.
        fn entry<'a>(&'a mut self, key: Self::Key) -> Entry<'a, Self::Key, Self::Value>
            where Self: Insert + Remove;
    }

    /// A map that supports lookups using keys of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Map>::Key>: Map {
        /// Checks if the map contains a key that is equivalent to the given key.
        ///
        /// This is equivalent to `self.get(key).is_some()`, but may be optimized.
        fn contains_key(&self, key: &Q) -> bool {
            self.get(key).is_some()
        }

        /// Returns a reference to the value in the map whose key is equivalent to the given key.
        ///
        /// Returns `None` if the map contains no such key.
        fn get(&self, key: &Q) -> Option<&Self::Value>;

        /// Returns a mutable reference to the value in the map whose key is equivalent to the
        /// given key.
        ///
        /// Returns `None` if the map contains no such key.
        fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;
    }

    /// A map that supports removals using keys of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Map>::Key>: Get<Q> + collection::Remove {
        /// Removes the key in the map that is equivalent to the given key and returns its value.
        ///
        /// Returns `None` if the map contains no such key.
        fn remove(&mut self, key: &Q) -> Option<Self::Value>;
    }

    /// A map that supports insertion.
    pub trait Insert: Map + collection::Insert {
        /// Inserts the given key and value into the map and returns the previous value
        /// corresponding to the given key, if any.
        fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
    }

    /// An occupied map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait OccupiedEntry {
        /// The type of the entry's key.
        type Key;

        /// The type of the entry's value.
        type Value;

        /// The return type of `into_mut`.
        type MutValue;

        /// Returns a reference to the entry's value.
        fn get(&self) -> &Self::Value;

        /// Returns a mutable reference to the entry's value.
        fn get_mut(&mut self) -> &mut Self::Value;

        /// Returns a mutable reference to the entry's value with the same lifetime as the map.
        fn into_mut(self: Box<Self>) -> Self::MutValue;

        /// Replaces the entry's value with the given one and returns the old value.
        fn insert(&mut self, value: Self::Value) -> Self::Value {
            ::std::mem::replace(self.get_mut(), value)
        }

        /// Removes the entry from the map and returns its value.
        fn remove(self: Box<Self>) -> Self::Value;
    }

    /// A vacant map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait VacantEntry {
        /// The type of the entry's key.
        type Key;

        /// The type of the entry's value.
        type Value;

        /// The return type of `insert`.
        type MutValue;

        /// Inserts the entry into the map with the given value and returns a mutable reference to
        /// it with the same lifetime as the map.
        fn insert(self: Box<Self>, value: Self::Value) -> Self::MutValue;
    }

    /// A map entry.
    pub enum Entry<'a, K: 'a, V: 'a> {
        /// An occupied map entry.
        Occupied(Box<OccupiedEntry<Key = K, Value = V, MutValue = &'a mut V> + 'a>),
        /// A vacant map entry.
        Vacant(Box<VacantEntry<Key = K, Value = V, MutValue = &'a mut V> + 'a>),
    }

    impl<'a, K: 'a, V: 'a> Entry<'a, K, V> {
        /// Ensures the entry is occupied by inserting it with the given default value if it is
        /// vacant.
        pub fn or_insert(self, default: V) -> &'a mut V {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(default),
            }
        }

        /// Ensures the entry is occupied by inserting it with the result of the given function if
        /// it is vacant.
        pub fn or_insert_with<F: FnOnce() -> V>(self, f: F) -> &'a mut V {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(f()),
            }
        }
    }

    #[cfg(test)]
    pub fn count<M, I>(items: I) -> M
    where
        M: Default + map::Insert<Value = usize> + map::Remove,
        I: IntoIterator<Item = M::Key>,
    {
        let mut map = M::default();
        for item in items { *map.entry(item).or_insert(0) += 1; }
        map
    }
}

pub mod seq {
    //! Sequences.

    use super::*;

    /// A sequence that supports insertion.
    pub trait PushBack: collection::Insert {
        /// Pushes the given item onto the back of the sequence.
        fn push_back(&mut self, item: Self::Item);
    }

    /// A queue.
    pub trait Queue: PushBack + collection::Remove {
        /// Returns a reference to the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn front(&self) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn front_mut(&mut self) -> Option<&mut Self::Item>;

        /// Removes and returns the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn pop_front(&mut self) -> Option<Self::Item>;
    }

    /// A stack.
    pub trait Stack: PushBack + collection::Remove {
        /// Returns a reference to the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn back(&self) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn back_mut(&mut self) -> Option<&mut Self::Item>;

        /// Removes and returns the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn pop_back(&mut self) -> Option<Self::Item>;
    }

    /// A deque (double-ended queue).
    pub trait Deque: Queue + Stack {
        /// Pushes the given item onto the front of the deque.
        fn push_front(&mut self, item: Self::Item);
    }
}

pub mod set {
    //! Sets.

    use super::*;

    /// A set.
    ///
    /// A set is a collection whose items are distinguished according to some uniqueness criteria.
    pub trait Set: Collection {
        /// Checks if the set is disjoint from the given set.
        fn is_disjoint(&self, other: &Self) -> bool where Self: Sized;

        /// Checks if the set is a subset of the given set.
        fn is_subset(&self, other: &Self) -> bool where Self: Sized;

        /// Checks if the set is a superset of the given set.
        fn is_superset(&self, other: &Self) -> bool where Self: Sized {
            other.is_subset(self)
        }
    }

    /// A set that supports retrievals using items of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Collection>::Item>: Set {
        /// Checks if the set contains an item that is equivalent to the given item.
        ///
        /// This is equivalent to `self.get(item).is_some()`, but may be optimized.
        fn contains(&self, item: &Q) -> bool {
            self.get(item).is_some()
        }

        /// Returns the item in the set that is equivalent to the given item.
        ///
        /// Returns `None` if the set contains no such item.
        fn get(&self, item: &Q) -> Option<&Self::Item>;
    }

    /// A set that supports removal using items of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Collection>::Item>: Get<Q> + collection::Remove {
        /// Removes the item in the set that is equivalent to the given item.
        ///
        /// Returns `true` if the set contained such an item, `false` otherwise.
        ///
        /// This is equivalent to `self.take(item).is_some()`, but may be optimized.
        fn remove(&mut self, item: &Q) -> bool {
            self.take(item).is_some()
        }

        /// Removes and returns the item in the set that is equivalent to the given item.
        ///
        /// Returns `None` if the set contained no such item.
        fn take(&mut self, item: &Q) -> Option<Self::Item>;
    }

    /// A set that supports insertion.
    pub trait Insert: Set + collection::Insert {
        /// Inserts the given item into the set without replacement.
        ///
        /// Returns `true` if the set contained an equivalent item, `false` otherwise.
        fn insert(&mut self, item: Self::Item) -> bool;

        /// Inserts the given item into the set with replacement.
        ///
        /// Returns the equivalent item if the set contained one, `None` otherwise.
        fn replace(&mut self, item: Self::Item) -> Option<Self::Item>;
    }
}

#[allow(dead_code)]
fn assert_object_safe() {
    let _: Collection<Item = String>;
    let _: collection::Insert<Item = String>;
    let _: collection::Remove<Item = String>;

    let _: &List<Item = String>;
    let _: &list::Insert<Item = String>;
    let _: &list::Remove<Item = String>;

    let _: &Map<Item = (String, i32), Key = String, Value = i32>;
    let _: &map::Insert<Item = (String, i32), Key = String, Value = i32>;
    let _: &map::Get<str, Item = (String, i32), Key = String, Value = i32>;
    let _: &map::Remove<str, Item = (String, i32), Key = String, Value = i32>;
    let _: &map::OccupiedEntry<Key = String, Value = i32, MutValue = &mut i32>;
    let _: &map::VacantEntry<Key = String, Value = i32, MutValue = &mut i32>;

    let _: &seq::PushBack<Item = String>;
    let _: &Queue<Item = String>;
    let _: &Stack<Item = String>;
    let _: &Deque<Item = String>;

    let _: &Set<Item = String>;
    let _: &set::Insert<Item = String>;
    let _: &set::Get<str, Item = String>;
    let _: &set::Remove<str, Item = String>;
}
<commit_msg>Clean up docs<commit_after>//! Collection traits for generic programming.

#![deny(missing_docs)]
#![feature(linked_list_extras)]
#![feature(set_recovery)]

mod std_impls;

pub use collection::Collection;
pub use list::List;
pub use map::Map;
pub use seq::{Deque, Queue, Stack};
pub use set::Set;

pub mod collection {
    //! Collections.

    /// A collection.
    pub trait Collection {
        /// The type of the collection's items.
        type Item;

        /// Checks if the collection contains zero items.
        ///
        /// This is equivalent to `self.len() == 0`, but may be optimized.
        fn is_empty(&self) -> bool {
            self.len() == 0
        }

        /// Returns the number of items in the collection.
        fn len(&self) -> usize;
    }

    /// A collection that supports insertion.
    pub trait Insert: Collection {
        /// Moves all items from the given collection into the collection.
        fn append(&mut self, other: &mut Self) where Self: Sized;
    }

    /// A collection that supports removal.
    pub trait Remove: Collection {
        /// Removes all items from the collection.
        fn clear(&mut self);
    }
}

pub mod list {
    //! Lists.

    use super::*;

    /// A list.
    pub trait List: Collection {
        /// Returns a reference to the item at the given index in the list.
        ///
        /// Returns `None` if `index >= self.len()`.
        fn get(&self, index: usize) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the given index in the list.
        ///
        /// Returns `None` if `index >= self.len()`.
        fn get_mut(&mut self, index: usize) -> Option<&mut Self::Item>;

        /// Swaps the items at the given indices in the list.
        ///
        /// # Panics
        ///
        /// Panics if `i >= self.len() || j >= self.len()`.
        fn swap(&mut self, i: usize, j: usize);
    }

    /// A list that supports insertion.
    pub trait Insert: List {
        /// Inserts the given item into the list at the given index.
        ///
        /// All items after the given index are shifted one index to the right.
        ///
        /// # Panics
        ///
        /// Panics if `index > self.len()`.
        fn insert(&mut self, index: usize, item: Self::Item);

        /// Pushes the given item onto the back of the list.
        ///
        /// This is equivalent to `self.insert(self.len(), item)`, but may be optimized.
        fn push(&mut self, item: Self::Item) {
            let len = self.len();
            self.insert(len, item);
        }
    }

    /// A list that supports removal.
    pub trait Remove: List {
        /// Removes the last item in the list and returns it.
        ///
        /// Returns `None` if the list is empty.
        ///
        /// This is equivalent to `self.remove(self.len() - 1)`, but may be optimized.
        fn pop(&mut self) -> Option<Self::Item> {
            if self.is_empty() {
                None
            } else {
                let len = self.len();
                self.remove(len - 1)
            }
        }

        /// Removes the item at the given index in the list and returns it.
        ///
        /// Returns `None` if `index >= self.len()`.
        fn remove(&mut self, index: usize) -> Option<Self::Item>;

        /// Splits the list in two at the given index.
        ///
        /// After this method returns, `self` contains the items `0..index` and the returned list
        /// contains the items `index..self.len()`.
        ///
        /// # Panics
        ///
        /// Panics if `index > self.len()`.
        fn split_off(&mut self, index: usize) -> Self where Self: Sized;

        /// Removes the item at the given index in the list and returns it, replacing it with the
        /// last item in the list.
        ///
        /// Returns `None` if `index >= self.len()`.
        fn swap_remove(&mut self, index: usize) -> Option<Self::Item> {
            if index >= self.len() {
                None
            } else {
                let len = self.len();
                self.swap(index, len - 1);
                self.pop()
            }
        }
    }
}

pub mod map {
    //! Maps.

    use super::*;

    /// A map.
    ///
    /// A map is a collection that associates keys with values, where the keys are distinguished
    /// according to some uniqueness criteria.
    pub trait Map: Collection<Item = (<Self as Map>::Key, <Self as Map>::Value)> {
        /// The type of the map's keys.
        type Key;

        /// The type of the map's values.
        type Value;

        /// Returns the entry in the map corresponding to the given key.
        fn entry<'a>(&'a mut self, key: Self::Key) -> Entry<'a, Self::Key, Self::Value>
            where Self: Insert + Remove;
    }

    /// A map that supports retrievals using keys of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Map>::Key>: Map {
        /// Checks if the map contains a key that is equivalent to the given key.
        ///
        /// This is equivalent to `self.get(key).is_some()`, but may be optimized.
        fn contains_key(&self, key: &Q) -> bool {
            self.get(key).is_some()
        }

        /// Returns a reference to the value of the key in the map that is equivalent to the given
        /// key.
        ///
        /// Returns `None` if the map contains no such key.
        fn get(&self, key: &Q) -> Option<&Self::Value>;

        /// Returns a mutable reference to the value of the key in the map that is equivalent to
        /// the given key.
        ///
        /// Returns `None` if the map contains no such key.
        fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;
    }

    /// A map that supports removals using keys of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Map>::Key>: Get<Q> + collection::Remove {
        /// Removes the key in the map that is equivalent to the given key and returns its value.
        ///
        /// Returns `None` if the map contains no such key.
        fn remove(&mut self, key: &Q) -> Option<Self::Value>;
    }

    /// A map that supports insertion.
    pub trait Insert: Map + collection::Insert {
        /// Inserts the given key and value into the map without replacing an equivalent key.
        ///
        /// Returns the equivalent key's value if the map contained one, `None` otherwise.
        fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
    }

    /// An occupied map entry.
    pub trait OccupiedEntry {
        /// The type of the entry's key.
        type Key;

        /// The type of the entry's value.
        type Value;

        /// The type of the mutable reference to the entry's value with the same lifetime as the
        /// map.
        type MutValue;

        /// Returns a reference to the entry's value.
        fn get(&self) -> &Self::Value;

        /// Returns a mutable reference to the entry's value.
        fn get_mut(&mut self) -> &mut Self::Value;

        /// Returns a mutable reference to the entry's value with the same lifetime as the map.
        fn into_mut(self: Box<Self>) -> Self::MutValue;

        /// Replaces the entry's value with the given one and returns the old value.
        fn insert(&mut self, value: Self::Value) -> Self::Value {
            ::std::mem::replace(self.get_mut(), value)
        }

        /// Removes the entry from the map and returns its value.
        fn remove(self: Box<Self>) -> Self::Value;
    }

    /// A vacant map entry.
    pub trait VacantEntry {
        /// The type of the entry's key.
        type Key;

        /// The type of the entry's value.
        type Value;

        /// The type of the mutable reference to the entry's value with the same lifetime as the
        /// map.
        type MutValue;

        /// Inserts the entry into the map with the given value.
        ///
        /// Returns a mutable reference to the value with the same lifetime as the map.
        fn insert(self: Box<Self>, value: Self::Value) -> Self::MutValue;
    }

    /// A map entry.
    pub enum Entry<'a, K: 'a, V: 'a> {
        /// An occupied map entry.
        Occupied(Box<OccupiedEntry<Key = K, Value = V, MutValue = &'a mut V> + 'a>),
        /// A vacant map entry.
        Vacant(Box<VacantEntry<Key = K, Value = V, MutValue = &'a mut V> + 'a>),
    }

    impl<'a, K: 'a, V: 'a> Entry<'a, K, V> {
        /// Ensures that the entry is occupied by inserting it into the map with the given value if
        /// it is vacant.
        ///
        /// Returns a mutable reference to the value with the same lifetime as the map.
        pub fn or_insert(self, default: V) -> &'a mut V {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(default),
            }
        }

        /// Ensures that the entry is occupied by inserting it into the map with the result of the
        /// given function if it is vacant.
        ///
        /// Returns a mutable reference to the value with the same lifetime as the map.
        pub fn or_insert_with<F: FnOnce() -> V>(self, f: F) -> &'a mut V {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(f()),
            }
        }
    }

    #[cfg(test)]
    pub fn count<M, I>(items: I) -> M
    where
        M: Default + map::Insert<Value = usize> + map::Remove,
        I: IntoIterator<Item = M::Key>,
    {
        let mut map = M::default();
        for item in items { *map.entry(item).or_insert(0) += 1; }
        map
    }
}

pub mod seq {
    //! Sequences.

    use super::*;

    /// A sequence that supports insertion.
    pub trait PushBack: collection::Insert {
        /// Pushes the given item onto the back of the sequence.
        fn push_back(&mut self, item: Self::Item);
    }

    /// A queue.
    pub trait Queue: PushBack + collection::Remove {
        /// Returns a reference to the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn front(&self) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn front_mut(&mut self) -> Option<&mut Self::Item>;

        /// Removes the item at the front of the queue and returns it.
        ///
        /// Returns `None` if the queue is empty.
        fn pop_front(&mut self) -> Option<Self::Item>;
    }

    /// A stack.
    pub trait Stack: PushBack + collection::Remove {
        /// Returns a reference to the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn back(&self) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn back_mut(&mut self) -> Option<&mut Self::Item>;

        /// Removes the item at the back of the stack and returns it.
        ///
        /// Returns `None` if the stack is empty.
        fn pop_back(&mut self) -> Option<Self::Item>;
    }

    /// A deque (double-ended queue).
    pub trait Deque: Queue + Stack {
        /// Pushes the given item onto the front of the deque.
        fn push_front(&mut self, item: Self::Item);
    }
}

pub mod set {
    //! Sets.

    use super::*;

    /// A set.
    ///
    /// A set is a collection whose items are distinguished according to some uniqueness criteria.
    pub trait Set: Collection {
        /// Checks if the set is disjoint from the given set.
        fn is_disjoint(&self, other: &Self) -> bool where Self: Sized;

        /// Checks if the set is a subset of the given set.
        fn is_subset(&self, other: &Self) -> bool where Self: Sized;

        /// Checks if the set is a superset of the given set.
        fn is_superset(&self, other: &Self) -> bool where Self: Sized {
            other.is_subset(self)
        }
    }

    /// A set that supports retrievals using items of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Collection>::Item>: Set {
        /// Checks if the set contains an item that is equivalent to the given item.
        ///
        /// This is equivalent to `self.get(item).is_some()`, but may be optimized.
        fn contains(&self, item: &Q) -> bool {
            self.get(item).is_some()
        }

        /// Returns a reference to the item in the set that is equivalent to the given item.
        ///
        /// Returns `None` if the set contains no such item.
        fn get(&self, item: &Q) -> Option<&Self::Item>;
    }

    /// A set that supports removal using items of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Collection>::Item>: Get<Q> + collection::Remove {
        /// Removes the item in the set that is equivalent to the given item.
        ///
        /// Returns `true` if the set contained such an item, `false` otherwise.
        ///
        /// This is equivalent to `self.take(item).is_some()`, but may be optimized.
        fn remove(&mut self, item: &Q) -> bool {
            self.take(item).is_some()
        }

        /// Removes the item in the set that is equivalent to the given item and returns it.
        ///
        /// Returns `None` if the set contained no such item.
        fn take(&mut self, item: &Q) -> Option<Self::Item>;
    }

    /// A set that supports insertion.
    pub trait Insert: Set + collection::Insert {
        /// Inserts the given item into the set without replacing an equivalent item.
        ///
        /// Returns `true` if the set did not contain an equivalent item, `false` otherwise.
        fn insert(&mut self, item: Self::Item) -> bool;

        /// Inserts the given item into the set, replacing an equivalent item.
        ///
        /// Returns the equivalent item if the set contained one, `None` otherwise.
        fn replace(&mut self, item: Self::Item) -> Option<Self::Item>;
    }
}

#[allow(dead_code)]
fn assert_object_safe() {
    let _: Collection<Item = String>;
    let _: collection::Insert<Item = String>;
    let _: collection::Remove<Item = String>;

    let _: &List<Item = String>;
    let _: &list::Insert<Item = String>;
    let _: &list::Remove<Item = String>;

    let _: &Map<Item = (String, i32), Key = String, Value = i32>;
    let _: &map::Insert<Item = (String, i32), Key = String, Value = i32>;
    let _: &map::Get<str, Item = (String, i32), Key = String, Value = i32>;
    let _: &map::Remove<str, Item = (String, i32), Key = String, Value = i32>;
    let _: &map::OccupiedEntry<Key = String, Value = i32, MutValue = &mut i32>;
    let _: &map::VacantEntry<Key = String, Value = i32, MutValue = &mut i32>;

    let _: &seq::PushBack<Item = String>;
    let _: &Queue<Item = String>;
    let _: &Stack<Item = String>;
    let _: &Deque<Item = String>;

    let _: &Set<Item = String>;
    let _: &set::Insert<Item = String>;
    let _: &set::Get<str, Item = String>;
    let _: &set::Remove<str, Item = String>;
}
<|endoftext|>


<commit_before>//! Tiny OBJ loader, inspired by Syoyo's excellent [tinyobjloader](https://github.com/syoyo/tinyobjloader)

#![allow(dead_code)]

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::cmp::{Eq, Ord, PartialOrd, Ordering};
use std::collections::BTreeMap;
use std::str::{FromStr, Words};

/// A mesh for some model containing its triangle geometry
/// This object could be a single polygon group or object within a file
/// that defines multiple groups/objects or be the only mesh within the file
/// if it only contains a single mesh
#[derive(Debug)]
pub struct Mesh {
    positions: Vec<f32>,
    normals: Option<Vec<f32>>,
    texcoords: Option<Vec<f32>>,
    faces: Vec<u32>,
}

impl Mesh {
    /// Create a new mesh specifying the geometry for the mesh
    pub fn new(pos: Vec<f32>, norm: Option<Vec<f32>>, tex: Option<Vec<f32>>, faces: Vec<u32>) -> Mesh {
        Mesh { positions: pos, normals: norm, texcoords: tex, faces: faces }
    }
}

/// A named model within the file
/// This could be a group or object or the single model exported by the file
#[derive(Debug)]
pub struct Model {
    mesh: Mesh,
    name: String,
}

impl Model {
    /// Create a new model, associating a name with a mesh
    pub fn new(mesh: Mesh, name: String) -> Model {
        Model { mesh: mesh, name: name }
    }
}

/// TODO: Decide on various errors we'll return
#[derive(Debug)]
pub enum LoadError {
    OpenFileFailed,
    ReadError,
    UnrecognizedCharacter,
    GenericFailure,
}

/// LoadResult is a result containing all the models loaded from the file or any
/// error that occured while loading
pub type LoadResult = Result<Vec<Model>, LoadError>;

/// Struct storing indices corresponding to the vertex
/// Some vertices may not have texcoords or normals, 0 is used to indicate this
/// as OBJ indices begin at 1
/// TODO: Should use std::btree_map::BTreeMap to store the mapping of VertexIndices -> index
#[derive(Eq, PartialEq, PartialOrd, Ord, Debug)]
struct VertexIndices {
    v: u32,
    vt: u32,
    vn: u32,
}

impl VertexIndices {
    /// Parse the vertex indices from the face string
    /// Valid face strings are those that are valid for a Wavefront OBJ file
    /// Returns None if the face string is invalid
    pub fn parse(face_str: &str) -> Option<VertexIndices> {
        println!("Parsing face string {}", face_str);
        let mut indices = [0; 3];
        for i in face_str.split('/').enumerate() {
            println!("Index: {}, element index: {}", i.1, i.0);
            match FromStr::from_str(i.1) {
                Ok(x) => indices[i.0] = x,
                Err(_) => return None,
            }
        }
        Some(VertexIndices { v: indices[0], vt: indices[1], vn: indices[2] })
    }
}

/// Parse vertex indices for a face and write them to the index buffer
/// will push new positions, normals and texcoords and create a new index if the vertex hasn't been created
/// returns false if parsing a face failed
fn parse_face(face_str: Words, pos: &mut Vec<f32>, normals: &mut Vec<f32>, texcoords: &mut Vec<f32>,
              indices: &mut Vec<u32>, vertex_map: &mut BTreeMap<VertexIndices, u32>) -> bool {
    true
}

/// Load the various meshes in an OBJ file
pub fn load_obj(file_name: &str) -> LoadResult {
    println!("Loading file {}", file_name);
    let mut file = match File::open(file_name) {
        Ok(f) => f,
        Err(e) => {
            println!("tobj::load_obj - failed to open {} due to {}", file_name, e);
            return Err(LoadError::OpenFileFailed);
        },
    };
    let mut reader = BufReader::new(file);
    load_obj_buf(&mut reader)
}

/// Load the various meshes in an OBJ buffer
pub fn load_obj_buf<B: BufRead>(reader: &mut B) -> LoadResult {
    let mut models = Vec::new();
    /*
    let mut tmp_pos = Vec::new();
    let mut tmp_normals = Vec::new();
    let mut tmp_texcoords = Vec::new();
    */
    for line in reader.lines() {
        // We just need the line for debugging for a bit
        let (line, mut words) = match line {
            Ok(ref line) => (&line[..], line[..].words()),
            Err(e) => {
                println!("tobj::load_obj - failed to read line due to {}", e);
                return Err(LoadError::ReadError);
            },
        };
        match words.next() {
            Some("#") => { println!("Skipping comment"); continue; },
            Some("v") => { println!("Will parse vertex {}", line); },
            Some("vt") => { println!("Will parse texcoord {}", line); },
            Some("vn") => { println!("Will parse normal {}", line); },
            Some("f") => {
                println!("Will parse face {}", line);
                let face = match words.next() {
                    Some(f) => VertexIndices::parse(f),
                    None => None,
                };
                match face {
                    Some(f) => println!("Valid face, {:?}", f),
                    None => println!("Invalid face string"),
                }
            },
            Some("o") => { println!("Will parse object {}", line); },
            Some("g") => { println!("Will parse group {}", line); },
            Some("mtllib") => { println!("Will parse material lib {}", line); },
            Some("usemtl") => { println!("Will parse usemtl {}", line); },
            None => { println!("Skipping empty line"); continue; },
            Some(_) => { println!("Unrecognized character"); return Err(LoadError::UnrecognizedCharacter) },
        }
    }
    Ok(models)
}

#[test]
fn test_basic(){
    assert!(load_obj("triangle.obj").is_ok());
}

<commit_msg>Now parse out positions, normals and texcoords<commit_after>//! Tiny OBJ loader, inspired by Syoyo's excellent [tinyobjloader](https://github.com/syoyo/tinyobjloader)

#![allow(dead_code)]

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::cmp::{Eq, Ord, PartialOrd, Ordering};
use std::collections::BTreeMap;
use std::str::{FromStr, Words};

/// A mesh for some model containing its triangle geometry
/// This object could be a single polygon group or object within a file
/// that defines multiple groups/objects or be the only mesh within the file
/// if it only contains a single mesh
#[derive(Debug)]
pub struct Mesh {
    positions: Vec<f32>,
    normals: Option<Vec<f32>>,
    texcoords: Option<Vec<f32>>,
    faces: Vec<u32>,
}

impl Mesh {
    /// Create a new mesh specifying the geometry for the mesh
    pub fn new(pos: Vec<f32>, norm: Option<Vec<f32>>, tex: Option<Vec<f32>>, faces: Vec<u32>) -> Mesh {
        Mesh { positions: pos, normals: norm, texcoords: tex, faces: faces }
    }
}

/// A named model within the file
/// This could be a group or object or the single model exported by the file
#[derive(Debug)]
pub struct Model {
    mesh: Mesh,
    name: String,
}

impl Model {
    /// Create a new model, associating a name with a mesh
    pub fn new(mesh: Mesh, name: String) -> Model {
        Model { mesh: mesh, name: name }
    }
}

/// TODO: Decide on various errors we'll return
#[derive(Debug)]
pub enum LoadError {
    OpenFileFailed,
    ReadError,
    UnrecognizedCharacter,
    PositionParseError,
    NormalParseError,
    TexcoordParseError,
    GenericFailure,
}

/// LoadResult is a result containing all the models loaded from the file or any
/// error that occured while loading
pub type LoadResult = Result<Vec<Model>, LoadError>;

/// Struct storing indices corresponding to the vertex
/// Some vertices may not have texcoords or normals, 0 is used to indicate this
/// as OBJ indices begin at 1
/// TODO: Should use std::btree_map::BTreeMap to store the mapping of VertexIndices -> index
#[derive(Eq, PartialEq, PartialOrd, Ord, Debug)]
struct VertexIndices {
    v: u32,
    vt: u32,
    vn: u32,
}

impl VertexIndices {
    /// Parse the vertex indices from the face string
    /// Valid face strings are those that are valid for a Wavefront OBJ file
    /// Returns None if the face string is invalid
    pub fn parse(face_str: &str) -> Option<VertexIndices> {
        println!("Parsing face string {}", face_str);
        let mut indices = [0; 3];
        for i in face_str.split('/').enumerate() {
            println!("Index: {}, element index: {}", i.1, i.0);
            match FromStr::from_str(i.1) {
                Ok(x) => indices[i.0] = x,
                Err(_) => return None,
            }
        }
        Some(VertexIndices { v: indices[0], vt: indices[1], vn: indices[2] })
    }
}

/// Parse the floatn information from the words, words is an iterator over the float strings
/// Returns false if parsing failed
fn parse_floatn(val_str: Words, vals: &mut Vec<f32>, n: usize) -> bool {
    let sz = vals.len();
    for p in val_str {
        match FromStr::from_str(p) {
            Ok(x) => vals.push(x),
            Err(_) => return false,
        }
    }
    // Require that we found an x, y, z coordinate
    sz + n == vals.len()
}

/// Parse vertex indices for a face and write them to the index buffer
/// will push new positions, normals and texcoords and create a new index if the vertex hasn't been created
/// returns false if parsing a face failed
fn parse_face(face_str: Words, pos: &mut Vec<f32>, normals: &mut Vec<f32>, texcoords: &mut Vec<f32>,
              indices: &mut Vec<u32>, vertex_map: &mut BTreeMap<VertexIndices, u32>) -> bool {
    true
}

/// Load the various meshes in an OBJ file
pub fn load_obj(file_name: &str) -> LoadResult {
    println!("Loading file {}", file_name);
    let mut file = match File::open(file_name) {
        Ok(f) => f,
        Err(e) => {
            println!("tobj::load_obj - failed to open {} due to {}", file_name, e);
            return Err(LoadError::OpenFileFailed);
        },
    };
    let mut reader = BufReader::new(file);
    load_obj_buf(&mut reader)
}

/// Load the various meshes in an OBJ buffer
pub fn load_obj_buf<B: BufRead>(reader: &mut B) -> LoadResult {
    let mut models = Vec::new();
    let mut tmp_pos = Vec::new();
    let mut tmp_normals = Vec::new();
    let mut tmp_texcoords = Vec::new();
    for line in reader.lines() {
        // We just need the line for debugging for a bit
        let (line, mut words) = match line {
            Ok(ref line) => (&line[..], line[..].words()),
            Err(e) => {
                println!("tobj::load_obj - failed to read line due to {}", e);
                return Err(LoadError::ReadError);
            },
        };
        match words.next() {
            Some("#") => { println!("Skipping comment"); continue; },
            Some("v") => {
                println!("Will parse vertex {}", line);
                if !parse_floatn(words, &mut tmp_pos, 3) {
                    return Err(LoadError::PositionParseError);
                }
            },
            Some("vt") => {
                println!("Will parse texcoord {}", line);
                if !parse_floatn(words, &mut tmp_texcoords, 2) {
                    return Err(LoadError::TexcoordParseError);
                }
            },
            Some("vn") => {
                println!("Will parse normal {}", line);
                if !parse_floatn(words, &mut tmp_normals, 3) {
                    return Err(LoadError::NormalParseError);
                }
            },
            Some("f") => {
                println!("Will parse face {}", line);
                let face = match words.next() {
                    Some(f) => VertexIndices::parse(f),
                    None => None,
                };
                match face {
                    Some(f) => println!("Valid face, {:?}", f),
                    None => println!("Invalid face string"),
                }
            },
            Some("o") => { println!("Will parse object {}", line); },
            Some("g") => { println!("Will parse group {}", line); },
            Some("mtllib") => { println!("Will parse material lib {}", line); },
            Some("usemtl") => { println!("Will parse usemtl {}", line); },
            None => { println!("Skipping empty line"); continue; },
            Some(_) => { println!("Unrecognized character"); return Err(LoadError::UnrecognizedCharacter) },
        }
    }
    println!("Positions: {:?}", tmp_pos);
    println!("Normals: {:?}", tmp_normals);
    println!("Texcoords: {:?}", tmp_texcoords);
    Ok(models)
}

#[test]
fn test_basic(){
    assert!(load_obj("triangle.obj").is_ok());
}

<|endoftext|>


<commit_before>#![crate_type="lib"]
#![feature(str_char)]

pub use sys::Window;

pub use button::Button;
pub use cell::{CopyCell, CloneCell};
pub use click::Click;
pub use color::Color;
pub use enter::Enter;
pub use event::Event;
pub use label::Label;
pub use place::Place;
pub use point::Point;
pub use progress_bar::ProgressBar;
pub use rect::Rect;
pub use renderer::Renderer;
pub use text_box::TextBox;
pub use widget::Widget;

pub mod button;
pub mod cell;
pub mod click;
pub mod color;
pub mod enter;
pub mod event;
pub mod label;
pub mod place;
pub mod point;
pub mod progress_bar;
pub mod rect;
pub mod renderer;
pub mod text_box;
pub mod widget;

#[cfg(target_os = "redox")]
#[path="orbital/mod.rs"]
pub mod sys;

#[cfg(not(target_os = "redox"))]
#[path="sdl2/mod.rs"]
pub mod sys;

pub fn example() {
    let mut window = Window::new(Rect::new(100, 100, 420, 420), "OrbTK");

    let x = 10;
    let mut y = 10;

    let label = Label::new()
        .text("Test Label")
        .position(x, y)
        .size(400, 16)
        .place(&mut window);

    y += label.rect.get().height as isize + 10;

    let text_box = TextBox::new()
        .position(x, y)
        .size(302, 16)
        .on_enter(move |text_box: &TextBox| -> bool {
            label.text.set(text_box.text.get());
            false
        })
        .place(&mut window);

    y += text_box.rect.get().height as isize + 10;

    let progress_label = Label::new()
        .text("Progress: 0%")
        .position(x, y)
        .size(400, 16)
        .place(&mut window);

    y += progress_label.rect.get().height as isize + 10;

    let progress_bar = ProgressBar::new()
        .position(x, y)
        .size(400, 16)
        .on_click(move |progress_bar: &ProgressBar, point: Point| {
            let progress = point.x * 100 / progress_bar.rect.get().width as isize;
            progress_label.text.set(format!("Progress: {}%", progress));
            progress_bar.value.set(progress);
        })
        .place(&mut window);

    y += progress_bar.rect.get().height as isize + 10;

    let multi_line_label = Label::new()
        .text("Multi-Line Text")
        .position(x, y)
        .size(400, 16)
        .place(&mut window);

    y += multi_line_label.rect.get().height as isize + 10;

    TextBox::new()
        .position(x, y)
        .size(400, 128)
        .place(&mut window);

    window.exec();
}
<commit_msg>Readd button<commit_after>#![crate_type="lib"]
#![feature(str_char)]

pub use sys::Window;

pub use button::Button;
pub use cell::{CopyCell, CloneCell};
pub use click::Click;
pub use color::Color;
pub use enter::Enter;
pub use event::Event;
pub use label::Label;
pub use place::Place;
pub use point::Point;
pub use progress_bar::ProgressBar;
pub use rect::Rect;
pub use renderer::Renderer;
pub use text_box::TextBox;
pub use widget::Widget;

pub mod button;
pub mod cell;
pub mod click;
pub mod color;
pub mod enter;
pub mod event;
pub mod label;
pub mod place;
pub mod point;
pub mod progress_bar;
pub mod rect;
pub mod renderer;
pub mod text_box;
pub mod widget;

#[cfg(target_os = "redox")]
#[path="orbital/mod.rs"]
pub mod sys;

#[cfg(not(target_os = "redox"))]
#[path="sdl2/mod.rs"]
pub mod sys;

pub fn example() {
    let mut window = Window::new(Rect::new(100, 100, 420, 420), "OrbTK");

    let x = 10;
    let mut y = 10;

    let label = Label::new()
        .position(x, y)
        .size(400, 16)
        .text("Test Label")
        .place(&mut window);

    y += label.rect.get().height as isize + 10;

    let text_box = TextBox::new()
        .position(x, y)
        .size(342, 16)
        .on_enter(move |text_box: &TextBox| -> bool {
            label.text.set(text_box.text.get());
            false
        })
        .place(&mut window);

    let button = Button::new()
        .position(x + text_box.rect.get().width as isize + 10, y)
        .size(48, text_box.rect.get().height)
        .text("Update")
        .on_click(move |_button: &Button, _point: Point| {
            text_box.trigger_enter();
        })
        .place(&mut window);

    y += button.rect.get().height as isize + 10;

    let progress_label = Label::new()
        .text("Progress: 0%")
        .position(x, y)
        .size(400, 16)
        .place(&mut window);

    y += progress_label.rect.get().height as isize + 10;

    let progress_bar = ProgressBar::new()
        .position(x, y)
        .size(400, 16)
        .on_click(move |progress_bar: &ProgressBar, point: Point| {
            let progress = point.x * 100 / progress_bar.rect.get().width as isize;
            progress_label.text.set(format!("Progress: {}%", progress));
            progress_bar.value.set(progress);
        })
        .place(&mut window);

    y += progress_bar.rect.get().height as isize + 10;

    let multi_line_label = Label::new()
        .text("Multi-Line Text")
        .position(x, y)
        .size(400, 16)
        .place(&mut window);

    y += multi_line_label.rect.get().height as isize + 10;

    TextBox::new()
        .position(x, y)
        .size(400, 128)
        .place(&mut window);

    window.exec();
}
<|endoftext|>


<commit_before>use std::io::{ Result, Read };

trait ReadExt: Read {
    /// Read all bytes until EOF in this source, returning them as a new `Vec`.
    ///
    /// See `read_to_end` for other semantics.
    fn read_into_vec(&mut self) -> Result<Vec<u8>> {
        let mut buf = Vec::new();
        let res = self.read_to_end(&mut buf);
        res.map(|_| buf)
    }

    /// Read all bytes until EOF in this source, returning them as a new buffer.
    ///
    /// See `read_to_string` for other semantics.
    fn read_into_string(&mut self) -> Result<String> {
        let mut buf = String::new();
        let res = self.read_to_string(&mut buf);
        res.map(|_| buf)
    }
}
<commit_msg>fix(lib): make trait public and impl for Read<commit_after>use std::io::{ Result, Read };

pub trait ReadExt: Read {
    /// Read all bytes until EOF in this source, returning them as a new `Vec`.
    ///
    /// See `read_to_end` for other semantics.
    fn read_into_vec(&mut self) -> Result<Vec<u8>> {
        let mut buf = Vec::new();
        let res = self.read_to_end(&mut buf);
        res.map(|_| buf)
    }

    /// Read all bytes until EOF in this source, returning them as a new buffer.
    ///
    /// See `read_to_string` for other semantics.
    fn read_into_string(&mut self) -> Result<String> {
        let mut buf = String::new();
        let res = self.read_to_string(&mut buf);
        res.map(|_| buf)
    }
}

impl<T> ReadExt for T where T: Read {}
<|endoftext|>


<commit_before>#![crate_name = "nest"]
#![warn(missing_docs)]
#![deny(warnings)]

//! nest is a glium port of the [nest](https://crates.io/crates/nest)
//! crate which is a port of the [nest](https://nest.org/) lua graphics
//! library. This library was developed as a 2D graphics prototyping library and
//! is not ment for high-performance.
//!
//! # Example
//!
//! ```rust,no_run
//! extern crate nest;
//! use nest::{Window, Event};
//!
//! fn main() {
//! let mut app = Window::new("Window Example", 640, 480);
//!
//! 'main: loop {
//! Note rust requires this code to be in a closure to please the borrow checker
//! {
//! let mut frame = app.next_frame();
//! frame.clear();
//!
//! frame.set_color(1.0, 1.0, 1.0, 1.0);
//! frame.draw_rect(0.0, 0.0, 1.0, 1.0);
//!
//! frame.finish();
//! }
//!
//! for ev in app.poll_events() {
//! match ev {
//! Event::Closed => break 'main,
//! _ => (),
//! }
//! }
//! }
//! }
//! ```
//!
//! Current renderable objects are:
//!
//! Line (soon to be depricated)
//! Polygon (TrianglFan)
//! Rectangle
//! Circle (really an oval)
//! Image (with cropping)
//! Color (HTML / RGBA)
//! Alpha Blend Transparency
//!
//! Planned features include:
//!
//! - Rotation
//! - Text (ttf fonts)
//! - Text (char-map)
//! - Audio
//!

#[macro_use]
extern crate glium;
extern crate image as img;

pub mod support;
mod frame;
mod window;
mod image;
mod shape;

pub use window::Window;
pub use frame::Frame;
pub use shape::*;
pub use support::events::Event;
pub use support::vertex;
pub use support::shaders::ShaderMode;
pub use image::Image;
pub use image::LoadImageError;
pub use image::ImageParameters;
/// Re-export of `glium::glutin::ElementState`
pub use glium::glutin::ElementState;
/// Re-export of `glium::glutin::VirtualKeyCode`
pub use glium::glutin::VirtualKeyCode;
<commit_msg>add color module to lib.rs<commit_after>#![crate_name = "nest"]
#![warn(missing_docs)]
#![deny(warnings)]

//! nest is a glium port of the [nest](https://crates.io/crates/nest)
//! crate which is a port of the [nest](https://nest.org/) lua graphics
//! library. This library was developed as a 2D graphics prototyping library and
//! is not ment for high-performance.
//!
//! # Example
//!
//! ```rust,no_run
//! extern crate nest;
//! use nest::{Window, Event};
//!
//! fn main() {
//! let mut app = Window::new("Window Example", 640, 480);
//!
//! 'main: loop {
//! Note rust requires this code to be in a closure to please the borrow checker
//! {
//! let mut frame = app.next_frame();
//! frame.clear();
//!
//! frame.set_color(1.0, 1.0, 1.0, 1.0);
//! frame.draw_rect(0.0, 0.0, 1.0, 1.0);
//!
//! frame.finish();
//! }
//!
//! for ev in app.poll_events() {
//! match ev {
//! Event::Closed => break 'main,
//! _ => (),
//! }
//! }
//! }
//! }
//! ```
//!
//! Current renderable objects are:
//!
//! Line (soon to be depricated)
//! Polygon (TrianglFan)
//! Rectangle
//! Circle (really an oval)
//! Image (with cropping)
//! Color (HTML / RGBA)
//! Alpha Blend Transparency
//!
//! Planned features include:
//!
//! - Rotation
//! - Text (ttf fonts)
//! - Text (char-map)
//! - Audio
//!

#[macro_use]
extern crate glium;
extern crate image as img;
extern crate cgmath as cgm;

pub mod support;
mod frame;
mod window;
mod image;
mod shape;
mod color;

pub use window::Window;
pub use frame::Frame;
pub use shape::*;
pub use support::events::Event;
pub use support::vertex;
pub use support::shaders::ShaderMode;
pub use image::Image;
pub use image::LoadImageError;
pub use image::ImageParameters;
/// Re-export of `glium::glutin::ElementState`
pub use glium::glutin::ElementState;
/// Re-export of `glium::glutin::VirtualKeyCode`
pub use glium::glutin::VirtualKeyCode;
<|endoftext|>