<commit_before>use std::fs::Metadata;
use std::path::{Path, PathBuf};

use log::warn;

pub fn walk_dir<P: AsRef<Path>>(root: P) -> std::io::Result<WalkDir> {
    let metadata = std::fs::symlink_metadata(&root)?;
    let pending = vec!(list_dir(&root)?);

    Ok(WalkDir {
        root: Some(WalkEntry {
            path: root.as_ref().to_path_buf(),
            metadata: metadata,
        }),
        pending: pending,
    })
}

fn list_dir<P: AsRef<Path>>(path: P) -> std::io::Result<ListDir> {
    let iter = std::fs::read_dir(path)?;

    Ok(ListDir {
        iter: iter,
    })
}

pub struct WalkDir {
    // TODO: Add support for stopping at device boundaries.
    root: Option<WalkEntry>,
    pending: Vec<ListDir>,
}

pub struct WalkEntry {
    path: PathBuf,
    metadata: Metadata,
}

impl WalkDir {

    fn push(&mut self, entry: &WalkEntry) {
        match list_dir(&entry.path) {
            Ok(iter) => {
                self.pending.push(iter);
            },
            Err(error) => {
                warn!("failed to read '{}': {}", entry.path.display(), error);
            },
        }
    }

    fn pop(&mut self) -> Option<WalkEntry> {
        while let Some(iter) = self.pending.last_mut() {
            for entry in iter {
                return Some(entry);
            }

            self.pending.pop();
        }

        None
    }
}

impl std::iter::Iterator for WalkDir {

    type Item = WalkEntry;

    fn next(&mut self) -> Option<WalkEntry> {
        if self.root.is_some() {
            return self.root.take();
        }

        let entry = self.pop()?;

        if entry.metadata.is_dir() {
            self.push(&entry);
        }

        Some(entry)
    }
}

/// Iterator over the entries in a directory.
///
/// This iterator is very similar to the standard `ReadDir` iterator, except
/// that it is forgetful and only yields entries that did not cause any errors.
///
/// Unlike the `ReadDir` iterator entries, `ListDir` entries are guaranteed to
/// have valid metadata objects attached.
struct ListDir {
    iter: std::fs::ReadDir,
}

impl std::iter::Iterator for ListDir {

    type Item = WalkEntry;

    fn next(&mut self) -> Option<WalkEntry> {
        for entry in &mut self.iter {
            let entry = match entry {
                Ok(entry) => entry,
                Err(error) => {
                    warn!("directory iteration error: {}", error);
                    continue
                },
            };

            let path = entry.path();
            let metadata = match entry.metadata() {
                Ok(metadata) => metadata,
                Err(error) => {
                    warn!("failed to stat '{}': {}", path.display(), error);
                    continue
                },
            };

            return Some(WalkEntry {
                path: path,
                metadata: metadata,
            });
        }

        None
    }
}

#[cfg(test)]
mod tests {

    use std::fs::File;

    use super::*;

    // TODO: Add test case for non-existing directory.

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

        let mut iter = list_dir(&tempdir).unwrap();

        assert!(iter.next().is_none());
    }

    #[test]
    fn test_list_dir_with_files() {
        let tempdir = tempfile::tempdir().unwrap();
        File::create(tempdir.path().join("abc")).unwrap();
        File::create(tempdir.path().join("def")).unwrap();
        File::create(tempdir.path().join("ghi")).unwrap();

        let mut results = list_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 3);

        assert_eq!(results[0].path, tempdir.path().join("abc"));
        assert!(results[0].metadata.is_file());

        assert_eq!(results[1].path, tempdir.path().join("def"));
        assert!(results[1].metadata.is_file());

        assert_eq!(results[2].path, tempdir.path().join("ghi"));
        assert!(results[2].metadata.is_file());
    }

    #[test]
    fn test_list_dir_with_dirs() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::create_dir(tempdir.path().join("abc")).unwrap();
        std::fs::create_dir(tempdir.path().join("def")).unwrap();

        let mut results = list_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].path, tempdir.path().join("abc"));
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("def"));
        assert!(results[1].metadata.is_dir());
    }

    #[cfg(target_family = "unix")]
    #[test]
    fn test_list_dir_with_links() {
        let tempdir = tempfile::tempdir().unwrap();
        let source = tempdir.path().join("abc");
        let target = tempdir.path().join("def");

        File::create(&source).unwrap();
        std::os::unix::fs::symlink(&source, &target).unwrap();

        let mut results = list_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].path, source);
        assert!(results[0].metadata.file_type().is_file());

        assert_eq!(results[1].path, target);
        assert!(results[1].metadata.file_type().is_symlink());
    }

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

        let mut iter = walk_dir(&tempdir).unwrap();

        let entry = iter.next().unwrap();
        assert_eq!(entry.path, tempdir.path());
        assert!(entry.metadata.is_dir());

        assert!(iter.next().is_none());
    }

    #[test]
    fn test_walk_dir_with_flat_files() {
        let tempdir = tempfile::tempdir().unwrap();
        File::create(tempdir.path().join("abc")).unwrap();
        File::create(tempdir.path().join("def")).unwrap();
        File::create(tempdir.path().join("ghi")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 4);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("abc"));
        assert!(results[1].metadata.is_file());

        assert_eq!(results[2].path, tempdir.path().join("def"));
        assert!(results[2].metadata.is_file());

        assert_eq!(results[3].path, tempdir.path().join("ghi"));
        assert!(results[3].metadata.is_file());
    }

    #[test]
    fn test_walk_dir_with_flat_dirs() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::create_dir(tempdir.path().join("abc")).unwrap();
        std::fs::create_dir(tempdir.path().join("def")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 3);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("abc"));
        assert!(results[1].metadata.is_dir());

        assert_eq!(results[2].path, tempdir.path().join("def"));
        assert!(results[2].metadata.is_dir());
    }

    #[test]
    fn test_walk_dir_with_nested_dirs() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::create_dir(tempdir.path().join("abc")).unwrap();
        std::fs::create_dir(tempdir.path().join("abc").join("def")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 3);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("abc"));
        assert!(results[1].metadata.is_dir());

        assert_eq!(results[2].path, tempdir.path().join("abc").join("def"));
        assert!(results[2].metadata.is_dir());
    }

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

        let mut dir = tempdir.path().to_path_buf();
        for _ in 0..512 {
            dir.push("foo");
            std::fs::create_dir(&dir).unwrap();
        }

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 513);

        for entry in &results[1..] {
            assert!(entry.path.starts_with(&tempdir));
            assert!(entry.path.ends_with("foo"));
            assert!(entry.metadata.is_dir());
        }
    }

    #[test]
    fn test_walk_dir_with_files_inside_dir() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::create_dir(tempdir.path().join("foo")).unwrap();
        File::create(tempdir.path().join("foo").join("abc")).unwrap();
        File::create(tempdir.path().join("foo").join("def")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 4);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("foo"));
        assert!(results[1].metadata.is_dir());

        assert_eq!(results[2].path, tempdir.path().join("foo").join("abc"));
        assert!(results[2].metadata.is_file());

        assert_eq!(results[3].path, tempdir.path().join("foo").join("def"));
        assert!(results[3].metadata.is_file());
    }

    #[cfg(target_family = "unix")]
    #[test]
    fn test_walk_dir_with_dir_symlinks() {
        let tempdir = tempfile::tempdir().unwrap();
        let dir = tempdir.path().join("abc");
        let file = dir.join("def");
        let symlink = tempdir.path().join("ghi");

        std::fs::create_dir(&dir).unwrap();
        File::create(&file).unwrap();
        std::os::unix::fs::symlink(&dir, &symlink).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 4);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.file_type().is_dir());

        assert_eq!(results[1].path, dir);
        assert!(results[1].metadata.file_type().is_dir());

        assert_eq!(results[2].path, file);
        assert!(results[2].metadata.file_type().is_file());

        assert_eq!(results[3].path, symlink);
        assert!(results[3].metadata.file_type().is_symlink());
    }

    #[cfg(target_family = "unix")]
    #[test]
    fn test_walk_dir_with_circular_symlinks() {
        let tempdir = tempfile::tempdir().unwrap();
        let dir = tempdir.path().join("foo");
        let symlink = tempdir.path().join("foo").join("bar");

        std::fs::create_dir(&dir).unwrap();
        std::os::unix::fs::symlink(&dir, &symlink).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 3);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.file_type().is_dir());

        assert_eq!(results[1].path, dir);
        assert!(results[1].metadata.file_type().is_dir());

        assert_eq!(results[2].path, symlink);
        assert!(results[2].metadata.file_type().is_symlink());
    }

    #[test]
    fn test_walk_dir_with_unicode_names() {
        let tempdir = tempfile::tempdir().unwrap();
        File::create(tempdir.path().join("zażółć gęślą jaźń")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 2);
        assert_eq!(results[0].path, tempdir.path());
        assert_eq!(results[1].path, tempdir.path().join("zażółć gęślą jaźń"));
    }

    #[test]
    fn test_walk_dir_metadata_size() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::write(tempdir.path().join("foo"), b"123456789").unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 2);
        assert_eq!(results[1].metadata.len(), 9);
    }
}
<commit_msg>Rename the type of a filesystem entry.<commit_after>use std::fs::Metadata;
use std::path::{Path, PathBuf};

use log::warn;

pub struct Entry {
    pub path: PathBuf,
    pub metadata: Metadata,
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> std::io::Result<WalkDir> {
    let metadata = std::fs::symlink_metadata(&root)?;
    let pending = vec!(list_dir(&root)?);

    Ok(WalkDir {
        root: Some(Entry {
            path: root.as_ref().to_path_buf(),
            metadata: metadata,
        }),
        pending: pending,
    })
}

fn list_dir<P: AsRef<Path>>(path: P) -> std::io::Result<ListDir> {
    let iter = std::fs::read_dir(path)?;

    Ok(ListDir {
        iter: iter,
    })
}

pub struct WalkDir {
    // TODO: Add support for stopping at device boundaries.
    root: Option<Entry>,
    pending: Vec<ListDir>,
}

impl WalkDir {

    fn push(&mut self, entry: &Entry) {
        match list_dir(&entry.path) {
            Ok(iter) => {
                self.pending.push(iter);
            },
            Err(error) => {
                warn!("failed to read '{}': {}", entry.path.display(), error);
            },
        }
    }

    fn pop(&mut self) -> Option<Entry> {
        while let Some(iter) = self.pending.last_mut() {
            for entry in iter {
                return Some(entry);
            }

            self.pending.pop();
        }

        None
    }
}

impl std::iter::Iterator for WalkDir {

    type Item = Entry;

    fn next(&mut self) -> Option<Entry> {
        if self.root.is_some() {
            return self.root.take();
        }

        let entry = self.pop()?;

        if entry.metadata.is_dir() {
            self.push(&entry);
        }

        Some(entry)
    }
}

/// Iterator over the entries in a directory.
///
/// This iterator is very similar to the standard `ReadDir` iterator, except
/// that it is forgetful and only yields entries that did not cause any errors.
///
/// Unlike the `ReadDir` iterator entries, `ListDir` entries are guaranteed to
/// have valid metadata objects attached.
struct ListDir {
    iter: std::fs::ReadDir,
}

impl std::iter::Iterator for ListDir {

    type Item = Entry;

    fn next(&mut self) -> Option<Entry> {
        for entry in &mut self.iter {
            let entry = match entry {
                Ok(entry) => entry,
                Err(error) => {
                    warn!("directory iteration error: {}", error);
                    continue
                },
            };

            let path = entry.path();
            let metadata = match entry.metadata() {
                Ok(metadata) => metadata,
                Err(error) => {
                    warn!("failed to stat '{}': {}", path.display(), error);
                    continue
                },
            };

            return Some(Entry {
                path: path,
                metadata: metadata,
            });
        }

        None
    }
}

#[cfg(test)]
mod tests {

    use std::fs::File;

    use super::*;

    // TODO: Add test case for non-existing directory.

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

        let mut iter = list_dir(&tempdir).unwrap();

        assert!(iter.next().is_none());
    }

    #[test]
    fn test_list_dir_with_files() {
        let tempdir = tempfile::tempdir().unwrap();
        File::create(tempdir.path().join("abc")).unwrap();
        File::create(tempdir.path().join("def")).unwrap();
        File::create(tempdir.path().join("ghi")).unwrap();

        let mut results = list_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 3);

        assert_eq!(results[0].path, tempdir.path().join("abc"));
        assert!(results[0].metadata.is_file());

        assert_eq!(results[1].path, tempdir.path().join("def"));
        assert!(results[1].metadata.is_file());

        assert_eq!(results[2].path, tempdir.path().join("ghi"));
        assert!(results[2].metadata.is_file());
    }

    #[test]
    fn test_list_dir_with_dirs() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::create_dir(tempdir.path().join("abc")).unwrap();
        std::fs::create_dir(tempdir.path().join("def")).unwrap();

        let mut results = list_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].path, tempdir.path().join("abc"));
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("def"));
        assert!(results[1].metadata.is_dir());
    }

    #[cfg(target_family = "unix")]
    #[test]
    fn test_list_dir_with_links() {
        let tempdir = tempfile::tempdir().unwrap();
        let source = tempdir.path().join("abc");
        let target = tempdir.path().join("def");

        File::create(&source).unwrap();
        std::os::unix::fs::symlink(&source, &target).unwrap();

        let mut results = list_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].path, source);
        assert!(results[0].metadata.file_type().is_file());

        assert_eq!(results[1].path, target);
        assert!(results[1].metadata.file_type().is_symlink());
    }

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

        let mut iter = walk_dir(&tempdir).unwrap();

        let entry = iter.next().unwrap();
        assert_eq!(entry.path, tempdir.path());
        assert!(entry.metadata.is_dir());

        assert!(iter.next().is_none());
    }

    #[test]
    fn test_walk_dir_with_flat_files() {
        let tempdir = tempfile::tempdir().unwrap();
        File::create(tempdir.path().join("abc")).unwrap();
        File::create(tempdir.path().join("def")).unwrap();
        File::create(tempdir.path().join("ghi")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 4);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("abc"));
        assert!(results[1].metadata.is_file());

        assert_eq!(results[2].path, tempdir.path().join("def"));
        assert!(results[2].metadata.is_file());

        assert_eq!(results[3].path, tempdir.path().join("ghi"));
        assert!(results[3].metadata.is_file());
    }

    #[test]
    fn test_walk_dir_with_flat_dirs() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::create_dir(tempdir.path().join("abc")).unwrap();
        std::fs::create_dir(tempdir.path().join("def")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 3);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("abc"));
        assert!(results[1].metadata.is_dir());

        assert_eq!(results[2].path, tempdir.path().join("def"));
        assert!(results[2].metadata.is_dir());
    }

    #[test]
    fn test_walk_dir_with_nested_dirs() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::create_dir(tempdir.path().join("abc")).unwrap();
        std::fs::create_dir(tempdir.path().join("abc").join("def")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 3);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("abc"));
        assert!(results[1].metadata.is_dir());

        assert_eq!(results[2].path, tempdir.path().join("abc").join("def"));
        assert!(results[2].metadata.is_dir());
    }

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

        let mut dir = tempdir.path().to_path_buf();
        for _ in 0..512 {
            dir.push("foo");
            std::fs::create_dir(&dir).unwrap();
        }

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 513);

        for entry in &results[1..] {
            assert!(entry.path.starts_with(&tempdir));
            assert!(entry.path.ends_with("foo"));
            assert!(entry.metadata.is_dir());
        }
    }

    #[test]
    fn test_walk_dir_with_files_inside_dir() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::create_dir(tempdir.path().join("foo")).unwrap();
        File::create(tempdir.path().join("foo").join("abc")).unwrap();
        File::create(tempdir.path().join("foo").join("def")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 4);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.is_dir());

        assert_eq!(results[1].path, tempdir.path().join("foo"));
        assert!(results[1].metadata.is_dir());

        assert_eq!(results[2].path, tempdir.path().join("foo").join("abc"));
        assert!(results[2].metadata.is_file());

        assert_eq!(results[3].path, tempdir.path().join("foo").join("def"));
        assert!(results[3].metadata.is_file());
    }

    #[cfg(target_family = "unix")]
    #[test]
    fn test_walk_dir_with_dir_symlinks() {
        let tempdir = tempfile::tempdir().unwrap();
        let dir = tempdir.path().join("abc");
        let file = dir.join("def");
        let symlink = tempdir.path().join("ghi");

        std::fs::create_dir(&dir).unwrap();
        File::create(&file).unwrap();
        std::os::unix::fs::symlink(&dir, &symlink).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 4);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.file_type().is_dir());

        assert_eq!(results[1].path, dir);
        assert!(results[1].metadata.file_type().is_dir());

        assert_eq!(results[2].path, file);
        assert!(results[2].metadata.file_type().is_file());

        assert_eq!(results[3].path, symlink);
        assert!(results[3].metadata.file_type().is_symlink());
    }

    #[cfg(target_family = "unix")]
    #[test]
    fn test_walk_dir_with_circular_symlinks() {
        let tempdir = tempfile::tempdir().unwrap();
        let dir = tempdir.path().join("foo");
        let symlink = tempdir.path().join("foo").join("bar");

        std::fs::create_dir(&dir).unwrap();
        std::os::unix::fs::symlink(&dir, &symlink).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 3);

        assert_eq!(results[0].path, tempdir.path());
        assert!(results[0].metadata.file_type().is_dir());

        assert_eq!(results[1].path, dir);
        assert!(results[1].metadata.file_type().is_dir());

        assert_eq!(results[2].path, symlink);
        assert!(results[2].metadata.file_type().is_symlink());
    }

    #[test]
    fn test_walk_dir_with_unicode_names() {
        let tempdir = tempfile::tempdir().unwrap();
        File::create(tempdir.path().join("zażółć gęślą jaźń")).unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 2);
        assert_eq!(results[0].path, tempdir.path());
        assert_eq!(results[1].path, tempdir.path().join("zażółć gęślą jaźń"));
    }

    #[test]
    fn test_walk_dir_metadata_size() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::write(tempdir.path().join("foo"), b"123456789").unwrap();

        let mut results = walk_dir(&tempdir).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|entry| entry.path.clone());

        assert_eq!(results.len(), 2);
        assert_eq!(results[1].metadata.len(), 9);
    }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Map_range
fn map_range(from_range : (f64,f64), to_range : (f64,f64), s : f64 ) -> f64{
    to_range.0 + (s - from_range.0) * (to_range.1 - to_range.0) / (from_range.1 - from_range.0)
}

#[cfg(not(test))]
fn main(){
    let input : Vec<f64> = vec![0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0];
    let result = input.into_iter().map( |x| map_range((0.0,10.0),(-1.0,0.0),x)).collect::<Vec<f64>>();
    print!("{:?}",result);
}

#[test]
fn test_basic(){
    assert_eq!(map_range((1.0,5.0),(10.0,50.0),2.0),20.0)
}
<commit_msg>formatted map_range.rs with rustfmt<commit_after>// http://rosettacode.org/wiki/Map_range
fn map_range(from_range: (f64, f64), to_range: (f64, f64), s: f64) -> f64 {
    to_range.0 + (s - from_range.0) * (to_range.1 - to_range.0) / (from_range.1 - from_range.0)
}

#[cfg(not(test))]
fn main() {
    let input: Vec<f64> = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
    let result = input.into_iter()
                      .map(|x| map_range((0.0, 10.0), (-1.0, 0.0), x))
                      .collect::<Vec<f64>>();
    print!("{:?}", result);
}

#[test]
fn test_basic() {
    assert_eq!(map_range((1.0, 5.0), (10.0, 50.0), 2.0), 20.0)
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The `Clone` trait for types that cannot be 'implicitly copied'.
//!
//! In Rust, some simple types are "implicitly copyable" and when you
//! assign them or pass them as arguments, the receiver will get a copy,
//! leaving the original value in place. These types do not require
//! allocation to copy and do not have finalizers (i.e. they do not
//! contain owned boxes or implement `Drop`), so the compiler considers
//! them cheap and safe to copy. For other types copies must be made
//! explicitly, by convention implementing the `Clone` trait and calling
//! the `clone` method.
//!
//! Basic usage example:
//!
//! ```
//! let s = String::new(); // String type implements Clone
//! let copy = s.clone(); // so we can clone it
//! ```
//!
//! To easily implement the Clone trait, you can also use
//! `#[derive(Clone)]`. Example:
//!
//! ```
//! #[derive(Clone)] // we add the Clone trait to Morpheus struct
//! struct Morpheus {
//!    blue_pill: f32,
//!    red_pill: i64,
//! }
//!
//! fn main() {
//!    let f = Morpheus { blue_pill: 0.0, red_pill: 0 };
//!    let copy = f.clone(); // and now we can clone it!
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A common trait for cloning an object.
///
/// This trait can be used with `#[derive]`.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Clone : Sized {
    /// Returns a copy of the value.
    ///
    /// # Examples
    ///
    /// ```
    /// let hello = "Hello"; // &str implements Clone
    ///
    /// assert_eq!("Hello", hello.clone());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn clone(&self) -> Self;

    /// Performs copy-assignment from `source`.
    ///
    /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality,
    /// but can be overridden to reuse the resources of `a` to avoid unnecessary
    /// allocations.
    #[inline(always)]
    #[stable(feature = "rust1", since = "1.0.0")]
    fn clone_from(&mut self, source: &Self) {
        *self = source.clone()
    }
}

// FIXME(aburka): this method is used solely by #[derive] to
// assert that every component of a type implements Clone.
//
// This should never be called by user code.
#[doc(hidden)]
#[inline(always)]
#[unstable(feature = "derive_clone_copy",
           reason = "deriving hack, should not be public",
           issue = "0")]
pub fn assert_receiver_is_clone<T: Clone + ?Sized>(_: &T) {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Clone for &'a T {
    /// Returns a shallow copy of the reference.
    #[inline]
    fn clone(&self) -> &'a T { *self }
}

macro_rules! clone_impl {
    ($t:ty) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl Clone for $t {
            /// Returns a deep copy of the value.
            #[inline]
            fn clone(&self) -> $t { *self }
        }
    }
}

clone_impl! { isize }
clone_impl! { i8 }
clone_impl! { i16 }
clone_impl! { i32 }
clone_impl! { i64 }

clone_impl! { usize }
clone_impl! { u8 }
clone_impl! { u16 }
clone_impl! { u32 }
clone_impl! { u64 }

clone_impl! { f32 }
clone_impl! { f64 }

clone_impl! { () }
clone_impl! { bool }
clone_impl! { char }
<commit_msg>implement RFC 1521<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The `Clone` trait for types that cannot be 'implicitly copied'.
//!
//! In Rust, some simple types are "implicitly copyable" and when you
//! assign them or pass them as arguments, the receiver will get a copy,
//! leaving the original value in place. These types do not require
//! allocation to copy and do not have finalizers (i.e. they do not
//! contain owned boxes or implement `Drop`), so the compiler considers
//! them cheap and safe to copy. For other types copies must be made
//! explicitly, by convention implementing the `Clone` trait and calling
//! the `clone` method.
//!
//! Basic usage example:
//!
//! ```
//! let s = String::new(); // String type implements Clone
//! let copy = s.clone(); // so we can clone it
//! ```
//!
//! To easily implement the Clone trait, you can also use
//! `#[derive(Clone)]`. Example:
//!
//! ```
//! #[derive(Clone)] // we add the Clone trait to Morpheus struct
//! struct Morpheus {
//!    blue_pill: f32,
//!    red_pill: i64,
//! }
//!
//! fn main() {
//!    let f = Morpheus { blue_pill: 0.0, red_pill: 0 };
//!    let copy = f.clone(); // and now we can clone it!
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A common trait for cloning an object.
///
/// This trait can be used with `#[derive]`.
///
/// Types that are `Copy` should have a trivial implementation of `Clone`. More formally:
/// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`.
/// Manual implementations should be careful to uphold this invariant; however, unsafe code
/// must not rely on it to ensure memory safety.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Clone : Sized {
    /// Returns a copy of the value.
    ///
    /// # Examples
    ///
    /// ```
    /// let hello = "Hello"; // &str implements Clone
    ///
    /// assert_eq!("Hello", hello.clone());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn clone(&self) -> Self;

    /// Performs copy-assignment from `source`.
    ///
    /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality,
    /// but can be overridden to reuse the resources of `a` to avoid unnecessary
    /// allocations.
    #[inline(always)]
    #[stable(feature = "rust1", since = "1.0.0")]
    fn clone_from(&mut self, source: &Self) {
        *self = source.clone()
    }
}

// FIXME(aburka): this method is used solely by #[derive] to
// assert that every component of a type implements Clone.
//
// This should never be called by user code.
#[doc(hidden)]
#[inline(always)]
#[unstable(feature = "derive_clone_copy",
           reason = "deriving hack, should not be public",
           issue = "0")]
pub fn assert_receiver_is_clone<T: Clone + ?Sized>(_: &T) {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Clone for &'a T {
    /// Returns a shallow copy of the reference.
    #[inline]
    fn clone(&self) -> &'a T { *self }
}

macro_rules! clone_impl {
    ($t:ty) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl Clone for $t {
            /// Returns a deep copy of the value.
            #[inline]
            fn clone(&self) -> $t { *self }
        }
    }
}

clone_impl! { isize }
clone_impl! { i8 }
clone_impl! { i16 }
clone_impl! { i32 }
clone_impl! { i64 }

clone_impl! { usize }
clone_impl! { u8 }
clone_impl! { u16 }
clone_impl! { u32 }
clone_impl! { u64 }

clone_impl! { f32 }
clone_impl! { f64 }

clone_impl! { () }
clone_impl! { bool }
clone_impl! { char }
<|endoftext|>


<commit_before>use database::schema::*;
use database::models::Tag;
use uuid::Uuid;

#[derive(Debug, Default, Queryable, Identifiable, Associations)]
#[belongs_to(Tag)]
pub struct Verification {
  pub id: i32,
  pub tag_id: i32,
  pub verified: bool,
  pub verification_string: Option<String>
}

impl Verification {
  pub fn into_new(self, tag_id: i32) -> NewVerification {
    NewVerification {
      tag_id: tag_id,
      verified: self.verified,
      verification_string: self.verification_string
    }
  }
}

#[derive(Debug, Insertable)]
#[table_name="verifications"]
pub struct NewVerification {
  pub tag_id: i32,
  pub verified: bool,
  pub verification_string: Option<String>
}

impl NewVerification {
  pub fn create_verification_string(&mut self) -> &String {
    let string = Uuid::new_v4().simple().to_string();
    self.verification_string = Some(string);
    self.verification_string.as_ref().unwrap()
  }
}
<commit_msg>refactor: update verifications to the new declaration syntax<commit_after>use database::schema::*;
use database::models::Tag;
use uuid::Uuid;

insertable! {
  #[derive(Debug, Default, Queryable, Identifiable, Associations)]
  #[belongs_to(Tag)]
  pub struct Verification,
  #[derive(Debug, Insertable)]
  #[table_name="verifications"]
  pub struct NewVerification {
    pub tag_id: i32,
    pub verified: bool,
    pub verification_string: Option<String>
  }
}

impl Verification {
  pub fn into_new(self, tag_id: i32) -> NewVerification {
    NewVerification {
      tag_id: tag_id,
      verified: self.verified,
      verification_string: self.verification_string
    }
  }
}

impl NewVerification {
  pub fn create_verification_string(&mut self) -> &String {
    let string = Uuid::new_v4().simple().to_string();
    self.verification_string = Some(string);
    self.verification_string.as_ref().unwrap()
  }
}
<|endoftext|>


<commit_before>//! multipart/form-data
use std::borrow::Cow;
use std::fmt;
use std::fs::File;
use std::io::{self, Cursor, Read};
use std::path::Path;

use mime_guess::{self, Mime};
use url::percent_encoding;
use uuid::Uuid;

use {Body};

/// A multipart/form-data request.
pub struct Form {
    boundary: String,
    fields: Vec<(Cow<'static, str>, Part)>,
    headers: Vec<String>,
}

impl Form {
    /// Creates a new Form without any content.
    pub fn new() -> Form {
        Form {
            boundary: format!("{}", Uuid::new_v4().simple()),
            fields: Vec::new(),
            headers: Vec::new(),
        }
    }

    /// Get the boundary that this form will use.
    #[inline]
    pub fn boundary(&self) -> &str {
        &self.boundary
    }

    /// Add a data field with supplied name and value.
    ///
    /// # Examples
    ///
    /// ```
    /// let form = reqwest::multipart::Form::new()
    ///     .text("username", "seanmonstar")
    ///     .text("password", "secret");
    /// ```
    pub fn text<T, U>(self, name: T, value: U) -> Form
    where T: Into<Cow<'static, str>>,
          U: Into<Cow<'static, str>>,
    {
        self.part(name, Part::text(value))
    }

    /// Adds a file field.
    ///
    /// The path will be used to try to guess the filename and mime.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # fn run() -> ::std::io::Result<()> {
    /// let files = reqwest::multipart::Form::new()
    ///     .file("key", "/path/to/file")?;
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// Errors when the file cannot be opened.
    pub fn file<T, U>(self, name: T, path: U) -> io::Result<Form>
    where T: Into<Cow<'static, str>>,
          U: AsRef<Path>
    {
        Ok(self.part(name, Part::file(path)?))
    }

    /// Adds a customized Part.
    pub fn part<T>(mut self, name: T, part: Part) -> Form
    where T: Into<Cow<'static, str>>,
    {
        self.fields.push((name.into(), part));
        self
    }

    pub(crate) fn reader(self) -> Reader {
        Reader::new(self)
    }

    // If predictable, computes the length the request will have
    // The length should be preditable if only String and file fields have been added,
    // but not if a generic reader has been added;
    pub(crate) fn compute_length(&mut self) -> Option<u64> {
        let mut length = 0u64;
        for &(ref name, ref field) in self.fields.iter() {
            match ::body::len(&field.value) {
                Some(value_length) => {
                    // We are constructing the header just to get its length. To not have to
                    // construct it again when the request is sent we cache these headers.
                    let header = header(name, field);
                    let header_length = header.len();
                    self.headers.push(header);
                    // The additions mimick the format string out of which the field is constructed
                    // in Reader. Not the cleanest solution because if that format string is
                    // ever changed then this formula needs to be changed too which is not an
                    // obvious dependency in the code.
                    length += 2 + self.boundary.len() as u64 + 2 + header_length as u64 + 4 + value_length + 2
                }
                _ => return None,
            }
        }
        // If there is a at least one field there is a special boundary for the very last field.
        if self.fields.len() != 0 {
            length += 2 + self.boundary.len() as u64 + 4
        }
        Some(length)
    }
}

impl fmt::Debug for Form {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Form")
            .field("boundary", &self.boundary)
            .field("parts", &self.fields)
            .finish()
    }
}

/// A field in a multipart form.
pub struct Part {
    value: Body,
    mime: Option<Mime>,
    file_name: Option<Cow<'static, str>>,
}

impl Part {
    /// Makes a text parameter.
    pub fn text<T>(value: T) -> Part
    where T: Into<Cow<'static, str>>,
    {
        let body = match value.into() {
            Cow::Borrowed(slice) => Body::from(slice),
            Cow::Owned(string) => Body::from(string),
        };
        Part::new(body)
    }

    /// Adds a generic reader.
    ///
    /// Does not set filename or mime.
    pub fn reader<T: Read + Send + 'static>(value: T) -> Part {
        Part::new(Body::new(value))
    }

    /// Adds a generic reader with known length.
    ///
    /// Does not set filename or mime.
    pub fn reader_with_length<T: Read + Send + 'static>(value: T, length: u64) -> Part {
        Part::new(Body::sized(value, length))
    }

    /// Makes a file parameter.
    ///
    /// # Errors
    ///
    /// Errors when the file cannot be opened.
    pub fn file<T: AsRef<Path>>(path: T) -> io::Result<Part> {
        let path = path.as_ref();
        let file_name = path.file_name().and_then(|filename| {
            Some(Cow::from(filename.to_string_lossy().into_owned()))
        });
        let ext = path.extension()
            .and_then(|ext| ext.to_str())
            .unwrap_or("");
        let mime = mime_guess::get_mime_type(ext);
        let file = File::open(path)?;
        let mut field = Part::new(Body::from(file));
        field.mime = Some(mime);
        field.file_name = file_name;
        Ok(field)
    }

    fn new(value: Body) -> Part {
        Part {
            value: value,
            mime: None,
            file_name: None,
        }
    }

    /// Sets the mime, builder style.
    pub fn mime(mut self, mime: Mime) -> Part {
        self.mime = Some(mime);
        self
    }

    /// Sets the filename, builder style.
    pub fn file_name<T: Into<Cow<'static, str>>>(mut self, filename: T) -> Part {
        self.file_name = Some(filename.into());
        self
    }
}

impl fmt::Debug for Part {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Part")
            .field("value", &self.value)
            .field("mime", &self.mime)
            .field("file_name", &self.file_name)
            .finish()
    }
}

pub(crate) struct Reader {
    form: Form,
    active_reader: Option<Box<Read + Send>>,
}

impl fmt::Debug for Reader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Reader")
            .field("form", &self.form)
            .finish()
    }
}

impl Reader {
    fn new(form: Form) -> Reader {
        let mut reader = Reader {
            form: form,
            active_reader: None,
        };
        reader.next_reader();
        reader
    }

    fn next_reader(&mut self) {
        self.active_reader = if self.form.fields.len() != 0 {
            // We need to move out of the vector here because we are consuming the field's reader
            let (name, field) = self.form.fields.remove(0);
            let reader = Cursor::new(format!(
                "--{}\r\n{}\r\n\r\n",
                self.form.boundary,
                // Try to use cached headers created by compute_length
                if self.form.headers.len() > 0 {
                    self.form.headers.remove(0)
                } else {
                    header(&name, &field)
                }
            )).chain(::body::reader(field.value))
                .chain(Cursor::new("\r\n"));
            // According to https://tools.ietf.org/html/rfc2046#section-5.1.1
            // the very last field has a special boundary
            if self.form.fields.len() != 0 {
                Some(Box::new(reader))
            } else {
                Some(Box::new(reader.chain(Cursor::new(
                    format!("--{}--\r\n", self.form.boundary),
                ))))
            }
        } else {
            None
        }
    }
}

impl Read for Reader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut total_bytes_read = 0usize;
        let mut last_read_bytes;
        loop {
            match self.active_reader {
                Some(ref mut reader) => {
                    last_read_bytes = reader.read(&mut buf[total_bytes_read..])?;
                    total_bytes_read += last_read_bytes;
                    if total_bytes_read == buf.len() {
                        return Ok(total_bytes_read);
                    }
                }
                None => return Ok(total_bytes_read),
            };
            if last_read_bytes == 0 && buf.len() != 0 {
                self.next_reader();
            }
        }
    }
}

fn header(name: &str, field: &Part) -> String {
    format!(
        "Content-Disposition: form-data; {}{}{}",
        format_parameter("name", name),
        match field.file_name {
            Some(ref file_name) => format!("; {}", format_parameter("filename", file_name)),
            None => String::new(),
        },
        match field.mime {
            Some(ref mime) => format!("\r\nContent-Type: {}", mime),
            None => "".to_string(),
        }
    )
}

fn format_parameter(name: &str, value: &str) -> String {
    let legal_value =
        percent_encoding::utf8_percent_encode(value, percent_encoding::PATH_SEGMENT_ENCODE_SET)
            .to_string();
    if value.len() == legal_value.len() {
        // nothing has been percent encoded
        format!("{}=\"{}\"", name, value)
    } else {
        // something has been percent encoded
        format!("{}*=utf-8''{}", name, legal_value)
    }
}

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

    #[test]
    fn form_empty() {
        let mut output = Vec::new();
        let mut form = Form::new();
        let length = form.compute_length();
        form.reader().read_to_end(&mut output).unwrap();
        assert_eq!(output, b"");
        assert_eq!(length.unwrap(), 0);
    }

    #[test]
    fn read_to_end() {
        let mut output = Vec::new();
        let mut form = Form::new()
            .part("reader1", Part::reader(::std::io::empty()))
            .part("key1", Part::text("value1"))
            .part(
                "key2",
                Part::text("value2").mime(::mime::IMAGE_BMP),
            )
            .part("reader2", Part::reader(::std::io::empty()))
            .part(
                "key3",
                Part::text("value3").file_name("filename"),
            );
        form.boundary = "boundary".to_string();
        let length = form.compute_length();
        let expected = "--boundary\r\n\
                        Content-Disposition: form-data; name=\"reader1\"\r\n\r\n\
                        \r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key1\"\r\n\r\n\
                        value1\r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key2\"\r\n\
                        Content-Type: image/bmp\r\n\r\n\
                        value2\r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"reader2\"\r\n\r\n\
                        \r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key3\"; filename=\"filename\"\r\n\r\n\
                        value3\r\n--boundary--\r\n";
        form.reader().read_to_end(&mut output).unwrap();
        // These prints are for debug purposes in case the test fails
        println!(
            "START REAL\n{}\nEND REAL",
            ::std::str::from_utf8(&output).unwrap()
        );
        println!("START EXPECTED\n{}\nEND EXPECTED", expected);
        assert_eq!(::std::str::from_utf8(&output).unwrap(), expected);
        assert!(length.is_none());
    }

    #[test]
    fn read_to_end_with_length() {
        let mut output = Vec::new();
        let mut form = Form::new()
            .text("key1", "value1")
            .part(
                "key2",
                Part::text("value2").mime(::mime::IMAGE_BMP),
            )
            .part(
                "key3",
                Part::text("value3").file_name("filename"),
            );
        form.boundary = "boundary".to_string();
        let length = form.compute_length();
        let expected = "--boundary\r\n\
                        Content-Disposition: form-data; name=\"key1\"\r\n\r\n\
                        value1\r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key2\"\r\n\
                        Content-Type: image/bmp\r\n\r\n\
                        value2\r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key3\"; filename=\"filename\"\r\n\r\n\
                        value3\r\n--boundary--\r\n";
        form.reader().read_to_end(&mut output).unwrap();
        // These prints are for debug purposes in case the test fails
        println!(
            "START REAL\n{}\nEND REAL",
            ::std::str::from_utf8(&output).unwrap()
        );
        println!("START EXPECTED\n{}\nEND EXPECTED", expected);
        assert_eq!(::std::str::from_utf8(&output).unwrap(), expected);
        assert_eq!(length.unwrap(), expected.len() as u64);
    }

    #[test]
    fn header_percent_encoding() {
        let name = "start%'\"\r\nßend";
        let field = Part::text("");
        let expected = "Content-Disposition: form-data; name*=utf-8''start%25\'%22%0D%0A%C3%9Fend";

        assert_eq!(header(name, &field), expected);
    }
}
<commit_msg>Add a way to add headers to parts of multipart form data (#331)<commit_after>//! multipart/form-data
use std::borrow::Cow;
use std::fmt;
use std::fs::File;
use std::io::{self, Cursor, Read};
use std::path::Path;

use mime_guess::{self, Mime};
use url::percent_encoding;
use uuid::Uuid;
use http::HeaderMap;

use {Body};

/// A multipart/form-data request.
pub struct Form {
    boundary: String,
    fields: Vec<(Cow<'static, str>, Part)>,
    headers: Vec<String>,
}

impl Form {
    /// Creates a new Form without any content.
    pub fn new() -> Form {
        Form {
            boundary: format!("{}", Uuid::new_v4().simple()),
            fields: Vec::new(),
            headers: Vec::new(),
        }
    }

    /// Get the boundary that this form will use.
    #[inline]
    pub fn boundary(&self) -> &str {
        &self.boundary
    }

    /// Add a data field with supplied name and value.
    ///
    /// # Examples
    ///
    /// ```
    /// let form = reqwest::multipart::Form::new()
    ///     .text("username", "seanmonstar")
    ///     .text("password", "secret");
    /// ```
    pub fn text<T, U>(self, name: T, value: U) -> Form
    where T: Into<Cow<'static, str>>,
          U: Into<Cow<'static, str>>,
    {
        self.part(name, Part::text(value))
    }

    /// Adds a file field.
    ///
    /// The path will be used to try to guess the filename and mime.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # fn run() -> ::std::io::Result<()> {
    /// let files = reqwest::multipart::Form::new()
    ///     .file("key", "/path/to/file")?;
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// Errors when the file cannot be opened.
    pub fn file<T, U>(self, name: T, path: U) -> io::Result<Form>
    where T: Into<Cow<'static, str>>,
          U: AsRef<Path>
    {
        Ok(self.part(name, Part::file(path)?))
    }

    /// Adds a customized Part.
    pub fn part<T>(mut self, name: T, part: Part) -> Form
    where T: Into<Cow<'static, str>>,
    {
        self.fields.push((name.into(), part));
        self
    }

    pub(crate) fn reader(self) -> Reader {
        Reader::new(self)
    }

    // If predictable, computes the length the request will have
    // The length should be preditable if only String and file fields have been added,
    // but not if a generic reader has been added;
    pub(crate) fn compute_length(&mut self) -> Option<u64> {
        let mut length = 0u64;
        for &(ref name, ref field) in self.fields.iter() {
            match ::body::len(&field.value) {
                Some(value_length) => {
                    // We are constructing the header just to get its length. To not have to
                    // construct it again when the request is sent we cache these headers.
                    let header = header(name, field);
                    let header_length = header.len();
                    self.headers.push(header);
                    // The additions mimick the format string out of which the field is constructed
                    // in Reader. Not the cleanest solution because if that format string is
                    // ever changed then this formula needs to be changed too which is not an
                    // obvious dependency in the code.
                    length += 2 + self.boundary.len() as u64 + 2 + header_length as u64 + 4 + value_length + 2
                }
                _ => return None,
            }
        }
        // If there is a at least one field there is a special boundary for the very last field.
        if self.fields.len() != 0 {
            length += 2 + self.boundary.len() as u64 + 4
        }
        Some(length)
    }
}

impl fmt::Debug for Form {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Form")
            .field("boundary", &self.boundary)
            .field("parts", &self.fields)
            .finish()
    }
}

/// A field in a multipart form.
pub struct Part {
    value: Body,
    mime: Option<Mime>,
    file_name: Option<Cow<'static, str>>,
    headers: HeaderMap<String>,
}

impl Part {
    /// Makes a text parameter.
    pub fn text<T>(value: T) -> Part
    where T: Into<Cow<'static, str>>,
    {
        let body = match value.into() {
            Cow::Borrowed(slice) => Body::from(slice),
            Cow::Owned(string) => Body::from(string),
        };
        Part::new(body)
    }

    /// Adds a generic reader.
    ///
    /// Does not set filename or mime.
    pub fn reader<T: Read + Send + 'static>(value: T) -> Part {
        Part::new(Body::new(value))
    }

    /// Adds a generic reader with known length.
    ///
    /// Does not set filename or mime.
    pub fn reader_with_length<T: Read + Send + 'static>(value: T, length: u64) -> Part {
        Part::new(Body::sized(value, length))
    }

    /// Makes a file parameter.
    ///
    /// # Errors
    ///
    /// Errors when the file cannot be opened.
    pub fn file<T: AsRef<Path>>(path: T) -> io::Result<Part> {
        let path = path.as_ref();
        let file_name = path.file_name().and_then(|filename| {
            Some(Cow::from(filename.to_string_lossy().into_owned()))
        });
        let ext = path.extension()
            .and_then(|ext| ext.to_str())
            .unwrap_or("");
        let mime = mime_guess::get_mime_type(ext);
        let file = File::open(path)?;
        let mut field = Part::new(Body::from(file));
        field.mime = Some(mime);
        field.file_name = file_name;
        Ok(field)
    }

    fn new(value: Body) -> Part {
        Part {
            value: value,
            mime: None,
            file_name: None,
            headers: HeaderMap::default()
        }
    }

    /// Sets the mime, builder style.
    pub fn mime(mut self, mime: Mime) -> Part {
        self.mime = Some(mime);
        self
    }

    /// Sets the filename, builder style.
    pub fn file_name<T: Into<Cow<'static, str>>>(mut self, filename: T) -> Part {
        self.file_name = Some(filename.into());
        self
    }

    /// Returns a reference to the map with additional header fields
    pub fn headers(&self) -> &HeaderMap<String> {
        &self.headers
    }

    /// Returns a reference to the map with additional header fields
    pub fn headers_mut(&mut self) -> &mut HeaderMap<String> {
        &mut self.headers
    }
}

impl fmt::Debug for Part {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Part")
            .field("value", &self.value)
            .field("mime", &self.mime)
            .field("file_name", &self.file_name)
            .field("headers", &self.headers)
            .finish()
    }
}

pub(crate) struct Reader {
    form: Form,
    active_reader: Option<Box<Read + Send>>,
}

impl fmt::Debug for Reader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Reader")
            .field("form", &self.form)
            .finish()
    }
}

impl Reader {
    fn new(form: Form) -> Reader {
        let mut reader = Reader {
            form: form,
            active_reader: None,
        };
        reader.next_reader();
        reader
    }

    fn next_reader(&mut self) {
        self.active_reader = if self.form.fields.len() != 0 {
            // We need to move out of the vector here because we are consuming the field's reader
            let (name, field) = self.form.fields.remove(0);
            let reader = Cursor::new(format!(
                "--{}\r\n{}\r\n\r\n",
                self.form.boundary,
                // Try to use cached headers created by compute_length
                if self.form.headers.len() > 0 {
                    self.form.headers.remove(0)
                } else {
                    header(&name, &field)
                }
            )).chain(::body::reader(field.value))
                .chain(Cursor::new("\r\n"));
            // According to https://tools.ietf.org/html/rfc2046#section-5.1.1
            // the very last field has a special boundary
            if self.form.fields.len() != 0 {
                Some(Box::new(reader))
            } else {
                Some(Box::new(reader.chain(Cursor::new(
                    format!("--{}--\r\n", self.form.boundary),
                ))))
            }
        } else {
            None
        }
    }
}

impl Read for Reader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut total_bytes_read = 0usize;
        let mut last_read_bytes;
        loop {
            match self.active_reader {
                Some(ref mut reader) => {
                    last_read_bytes = reader.read(&mut buf[total_bytes_read..])?;
                    total_bytes_read += last_read_bytes;
                    if total_bytes_read == buf.len() {
                        return Ok(total_bytes_read);
                    }
                }
                None => return Ok(total_bytes_read),
            };
            if last_read_bytes == 0 && buf.len() != 0 {
                self.next_reader();
            }
        }
    }
}

fn header(name: &str, field: &Part) -> String {
    format!(
        "Content-Disposition: form-data; {}{}{}{}",
        format_parameter("name", name),
        match field.file_name {
            Some(ref file_name) => format!("; {}", format_parameter("filename", file_name)),
            None => String::new(),
        },
        match field.mime {
            Some(ref mime) => format!("\r\nContent-Type: {}", mime),
            None => "".to_string(),
        },
        field.headers.iter().fold(
            "".to_string(),
            |header, (k,v)| header + "\r\n" + k.as_str() + ": " + v
        )
    )
}

fn format_parameter(name: &str, value: &str) -> String {
    let legal_value =
        percent_encoding::utf8_percent_encode(value, percent_encoding::PATH_SEGMENT_ENCODE_SET)
            .to_string();
    if value.len() == legal_value.len() {
        // nothing has been percent encoded
        format!("{}=\"{}\"", name, value)
    } else {
        // something has been percent encoded
        format!("{}*=utf-8''{}", name, legal_value)
    }
}

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

    #[test]
    fn form_empty() {
        let mut output = Vec::new();
        let mut form = Form::new();
        let length = form.compute_length();
        form.reader().read_to_end(&mut output).unwrap();
        assert_eq!(output, b"");
        assert_eq!(length.unwrap(), 0);
    }

    #[test]
    fn read_to_end() {
        let mut output = Vec::new();
        let mut form = Form::new()
            .part("reader1", Part::reader(::std::io::empty()))
            .part("key1", Part::text("value1"))
            .part(
                "key2",
                Part::text("value2").mime(::mime::IMAGE_BMP),
            )
            .part("reader2", Part::reader(::std::io::empty()))
            .part(
                "key3",
                Part::text("value3").file_name("filename"),
            );
        form.boundary = "boundary".to_string();
        let length = form.compute_length();
        let expected = "--boundary\r\n\
                        Content-Disposition: form-data; name=\"reader1\"\r\n\r\n\
                        \r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key1\"\r\n\r\n\
                        value1\r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key2\"\r\n\
                        Content-Type: image/bmp\r\n\r\n\
                        value2\r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"reader2\"\r\n\r\n\
                        \r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key3\"; filename=\"filename\"\r\n\r\n\
                        value3\r\n--boundary--\r\n";
        form.reader().read_to_end(&mut output).unwrap();
        // These prints are for debug purposes in case the test fails
        println!(
            "START REAL\n{}\nEND REAL",
            ::std::str::from_utf8(&output).unwrap()
        );
        println!("START EXPECTED\n{}\nEND EXPECTED", expected);
        assert_eq!(::std::str::from_utf8(&output).unwrap(), expected);
        assert!(length.is_none());
    }

    #[test]
    fn read_to_end_with_length() {
        let mut output = Vec::new();
        let mut form = Form::new()
            .text("key1", "value1")
            .part(
                "key2",
                Part::text("value2").mime(::mime::IMAGE_BMP),
            )
            .part(
                "key3",
                Part::text("value3").file_name("filename"),
            );
        form.boundary = "boundary".to_string();
        let length = form.compute_length();
        let expected = "--boundary\r\n\
                        Content-Disposition: form-data; name=\"key1\"\r\n\r\n\
                        value1\r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key2\"\r\n\
                        Content-Type: image/bmp\r\n\r\n\
                        value2\r\n\
                        --boundary\r\n\
                        Content-Disposition: form-data; name=\"key3\"; filename=\"filename\"\r\n\r\n\
                        value3\r\n--boundary--\r\n";
        form.reader().read_to_end(&mut output).unwrap();
        // These prints are for debug purposes in case the test fails
        println!(
            "START REAL\n{}\nEND REAL",
            ::std::str::from_utf8(&output).unwrap()
        );
        println!("START EXPECTED\n{}\nEND EXPECTED", expected);
        assert_eq!(::std::str::from_utf8(&output).unwrap(), expected);
        assert_eq!(length.unwrap(), expected.len() as u64);
    }

    #[test]
    fn read_to_end_with_header() {
        let mut output = Vec::new();
        let mut part = Part::text("value2").mime(::mime::IMAGE_BMP);
        part.headers_mut().insert("Hdr3", "/a/b/c".to_string());
        let mut form = Form::new().part("key2", part);
        form.boundary = "boundary".to_string();
        let expected = "--boundary\r\n\
                        Content-Disposition: form-data; name=\"key2\"\r\n\
                        Content-Type: image/bmp\r\n\
                        hdr3: /a/b/c\r\n\
                        \r\n\
                        value2\r\n\
                        --boundary--\r\n";
        form.reader().read_to_end(&mut output).unwrap();
        // These prints are for debug purposes in case the test fails
        println!(
            "START REAL\n{}\nEND REAL",
            ::std::str::from_utf8(&output).unwrap()
        );
        println!("START EXPECTED\n{}\nEND EXPECTED", expected);
        assert_eq!(::std::str::from_utf8(&output).unwrap(), expected);
    }

    #[test]
    fn header_percent_encoding() {
        let name = "start%'\"\r\nßend";
        let field = Part::text("");
        let expected = "Content-Disposition: form-data; name*=utf-8''start%25\'%22%0D%0A%C3%9Fend";

        assert_eq!(header(name, &field), expected);
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::collections::HashMap;
use graph_iterator::EdgeMapper;
use byteorder::{ReadBytesExt, WriteBytesExt};

#[inline]
pub fn encode<W: Write>(writer: &mut W, diff: u64) {
    assert!(diff > 0);
    for &shift in [56, 48, 40, 32, 24, 16, 8].iter() {
        if (diff >> shift) != 0 {
            writer.write_u8(0u8).ok().expect("write error");
        }
    }
    for &shift in [56, 48, 40, 32, 24, 16, 8].iter() {
        if (diff >> shift) != 0 {
            writer.write_u8((diff >> shift) as u8).ok().expect("write error");
        }
    }
    writer.write_u8(diff as u8).ok().expect("write error");
}

#[inline]
pub fn decode<R: Read>(reader: &mut R) -> Option<u64> {
    if let Ok(mut read) = reader.read_u8() {
        let mut count = 0u64;
        while read == 0 {
            count += 1;
            read = reader.read_u8().unwrap();
        }

        let mut diff = read as u64;
        for _ in (0..count) {
            diff = (diff << 8) + (reader.read_u8().unwrap() as u64);
        }

        Some(diff)
    }
    else { None }
}

#[test]
fn test_encode_decode() {
    let test_vec = vec![1, 2, 1 << 20, 1 << 60];
    let mut writer = MemWriter::new();
    for &elt in test_vec.iter() {
        encode(&mut writer, elt);
    }

    let mut test_out = Vec::new();
    let mut reader = MemReader::new(writer.into_inner());
    while let Some(elt) = decode(&mut reader) {
        test_out.push(elt);
    }

    assert_eq!(test_vec, test_out);
}

pub struct Decoder<R: Read> {
    reader:     R,
    current:    u64,
}

impl<R: Read> Decoder<R> {
    pub fn new(reader: R) -> Decoder<R> {
        Decoder { reader: reader, current: 0 }
    }
}

impl<R: Read> Iterator for Decoder<R> {
    type Item = u64;
    fn next(&mut self) -> Option<u64> {
        if let Some(diff) = decode(&mut self.reader) {
            assert!(self.current < self.current + diff);
            self.current += diff;
            Some(self.current)
        }
        else { None }
    }
}

pub fn to_hilbert<I, O>(graph: &I, mut output: O) -> ()
where I : EdgeMapper,
      O : FnMut(u64)->(),
{
    let hilbert = BytewiseHilbert::new();
    let mut buffer = Vec::new();
    graph.map_edges(|node, edge| { buffer.push(hilbert.entangle((node, edge))); });
    buffer.sort();
    for &element in buffer.iter() { output(element); }
}

pub fn convert_to_hilbert<I, O>(graph: &I, make_dense: bool, mut output: O) -> ()
where I : EdgeMapper,
      O : FnMut(u16, u16, u32, &Vec<(u16, u16)>) -> (),
{
    let mut uppers: HashMap<u32,Vec<u32>> = HashMap::new();
    let mut names = Vec::new();
    let mut names_count = 0i32;
    let hilbert = BytewiseHilbert::new();

    graph.map_edges(|mut node, mut edge| {
        if make_dense {
            while names.len() as u32 <= node { names.push(-1i32); }
            while names.len() as u32 <= edge { names.push(-1i32); }
            if names[node as usize] == -1i32 { names[node as usize] = names_count; node = names_count as u32; names_count += 1; }
            if names[edge as usize] == -1i32 { names[edge as usize] = names_count; edge = names_count as u32; names_count += 1; }
        }

        let entangled = hilbert.entangle((node as u32, edge as u32));
        let upper = (entangled >> 32) as u32;
        let lower = entangled as u32;

        uppers.entry(upper).or_insert(Vec::new()).push(lower);
    });

    let mut keys: Vec<u32> = uppers.keys().map(|x|x.clone()).collect();
    keys.sort();

    let mut temp = Vec::new();
    for &upper in keys.iter() {
        let mut lowers = uppers.remove(&upper).unwrap();
        if lowers.len() > 0 {
            let upair = hilbert.detangle((upper as u64) << 32);
            let upperx = (upair.0 >> 16) as u16;
            let uppery = (upair.1 >> 16) as u16;
            let length = lowers.len() as u32;

            lowers.sort();  // TODO : Check Radix sort perf
            temp.clear();

            for &lower in lowers.iter() {
                let lpair = hilbert.detangle(((upper as u64) << 32) + (lower as u64));
                let lowerx = (lpair.0 & 65535u32) as u16;
                let lowery = (lpair.1 & 65535u32) as u16;
                temp.push((lowerx, lowery));
            }

            output(upperx, uppery, length, &temp);
        }
    }
}

pub fn merge<I: Iterator<Item=u64>, O: FnMut(u64)->()>(mut iterators: Vec<I>, mut output: O) {
    let mut values = Vec::new();
    for iterator in iterators.iter_mut() { values.push(iterator.next()); }

    let mut val_old = 0;
    let mut done = false;
    while !done {
        let mut arg_min = iterators.len();
        let mut val_min = 0u64;
        for (index, &value) in values.iter().enumerate() {
            if let Some(val) = value {
                if arg_min > index || val < val_min {
                    arg_min = index;
                    val_min = val;
                    // done = false;
                }
            }
        }

        if arg_min < iterators.len() {
            values[arg_min] = iterators[arg_min].next();
            if let Some(val) = values[arg_min] {
                assert!(val > val_min);
            }
            assert!(val_old <= val_min);
            val_old = val_min;
            output(val_min);
        }
        else {
            done = true;
        }
    }

    // confirm that we haven't left anything behind
    assert!(!values.iter().any(|x|x.is_some()));
}

// algorithm drawn in large part from http://en.wikipedia.org/wiki/Hilbert_curve
// bytewise implementation based on tracking cumulative rotation / mirroring.

pub struct BytewiseCached {
    hilbert:    BytewiseHilbert,
    prev_hi:    u64,
    prev_out:   (u32, u32),
    prev_rot:   (bool, bool),
}

impl BytewiseCached {
    pub fn detangle(&mut self, tangle: u64) -> (u32, u32) {
        let (mut x_byte, mut y_byte) = self.hilbert.detangle[tangle as u16 as usize];

        // validate self.prev_rot, self.prev_out
        if self.prev_hi != (tangle >> 16) {
            self.prev_hi = tangle >> 16;

            // detangle with a bit set to see what happens to it
            let low = 255; //self.hilbert.entangle((0xF, 0)) as u16;
            let (x, y) = self.hilbert.detangle((self.prev_hi << 16) + low as u64);

            let value = (x as u8, y as u8);
            self.prev_rot = match value {
                (0x0F, 0x00) => (false, false), // nothing
                (0x00, 0x0F) => (true, false),  // swapped
                (0xF0, 0xFF) => (false, true),  // flipped
                (0xFF, 0xF0) => (true, true),   // flipped & swapped
                val => panic!(format!("Found : ({:x}, {:x})", val.0, val.1)),
            };
            self.prev_out = (x & 0xFFFFFF00, y & 0xFFFFFF00);
        }

        if self.prev_rot.1 {
            x_byte = 255 - x_byte;
            y_byte = 255 - y_byte;
        }
        if self.prev_rot.0 {
            let temp = x_byte; x_byte = y_byte; y_byte = temp;
        }

        return (self.prev_out.0 + x_byte as u32, self.prev_out.1 + y_byte as u32);
    }
    pub fn new() -> BytewiseCached {
        let mut result = BytewiseCached {
            hilbert: BytewiseHilbert::new(),
            prev_hi: 0xFFFFFFFFFFFFFFFF,
            prev_out: (0,0),
            prev_rot: (false, false),
        };

        result.detangle(0); // ensures that we set the cached stuff correctly
        return result;
    }
}

pub struct BytewiseHilbert {
    entangle: Vec<u16>,         // entangle[x_byte << 16 + y_byte] -> tangle
    detangle: Vec<(u8, u8)>,    // detangle[tangle] -> (x_byte, y_byte)
    rotation: Vec<u8>,          // info on rotation, keyed per self.entangle
}

impl BytewiseHilbert {
    pub fn new() -> BytewiseHilbert {
        let mut entangle = Vec::new();
        let mut detangle: Vec<_> = (0..65536).map(|_| (0u8, 0u8)).collect();
        let mut rotation = Vec::new();
        for x in (0u32..256) {
            for y in (0u32..256) {
                let entangled = bit_entangle(((x << 24), (y << 24) + (1 << 23)));
                entangle.push((entangled >> 48) as u16);
                detangle[(entangled >> 48) as usize] = (x as u8, y as u8);
                rotation.push(((entangled >> 44) & 0x0F) as u8);

                //  note to self: math is hard.
                //  rotation decode:    lsbs
                //  0100 -N--> 0100 --> 0100
                //  0100 -S--> 1000 --> 1110
                //  0100 -F--> 1011 --> 1100
                //  0100 -FS-> 0111 --> 0110
            }
        }

        return BytewiseHilbert {entangle: entangle, detangle: detangle, rotation: rotation};
    }

    pub fn entangle(&self, (mut x, mut y): (u32, u32)) -> u64 {
        let init_x = x;
        let init_y = y;
        let mut result = 0u64;
        for i in (0 .. 4) {
            let x_byte = (x >> (24 - (8 * i))) as u8;
            let y_byte = (y >> (24 - (8 * i))) as u8;
            result = (result << 16) + self.entangle[(((x_byte as u16) << 8) + y_byte as u16) as usize] as u64;
            let rotation = self.rotation[(((x_byte as u16) << 8) + y_byte as u16) as usize];
            if (rotation & 0x2) > 0 { let temp = x; x = y; y = temp; }
            if rotation == 12 || rotation == 6 { x = 0xFFFFFFFF - x; y = 0xFFFFFFFF - y }
        }

        debug_assert!(bit_entangle((init_x, init_y)) == result);
        return result;
    }

    pub fn detangle(&self, tangle: u64) -> (u32, u32) {
        let init_tangle = tangle;
        let mut result = (0u32, 0u32);
        for log_s in (0u32 .. 4) {
            let shifted = (tangle >> (16 * log_s)) as u16;
            let (x_byte, y_byte) = self.detangle[shifted as usize];
            let rotation = self.rotation[(((x_byte as u16) << 8) + y_byte as u16) as usize];
            if rotation == 12 || rotation == 6 {
                result.0 = (1 << 8 * log_s) - result.0 - 1;
                result.1 = (1 << 8 * log_s) - result.1 - 1;
            }
            if (rotation & 0x2) > 0 {
                let temp = result.0; result.0 = result.1; result.1 = temp;
            }

            result.0 += (x_byte as u32) << (8 * log_s);
            result.1 += (y_byte as u32) << (8 * log_s);
        }

        debug_assert!(bit_detangle(init_tangle) == result);
        return result;
    }
}

fn bit_entangle(mut pair: (u32, u32)) -> u64 {
    let mut result = 0u64;
    for log_s_rev in (0 .. 32) {
        let log_s = 31 - log_s_rev;
        let rx = (pair.0 >> log_s) & 1u32;
        let ry = (pair.1 >> log_s) & 1u32;
        result += (((3 * rx) ^ ry) as u64) << (2 * log_s);
        pair = bit_rotate(log_s, pair, rx, ry);
    }

    return result;
}

fn bit_detangle(tangle: u64) -> (u32, u32) {
    let mut result = (0u32, 0u32);
    for log_s in (0 .. 32) {
        let shifted = ((tangle >> (2 * log_s)) & 3u64) as u32;

        let rx = (shifted >> 1) & 1u32;
        let ry = (shifted ^ rx) & 1u32;
        result = bit_rotate(log_s, result, rx, ry);
        result = (result.0 + (rx << log_s), result.1 + (ry << log_s));
    }

    return result;
}

fn bit_rotate(logn: usize, pair: (u32, u32), rx: u32, ry: u32) -> (u32, u32) {
    if ry == 0 {
        if rx != 0 {
            ((1 << logn) - pair.1 - 1, (1 << logn) - pair.0 - 1)
        }
        else { (pair.1, pair.0) }
    }
    else { pair }
}
<commit_msg>updated test<commit_after>use std::io::{Read, Write};
use std::collections::HashMap;
use graph_iterator::EdgeMapper;
use byteorder::{ReadBytesExt, WriteBytesExt};

#[inline]
pub fn encode<W: Write>(writer: &mut W, diff: u64) {
    assert!(diff > 0);
    for &shift in [56, 48, 40, 32, 24, 16, 8].iter() {
        if (diff >> shift) != 0 {
            writer.write_u8(0u8).ok().expect("write error");
        }
    }
    for &shift in [56, 48, 40, 32, 24, 16, 8].iter() {
        if (diff >> shift) != 0 {
            writer.write_u8((diff >> shift) as u8).ok().expect("write error");
        }
    }
    writer.write_u8(diff as u8).ok().expect("write error");
}

#[inline]
pub fn decode<R: Read>(reader: &mut R) -> Option<u64> {
    if let Ok(mut read) = reader.read_u8() {
        let mut count = 0u64;
        while read == 0 {
            count += 1;
            read = reader.read_u8().unwrap();
        }

        let mut diff = read as u64;
        for _ in (0..count) {
            diff = (diff << 8) + (reader.read_u8().unwrap() as u64);
        }

        Some(diff)
    }
    else { None }
}

#[test]
fn test_encode_decode() {
    let test_vec = vec![1, 2, 1 << 20, 1 << 60];
    let mut writer = Vec::new();
    for &elt in test_vec.iter() {
        encode(&mut writer, elt);
    }

    let mut test_out = Vec::new();
    let mut reader = &writer[..];
    while let Some(elt) = decode(&mut reader) {
        test_out.push(elt);
    }

    assert_eq!(test_vec, test_out);
}

pub struct Decoder<R: Read> {
    reader:     R,
    current:    u64,
}

impl<R: Read> Decoder<R> {
    pub fn new(reader: R) -> Decoder<R> {
        Decoder { reader: reader, current: 0 }
    }
}

impl<R: Read> Iterator for Decoder<R> {
    type Item = u64;
    fn next(&mut self) -> Option<u64> {
        if let Some(diff) = decode(&mut self.reader) {
            assert!(self.current < self.current + diff);
            self.current += diff;
            Some(self.current)
        }
        else { None }
    }
}

pub fn to_hilbert<I, O>(graph: &I, mut output: O) -> ()
where I : EdgeMapper,
      O : FnMut(u64)->(),
{
    let hilbert = BytewiseHilbert::new();
    let mut buffer = Vec::new();
    graph.map_edges(|node, edge| { buffer.push(hilbert.entangle((node, edge))); });
    buffer.sort();
    for &element in buffer.iter() { output(element); }
}

pub fn convert_to_hilbert<I, O>(graph: &I, make_dense: bool, mut output: O) -> ()
where I : EdgeMapper,
      O : FnMut(u16, u16, u32, &Vec<(u16, u16)>) -> (),
{
    let mut uppers: HashMap<u32,Vec<u32>> = HashMap::new();
    let mut names = Vec::new();
    let mut names_count = 0i32;
    let hilbert = BytewiseHilbert::new();

    graph.map_edges(|mut node, mut edge| {
        if make_dense {
            while names.len() as u32 <= node { names.push(-1i32); }
            while names.len() as u32 <= edge { names.push(-1i32); }
            if names[node as usize] == -1i32 { names[node as usize] = names_count; node = names_count as u32; names_count += 1; }
            if names[edge as usize] == -1i32 { names[edge as usize] = names_count; edge = names_count as u32; names_count += 1; }
        }

        let entangled = hilbert.entangle((node as u32, edge as u32));
        let upper = (entangled >> 32) as u32;
        let lower = entangled as u32;

        uppers.entry(upper).or_insert(Vec::new()).push(lower);
    });

    let mut keys: Vec<u32> = uppers.keys().map(|x|x.clone()).collect();
    keys.sort();

    let mut temp = Vec::new();
    for &upper in keys.iter() {
        let mut lowers = uppers.remove(&upper).unwrap();
        if lowers.len() > 0 {
            let upair = hilbert.detangle((upper as u64) << 32);
            let upperx = (upair.0 >> 16) as u16;
            let uppery = (upair.1 >> 16) as u16;
            let length = lowers.len() as u32;

            lowers.sort();  // TODO : Check Radix sort perf
            temp.clear();

            for &lower in lowers.iter() {
                let lpair = hilbert.detangle(((upper as u64) << 32) + (lower as u64));
                let lowerx = (lpair.0 & 65535u32) as u16;
                let lowery = (lpair.1 & 65535u32) as u16;
                temp.push((lowerx, lowery));
            }

            output(upperx, uppery, length, &temp);
        }
    }
}

pub fn merge<I: Iterator<Item=u64>, O: FnMut(u64)->()>(mut iterators: Vec<I>, mut output: O) {
    let mut values = Vec::new();
    for iterator in iterators.iter_mut() { values.push(iterator.next()); }

    let mut val_old = 0;
    let mut done = false;
    while !done {
        let mut arg_min = iterators.len();
        let mut val_min = 0u64;
        for (index, &value) in values.iter().enumerate() {
            if let Some(val) = value {
                if arg_min > index || val < val_min {
                    arg_min = index;
                    val_min = val;
                    // done = false;
                }
            }
        }

        if arg_min < iterators.len() {
            values[arg_min] = iterators[arg_min].next();
            if let Some(val) = values[arg_min] {
                assert!(val > val_min);
            }
            assert!(val_old <= val_min);
            val_old = val_min;
            output(val_min);
        }
        else {
            done = true;
        }
    }

    // confirm that we haven't left anything behind
    assert!(!values.iter().any(|x|x.is_some()));
}

// algorithm drawn in large part from http://en.wikipedia.org/wiki/Hilbert_curve
// bytewise implementation based on tracking cumulative rotation / mirroring.

pub struct BytewiseCached {
    hilbert:    BytewiseHilbert,
    prev_hi:    u64,
    prev_out:   (u32, u32),
    prev_rot:   (bool, bool),
}

impl BytewiseCached {
    pub fn detangle(&mut self, tangle: u64) -> (u32, u32) {
        let (mut x_byte, mut y_byte) = self.hilbert.detangle[tangle as u16 as usize];

        // validate self.prev_rot, self.prev_out
        if self.prev_hi != (tangle >> 16) {
            self.prev_hi = tangle >> 16;

            // detangle with a bit set to see what happens to it
            let low = 255; //self.hilbert.entangle((0xF, 0)) as u16;
            let (x, y) = self.hilbert.detangle((self.prev_hi << 16) + low as u64);

            let value = (x as u8, y as u8);
            self.prev_rot = match value {
                (0x0F, 0x00) => (false, false), // nothing
                (0x00, 0x0F) => (true, false),  // swapped
                (0xF0, 0xFF) => (false, true),  // flipped
                (0xFF, 0xF0) => (true, true),   // flipped & swapped
                val => panic!(format!("Found : ({:x}, {:x})", val.0, val.1)),
            };
            self.prev_out = (x & 0xFFFFFF00, y & 0xFFFFFF00);
        }

        if self.prev_rot.1 {
            x_byte = 255 - x_byte;
            y_byte = 255 - y_byte;
        }
        if self.prev_rot.0 {
            let temp = x_byte; x_byte = y_byte; y_byte = temp;
        }

        return (self.prev_out.0 + x_byte as u32, self.prev_out.1 + y_byte as u32);
    }
    pub fn new() -> BytewiseCached {
        let mut result = BytewiseCached {
            hilbert: BytewiseHilbert::new(),
            prev_hi: 0xFFFFFFFFFFFFFFFF,
            prev_out: (0,0),
            prev_rot: (false, false),
        };

        result.detangle(0); // ensures that we set the cached stuff correctly
        return result;
    }
}

pub struct BytewiseHilbert {
    entangle: Vec<u16>,         // entangle[x_byte << 16 + y_byte] -> tangle
    detangle: Vec<(u8, u8)>,    // detangle[tangle] -> (x_byte, y_byte)
    rotation: Vec<u8>,          // info on rotation, keyed per self.entangle
}

impl BytewiseHilbert {
    pub fn new() -> BytewiseHilbert {
        let mut entangle = Vec::new();
        let mut detangle: Vec<_> = (0..65536).map(|_| (0u8, 0u8)).collect();
        let mut rotation = Vec::new();
        for x in (0u32..256) {
            for y in (0u32..256) {
                let entangled = bit_entangle(((x << 24), (y << 24) + (1 << 23)));
                entangle.push((entangled >> 48) as u16);
                detangle[(entangled >> 48) as usize] = (x as u8, y as u8);
                rotation.push(((entangled >> 44) & 0x0F) as u8);

                //  note to self: math is hard.
                //  rotation decode:    lsbs
                //  0100 -N--> 0100 --> 0100
                //  0100 -S--> 1000 --> 1110
                //  0100 -F--> 1011 --> 1100
                //  0100 -FS-> 0111 --> 0110
            }
        }

        return BytewiseHilbert {entangle: entangle, detangle: detangle, rotation: rotation};
    }

    pub fn entangle(&self, (mut x, mut y): (u32, u32)) -> u64 {
        let init_x = x;
        let init_y = y;
        let mut result = 0u64;
        for i in (0 .. 4) {
            let x_byte = (x >> (24 - (8 * i))) as u8;
            let y_byte = (y >> (24 - (8 * i))) as u8;
            result = (result << 16) + self.entangle[(((x_byte as u16) << 8) + y_byte as u16) as usize] as u64;
            let rotation = self.rotation[(((x_byte as u16) << 8) + y_byte as u16) as usize];
            if (rotation & 0x2) > 0 { let temp = x; x = y; y = temp; }
            if rotation == 12 || rotation == 6 { x = 0xFFFFFFFF - x; y = 0xFFFFFFFF - y }
        }

        debug_assert!(bit_entangle((init_x, init_y)) == result);
        return result;
    }

    pub fn detangle(&self, tangle: u64) -> (u32, u32) {
        let init_tangle = tangle;
        let mut result = (0u32, 0u32);
        for log_s in (0u32 .. 4) {
            let shifted = (tangle >> (16 * log_s)) as u16;
            let (x_byte, y_byte) = self.detangle[shifted as usize];
            let rotation = self.rotation[(((x_byte as u16) << 8) + y_byte as u16) as usize];
            if rotation == 12 || rotation == 6 {
                result.0 = (1 << 8 * log_s) - result.0 - 1;
                result.1 = (1 << 8 * log_s) - result.1 - 1;
            }
            if (rotation & 0x2) > 0 {
                let temp = result.0; result.0 = result.1; result.1 = temp;
            }

            result.0 += (x_byte as u32) << (8 * log_s);
            result.1 += (y_byte as u32) << (8 * log_s);
        }

        debug_assert!(bit_detangle(init_tangle) == result);
        return result;
    }
}

fn bit_entangle(mut pair: (u32, u32)) -> u64 {
    let mut result = 0u64;
    for log_s_rev in (0 .. 32) {
        let log_s = 31 - log_s_rev;
        let rx = (pair.0 >> log_s) & 1u32;
        let ry = (pair.1 >> log_s) & 1u32;
        result += (((3 * rx) ^ ry) as u64) << (2 * log_s);
        pair = bit_rotate(log_s, pair, rx, ry);
    }

    return result;
}

fn bit_detangle(tangle: u64) -> (u32, u32) {
    let mut result = (0u32, 0u32);
    for log_s in (0 .. 32) {
        let shifted = ((tangle >> (2 * log_s)) & 3u64) as u32;

        let rx = (shifted >> 1) & 1u32;
        let ry = (shifted ^ rx) & 1u32;
        result = bit_rotate(log_s, result, rx, ry);
        result = (result.0 + (rx << log_s), result.1 + (ry << log_s));
    }

    return result;
}

fn bit_rotate(logn: usize, pair: (u32, u32), rx: u32, ry: u32) -> (u32, u32) {
    if ry == 0 {
        if rx != 0 {
            ((1 << logn) - pair.1 - 1, (1 << logn) - pair.0 - 1)
        }
        else { (pair.1, pair.0) }
    }
    else { pair }
}
<|endoftext|>