<commit_before>use std::collections::BTreeMap;
use std::fmt;
use std::fmt::{Debug, Display};
use std::iter::FromIterator;

use itertools::Itertools;
use lazy_init::Lazy;

/// Token features.
///
/// In the CoNLL-X specification, these are morphological features of the
/// token. Typically, the features are a list or a key-value mapping.
pub struct Features {
    features: String,
    feature_map: Lazy<BTreeMap<String, Option<String>>>,
}

impl Features {
    /// Create features from a string. The casual format uses key-value
    /// pairs that are separated by a vertical bar (`|`) and keys and
    /// values using a colon (`:`). Arbitrary strings will also be accepted,
    /// however they will not give a nice feature-value mapping when using
    /// `as_map`.
    pub fn from_string<S>(s: S) -> Self
    where
        S: Into<String>,
    {
        Features {
            features: s.into(),
            feature_map: Lazy::new(),
        }
    }

    pub fn from_iter<I, S, T>(iter: I) -> Self
    where
        I: IntoIterator<Item = (S, Option<T>)>,
        S: Into<String>,
        T: Into<String>,
    {
        let feature_map =
            BTreeMap::from_iter(iter.into_iter().map(|(k, v)| (k.into(), v.map(Into::into))));
        let features = map_to_string(&feature_map);

        let lazy_feature_map = Lazy::new();
        lazy_feature_map.get_or_create(|| feature_map);

        Features {
            features,
            feature_map: lazy_feature_map,
        }
    }

    /// Get the features field as a key-value mapping. This assumes that
    /// the key-value pairs are separed using a vertical bar (`|`) and keys
    /// and values using a colon (`:`). If the value is absent, corresponding
    /// value in the mapping is `None`.
    ///
    /// The feature map is constructed lazily:
    ///
    /// * If `as_map` is never called, the feature map is never created.
    /// * If `as_map` is called once or more, the feature map is only created
    ///   once.
    pub fn as_map(&self) -> &BTreeMap<String, Option<String>> {
        self.feature_map.get_or_create(|| self.as_map_eager())
    }

    /// Get the features field.
    pub fn as_str(&self) -> &str {
        self.features.as_ref()
    }

    /// Unwrap the contained feature string and map. Since the feature map is
    /// initialized lazily, this will force initialization of the feature map
    /// when necessary.
    pub fn into_inner(self) -> (String, BTreeMap<String, Option<String>>) {
        let _ = self.feature_map.get_or_create(|| self.as_map_eager());
        (
            self.features,
            self.feature_map
                .into_inner()
                .expect("feature map should have been initialized"),
        )
    }

    /// Unwrap the contained feature map. Since the feature map is initialized
    /// lazily, this will force initialization of the feature map when necessary.
    pub fn into_inner_map(self) -> BTreeMap<String, Option<String>> {
        let _ = self.feature_map.get_or_create(|| self.as_map_eager());
        self.feature_map
            .into_inner()
            .expect("feature map should have been initialized")
    }

    /// Unwrap the contained feature string.
    pub fn into_inner_string(self) -> String {
        self.features
    }

    fn as_map_eager(&self) -> BTreeMap<String, Option<String>> {
        let mut features = BTreeMap::new();

        for fv in self.features.split('|') {
            let mut iter = fv.split(':');
            if let Some(k) = iter.next() {
                let v = iter.next().map(|s| s.to_owned());
                features.insert(k.to_owned(), v.to_owned());
            }
        }

        features
    }
}

impl Clone for Features {
    fn clone(&self) -> Self {
        Features {
            features: self.features.clone(),
            feature_map: Lazy::new(),
        }
    }
}

impl Debug for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Features {{ features: {} }}", self.features)
    }
}

impl Display for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.features.as_ref())
    }
}

impl Eq for Features {}

impl PartialEq for Features {
    fn eq(&self, other: &Features) -> bool {
        self.features.eq(&other.features)
    }
}

fn map_to_string(feature_map: &BTreeMap<String, Option<String>>) -> String {
    feature_map
        .iter()
        .map(|(k, v)| match *v {
            Some(ref v) => format!("{}:{}", k, v),
            None => k.to_owned(),
        })
        .join("|")
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::Features;

    #[test]
    quickcheck! {
        fn from_iter(feature_map: BTreeMap<String, Option<String>>) -> bool{
            &feature_map == Features::from_iter(feature_map.clone()).as_map()
        }
    }

    #[test]
    fn from_iter_as_string() {
        let feature_map = btreemap!{
            "feature2" => Some("y"),
            "feature3" => None,
            "feature1" => Some("x")
        };

        let features = Features::from_iter(feature_map);

        assert_eq!(features.as_str(), "feature1:x|feature2:y|feature3");
    }
}
<commit_msg>Remove unnecessary test attribute.<commit_after>use std::collections::BTreeMap;
use std::fmt;
use std::fmt::{Debug, Display};
use std::iter::FromIterator;

use itertools::Itertools;
use lazy_init::Lazy;

/// Token features.
///
/// In the CoNLL-X specification, these are morphological features of the
/// token. Typically, the features are a list or a key-value mapping.
pub struct Features {
    features: String,
    feature_map: Lazy<BTreeMap<String, Option<String>>>,
}

impl Features {
    /// Create features from a string. The casual format uses key-value
    /// pairs that are separated by a vertical bar (`|`) and keys and
    /// values using a colon (`:`). Arbitrary strings will also be accepted,
    /// however they will not give a nice feature-value mapping when using
    /// `as_map`.
    pub fn from_string<S>(s: S) -> Self
    where
        S: Into<String>,
    {
        Features {
            features: s.into(),
            feature_map: Lazy::new(),
        }
    }

    pub fn from_iter<I, S, T>(iter: I) -> Self
    where
        I: IntoIterator<Item = (S, Option<T>)>,
        S: Into<String>,
        T: Into<String>,
    {
        let feature_map =
            BTreeMap::from_iter(iter.into_iter().map(|(k, v)| (k.into(), v.map(Into::into))));
        let features = map_to_string(&feature_map);

        let lazy_feature_map = Lazy::new();
        lazy_feature_map.get_or_create(|| feature_map);

        Features {
            features,
            feature_map: lazy_feature_map,
        }
    }

    /// Get the features field as a key-value mapping. This assumes that
    /// the key-value pairs are separed using a vertical bar (`|`) and keys
    /// and values using a colon (`:`). If the value is absent, corresponding
    /// value in the mapping is `None`.
    ///
    /// The feature map is constructed lazily:
    ///
    /// * If `as_map` is never called, the feature map is never created.
    /// * If `as_map` is called once or more, the feature map is only created
    ///   once.
    pub fn as_map(&self) -> &BTreeMap<String, Option<String>> {
        self.feature_map.get_or_create(|| self.as_map_eager())
    }

    /// Get the features field.
    pub fn as_str(&self) -> &str {
        self.features.as_ref()
    }

    /// Unwrap the contained feature string and map. Since the feature map is
    /// initialized lazily, this will force initialization of the feature map
    /// when necessary.
    pub fn into_inner(self) -> (String, BTreeMap<String, Option<String>>) {
        let _ = self.feature_map.get_or_create(|| self.as_map_eager());
        (
            self.features,
            self.feature_map
                .into_inner()
                .expect("feature map should have been initialized"),
        )
    }

    /// Unwrap the contained feature map. Since the feature map is initialized
    /// lazily, this will force initialization of the feature map when necessary.
    pub fn into_inner_map(self) -> BTreeMap<String, Option<String>> {
        let _ = self.feature_map.get_or_create(|| self.as_map_eager());
        self.feature_map
            .into_inner()
            .expect("feature map should have been initialized")
    }

    /// Unwrap the contained feature string.
    pub fn into_inner_string(self) -> String {
        self.features
    }

    fn as_map_eager(&self) -> BTreeMap<String, Option<String>> {
        let mut features = BTreeMap::new();

        for fv in self.features.split('|') {
            let mut iter = fv.split(':');
            if let Some(k) = iter.next() {
                let v = iter.next().map(|s| s.to_owned());
                features.insert(k.to_owned(), v.to_owned());
            }
        }

        features
    }
}

impl Clone for Features {
    fn clone(&self) -> Self {
        Features {
            features: self.features.clone(),
            feature_map: Lazy::new(),
        }
    }
}

impl Debug for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Features {{ features: {} }}", self.features)
    }
}

impl Display for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.features.as_ref())
    }
}

impl Eq for Features {}

impl PartialEq for Features {
    fn eq(&self, other: &Features) -> bool {
        self.features.eq(&other.features)
    }
}

fn map_to_string(feature_map: &BTreeMap<String, Option<String>>) -> String {
    feature_map
        .iter()
        .map(|(k, v)| match *v {
            Some(ref v) => format!("{}:{}", k, v),
            None => k.to_owned(),
        })
        .join("|")
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::Features;

    quickcheck! {
        fn from_iter(feature_map: BTreeMap<String, Option<String>>) -> bool{
            &feature_map == Features::from_iter(feature_map.clone()).as_map()
        }
    }

    #[test]
    fn from_iter_as_string() {
        let feature_map = btreemap!{
            "feature2" => Some("y"),
            "feature3" => None,
            "feature1" => Some("x")
        };

        let features = Features::from_iter(feature_map);

        assert_eq!(features.as_str(), "feature1:x|feature2:y|feature3");
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Linux-specific utilities for working with the filesystem.

use std::path::Path;

// TODO: Document behaviour for symlinks.
/// Collects extended flags of the specified file.
///
/// The returned mask represents file attributes specific to the Linux extended
/// file system. Normally, they can be inspected using the `lsattr` command and
/// can be set through the `chattr` command.
///
/// See the [Wikipedia] article and the [man] page for more details.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Chattr
/// [man]: https://linux.die.net/man/1/chattr
///
/// # Examples
///
/// ```no_run
/// const FS_FL_USER_VISIBLE: u32 = 0x0003DFFF;
///
/// let flags = rrg::fs::linux::flags("/tmp/foo").unwrap();
/// assert_eq!(flags & FS_FL_USER_VISIBLE, 0);
/// ```
pub fn flags<P>(path: P) -> std::io::Result<u32> where
    P: AsRef<Path>
{
    let file = std::fs::File::open(path)?;

    let mut flags = 0;
    let code = unsafe {
        // This block is safe: we simply pass a raw file descriptor (that is
        // valid until the end of the scope of this function) because this is
        // what the low-level API expects.
        use std::os::unix::io::AsRawFd as _;
        ioctls::fs_ioc_getflags(file.as_raw_fd(), &mut flags)
    };

    if code == 0 {
        Ok(flags as u32)
    } else {
        Err(std::io::Error::from_raw_os_error(code))
    }
}

pub fn ext_attr_names<P>(path: P) -> std::io::Result<Vec<std::ffi::OsString>>
where
    P: AsRef<Path>,
{
    extern "C" {
        // https://man7.org/linux/man-pages/man2/listxattr.2.html
        fn llistxattr(
            path: *const libc::c_char,
            list: *mut libc::c_char,
            size: libc::size_t,
        ) -> libc::ssize_t;
    }

    use std::os::unix::ffi::OsStrExt as _;

    let os_str_path = path.as_ref().as_os_str();
    let c_str_path = std::ffi::CString::new(os_str_path.as_bytes())
        // It is not possible to have a null byte in a Linux path.
        .expect("path with a null character");

    // SAFETY: The correctness of the path is guaranteed by conversion to the
    // `CString` type above. The rest is just is a FFI call respecting the spec.
    let len = unsafe {
        // First we call `llistxattr` with empty buffer to get the size of the
        // buffer that will collect the actual results.
        llistxattr(c_str_path.as_ptr(), std::ptr::null_mut(), 0)
    };
    if len < 0 {
        return Err(std::io::Error::last_os_error());
    }

    let mut buf = vec![0; len as usize];

    // SAFETY: The correctness of the path is guaranteed by conversion to the
    // `CString` type above. For remaining parameters we provide a buffer with
    // length obtained through the previous call and we explicitly supply its
    // length as well. In case the result length increases between the calls the
    // system will report an error but will not cause memory issues.
    let len = unsafe {
        // Now we can call `llistxattr` with the actual buffer of the size we
        // determined by the previous call.
        llistxattr(c_str_path.as_ptr(), buf.as_mut_ptr(), buf.len())
    };
    if len < 0 {
        return Err(std::io::Error::last_os_error());
    }

    // It is possible that the `len` value is smaller than as returned by the
    // first `llistxattr` call if somebody tampered with the file in the mean-
    // time. To avoid having spurious empty slices (as each following null byte
    // would cause the `split_inclusive` iterator to yield one), we trim the
    // buffer to the acutally returned length.
    //
    // Note that it is impossible for the `len` value to increase, as otherwise
    // the `llistxattr` would fail.
    let result = buf[..len as usize]
        .split_inclusive(|byte| *byte == 0)
        .map(|slice| {
            // SAFETY: The slice is guaranteed to be terminated with a null byte
            // and not contain any null bytes elsewhere because of the splitting
            // above. This holds true also for the last slice provided by the
            // iterator.
            let c_str = unsafe {
                std::ffi::CStr::from_ptr(slice.as_ptr())
            };

            std::ffi::OsStr::from_bytes(c_str.to_bytes()).to_os_string()
        })
        .collect();

    Ok(result)
}

pub fn ext_attr_value<P, S>(path: P, name: S) -> std::io::Result<Vec<u8>>
where
    P: AsRef<Path>,
    S: AsRef<std::ffi::OsStr>,
{
    extern "C" {
        // https://man7.org/linux/man-pages/man2/getxattr.2.html
        fn lgetxattr(
            path: *const libc::c_char,
            name: *const libc::c_char,
            value: *mut libc::c_void,
            size: libc::size_t,
        ) -> libc::ssize_t;
    }

    use std::os::unix::ffi::OsStrExt as _;

    let os_str_path = path.as_ref().as_os_str();
    let c_str_path = std::ffi::CString::new(os_str_path.as_bytes())
        // It is not possible to have a null byte in a Linux path.
        .expect("path with a null character");

    let c_str_name = std::ffi::CString::new(name.as_ref().as_bytes())
        // While `name` as returned by the `ext_attr_names` function cannot have
        // null bytes inside, we cannot guarantee that the user doesn't supply
        // a bogus string here. Thus, we have to do proper error handling here.
        .map_err(|error| {
            std::io::Error::new(std::io::ErrorKind::InvalidInput, error)
        })?;

    // SAFETY: The correctness of the path and name is guaranteed by conversion
    // to the `CString` type above. The rest is just is a FFI call respecting
    // the spec.
    let len = unsafe {
        // First we call `lgetxattr` with empty buffer to get the size of the
        // buffer that will collect the actual results.
        lgetxattr(c_str_path.as_ptr(), c_str_name.as_ptr(), std::ptr::null_mut(), 0)
    };
    if len < 0 {
        return Err(std::io::Error::last_os_error());
    }

    let mut buf = vec![0; len as usize];
    let buf_ptr = buf.as_mut_ptr() as *mut libc::c_void;

    // SAFETY: The correctness of the path and name is guaranteed by conversion
    // to the `CString` type above. For remaining parameters we provide a buffer
    // with length obtained through the previous call and we explicitly supply
    // its length as well. In case the result length increases between the calls
    // the system will report an error but will not cause memory issues.
    let len = unsafe {
        // Now we can call `lgetxattr` with the actual buffer of the size we
        // determined by the previous call.
        lgetxattr(c_str_path.as_ptr(), c_str_name.as_ptr(), buf_ptr, buf.len())
    };
    if len < 0 {
        return Err(std::io::Error::last_os_error());
    }

    // In very rare cases (if the users tampers with the file inbetween calls to
    // the `lgetxattr`), the length value can decrease. To avoid returning any
    // garbage at the end, we have to truncate the buffer to its real length.
    buf.truncate(len as usize);
    Ok(buf)
}

#[cfg(test)]
mod tests {

    use std::fs::File;

    use super::*;

    // TODO: Write tests for symlinks.

    #[test]
    fn test_flags_non_existing() {
        let tempdir = tempfile::tempdir().unwrap();

        assert!(flags(tempdir.path().join("foo")).is_err());
    }

    #[test]
    fn test_flags_noatime() {
        // https://elixir.bootlin.com/linux/v5.8.14/source/include/uapi/linux/fs.h#L245
        const FS_NOATIME_FL: std::os::raw::c_long = 0x00000080;

        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = File::create(tempdir.path().join("foo")).unwrap();

        unsafe {
            use std::os::unix::io::AsRawFd as _;
            let fd = tempfile.as_raw_fd();

            assert_eq!(ioctls::fs_ioc_setflags(fd, &FS_NOATIME_FL), 0);
        }

        let flags = flags(tempdir.path().join("foo")).unwrap();
        assert_eq!(flags & FS_NOATIME_FL as u32, FS_NOATIME_FL as u32);
    }

    #[test]
    fn ext_attr_names_none() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();

        let ext_attr_names = ext_attr_names(tempfile.path()).unwrap();
        assert!(ext_attr_names.is_empty());
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_names_single() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"");

        let ext_attr_names = ext_attr_names(tempfile.path()).unwrap();
        assert_eq!(ext_attr_names, vec!["user.foo"]);
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_names_multiple() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"");
        setfattr(tempfile.path(), "user.bar", b"");
        setfattr(tempfile.path(), "user.baz", b"");

        let ext_attr_names = ext_attr_names(tempfile.path()).unwrap();
        assert_eq!(ext_attr_names, vec!["user.foo", "user.bar", "user.baz"]);
    }

    #[test]
    fn ext_attr_value_not_existing() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();

        let error = ext_attr_value(tempfile.path(), "user.foo").unwrap_err();
        assert_eq!(error.raw_os_error(), Some(libc::ENODATA));
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_value_single() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"bar");

        let value = ext_attr_value(tempfile.path(), "user.foo").unwrap();
        assert_eq!(value, b"bar");
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_value_single_not_unicode() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"\xff\xfe\xff");

        let value = ext_attr_value(tempfile.path(), "user.foo").unwrap();
        assert_eq!(value, b"\xff\xfe\xff");
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_value_multiple() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"quux");
        setfattr(tempfile.path(), "user.bar", b"norf");

        let foo_value = ext_attr_value(tempfile.path(), "user.foo").unwrap();
        assert_eq!(foo_value, b"quux");

        let bar_value = ext_attr_value(tempfile.path(), "user.bar").unwrap();
        assert_eq!(bar_value, b"norf");
    }

    #[cfg(feature = "test-setfattr")]
    fn setfattr<P, S>(path: P, name: S, value: &[u8])
    where
        P: AsRef<std::path::Path>,
        S: AsRef<std::ffi::OsStr>,
    {
        use std::os::unix::ffi::OsStrExt as _;

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg(name)
                .arg("--value").arg(std::ffi::OsStr::from_bytes(value))
                .arg(path.as_ref().as_os_str())
                .status()
                .unwrap()
                .success()
        };
    }
}
<commit_msg>Implement iterator over Linux extended attributes.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Linux-specific utilities for working with the filesystem.

use std::path::Path;

// TODO: Document behaviour for symlinks.
/// Collects extended flags of the specified file.
///
/// The returned mask represents file attributes specific to the Linux extended
/// file system. Normally, they can be inspected using the `lsattr` command and
/// can be set through the `chattr` command.
///
/// See the [Wikipedia] article and the [man] page for more details.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Chattr
/// [man]: https://linux.die.net/man/1/chattr
///
/// # Examples
///
/// ```no_run
/// const FS_FL_USER_VISIBLE: u32 = 0x0003DFFF;
///
/// let flags = rrg::fs::linux::flags("/tmp/foo").unwrap();
/// assert_eq!(flags & FS_FL_USER_VISIBLE, 0);
/// ```
pub fn flags<P>(path: P) -> std::io::Result<u32> where
    P: AsRef<Path>
{
    let file = std::fs::File::open(path)?;

    let mut flags = 0;
    let code = unsafe {
        // This block is safe: we simply pass a raw file descriptor (that is
        // valid until the end of the scope of this function) because this is
        // what the low-level API expects.
        use std::os::unix::io::AsRawFd as _;
        ioctls::fs_ioc_getflags(file.as_raw_fd(), &mut flags)
    };

    if code == 0 {
        Ok(flags as u32)
    } else {
        Err(std::io::Error::from_raw_os_error(code))
    }
}

// TODO: Merge this with more general implementation in the `unix` module.
pub struct ExtAttrs<'p> {
    path: &'p Path,
    names: std::vec::IntoIter<std::ffi::OsString>,
}

impl<'p> Iterator for ExtAttrs<'p> {

    type Item = std::io::Result<super::unix::ExtAttr>;

    fn next(&mut self) -> Option<std::io::Result<super::unix::ExtAttr>> {
        let name = self.names.next()?;
        let value = match ext_attr_value(self.path, &name) {
            Ok(value) => value,
            Err(error) => return Some(Err(error)),
        };

        // TODO: Modify the `ExtAttr` struct not to use `Option` for `value`.
        Some(Ok(super::unix::ExtAttr { name, value: Some(value) }))
    }
}

pub fn ext_attrs<'p>(path: &'p Path) -> std::io::Result<ExtAttrs<'p>> {
    let names = ext_attr_names(path)?;
    Ok(ExtAttrs {
        path,
        names: names.into_iter(),
    })
}

pub fn ext_attr_names<P>(path: P) -> std::io::Result<Vec<std::ffi::OsString>>
where
    P: AsRef<Path>,
{
    extern "C" {
        // https://man7.org/linux/man-pages/man2/listxattr.2.html
        fn llistxattr(
            path: *const libc::c_char,
            list: *mut libc::c_char,
            size: libc::size_t,
        ) -> libc::ssize_t;
    }

    use std::os::unix::ffi::OsStrExt as _;

    let os_str_path = path.as_ref().as_os_str();
    let c_str_path = std::ffi::CString::new(os_str_path.as_bytes())
        // It is not possible to have a null byte in a Linux path.
        .expect("path with a null character");

    // SAFETY: The correctness of the path is guaranteed by conversion to the
    // `CString` type above. The rest is just is a FFI call respecting the spec.
    let len = unsafe {
        // First we call `llistxattr` with empty buffer to get the size of the
        // buffer that will collect the actual results.
        llistxattr(c_str_path.as_ptr(), std::ptr::null_mut(), 0)
    };
    if len < 0 {
        return Err(std::io::Error::last_os_error());
    }

    let mut buf = vec![0; len as usize];

    // SAFETY: The correctness of the path is guaranteed by conversion to the
    // `CString` type above. For remaining parameters we provide a buffer with
    // length obtained through the previous call and we explicitly supply its
    // length as well. In case the result length increases between the calls the
    // system will report an error but will not cause memory issues.
    let len = unsafe {
        // Now we can call `llistxattr` with the actual buffer of the size we
        // determined by the previous call.
        llistxattr(c_str_path.as_ptr(), buf.as_mut_ptr(), buf.len())
    };
    if len < 0 {
        return Err(std::io::Error::last_os_error());
    }

    // It is possible that the `len` value is smaller than as returned by the
    // first `llistxattr` call if somebody tampered with the file in the mean-
    // time. To avoid having spurious empty slices (as each following null byte
    // would cause the `split_inclusive` iterator to yield one), we trim the
    // buffer to the acutally returned length.
    //
    // Note that it is impossible for the `len` value to increase, as otherwise
    // the `llistxattr` would fail.
    let result = buf[..len as usize]
        .split_inclusive(|byte| *byte == 0)
        .map(|slice| {
            // SAFETY: The slice is guaranteed to be terminated with a null byte
            // and not contain any null bytes elsewhere because of the splitting
            // above. This holds true also for the last slice provided by the
            // iterator.
            let c_str = unsafe {
                std::ffi::CStr::from_ptr(slice.as_ptr())
            };

            std::ffi::OsStr::from_bytes(c_str.to_bytes()).to_os_string()
        })
        .collect();

    Ok(result)
}

pub fn ext_attr_value<P, S>(path: P, name: S) -> std::io::Result<Vec<u8>>
where
    P: AsRef<Path>,
    S: AsRef<std::ffi::OsStr>,
{
    extern "C" {
        // https://man7.org/linux/man-pages/man2/getxattr.2.html
        fn lgetxattr(
            path: *const libc::c_char,
            name: *const libc::c_char,
            value: *mut libc::c_void,
            size: libc::size_t,
        ) -> libc::ssize_t;
    }

    use std::os::unix::ffi::OsStrExt as _;

    let os_str_path = path.as_ref().as_os_str();
    let c_str_path = std::ffi::CString::new(os_str_path.as_bytes())
        // It is not possible to have a null byte in a Linux path.
        .expect("path with a null character");

    let c_str_name = std::ffi::CString::new(name.as_ref().as_bytes())
        // While `name` as returned by the `ext_attr_names` function cannot have
        // null bytes inside, we cannot guarantee that the user doesn't supply
        // a bogus string here. Thus, we have to do proper error handling here.
        .map_err(|error| {
            std::io::Error::new(std::io::ErrorKind::InvalidInput, error)
        })?;

    // SAFETY: The correctness of the path and name is guaranteed by conversion
    // to the `CString` type above. The rest is just is a FFI call respecting
    // the spec.
    let len = unsafe {
        // First we call `lgetxattr` with empty buffer to get the size of the
        // buffer that will collect the actual results.
        lgetxattr(c_str_path.as_ptr(), c_str_name.as_ptr(), std::ptr::null_mut(), 0)
    };
    if len < 0 {
        return Err(std::io::Error::last_os_error());
    }

    let mut buf = vec![0; len as usize];
    let buf_ptr = buf.as_mut_ptr() as *mut libc::c_void;

    // SAFETY: The correctness of the path and name is guaranteed by conversion
    // to the `CString` type above. For remaining parameters we provide a buffer
    // with length obtained through the previous call and we explicitly supply
    // its length as well. In case the result length increases between the calls
    // the system will report an error but will not cause memory issues.
    let len = unsafe {
        // Now we can call `lgetxattr` with the actual buffer of the size we
        // determined by the previous call.
        lgetxattr(c_str_path.as_ptr(), c_str_name.as_ptr(), buf_ptr, buf.len())
    };
    if len < 0 {
        return Err(std::io::Error::last_os_error());
    }

    // In very rare cases (if the users tampers with the file inbetween calls to
    // the `lgetxattr`), the length value can decrease. To avoid returning any
    // garbage at the end, we have to truncate the buffer to its real length.
    buf.truncate(len as usize);
    Ok(buf)
}

#[cfg(test)]
mod tests {

    use std::fs::File;

    use super::*;

    // TODO: Write tests for symlinks.

    #[test]
    fn test_flags_non_existing() {
        let tempdir = tempfile::tempdir().unwrap();

        assert!(flags(tempdir.path().join("foo")).is_err());
    }

    #[test]
    fn test_flags_noatime() {
        // https://elixir.bootlin.com/linux/v5.8.14/source/include/uapi/linux/fs.h#L245
        const FS_NOATIME_FL: std::os::raw::c_long = 0x00000080;

        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = File::create(tempdir.path().join("foo")).unwrap();

        unsafe {
            use std::os::unix::io::AsRawFd as _;
            let fd = tempfile.as_raw_fd();

            assert_eq!(ioctls::fs_ioc_setflags(fd, &FS_NOATIME_FL), 0);
        }

        let flags = flags(tempdir.path().join("foo")).unwrap();
        assert_eq!(flags & FS_NOATIME_FL as u32, FS_NOATIME_FL as u32);
    }

    #[test]
    fn ext_attrs_none() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();

        let mut ext_attrs = ext_attrs(tempfile.path()).unwrap();
        assert!(ext_attrs.next().is_none());
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attrs_some() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.attr1", b"foo");
        setfattr(tempfile.path(), "user.attr2", b"bar");
        setfattr(tempfile.path(), "user.attr3", b"baz");

        let mut ext_attrs = ext_attrs(tempfile.path()).unwrap()
            .collect::<std::io::Result<Vec<_>>>().unwrap();
        ext_attrs.sort_by_cached_key(|attr| attr.name.clone());

        assert_eq!(ext_attrs[0].name, "user.attr1");
        assert_eq!(ext_attrs[0].value, Some(b"foo".to_vec()));

        assert_eq!(ext_attrs[1].name, "user.attr2");
        assert_eq!(ext_attrs[1].value, Some(b"bar".to_vec()));

        assert_eq!(ext_attrs[2].name, "user.attr3");
        assert_eq!(ext_attrs[2].value, Some(b"baz".to_vec()));
    }

    #[test]
    fn ext_attr_names_none() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();

        let ext_attr_names = ext_attr_names(tempfile.path()).unwrap();
        assert!(ext_attr_names.is_empty());
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_names_single() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"");

        let ext_attr_names = ext_attr_names(tempfile.path()).unwrap();
        assert_eq!(ext_attr_names, vec!["user.foo"]);
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_names_multiple() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"");
        setfattr(tempfile.path(), "user.bar", b"");
        setfattr(tempfile.path(), "user.baz", b"");

        let ext_attr_names = ext_attr_names(tempfile.path()).unwrap();
        assert_eq!(ext_attr_names, vec!["user.foo", "user.bar", "user.baz"]);
    }

    #[test]
    fn ext_attr_value_not_existing() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();

        let error = ext_attr_value(tempfile.path(), "user.foo").unwrap_err();
        assert_eq!(error.raw_os_error(), Some(libc::ENODATA));
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_value_single() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"bar");

        let value = ext_attr_value(tempfile.path(), "user.foo").unwrap();
        assert_eq!(value, b"bar");
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_value_single_not_unicode() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"\xff\xfe\xff");

        let value = ext_attr_value(tempfile.path(), "user.foo").unwrap();
        assert_eq!(value, b"\xff\xfe\xff");
    }

    #[cfg(feature = "test-setfattr")]
    #[test]
    fn ext_attr_value_multiple() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.foo", b"quux");
        setfattr(tempfile.path(), "user.bar", b"norf");

        let foo_value = ext_attr_value(tempfile.path(), "user.foo").unwrap();
        assert_eq!(foo_value, b"quux");

        let bar_value = ext_attr_value(tempfile.path(), "user.bar").unwrap();
        assert_eq!(bar_value, b"norf");
    }

    #[cfg(feature = "test-setfattr")]
    fn setfattr<P, S>(path: P, name: S, value: &[u8])
    where
        P: AsRef<std::path::Path>,
        S: AsRef<std::ffi::OsStr>,
    {
        use std::os::unix::ffi::OsStrExt as _;

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg(name)
                .arg("--value").arg(std::ffi::OsStr::from_bytes(value))
                .arg(path.as_ref().as_os_str())
                .status()
                .unwrap()
                .success()
        };
    }
}
<|endoftext|>


<commit_before>//! Provides utility functions for generating data sequences
use std::f64::consts;
use euclid::Modulus;

/// Generates a linearly spaced vector of the given length between
/// the specified values (inclusive). Equivalent to MATLAB linspace
///
/// # Note
///
/// Will become deprecated once `step_by` becomes stable
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::linear_spaced(9, 0.0, 64.0);
/// assert_eq!(x, [0.0, 8.0, 16.0, 24.0, 32.0, 40.0, 48.0, 56.0, 64.0]);
/// ```
pub fn linear_spaced(length: usize, start: f64, stop: f64) -> Vec<f64> {
    match length {
        0 => Vec::new(),
        1 => vec![stop],
        _ => {
            let step = (stop - start) / (length - 1) as f64;
            let mut vec = (0..length).map(|x| start + (x as f64) * step).collect::<Vec<f64>>();
            vec[length - 1] = stop;
            vec
        }
    }
}

/// Generates a base 10 log spaced vector of the given length between the specified
/// decade exponents (inclusive). Equivalent to MATLAB logspace
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::log_spaced(5, 0.0, 4.0);
/// assert_eq!(x, [1.0, 10.0, 100.0, 1000.0, 10000.0]);
/// ```
pub fn log_spaced(length: usize, start_exp: f64, stop_exp: f64) -> Vec<f64> {
    match length {
        0 => Vec::new(),
        1 => vec![10f64.powf(stop_exp)],
        _ => {
            let step = (stop_exp - start_exp) / (length - 1) as f64;
            let mut vec = (0..length)
                .map(|x| 10f64.powf(start_exp + (x as f64) * step))
                .collect::<Vec<f64>>();
            vec[length - 1] = 10f64.powf(stop_exp);
            vec
        }
    }
}

/// Creates a vector of `f64` points representing a periodic wave with an amplitude
/// of `1.0`, phase of `0.0`, and delay of `0`.
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::periodic(10, 8.0, 2.0);
/// assert_eq!(x, [0.0, 0.25, 0.5, 0.75, 0.0, 0.25, 0.5, 0.75, 0.0, 0.25]);
/// ```
pub fn periodic(length: usize, sampling_rate: f64, frequency: f64) -> Vec<f64> {
    periodic_custom(length, sampling_rate, frequency, 1.0, 0.0, 0)
}

/// Creates a vector of `f64` points representing a periodic wave.
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::periodic_custom(10, 8.0, 2.0, 10.0, 1.0, 2);
/// assert_eq!(x, [6.0, 8.5, 1.0, 3.5, 6.0, 8.5, 1.0, 3.5, 6.0, 8.5]);
/// ```
pub fn periodic_custom(length: usize,
                       sampling_rate: f64,
                       frequency: f64,
                       amplitude: f64,
                       phase: f64,
                       delay: i64)
                       -> Vec<f64> {

    let step = frequency / sampling_rate * amplitude;
    let mut phase = (phase - delay as f64 * step).modulus(amplitude);
    let mut data = vec![0.0; length];
    let mut k = 0.0;

    for d in &mut data {
        let mut x = phase + k * step;
        if x >= amplitude {
            x %= amplitude;
            phase = x;
            k = 0.0;
        }
        *d = x;
        k += 1.0;
    }
    data
}

/// Creates a vector of `f64` points representing a Sine wave with a mean of `0.0`,
/// phase of `0.0`, and delay of `0`.
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::sinusoidal(10, 8.0, 2.0, 1.0);
/// assert_eq!(x,
///     [0.0, 1.0, 0.00000000000000012246467991473532,
///     -1.0, -0.00000000000000024492935982947064, 1.0,
///     0.00000000000000036739403974420594, -1.0,
///     -0.0000000000000004898587196589413, 1.0]);
/// ```
pub fn sinusoidal(length: usize, sampling_rate: f64, frequency: f64, amplitude: f64) -> Vec<f64> {
    sinusoidal_custom(length, sampling_rate, frequency, amplitude, 0.0, 0.0, 0)
}

/// Creates a vector of `f64` points representing a Sine wave.
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::sinusoidal_custom(10, 8.0, 2.0, 1.0, 5.0, 2.0, 1);
/// assert_eq!(x,
///     [5.416146836547142, 5.909297426825682, 4.583853163452858,
///     4.090702573174318, 5.416146836547142, 5.909297426825682,
///     4.583853163452858, 4.090702573174318, 5.416146836547142,
///     5.909297426825682]);
/// ```
pub fn sinusoidal_custom(length: usize,
                         sampling_rate: f64,
                         frequency: f64,
                         amplitude: f64,
                         mean: f64,
                         phase: f64,
                         delay: i64)
                         -> Vec<f64> {

    let pi2 = consts::PI * 2.0;
    let step = frequency / sampling_rate * pi2;
    let phase = (phase - delay as f64 * step) % pi2;
    (0..length)
        .map(|i| mean + amplitude * (phase + i as f64 * step).sin())
        .collect()
}
<commit_msg>refactor: remove linear_spaced, don't introduce API that will be deprecated soon<commit_after>//! Provides utility functions for generating data sequences
use std::f64::consts;
use euclid::Modulus;

/// Generates a base 10 log spaced vector of the given length between the specified
/// decade exponents (inclusive). Equivalent to MATLAB logspace
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::log_spaced(5, 0.0, 4.0);
/// assert_eq!(x, [1.0, 10.0, 100.0, 1000.0, 10000.0]);
/// ```
pub fn log_spaced(length: usize, start_exp: f64, stop_exp: f64) -> Vec<f64> {
    match length {
        0 => Vec::new(),
        1 => vec![10f64.powf(stop_exp)],
        _ => {
            let step = (stop_exp - start_exp) / (length - 1) as f64;
            let mut vec = (0..length)
                .map(|x| 10f64.powf(start_exp + (x as f64) * step))
                .collect::<Vec<f64>>();
            vec[length - 1] = 10f64.powf(stop_exp);
            vec
        }
    }
}

/// Creates a vector of `f64` points representing a periodic wave with an amplitude
/// of `1.0`, phase of `0.0`, and delay of `0`.
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::periodic(10, 8.0, 2.0);
/// assert_eq!(x, [0.0, 0.25, 0.5, 0.75, 0.0, 0.25, 0.5, 0.75, 0.0, 0.25]);
/// ```
pub fn periodic(length: usize, sampling_rate: f64, frequency: f64) -> Vec<f64> {
    periodic_custom(length, sampling_rate, frequency, 1.0, 0.0, 0)
}

/// Creates a vector of `f64` points representing a periodic wave.
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::periodic_custom(10, 8.0, 2.0, 10.0, 1.0, 2);
/// assert_eq!(x, [6.0, 8.5, 1.0, 3.5, 6.0, 8.5, 1.0, 3.5, 6.0, 8.5]);
/// ```
pub fn periodic_custom(length: usize,
                       sampling_rate: f64,
                       frequency: f64,
                       amplitude: f64,
                       phase: f64,
                       delay: i64)
                       -> Vec<f64> {

    let step = frequency / sampling_rate * amplitude;
    let mut phase = (phase - delay as f64 * step).modulus(amplitude);
    let mut data = vec![0.0; length];
    let mut k = 0.0;

    for d in &mut data {
        let mut x = phase + k * step;
        if x >= amplitude {
            x %= amplitude;
            phase = x;
            k = 0.0;
        }
        *d = x;
        k += 1.0;
    }
    data
}

/// Creates a vector of `f64` points representing a Sine wave with a mean of `0.0`,
/// phase of `0.0`, and delay of `0`.
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::sinusoidal(10, 8.0, 2.0, 1.0);
/// assert_eq!(x,
///     [0.0, 1.0, 0.00000000000000012246467991473532,
///     -1.0, -0.00000000000000024492935982947064, 1.0,
///     0.00000000000000036739403974420594, -1.0,
///     -0.0000000000000004898587196589413, 1.0]);
/// ```
pub fn sinusoidal(length: usize, sampling_rate: f64, frequency: f64, amplitude: f64) -> Vec<f64> {
    sinusoidal_custom(length, sampling_rate, frequency, amplitude, 0.0, 0.0, 0)
}

/// Creates a vector of `f64` points representing a Sine wave.
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::sinusoidal_custom(10, 8.0, 2.0, 1.0, 5.0, 2.0, 1);
/// assert_eq!(x,
///     [5.416146836547142, 5.909297426825682, 4.583853163452858,
///     4.090702573174318, 5.416146836547142, 5.909297426825682,
///     4.583853163452858, 4.090702573174318, 5.416146836547142,
///     5.909297426825682]);
/// ```
pub fn sinusoidal_custom(length: usize,
                         sampling_rate: f64,
                         frequency: f64,
                         amplitude: f64,
                         mean: f64,
                         phase: f64,
                         delay: i64)
                         -> Vec<f64> {

    let pi2 = consts::PI * 2.0;
    let step = frequency / sampling_rate * pi2;
    let phase = (phase - delay as f64 * step) % pi2;
    (0..length)
        .map(|i| mean + amplitude * (phase + i as f64 * step).sin())
        .collect()
}
<|endoftext|>


<commit_before>//! Generator functions for matrices

use ndarray::*;
use rand::*;
use std::ops::*;

use super::convert::*;
use super::error::*;
use super::types::*;

/// Hermite conjugate matrix
pub fn conjugate(a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
where
    A: Conjugate,
    Si: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
{
    let mut a = replicate(&a.t());
    for val in a.iter_mut() {
        *val = Conjugate::conj(*val);
    }
    a
}

/// Generate random array
pub fn random(sh: Sh) -> ArrayBase<S, D>
where
    A: RandNormal,
    S: DataOwned<Elem = A>,
    D: Dimension,
    Sh: ShapeBuilder<Dim = D>,
{
    let mut rng = thread_rng();
    ArrayBase::from_shape_fn(sh, |_| A::randn(&mut rng))
}

/// Random Hermite matrix
pub fn random_hermite(n: usize) -> ArrayBase<S, Ix2>
where
    A: RandNormal + Conjugate + Add<Output = A>,
    S: DataOwned<Elem = A> + DataMut,
{
    let mut a = random((n, n));
    for i in 0..n {
        a[(i, i)] = a[(i, i)] + Conjugate::conj(a[(i, i)]);
        for j in (i + 1)..n {
            a[(i, j)] = Conjugate::conj(a[(j, i)])
        }
    }
    a
}

/// Random Hermite Positive-definite matrix
///
/// - Eigenvalue of matrix must be larger than 1 (thus non-singular)
///
pub fn random_hpd(n: usize) -> ArrayBase<S, Ix2>
where
    A: RandNormal + Conjugate + LinalgScalar,
    S: DataOwned<Elem = A> + DataMut,
{
    let a: Array2 = random((n, n));
    let ah: Array2 = conjugate(&a);
    ArrayBase::eye(n) + &ah.dot(&a)
}

/// construct matrix from diag
pub fn from_diag(d: &[A]) -> Array2
where
    A: LinalgScalar,
{
    let n = d.len();
    let mut e = Array::zeros((n, n));
    for i in 0..n {
        e[(i, i)] = d[i];
    }
    e
}

/// stack vectors into matrix horizontally
pub fn hstack(xs: &[ArrayBase<S, Ix1>]) -> Result<Array>
where
    A: LinalgScalar,
    S: Data<Elem = A>,
{
    let views: Vec<_> = xs
        .iter()
        .map(|x| {
            let n = x.len();
            x.view().into_shape((n, 1)).unwrap()
        })
        .collect();
    stack(Axis(1), &views).map_err(|e| e.into())
}

/// stack vectors into matrix vertically
pub fn vstack(xs: &[ArrayBase<S, Ix1>]) -> Result<Array>
where
    A: LinalgScalar,
    S: Data<Elem = A>,
{
    let views: Vec<_> = xs
        .iter()
        .map(|x| {
            let n = x.len();
            x.view().into_shape((1, n)).unwrap()
        })
        .collect();
    stack(Axis(0), &views).map_err(|e| e.into())
}
<commit_msg>random_unitary, random_regular<commit_after>//! Generator functions for matrices

use ndarray::*;
use rand::*;
use std::ops::*;

use super::convert::*;
use super::error::*;
use super::qr::*;
use super::types::*;

/// Hermite conjugate matrix
pub fn conjugate(a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
where
    A: Conjugate,
    Si: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
{
    let mut a = replicate(&a.t());
    for val in a.iter_mut() {
        *val = Conjugate::conj(*val);
    }
    a
}

/// Generate random array
pub fn random(sh: Sh) -> ArrayBase<S, D>
where
    A: RandNormal,
    S: DataOwned<Elem = A>,
    D: Dimension,
    Sh: ShapeBuilder<Dim = D>,
{
    let mut rng = thread_rng();
    ArrayBase::from_shape_fn(sh, |_| A::randn(&mut rng))
}

/// Generate random unitary matrix using QR decomposition
pub fn random_unitary(n: usize) -> Array2
where
    A: Scalar + RandNormal,
{
    let a: Array2 = random((n, n));
    let (q, _r) = a.qr_into().unwrap();
    q
}

/// Generate random regular matrix
pub fn random_regular(n: usize) -> Array2
where
    A: Scalar + RandNormal,
{
    let a: Array2 = random((n, n));
    let (q, mut r) = a.qr_into().unwrap();
    for i in 0..n {
        r[(i, i)] = A::from_f64(1.0) + AssociatedReal::inject(r[(i, i)].abs());
    }
    q.dot(&r)
}

/// Random Hermite matrix
pub fn random_hermite(n: usize) -> ArrayBase<S, Ix2>
where
    A: RandNormal + Conjugate + Add<Output = A>,
    S: DataOwned<Elem = A> + DataMut,
{
    let mut a = random((n, n));
    for i in 0..n {
        a[(i, i)] = a[(i, i)] + Conjugate::conj(a[(i, i)]);
        for j in (i + 1)..n {
            a[(i, j)] = Conjugate::conj(a[(j, i)])
        }
    }
    a
}

/// Random Hermite Positive-definite matrix
///
/// - Eigenvalue of matrix must be larger than 1 (thus non-singular)
///
pub fn random_hpd(n: usize) -> ArrayBase<S, Ix2>
where
    A: RandNormal + Conjugate + LinalgScalar,
    S: DataOwned<Elem = A> + DataMut,
{
    let a: Array2 = random((n, n));
    let ah: Array2 = conjugate(&a);
    ArrayBase::eye(n) + &ah.dot(&a)
}

/// construct matrix from diag
pub fn from_diag(d: &[A]) -> Array2
where
    A: LinalgScalar,
{
    let n = d.len();
    let mut e = Array::zeros((n, n));
    for i in 0..n {
        e[(i, i)] = d[i];
    }
    e
}

/// stack vectors into matrix horizontally
pub fn hstack(xs: &[ArrayBase<S, Ix1>]) -> Result<Array>
where
    A: LinalgScalar,
    S: Data<Elem = A>,
{
    let views: Vec<_> = xs
        .iter()
        .map(|x| {
            let n = x.len();
            x.view().into_shape((n, 1)).unwrap()
        })
        .collect();
    stack(Axis(1), &views).map_err(|e| e.into())
}

/// stack vectors into matrix vertically
pub fn vstack(xs: &[ArrayBase<S, Ix1>]) -> Result<Array>
where
    A: LinalgScalar,
    S: Data<Elem = A>,
{
    let views: Vec<_> = xs
        .iter()
        .map(|x| {
            let n = x.len();
            x.view().into_shape((1, n)).unwrap()
        })
        .collect();
    stack(Axis(0), &views).map_err(|e| e.into())
}
<|endoftext|>


<commit_before>//! Generator functions for matrices

use ndarray::*;
use rand::*;
use std::ops::*;

use super::convert::*;
use super::error::*;
use super::types::*;

/// Hermite conjugate matrix
pub fn conjugate(a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
where
    A: Conjugate,
    Si: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
{
    let mut a = replicate(&a.t());
    for val in a.iter_mut() {
        *val = Conjugate::conj(*val);
    }
    a
}

/// Generate random array
pub fn random(sh: Sh) -> ArrayBase<S, D>
where
    A: RandNormal,
    S: DataOwned<Elem = A>,
    D: Dimension,
    Sh: ShapeBuilder<Dim = D>,
{
    let mut rng = thread_rng();
    ArrayBase::from_shape_fn(sh, |_| A::randn(&mut rng))
}

/// Random Hermite matrix
pub fn random_hermite(n: usize, c_order: bool) -> ArrayBase<S, Ix2>
where
    A: RandNormal + Conjugate + Add<Output = A>,
    S: DataOwned<Elem = A> + DataMut,
{
    let mut a = if c_order {
        random((n, n))
    } else {
        random((n, n).f())
    };
    for i in 0..n {
        a[(i, i)] = a[(i, i)] + Conjugate::conj(a[(i, i)]);
        for j in (i + 1)..n {
            a[(i, j)] = Conjugate::conj(a[(j, i)])
        }
    }
    a
}

/// Random Hermite Positive-definite matrix
pub fn random_hpd(n: usize) -> ArrayBase<S, Ix2>
where
    A: RandNormal + Conjugate + LinalgScalar,
    S: DataOwned<Elem = A> + DataMut,
{
    let a: Array2 = random((n, n));
    let ah: Array2 = conjugate(&a);
    replicate(&ah.dot(&a))
}

/// construct matrix from diag
pub fn from_diag(d: &[A]) -> Array2
where
    A: LinalgScalar,
{
    let n = d.len();
    let mut e = Array::zeros((n, n));
    for i in 0..n {
        e[(i, i)] = d[i];
    }
    e
}

/// stack vectors into matrix horizontally
pub fn hstack(xs: &[ArrayBase<S, Ix1>]) -> Result<Array>
where
    A: LinalgScalar,
    S: Data<Elem = A>,
{
    let views: Vec<_> = xs.iter()
        .map(|x| {
            let n = x.len();
            x.view().into_shape((n, 1)).unwrap()
        })
        .collect();
    stack(Axis(1), &views).map_err(|e| e.into())
}

/// stack vectors into matrix vertically
pub fn vstack(xs: &[ArrayBase<S, Ix1>]) -> Result<Array>
where
    A: LinalgScalar,
    S: Data<Elem = A>,
{
    let views: Vec<_> = xs.iter()
        .map(|x| {
            let n = x.len();
            x.view().into_shape((1, n)).unwrap()
        })
        .collect();
    stack(Axis(0), &views).map_err(|e| e.into())
}
<commit_msg>Drop c_order flag from generate::random_hermite<commit_after>//! Generator functions for matrices

use ndarray::*;
use rand::*;
use std::ops::*;

use super::convert::*;
use super::error::*;
use super::types::*;

/// Hermite conjugate matrix
pub fn conjugate(a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
where
    A: Conjugate,
    Si: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
{
    let mut a = replicate(&a.t());
    for val in a.iter_mut() {
        *val = Conjugate::conj(*val);
    }
    a
}

/// Generate random array
pub fn random(sh: Sh) -> ArrayBase<S, D>
where
    A: RandNormal,
    S: DataOwned<Elem = A>,
    D: Dimension,
    Sh: ShapeBuilder<Dim = D>,
{
    let mut rng = thread_rng();
    ArrayBase::from_shape_fn(sh, |_| A::randn(&mut rng))
}

/// Random Hermite matrix
pub fn random_hermite(n: usize) -> ArrayBase<S, Ix2>
where
    A: RandNormal + Conjugate + Add<Output = A>,
    S: DataOwned<Elem = A> + DataMut,
{
    let mut a = random((n, n));
    for i in 0..n {
        a[(i, i)] = a[(i, i)] + Conjugate::conj(a[(i, i)]);
        for j in (i + 1)..n {
            a[(i, j)] = Conjugate::conj(a[(j, i)])
        }
    }
    a
}

/// Random Hermite Positive-definite matrix
pub fn random_hpd(n: usize) -> ArrayBase<S, Ix2>
where
    A: RandNormal + Conjugate + LinalgScalar,
    S: DataOwned<Elem = A> + DataMut,
{
    let a: Array2 = random((n, n));
    let ah: Array2 = conjugate(&a);
    replicate(&ah.dot(&a))
}

/// construct matrix from diag
pub fn from_diag(d: &[A]) -> Array2
where
    A: LinalgScalar,
{
    let n = d.len();
    let mut e = Array::zeros((n, n));
    for i in 0..n {
        e[(i, i)] = d[i];
    }
    e
}

/// stack vectors into matrix horizontally
pub fn hstack(xs: &[ArrayBase<S, Ix1>]) -> Result<Array>
where
    A: LinalgScalar,
    S: Data<Elem = A>,
{
    let views: Vec<_> = xs.iter()
        .map(|x| {
            let n = x.len();
            x.view().into_shape((n, 1)).unwrap()
        })
        .collect();
    stack(Axis(1), &views).map_err(|e| e.into())
}

/// stack vectors into matrix vertically
pub fn vstack(xs: &[ArrayBase<S, Ix1>]) -> Result<Array>
where
    A: LinalgScalar,
    S: Data<Elem = A>,
{
    let views: Vec<_> = xs.iter()
        .map(|x| {
            let n = x.len();
            x.view().into_shape((1, n)).unwrap()
        })
        .collect();
    stack(Axis(0), &views).map_err(|e| e.into())
}
<|endoftext|>


<commit_before>use geom::{vertex, Cuboid, Range, Rect, Vertex, Vertex2d, Vertex3d};
use math::{BaseNum, EuclideanSpace, Point2, Zero};
use std::ops::Deref;

/// The number of vertices in a triangle.
pub const NUM_VERTICES: u8 = 3;

/// A triangle as three vertices.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct Tri<V = vertex::Default>(pub [V; NUM_VERTICES as usize]);

/// An iterator yielding each of the vertices of the triangle.
#[derive(Clone, Debug)]
pub struct Vertices<V = vertex::Default> {
    tri: Tri<V>,
    index: u8,
}

/// An iterator yielding triangles whose vertices are produced by the given iterator yielding
/// vertices.
#[derive(Clone, Debug)]
pub struct IterFromVertices<I> {
    vertices: I,
}

impl<V> Tri<V>
where
    V: Vertex,
{
    /// Create a **Tri** by indexing into the given buffer.
    ///
    /// **Panics** if any of the given indices are out of range of the given `vertices` slice.
    pub fn from_index_tri(vertices: &[V], indices: &[usize; 3]) -> Self
    where
        V: Vertex,
    {
        from_index_tri(vertices, indices)
    }

    /// Create a **Tri** from the next three vertices yielded by the given `vertices` iterator.
    ///
    /// Returns **None** if there were not at least 3 vertices in the given iterator.
    pub fn from_vertices<I>(vertices: I) -> Option<Self>
    where
        I: IntoIterator<Item = V>,
    {
        from_vertices(vertices)
    }

    /// Produce an iterator yielding each of the vertices of the triangle.
    pub fn vertices(self) -> Vertices<V> {
        let tri = self;
        let index = 0;
        Vertices { tri, index }
    }

    /// Produce the centroid of the triangle aka the "mean"/"average" of all the points.
    pub fn centroid(self) -> V
    where
        V: EuclideanSpace,
    {
        EuclideanSpace::centroid(&self[..])
    }

    /// Maps the underlying vertices to a new type and returns the resulting `Tri`.
    pub fn map_vertices<F, V2>(self, mut map: F) -> Tri<V2>
    where
        F: FnMut(V) -> V2,
    {
        let (a, b, c) = self.into();
        Tri([map(a), map(b), map(c)])
    }
}

impl<V> Tri<V>
where
    V: Vertex2d,
{
    /// Returns `true` if the given 2D vertex is contained within the 2D `Tri`.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate nannou;
    /// # use nannou::prelude::*;
    /// # use nannou::geom::Tri;
    /// # fn main() {
    /// let a = Point2 { x: -0.5, y: 0.0 };
    /// let b = Point2 { x: 0.0, y: 1.0 };
    /// let c = Point2 { x: 0.5, y: -0.75 };
    /// let tri = Tri([a, b, c]);
    /// assert!(tri.contains(&Point2 { x: 0.0, y: 0.0 }));
    /// assert!(!tri.contains(&Point2 { x: 3.0, y: 3.0 }));
    /// # }
    /// ```
    pub fn contains(&self, v: &V) -> bool
    where
        V: Vertex2d,
    {
        let (a, b, c) = (*self).into();
        let (a, b, c) = (a.point2(), b.point2(), c.point2());
        let v = (*v).point2();

        fn sign<S>(a: Point2<S>, b: Point2<S>, c: Point2<S>) -> S
        where
            S: BaseNum,
        {
            (a[0] - c[0]) * (b[1] - c[1]) - (b[0] - c[0]) * (a[1] - c[1])
        }

        let b1 = sign(v, a, b) < V::Scalar::zero();
        let b2 = sign(v, b, c) < V::Scalar::zero();
        let b3 = sign(v, c, a) < V::Scalar::zero();

        (b1 == b2) && (b2 == b3)
    }

    /// The bounding `Rect` of the triangle.
    pub fn bounding_rect(self) -> Rect<V::Scalar>
    where
        V: Vertex2d,
    {
        let (a, b, c) = self.into();
        let (a, b, c) = (a.point2(), b.point2(), c.point2());
        let rect = Rect { x: Range::new(a.x, a.x), y: Range::new(a.y, a.y) };
        rect.stretch_to_point(b).stretch_to_point(c)
    }

    /// The bounding `Rect` of the triangle.
    pub fn bounding_cuboid(self) -> Cuboid<V::Scalar>
    where
        V: Vertex3d,
    {
        let (a, b, c) = self.into();
        let (a, b, c) = (a.point3(), b.point3(), c.point3());
        let cuboid = Cuboid {
            x: Range::new(a.x, a.x),
            y: Range::new(a.y, a.y),
            z: Range::new(a.z, a.z),
        };
        cuboid.stretch_to_point(b).stretch_to_point(c)
    }
}

impl<V> Iterator for Vertices<V>
where
    V: Clone,
{
    type Item = V;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index < NUM_VERTICES {
            let v = self.tri.0[self.index as usize].clone();
            self.index += 1;
            Some(v)
        } else {
            None
        }
    }
}

/// Returns the first `Tri` that contains the given vertex.
///
/// Returns `None` if no `Tri`'s contain the given vertex.
pub fn iter_contains<I, V>(tris: I, v: &V) -> Option<I::Item>
where
    I: IntoIterator,
    I::Item: AsRef<Tri<V>>,
    V: Vertex2d,
{
    tris.into_iter().find(|tri| tri.as_ref().contains(v))
}

/// Create a **Tri** from the next three vertices yielded by the given `vertices` iterator.
///
/// Returns **None** if there were not at least 3 vertices in the given iterator.
pub fn from_vertices<I>(vertices: I) -> Option<Tri<I::Item>>
where
    I: IntoIterator,
{
    let mut vertices = vertices.into_iter();
    match (vertices.next(), vertices.next(), vertices.next()) {
        (Some(a), Some(b), Some(c)) => Some(Tri([a, b, c])),
        _ => None,
    }
}

/// Produce an iterator yielding a triangle for every three vertices yielded by the given
/// `vertices` iterator.
pub fn iter_from_vertices<I>(vertices: I) -> IterFromVertices<I::IntoIter>
where
    I: IntoIterator,
{
    let vertices = vertices.into_iter();
    IterFromVertices { vertices }
}

/// Create a **Tri** by indexing into the given buffer.
///
/// **Panics** if any of the given indices are out of range of the given `vertices` slice.
pub fn from_index_tri<V>(vertices: &[V], indices: &[usize; 3]) -> Tri<V>
where
    V: Clone,
{
    let a = vertices[indices[0]].clone();
    let b = vertices[indices[1]].clone();
    let c = vertices[indices[2]].clone();
    Tri([a, b, c])
}

impl<V> Deref for Tri<V>
where
    V: Vertex,
{
    type Target = [V; 3];
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<V> From<[V; 3]> for Tri<V>
where
    V: Vertex,
{
    fn from(points: [V; 3]) -> Self {
        Tri(points)
    }
}

impl<V> From<(V, V, V)> for Tri<V>
where
    V: Vertex,
{
    fn from((a, b, c): (V, V, V)) -> Self {
        Tri([a, b, c])
    }
}

impl<V> Into<[V; 3]> for Tri<V>
where
    V: Vertex,
{
    fn into(self) -> [V; 3] {
        self.0
    }
}

impl<V> Into<(V, V, V)> for Tri<V>
where
    V: Vertex,
{
    fn into(self) -> (V, V, V) {
        (self[0], self[1], self[2])
    }
}

impl<V> AsRef<Tri<V>> for Tri<V>
where
    V: Vertex,
{
    fn as_ref(&self) -> &Tri<V> {
        self
    }
}

impl<V> AsRef<[V; 3]> for Tri<V>
where
    V: Vertex,
{
    fn as_ref(&self) -> &[V; 3] {
        &self.0
    }
}

impl<I> Iterator for IterFromVertices<I>
where
    I: Iterator,
{
    type Item = Tri<I::Item>;
    fn next(&mut self) -> Option<Self::Item> {
        from_vertices(&mut self.vertices)
    }
}
<commit_msg>Add iterator for flattening an iterator yielding triangles into their vertices<commit_after>use geom::{vertex, Cuboid, Range, Rect, Vertex, Vertex2d, Vertex3d};
use math::{BaseNum, EuclideanSpace, Point2, Zero};
use std::ops::Deref;

/// The number of vertices in a triangle.
pub const NUM_VERTICES: u8 = 3;

/// A triangle as three vertices.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct Tri<V = vertex::Default>(pub [V; NUM_VERTICES as usize]);

/// An iterator yielding each of the vertices of the triangle.
#[derive(Clone, Debug)]
pub struct Vertices<V = vertex::Default> {
    tri: Tri<V>,
    index: u8,
}

/// An iterator yielding triangles whose vertices are produced by the given iterator yielding
/// vertices.
#[derive(Clone, Debug)]
pub struct IterFromVertices<I> {
    vertices: I,
}

/// An iterator that flattens an iterator yielding triangles into its vertices.
#[derive(Clone, Debug)]
pub struct VerticesFromIter<I, V> {
    tris: I,
    tri: Option<Vertices<V>>,
}

impl<V> Tri<V>
where
    V: Vertex,
{
    /// Create a **Tri** by indexing into the given buffer.
    ///
    /// **Panics** if any of the given indices are out of range of the given `vertices` slice.
    pub fn from_index_tri(vertices: &[V], indices: &[usize; 3]) -> Self
    where
        V: Vertex,
    {
        from_index_tri(vertices, indices)
    }

    /// Create a **Tri** from the next three vertices yielded by the given `vertices` iterator.
    ///
    /// Returns **None** if there were not at least 3 vertices in the given iterator.
    pub fn from_vertices<I>(vertices: I) -> Option<Self>
    where
        I: IntoIterator<Item = V>,
    {
        from_vertices(vertices)
    }

    /// Produce an iterator yielding each of the vertices of the triangle.
    pub fn vertices(self) -> Vertices<V> {
        let tri = self;
        let index = 0;
        Vertices { tri, index }
    }

    /// Produce the centroid of the triangle aka the "mean"/"average" of all the points.
    pub fn centroid(self) -> V
    where
        V: EuclideanSpace,
    {
        EuclideanSpace::centroid(&self[..])
    }

    /// Maps the underlying vertices to a new type and returns the resulting `Tri`.
    pub fn map_vertices<F, V2>(self, mut map: F) -> Tri<V2>
    where
        F: FnMut(V) -> V2,
    {
        let (a, b, c) = self.into();
        Tri([map(a), map(b), map(c)])
    }
}

impl<V> Tri<V>
where
    V: Vertex2d,
{
    /// Returns `true` if the given 2D vertex is contained within the 2D `Tri`.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate nannou;
    /// # use nannou::prelude::*;
    /// # use nannou::geom::Tri;
    /// # fn main() {
    /// let a = Point2 { x: -0.5, y: 0.0 };
    /// let b = Point2 { x: 0.0, y: 1.0 };
    /// let c = Point2 { x: 0.5, y: -0.75 };
    /// let tri = Tri([a, b, c]);
    /// assert!(tri.contains(&Point2 { x: 0.0, y: 0.0 }));
    /// assert!(!tri.contains(&Point2 { x: 3.0, y: 3.0 }));
    /// # }
    /// ```
    pub fn contains(&self, v: &V) -> bool
    where
        V: Vertex2d,
    {
        let (a, b, c) = (*self).into();
        let (a, b, c) = (a.point2(), b.point2(), c.point2());
        let v = (*v).point2();

        fn sign<S>(a: Point2<S>, b: Point2<S>, c: Point2<S>) -> S
        where
            S: BaseNum,
        {
            (a[0] - c[0]) * (b[1] - c[1]) - (b[0] - c[0]) * (a[1] - c[1])
        }

        let b1 = sign(v, a, b) < V::Scalar::zero();
        let b2 = sign(v, b, c) < V::Scalar::zero();
        let b3 = sign(v, c, a) < V::Scalar::zero();

        (b1 == b2) && (b2 == b3)
    }

    /// The bounding `Rect` of the triangle.
    pub fn bounding_rect(self) -> Rect<V::Scalar>
    where
        V: Vertex2d,
    {
        let (a, b, c) = self.into();
        let (a, b, c) = (a.point2(), b.point2(), c.point2());
        let rect = Rect { x: Range::new(a.x, a.x), y: Range::new(a.y, a.y) };
        rect.stretch_to_point(b).stretch_to_point(c)
    }

    /// The bounding `Rect` of the triangle.
    pub fn bounding_cuboid(self) -> Cuboid<V::Scalar>
    where
        V: Vertex3d,
    {
        let (a, b, c) = self.into();
        let (a, b, c) = (a.point3(), b.point3(), c.point3());
        let cuboid = Cuboid {
            x: Range::new(a.x, a.x),
            y: Range::new(a.y, a.y),
            z: Range::new(a.z, a.z),
        };
        cuboid.stretch_to_point(b).stretch_to_point(c)
    }
}

/// Returns the first `Tri` that contains the given vertex.
///
/// Returns `None` if no `Tri`'s contain the given vertex.
pub fn iter_contains<I, V>(tris: I, v: &V) -> Option<I::Item>
where
    I: IntoIterator,
    I::Item: AsRef<Tri<V>>,
    V: Vertex2d,
{
    tris.into_iter().find(|tri| tri.as_ref().contains(v))
}

/// Create a **Tri** from the next three vertices yielded by the given `vertices` iterator.
///
/// Returns **None** if there were not at least 3 vertices in the given iterator.
pub fn from_vertices<I>(vertices: I) -> Option<Tri<I::Item>>
where
    I: IntoIterator,
{
    let mut vertices = vertices.into_iter();
    match (vertices.next(), vertices.next(), vertices.next()) {
        (Some(a), Some(b), Some(c)) => Some(Tri([a, b, c])),
        _ => None,
    }
}

/// Produce an iterator yielding a triangle for every three vertices yielded by the given
/// `vertices` iterator.
pub fn iter_from_vertices<I>(vertices: I) -> IterFromVertices<I::IntoIter>
where
    I: IntoIterator,
{
    let vertices = vertices.into_iter();
    IterFromVertices { vertices }
}

/// Create a **Tri** by indexing into the given buffer.
///
/// **Panics** if any of the given indices are out of range of the given `vertices` slice.
pub fn from_index_tri<V>(vertices: &[V], indices: &[usize; 3]) -> Tri<V>
where
    V: Clone,
{
    let a = vertices[indices[0]].clone();
    let b = vertices[indices[1]].clone();
    let c = vertices[indices[2]].clone();
    Tri([a, b, c])
}

/// Produce an iterator that flattens the given iterator yielding triangles into its vertices.
pub fn vertices_from_iter<I, V>(tris: I) -> VerticesFromIter<I::IntoIter, V>
where
    I: IntoIterator<Item = Tri<V>>,
{
    let tris = tris.into_iter();
    let tri = None;
    VerticesFromIter { tris, tri }
}

impl<V> Deref for Tri<V>
where
    V: Vertex,
{
    type Target = [V; 3];
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<V> From<[V; 3]> for Tri<V>
where
    V: Vertex,
{
    fn from(points: [V; 3]) -> Self {
        Tri(points)
    }
}

impl<V> From<(V, V, V)> for Tri<V>
where
    V: Vertex,
{
    fn from((a, b, c): (V, V, V)) -> Self {
        Tri([a, b, c])
    }
}

impl<V> Into<[V; 3]> for Tri<V>
where
    V: Vertex,
{
    fn into(self) -> [V; 3] {
        self.0
    }
}

impl<V> Into<(V, V, V)> for Tri<V>
where
    V: Vertex,
{
    fn into(self) -> (V, V, V) {
        (self[0], self[1], self[2])
    }
}

impl<V> AsRef<Tri<V>> for Tri<V>
where
    V: Vertex,
{
    fn as_ref(&self) -> &Tri<V> {
        self
    }
}

impl<V> AsRef<[V; 3]> for Tri<V>
where
    V: Vertex,
{
    fn as_ref(&self) -> &[V; 3] {
        &self.0
    }
}

impl<V> Iterator for Vertices<V>
where
    V: Clone,
{
    type Item = V;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index < NUM_VERTICES {
            let v = self.tri.0[self.index as usize].clone();
            self.index += 1;
            Some(v)
        } else {
            None
        }
    }
}

impl<V> ExactSizeIterator for Vertices<V>
where
    V: Clone,
{
    fn len(&self) -> usize {
        NUM_VERTICES as usize - self.index as usize
    }
}

impl<I> Iterator for IterFromVertices<I>
where
    I: Iterator,
{
    type Item = Tri<I::Item>;
    fn next(&mut self) -> Option<Self::Item> {
        from_vertices(&mut self.vertices)
    }
}

impl<I, V> Iterator for VerticesFromIter<I, V>
where
    I: Iterator<Item = Tri<V>>,
    V: Vertex,
{
    type Item = V;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(v) = self.tri.as_mut().and_then(|vs| vs.next()) {
                return Some(v);
            }
            match self.tris.next() {
                Some(t) => self.tri = Some(t.vertices()),
                None => return None,
            }
        }
    }
}

impl<I, V> ExactSizeIterator for VerticesFromIter<I, V>
where
    I: Iterator<Item = Tri<V>> + ExactSizeIterator,
    V: Vertex,
{
    fn len(&self) -> usize {
        let current_tri_vs = self.tri.as_ref().map(|vs| vs.len()).unwrap_or(0);
        let remaining_tri_vs = self.tris.len() * NUM_VERTICES as usize;
        current_tri_vs + remaining_tri_vs
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::f32::consts::{PI};
use std::num::{Float};

pub const EPSILON: f32 = 1.0E-9;
pub const DEGREES_TO_RADIANS: f32 = PI / 180.0;

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Point3D {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

static POINT3D_ORIGIN: Point3D = Point3D {
    x: 0.0,
    y: 0.0,
    z: 0.0
};

impl Point3D {
    pub fn from_xyz(x: f32, y: f32, z: f32) -> Point3D {
        Point3D {
            x: x,
            y: y,
            z: z
        }
    }

    pub fn from_vector(vector: &Vector3D) -> Point3D {
        Point3D::from_xyz(
            vector.x,
            vector.y,
            vector.z
        )
    }

    pub fn origin() -> &'static Point3D {
        &POINT3D_ORIGIN
    }

    pub fn translate_dist(&self, direction: &Direction3D, magnitude: f32) -> Point3D
    {
        Point3D::from_xyz(
            self.x + direction.x() * magnitude,
            self.y + direction.y() * magnitude,
            self.z + direction.z() * magnitude
        )
    }

    pub fn translate_vec(&self, vector: &Vector3D) -> Point3D {
        Point3D::from_xyz(
            self.x + vector.x,
            self.y + vector.y,
            self.z + vector.z
        )
    }

    pub fn rotate(&self, matrix: &Matrix3D) -> Point3D {
        Point3D::from_xyz(
            self.x * matrix.x.x + self.y * matrix.y.x + self.z * matrix.z.x,
            self.x * matrix.x.y + self.y * matrix.y.y + self.z * matrix.z.y,
            self.x * matrix.x.z + self.y * matrix.y.z + self.z * matrix.z.z)
    }

    pub fn eq_tol(&self, other: &Point3D, tolerance: f32) -> bool {
        (self.x - other.x).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance
    }

    pub fn distance(point1: &Point3D, point2: &Point3D) -> f32
    {
        Vector3D::from_xyz(
            point1.x - point2.x,
            point1.y - point2.y,
            point1.z - point2.z).magnitude()
    }

    pub fn midpoint(point1: &Point3D, point2: &Point3D) -> Point3D
    {
        Point3D::from_xyz(
            0.5 * (point1.x + point2.z),
            0.5 * (point1.y + point2.y),
            0.5 * (point1.z + point2.z))
    }
}

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Vector3D {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

static VECTOR3D_ZERO: Vector3D = Vector3D {
    x: 0.0,
    y: 0.0,
    z: 0.0
};

impl Vector3D {
    pub fn from_xyz(x: f32, y: f32, z: f32) -> Vector3D {
        Vector3D {
            x: x,
            y: y,
            z: z
        }
    }

    pub fn between_points(from: &Point3D, to: &Point3D) -> Vector3D {
        Vector3D::from_xyz(
            to.x - from.x,
            to.y - from.y,
            to.z - from.z
        )
    }

    pub fn from_point(point: &Point3D) -> Vector3D {
        Vector3D::from_xyz(
            point.x,
            point.y,
            point.z
        )
    }

    pub fn zero() -> &'static Vector3D {
        &VECTOR3D_ZERO
    }

    pub fn magnitude(&self) -> f32 {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }

    pub fn to_unit(&self) -> Direction3D {
        Direction3D::from_vector(self)
    }

    pub fn to_orthonormal_basis(&self) -> Matrix3D {
        Direction3D::from_vector(self).to_orthonormal_basis()
    }

    pub fn scale(&self, scale: f32) -> Vector3D {
        Vector3D::from_xyz(
            self.x * scale,
            self.y * scale,
            self.z * scale
        )
    }

    pub fn projection_dir(&self, direction: &Direction3D) -> Vector3D {
        direction.to_vector() * Vector3D::dot(self, direction.as_vector())
    }

    pub fn projection_vec(&self, direction: &Vector3D) -> Vector3D {
        let denominator = Vector3D::dot(direction, direction);
        if denominator > 0.0 {
            *direction * (Vector3D::dot(self, direction) / denominator)
        } else {
            *Vector3D::zero()
        }
    }

    pub fn rotate(&self, matrix: &Matrix3D) -> Vector3D
    {
        Vector3D::from_xyz(
            self.x * matrix.x.x + self.y * matrix.y.x + self.z * matrix.z.x,
            self.x * matrix.x.y + self.y * matrix.y.y + self.z * matrix.z.y,
            self.x * matrix.x.z + self.y * matrix.y.z + self.z * matrix.z.z
        )
    }

    pub fn eq_tol(&self, other: &Vector3D, tolerance: f32) -> bool {
        (self.x - other.x).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance
    }

    pub fn dot(vector1: &Vector3D, vector2: &Vector3D) -> f32
    {
        vector1.x * vector2.x +
        vector1.y * vector2.y +
        vector1.z * vector2.z
    }

    pub fn cross(vector1: &Vector3D, vector2: &Vector3D) -> Vector3D
    {
        Vector3D::from_xyz(
            vector1.y * vector2.z - vector1.z * vector2.y,
            vector1.z * vector2.x - vector1.x * vector2.z,
            vector1.x * vector2.y - vector1.y * vector2.x
        )
    }
}

impl Add<Vector3D, Vector3D> for Vector3D {
    fn add(&self, other: &Vector3D) -> Vector3D {
        Vector3D::from_xyz(
            self.x + other.x,
            self.y + other.y,
            self.z + other.z
        )
    }
}

impl Sub<Vector3D, Vector3D> for Vector3D {
    fn sub(&self, other: &Vector3D) -> Vector3D {
        Vector3D::from_xyz(
            self.x - other.x,
            self.y - other.y,
            self.z - other.z
        )
    }
}

impl Mul<f32, Vector3D> for Vector3D {
    fn mul(&self, scale: &f32) -> Vector3D {
        self.scale(*scale)
    }
}

impl Div<f32, Vector3D> for Vector3D {
    fn div(&self, scale: &f32) -> Vector3D {
        let inv_scale = 1.0 / *scale;
        self.scale(inv_scale)
    }
}

impl Neg<Vector3D> for Vector3D {
    fn neg(&self) -> Vector3D {
        Vector3D::from_xyz(
            -self.x,
            -self.y,
            -self.z
        )
    }
}

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Direction3D {
    direction: Vector3D
}

static DIRECTION3D_UNIT_X: Direction3D = Direction3D {
    direction: Vector3D {x: 1.0, y: 0.0, z: 0.0}
};
static DIRECTION3D_UNIT_Y: Direction3D = Direction3D {
    direction: Vector3D {x: 0.0, y: 1.0, z: 0.0}
};
static DIRECTION3D_UNIT_Z: Direction3D = Direction3D {
    direction: Vector3D {x: 0.0, y: 0.0, z: 1.0}
};

impl Direction3D {
    pub fn from_xyz(x: f32, y: f32, z: f32) -> Direction3D {
        Direction3D::from_vector(&Vector3D::from_xyz(x, y, z))
    }

    pub fn between_points(from: &Point3D, to: &Point3D) -> Direction3D {
        Direction3D::from_vector(&Vector3D::between_points(from, to))
    }

    pub fn from_point(point: &Point3D) -> Direction3D {
        Direction3D::from_vector(&Vector3D::from_point(point))
    }

    pub fn from_vector(vector: &Vector3D) -> Direction3D {
        let magnitude = vector.magnitude();
        if magnitude > 0.0 {
            Direction3D::from_normalized_vector(&vector.scale(1.0 / magnitude))
        } else {
            Direction3D::from_normalized_vector(vector)
        }
    }

    fn from_normalized_vector(normalized_vector: &Vector3D) -> Direction3D {
        Direction3D {direction: *normalized_vector}
    }

    pub fn unit_x() -> &'static Direction3D {
        &DIRECTION3D_UNIT_X
    }

    pub fn unit_y() -> &'static Direction3D {
        &DIRECTION3D_UNIT_Y
    }

    pub fn unit_z() -> &'static Direction3D {
        &DIRECTION3D_UNIT_Z
    }

    pub fn as_vector(&self) -> &Vector3D {
        &self.direction
    }

    pub fn to_vector(&self) -> Vector3D {
        Vector3D {
            x: self.direction.x,
            y: self.direction.y,
            z: self.direction.z
        }
    }

    pub fn x(&self) -> f32 {
        self.direction.x
    }

    pub fn y(&self) -> f32 {
        self.direction.y
    }

    pub fn z(&self) -> f32 {
        self.direction.z
    }

    pub fn to_orthonormal_basis(&self) -> Matrix3D
    {
        if self.direction.x.abs() >= self.direction.y.abs() && self.direction.x.abs() >= self.direction.z.abs() {
            let unit_x = &self.direction;

            let inv_xy_magnitude = 1.0 / (unit_x.x * unit_x.x + unit_x.y * unit_x.y).sqrt();
            let unit_y = Vector3D::from_xyz(
                -unit_x.y * inv_xy_magnitude,
                 unit_x.x * inv_xy_magnitude,
                 0.0);

            let unit_z = Vector3D::from_xyz(
                -unit_x.z * unit_y.y,
                 unit_x.z * unit_y.x,
                 unit_x.x * unit_y.y - unit_x.y * unit_y.x);

            return Matrix3D::new(unit_x, &unit_y, &unit_z);
        } else if self.direction.y.abs() >= self.direction.z.abs() {
            let unit_y = &self.direction;

            let inv_yz_magnitude = 1.0 / (unit_y.y * unit_y.y + unit_y.z * unit_y.z).sqrt();
            let unit_z = Vector3D::from_xyz(
                 0.0,
                -unit_y.z * inv_yz_magnitude,
                 unit_y.y * inv_yz_magnitude);

            let unit_x = Vector3D::from_xyz(
                 unit_y.y * unit_z.z - unit_y.z * unit_z.y,
                -unit_y.x * unit_z.z,
                 unit_y.x * unit_z.y);

            return Matrix3D::new(&unit_x, unit_y, &unit_z);
        } else {
            let unit_z = &self.direction;

            let inv_zx_magnitude = 1.0 / (unit_z.z * unit_z.z + unit_z.x * unit_z.x).sqrt();
            let unit_x = Vector3D::from_xyz(
                 unit_z.z * inv_zx_magnitude,
                 0.0,
                -unit_z.x * inv_zx_magnitude);

            let unit_y = Vector3D::from_xyz(
                 unit_z.y * unit_x.z,
                 unit_z.z * unit_x.x - unit_z.x * unit_x.z,
                -unit_z.y * unit_x.x);

            return Matrix3D::new(&unit_x, &unit_y, unit_z);
        }
    }
}

impl Neg<Direction3D> for Direction3D {
    fn neg(&self) -> Direction3D {
        Direction3D::from_normalized_vector(&self.as_vector().neg())
    }
}

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Ray3D {
    pub origin: Point3D,
    pub direction: Direction3D
}

impl Ray3D {
    pub fn new(origin: &Point3D, direction: &Direction3D) -> Ray3D {
        Ray3D {
            origin: *origin,
            direction: *direction
        }
    }

    pub fn point(&self, distance: f32) -> Point3D {
        self.origin.translate_dist(&self.direction, distance)
    }
}

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Matrix3D {
    pub x: Vector3D,
    pub y: Vector3D,
    pub z: Vector3D
}

static MATRIX3D_IDENTITY: Matrix3D = Matrix3D {
    x: Vector3D {x: 1.0, y: 0.0, z: 0.0},
    y: Vector3D {x: 0.0, y: 1.0, z: 0.0},
    z: Vector3D {x: 0.0, y: 0.0, z: 1.0}
};

impl Matrix3D {
    pub fn new(x: &Vector3D, y: &Vector3D, z: &Vector3D) -> Matrix3D {
        Matrix3D {
            x: *x,
            y: *y,
            z: *z
        }
    }

    pub fn identity() -> &'static Matrix3D {
        &MATRIX3D_IDENTITY
    }

    pub fn to_orthonormal_basis(&self) -> Matrix3D {
        let unit_x = self.x.to_unit();
        let vec_x = unit_x.to_vector();

        let unit_y = (self.y - vec_x * Vector3D::dot(&vec_x, &self.y)).to_unit();
        let vec_y = unit_y.to_vector();

        let unit_z = (self.z - vec_x * Vector3D::dot(&vec_x, &self.z) - vec_y * Vector3D::dot(&vec_y, &self.z)).to_unit();
        let vec_z = unit_z.to_vector();

        Matrix3D::new(&vec_x, &vec_y, &vec_z)
    }
}<commit_msg>Adds `eq_tol` for `Direction3D`, `Ray3D`, and `Matrix3D`.<commit_after>#![allow(dead_code)]

use std::f32::consts::{PI};
use std::num::{Float};

pub const EPSILON: f32 = 1.0E-9;
pub const DEGREES_TO_RADIANS: f32 = PI / 180.0;

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Point3D {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

static POINT3D_ORIGIN: Point3D = Point3D {
    x: 0.0,
    y: 0.0,
    z: 0.0
};

impl Point3D {
    pub fn from_xyz(x: f32, y: f32, z: f32) -> Point3D {
        Point3D {
            x: x,
            y: y,
            z: z
        }
    }

    pub fn from_vector(vector: &Vector3D) -> Point3D {
        Point3D::from_xyz(
            vector.x,
            vector.y,
            vector.z
        )
    }

    pub fn origin() -> &'static Point3D {
        &POINT3D_ORIGIN
    }

    pub fn translate_dist(&self, direction: &Direction3D, magnitude: f32) -> Point3D
    {
        Point3D::from_xyz(
            self.x + direction.x() * magnitude,
            self.y + direction.y() * magnitude,
            self.z + direction.z() * magnitude
        )
    }

    pub fn translate_vec(&self, vector: &Vector3D) -> Point3D {
        Point3D::from_xyz(
            self.x + vector.x,
            self.y + vector.y,
            self.z + vector.z
        )
    }

    pub fn rotate(&self, matrix: &Matrix3D) -> Point3D {
        Point3D::from_xyz(
            self.x * matrix.x.x + self.y * matrix.y.x + self.z * matrix.z.x,
            self.x * matrix.x.y + self.y * matrix.y.y + self.z * matrix.z.y,
            self.x * matrix.x.z + self.y * matrix.y.z + self.z * matrix.z.z)
    }

    pub fn eq_tol(&self, other: &Point3D, tolerance: f32) -> bool {
        (self.x - other.x).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance
    }

    pub fn distance(point1: &Point3D, point2: &Point3D) -> f32
    {
        Vector3D::from_xyz(
            point1.x - point2.x,
            point1.y - point2.y,
            point1.z - point2.z).magnitude()
    }

    pub fn midpoint(point1: &Point3D, point2: &Point3D) -> Point3D
    {
        Point3D::from_xyz(
            0.5 * (point1.x + point2.z),
            0.5 * (point1.y + point2.y),
            0.5 * (point1.z + point2.z))
    }
}

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Vector3D {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

static VECTOR3D_ZERO: Vector3D = Vector3D {
    x: 0.0,
    y: 0.0,
    z: 0.0
};

impl Vector3D {
    pub fn from_xyz(x: f32, y: f32, z: f32) -> Vector3D {
        Vector3D {
            x: x,
            y: y,
            z: z
        }
    }

    pub fn between_points(from: &Point3D, to: &Point3D) -> Vector3D {
        Vector3D::from_xyz(
            to.x - from.x,
            to.y - from.y,
            to.z - from.z
        )
    }

    pub fn from_point(point: &Point3D) -> Vector3D {
        Vector3D::from_xyz(
            point.x,
            point.y,
            point.z
        )
    }

    pub fn zero() -> &'static Vector3D {
        &VECTOR3D_ZERO
    }

    pub fn magnitude(&self) -> f32 {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }

    pub fn to_unit(&self) -> Direction3D {
        Direction3D::from_vector(self)
    }

    pub fn to_orthonormal_basis(&self) -> Matrix3D {
        Direction3D::from_vector(self).to_orthonormal_basis()
    }

    pub fn scale(&self, scale: f32) -> Vector3D {
        Vector3D::from_xyz(
            self.x * scale,
            self.y * scale,
            self.z * scale
        )
    }

    pub fn projection_dir(&self, direction: &Direction3D) -> Vector3D {
        direction.to_vector() * Vector3D::dot(self, direction.as_vector())
    }

    pub fn projection_vec(&self, direction: &Vector3D) -> Vector3D {
        let denominator = Vector3D::dot(direction, direction);
        if denominator > 0.0 {
            *direction * (Vector3D::dot(self, direction) / denominator)
        } else {
            *Vector3D::zero()
        }
    }

    pub fn rotate(&self, matrix: &Matrix3D) -> Vector3D
    {
        Vector3D::from_xyz(
            self.x * matrix.x.x + self.y * matrix.y.x + self.z * matrix.z.x,
            self.x * matrix.x.y + self.y * matrix.y.y + self.z * matrix.z.y,
            self.x * matrix.x.z + self.y * matrix.y.z + self.z * matrix.z.z
        )
    }

    pub fn eq_tol(&self, other: &Vector3D, tolerance: f32) -> bool {
        (self.x - other.x).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance
    }

    pub fn dot(vector1: &Vector3D, vector2: &Vector3D) -> f32
    {
        vector1.x * vector2.x +
        vector1.y * vector2.y +
        vector1.z * vector2.z
    }

    pub fn cross(vector1: &Vector3D, vector2: &Vector3D) -> Vector3D
    {
        Vector3D::from_xyz(
            vector1.y * vector2.z - vector1.z * vector2.y,
            vector1.z * vector2.x - vector1.x * vector2.z,
            vector1.x * vector2.y - vector1.y * vector2.x
        )
    }
}

impl Add<Vector3D, Vector3D> for Vector3D {
    fn add(&self, other: &Vector3D) -> Vector3D {
        Vector3D::from_xyz(
            self.x + other.x,
            self.y + other.y,
            self.z + other.z
        )
    }
}

impl Sub<Vector3D, Vector3D> for Vector3D {
    fn sub(&self, other: &Vector3D) -> Vector3D {
        Vector3D::from_xyz(
            self.x - other.x,
            self.y - other.y,
            self.z - other.z
        )
    }
}

impl Mul<f32, Vector3D> for Vector3D {
    fn mul(&self, scale: &f32) -> Vector3D {
        self.scale(*scale)
    }
}

impl Div<f32, Vector3D> for Vector3D {
    fn div(&self, scale: &f32) -> Vector3D {
        let inv_scale = 1.0 / *scale;
        self.scale(inv_scale)
    }
}

impl Neg<Vector3D> for Vector3D {
    fn neg(&self) -> Vector3D {
        Vector3D::from_xyz(
            -self.x,
            -self.y,
            -self.z
        )
    }
}

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Direction3D {
    direction: Vector3D
}

static DIRECTION3D_UNIT_X: Direction3D = Direction3D {
    direction: Vector3D {x: 1.0, y: 0.0, z: 0.0}
};
static DIRECTION3D_UNIT_Y: Direction3D = Direction3D {
    direction: Vector3D {x: 0.0, y: 1.0, z: 0.0}
};
static DIRECTION3D_UNIT_Z: Direction3D = Direction3D {
    direction: Vector3D {x: 0.0, y: 0.0, z: 1.0}
};

impl Direction3D {
    pub fn from_xyz(x: f32, y: f32, z: f32) -> Direction3D {
        Direction3D::from_vector(&Vector3D::from_xyz(x, y, z))
    }

    pub fn between_points(from: &Point3D, to: &Point3D) -> Direction3D {
        Direction3D::from_vector(&Vector3D::between_points(from, to))
    }

    pub fn from_point(point: &Point3D) -> Direction3D {
        Direction3D::from_vector(&Vector3D::from_point(point))
    }

    pub fn from_vector(vector: &Vector3D) -> Direction3D {
        let magnitude = vector.magnitude();
        if magnitude > 0.0 {
            Direction3D::from_normalized_vector(&vector.scale(1.0 / magnitude))
        } else {
            Direction3D::from_normalized_vector(vector)
        }
    }

    fn from_normalized_vector(normalized_vector: &Vector3D) -> Direction3D {
        Direction3D {direction: *normalized_vector}
    }

    pub fn unit_x() -> &'static Direction3D {
        &DIRECTION3D_UNIT_X
    }

    pub fn unit_y() -> &'static Direction3D {
        &DIRECTION3D_UNIT_Y
    }

    pub fn unit_z() -> &'static Direction3D {
        &DIRECTION3D_UNIT_Z
    }

    pub fn as_vector(&self) -> &Vector3D {
        &self.direction
    }

    pub fn to_vector(&self) -> Vector3D {
        Vector3D {
            x: self.direction.x,
            y: self.direction.y,
            z: self.direction.z
        }
    }

    pub fn x(&self) -> f32 {
        self.direction.x
    }

    pub fn y(&self) -> f32 {
        self.direction.y
    }

    pub fn z(&self) -> f32 {
        self.direction.z
    }

    pub fn to_orthonormal_basis(&self) -> Matrix3D
    {
        if self.direction.x.abs() >= self.direction.y.abs() && self.direction.x.abs() >= self.direction.z.abs() {
            let unit_x = &self.direction;

            let inv_xy_magnitude = 1.0 / (unit_x.x * unit_x.x + unit_x.y * unit_x.y).sqrt();
            let unit_y = Vector3D::from_xyz(
                -unit_x.y * inv_xy_magnitude,
                 unit_x.x * inv_xy_magnitude,
                 0.0);

            let unit_z = Vector3D::from_xyz(
                -unit_x.z * unit_y.y,
                 unit_x.z * unit_y.x,
                 unit_x.x * unit_y.y - unit_x.y * unit_y.x);

            return Matrix3D::new(unit_x, &unit_y, &unit_z);
        } else if self.direction.y.abs() >= self.direction.z.abs() {
            let unit_y = &self.direction;

            let inv_yz_magnitude = 1.0 / (unit_y.y * unit_y.y + unit_y.z * unit_y.z).sqrt();
            let unit_z = Vector3D::from_xyz(
                 0.0,
                -unit_y.z * inv_yz_magnitude,
                 unit_y.y * inv_yz_magnitude);

            let unit_x = Vector3D::from_xyz(
                 unit_y.y * unit_z.z - unit_y.z * unit_z.y,
                -unit_y.x * unit_z.z,
                 unit_y.x * unit_z.y);

            return Matrix3D::new(&unit_x, unit_y, &unit_z);
        } else {
            let unit_z = &self.direction;

            let inv_zx_magnitude = 1.0 / (unit_z.z * unit_z.z + unit_z.x * unit_z.x).sqrt();
            let unit_x = Vector3D::from_xyz(
                 unit_z.z * inv_zx_magnitude,
                 0.0,
                -unit_z.x * inv_zx_magnitude);

            let unit_y = Vector3D::from_xyz(
                 unit_z.y * unit_x.z,
                 unit_z.z * unit_x.x - unit_z.x * unit_x.z,
                -unit_z.y * unit_x.x);

            return Matrix3D::new(&unit_x, &unit_y, unit_z);
        }
    }

    pub fn eq_tol(&self, other: &Direction3D, tolerance: f32) -> bool {
        (self.x - other.x).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance &&
        (self.y - other.z).abs() < tolerance
    }
}

impl Neg<Direction3D> for Direction3D {
    fn neg(&self) -> Direction3D {
        Direction3D::from_normalized_vector(&self.as_vector().neg())
    }
}

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Ray3D {
    pub origin: Point3D,
    pub direction: Direction3D
}

impl Ray3D {
    pub fn new(origin: &Point3D, direction: &Direction3D) -> Ray3D {
        Ray3D {
            origin: *origin,
            direction: *direction
        }
    }

    pub fn point(&self, distance: f32) -> Point3D {
        self.origin.translate_dist(&self.direction, distance)
    }

    pub fn eq_tol(&self, other: &Ray3D, tolerance: f32) -> bool {
        self.origin.eq_tol(other.origin, tolerance) &&
        self.direction.eq_tol(oher.direction, tolerance)
    }
}

#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct Matrix3D {
    pub x: Vector3D,
    pub y: Vector3D,
    pub z: Vector3D
}

static MATRIX3D_IDENTITY: Matrix3D = Matrix3D {
    x: Vector3D {x: 1.0, y: 0.0, z: 0.0},
    y: Vector3D {x: 0.0, y: 1.0, z: 0.0},
    z: Vector3D {x: 0.0, y: 0.0, z: 1.0}
};

impl Matrix3D {
    pub fn new(x: &Vector3D, y: &Vector3D, z: &Vector3D) -> Matrix3D {
        Matrix3D {
            x: *x,
            y: *y,
            z: *z
        }
    }

    pub fn identity() -> &'static Matrix3D {
        &MATRIX3D_IDENTITY
    }

    pub fn to_orthonormal_basis(&self) -> Matrix3D {
        let unit_x = self.x.to_unit();
        let vec_x = unit_x.to_vector();

        let unit_y = (self.y - vec_x * Vector3D::dot(&vec_x, &self.y)).to_unit();
        let vec_y = unit_y.to_vector();

        let unit_z = (self.z - vec_x * Vector3D::dot(&vec_x, &self.z) - vec_y * Vector3D::dot(&vec_y, &self.z)).to_unit();
        let vec_z = unit_z.to_vector();

        Matrix3D::new(&vec_x, &vec_y, &vec_z)
    }

    pub fn eq_tol(&self, other: &Point3D, tolerance: f32) -> bool {
        self.x.eq_tol(other.x, tolerance) &&
        self.y.eq_tol(other.y, tolerance) &&
        self.z.eq_tol(other.z, tolerance)
    }
}<|endoftext|>