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

use basenum::BaseFloat;
use traits::{ GenNum, GenFloat };

pub trait Consts<T: BaseFloat>: GenFloat<T> {
    fn epsilon() -> Self;
    fn pi() -> Self;
    fn tau() -> Self;
    fn root_pi() -> Self;
    fn half_pi() -> Self;
    fn one_third_pi() -> Self;
    fn quarter_pi() -> Self;
    fn one_over_pi() -> Self;
    fn one_over_tau() -> Self;
    fn two_over_pi() -> Self;
    fn four_over_pi() -> Self;
    fn two_over_root_pi() -> Self;
    fn one_over_root_two() -> Self;
    fn root_half_pi() -> Self;
    fn root_tau() -> Self;
    fn root_ln_four() -> Self;
    fn e() -> Self;
    fn euler() -> Self;
    fn root_two() -> Self;
    fn root_three() -> Self;
    fn root_five() -> Self;
    fn ln_two() -> Self;
    fn ln_ten() -> Self;
    fn ln_ln_two() -> Self;
    fn one_third() -> Self;
    fn two_thirds() -> Self;
    fn golden_ratio() -> Self;
}

macro_rules! impl_Consts_for {
    ($($bt: ident),+) => {
        $(
            impl<T> Consts<$bt> for T where T: GenFloat<$bt> {
                #[inline(always)]
                fn epsilon() -> T {
                    GenNum::<$bt>::from_s(BaseFloat::epsilon())
                }
                #[inline(always)]
                fn pi() -> T {
                    GenNum::<$bt>::from_s(3.14159265358979323846264338327950288)
                }
                #[inline(always)]
                fn tau() -> T {
                    GenNum::<$bt>::from_s(6.28318530717958647692528676655900576)
                }
                #[inline(always)]
                fn root_pi() -> T {
                    GenNum::<$bt>::from_s(1.772453850905516027)
                }
                #[inline(always)]
                fn half_pi() -> T {
                    GenNum::<$bt>::from_s(1.57079632679489661923132169163975144)
                }
                #[inline(always)]
                fn one_third_pi() -> T {
                    GenNum::<$bt>::from_s(1.04719755119659774615421446109316763)
                }
                #[inline(always)]
                fn quarter_pi() -> T {
                    GenNum::<$bt>::from_s(0.785398163397448309615660845819875721)
                }
                #[inline(always)]
                fn one_over_pi() -> T {
                    GenNum::<$bt>::from_s(0.318309886183790671537767526745028724)
                }
                #[inline(always)]
                fn one_over_tau() -> T {
                    GenNum::<$bt>::from_s(0.159154943091895335768883763372514362)
                }
                #[inline(always)]
                fn two_over_pi() -> T {
                    GenNum::<$bt>::from_s(0.636619772367581343075535053490057448)
                }
                #[inline(always)]
                fn four_over_pi() -> T {
                    GenNum::<$bt>::from_s(1.273239544735162686151070106980114898)
                }
                #[inline(always)]
                fn two_over_root_pi() -> T {
                    GenNum::<$bt>::from_s(1.12837916709551257389615890312154517)
                }
                #[inline(always)]
                fn one_over_root_two() -> T {
                    GenNum::<$bt>::from_s(0.707106781186547524400844362104849039)
                }
                #[inline(always)]
                fn root_half_pi() -> T {
                    GenNum::<$bt>::from_s(1.253314137315500251)
                }
                #[inline(always)]
                fn root_tau() -> T {
                    GenNum::<$bt>::from_s(2.506628274631000502)
                }
                #[inline(always)]
                fn root_ln_four() -> T {
                    GenNum::<$bt>::from_s(1.17741002251547469)
                }
                #[inline(always)]
                fn e() -> T {
                    GenNum::<$bt>::from_s(2.71828182845904523536028747135266250)
                }
                #[inline(always)]
                fn euler() -> T {
                    GenNum::<$bt>::from_s(0.577215664901532860606)
                }
                #[inline(always)]
                fn root_two() -> T {
                    GenNum::<$bt>::from_s(1.41421356237309504880168872420969808)
                }
                #[inline(always)]
                fn root_three() -> T {
                    GenNum::<$bt>::from_s(1.73205080756887729352744634150587236)
                }
                #[inline(always)]
                fn root_five() -> T {
                    GenNum::<$bt>::from_s(2.23606797749978969640917366873127623)
                }
                #[inline(always)]
                fn ln_two() -> T {
                    GenNum::<$bt>::from_s(0.693147180559945309417232121458176568)
                }
                #[inline(always)]
                fn ln_ten() -> T {
                    GenNum::<$bt>::from_s(2.30258509299404568401799145468436421)
                }
                #[inline(always)]
                fn ln_ln_two() -> T {
                    GenNum::<$bt>::from_s(-0.3665129205816643)
                }
                #[inline(always)]
                fn one_third() -> T {
                    GenNum::<$bt>::from_s(0.3333333333333333333333333333333333333333)
                }
                #[inline(always)]
                fn two_thirds() -> T {
                    GenNum::<$bt>::from_s(0.666666666666666666666666666666666666667)
                }
                fn golden_ratio() -> T {
                    GenNum::<$bt>::from_s(1.61803398874989484820458683436563811)
                }
            }
        )+
    }
}

impl_Consts_for! { f32, f64 }

// NOTE: can't define these functions without the indirection (trait `Consts`),
//       because Rust does not support implicit conversion.

/// Returns the epsilon constant for floating point types.
#[inline(always)]
pub fn epsilon<F: BaseFloat, T: GenFloat<F>>() -> T {
    GenNum::<F>::from_s(BaseFloat::epsilon())
}

/// Returns the Archimedes' constant π.
///
/// # Example
///
/// ```rust
/// use glm::*;
/// use glm::ext::pi;
///
/// let v4: DVec4 = pi();
/// assert_eq!(v4, dvec4(pi(), pi(), pi(), pi()));
#[inline(always)]
pub fn pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::pi()
}

/// Returns π * 2.
#[inline(always)]
pub fn tau<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::tau()
}

/// Returns square root of π.
#[inline(always)]
pub fn root_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_pi()
}

/// Returns π / 2.
#[inline(always)]
pub fn half_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::half_pi()
}

/// Returns π / 3.
#[inline(always)]
pub fn one_third_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_third_pi()
}

/// Returns π / 4.
#[inline(always)]
pub fn quarter_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::quarter_pi()
}

/// Returns 1 / π.
#[inline(always)]
pub fn one_over_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_over_pi()
}

/// Returns 1 / tau.
#[inline(always)]
pub fn one_over_tau<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_over_tau()
}

/// Returns 2 / π.
#[inline(always)]
pub fn two_over_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::two_over_pi()
}

/// Returns 4 / π.
#[inline(always)]
pub fn four_over_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::four_over_pi()
}

/// Returns 2 / sqrt(π).
#[inline(always)]
pub fn two_over_root_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::two_over_root_pi()
}

/// Returns 1 / sqrt(2).
#[inline(always)]
pub fn one_over_root_two<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_over_root_two()
}

/// Returns sqrt(π / 2).
#[inline(always)]
pub fn root_half_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_half_pi()
}

/// Returns sqrt(tau).
#[inline(always)]
pub fn root_tau<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_tau()
}

/// Returns sqrt(ln(4)).
#[inline(always)]
pub fn root_ln_four<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_ln_four()
}

/// Returns e constant.
#[inline(always)]
pub fn e<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::e()
}

/// Returns Euler's constant.
#[inline(always)]
pub fn euler<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::euler()
}

/// Returns sqrt(2).
#[inline(always)]
pub fn root_two<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_two()
}

/// Returns sqrt(3).
#[inline(always)]
pub fn root_three<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_three()
}

/// Returns sqrt(5).
#[inline(always)]
pub fn root_five<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_five()
}

/// Returns ln(2).
#[inline(always)]
pub fn ln_two<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::ln_two()
}

/// Returns ln(10).
#[inline(always)]
pub fn ln_ten<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::ln_ten()
}

/// Returns ln(ln(2)).
#[inline(always)]
pub fn ln_ln_two<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::ln_ln_two()
}

/// Returns 1 / 3.
#[inline(always)]
pub fn one_third<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_third()
}

/// Returns 2 / 3.
#[inline(always)]
pub fn two_thirds<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::two_thirds()
}

/// Returns the golden ratio constant.
pub fn golden_ratio<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::golden_ratio()
}
<commit_msg>Obviously type of vector constants can be specified too by calling methods in `Consts`.<commit_after>//
// GLSL Mathematics for Rust.
//
// Copyright (c) 2015 The glm-rs authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use basenum::BaseFloat;
use traits::{ GenNum, GenFloat };

pub trait Consts<T: BaseFloat>: GenFloat<T> {
    fn epsilon() -> Self;
    fn pi() -> Self;
    fn tau() -> Self;
    fn root_pi() -> Self;
    fn half_pi() -> Self;
    fn one_third_pi() -> Self;
    fn quarter_pi() -> Self;
    fn one_over_pi() -> Self;
    fn one_over_tau() -> Self;
    fn two_over_pi() -> Self;
    fn four_over_pi() -> Self;
    fn two_over_root_pi() -> Self;
    fn one_over_root_two() -> Self;
    fn root_half_pi() -> Self;
    fn root_tau() -> Self;
    fn root_ln_four() -> Self;
    fn e() -> Self;
    fn euler() -> Self;
    fn root_two() -> Self;
    fn root_three() -> Self;
    fn root_five() -> Self;
    fn ln_two() -> Self;
    fn ln_ten() -> Self;
    fn ln_ln_two() -> Self;
    fn one_third() -> Self;
    fn two_thirds() -> Self;
    fn golden_ratio() -> Self;
}

macro_rules! impl_Consts_for {
    ($($bt: ident),+) => {
        $(
            impl<T> Consts<$bt> for T where T: GenFloat<$bt> {
                #[inline(always)]
                fn epsilon() -> T {
                    GenNum::<$bt>::from_s(BaseFloat::epsilon())
                }
                #[inline(always)]
                fn pi() -> T {
                    GenNum::<$bt>::from_s(3.14159265358979323846264338327950288)
                }
                #[inline(always)]
                fn tau() -> T {
                    GenNum::<$bt>::from_s(6.28318530717958647692528676655900576)
                }
                #[inline(always)]
                fn root_pi() -> T {
                    GenNum::<$bt>::from_s(1.772453850905516027)
                }
                #[inline(always)]
                fn half_pi() -> T {
                    GenNum::<$bt>::from_s(1.57079632679489661923132169163975144)
                }
                #[inline(always)]
                fn one_third_pi() -> T {
                    GenNum::<$bt>::from_s(1.04719755119659774615421446109316763)
                }
                #[inline(always)]
                fn quarter_pi() -> T {
                    GenNum::<$bt>::from_s(0.785398163397448309615660845819875721)
                }
                #[inline(always)]
                fn one_over_pi() -> T {
                    GenNum::<$bt>::from_s(0.318309886183790671537767526745028724)
                }
                #[inline(always)]
                fn one_over_tau() -> T {
                    GenNum::<$bt>::from_s(0.159154943091895335768883763372514362)
                }
                #[inline(always)]
                fn two_over_pi() -> T {
                    GenNum::<$bt>::from_s(0.636619772367581343075535053490057448)
                }
                #[inline(always)]
                fn four_over_pi() -> T {
                    GenNum::<$bt>::from_s(1.273239544735162686151070106980114898)
                }
                #[inline(always)]
                fn two_over_root_pi() -> T {
                    GenNum::<$bt>::from_s(1.12837916709551257389615890312154517)
                }
                #[inline(always)]
                fn one_over_root_two() -> T {
                    GenNum::<$bt>::from_s(0.707106781186547524400844362104849039)
                }
                #[inline(always)]
                fn root_half_pi() -> T {
                    GenNum::<$bt>::from_s(1.253314137315500251)
                }
                #[inline(always)]
                fn root_tau() -> T {
                    GenNum::<$bt>::from_s(2.506628274631000502)
                }
                #[inline(always)]
                fn root_ln_four() -> T {
                    GenNum::<$bt>::from_s(1.17741002251547469)
                }
                #[inline(always)]
                fn e() -> T {
                    GenNum::<$bt>::from_s(2.71828182845904523536028747135266250)
                }
                #[inline(always)]
                fn euler() -> T {
                    GenNum::<$bt>::from_s(0.577215664901532860606)
                }
                #[inline(always)]
                fn root_two() -> T {
                    GenNum::<$bt>::from_s(1.41421356237309504880168872420969808)
                }
                #[inline(always)]
                fn root_three() -> T {
                    GenNum::<$bt>::from_s(1.73205080756887729352744634150587236)
                }
                #[inline(always)]
                fn root_five() -> T {
                    GenNum::<$bt>::from_s(2.23606797749978969640917366873127623)
                }
                #[inline(always)]
                fn ln_two() -> T {
                    GenNum::<$bt>::from_s(0.693147180559945309417232121458176568)
                }
                #[inline(always)]
                fn ln_ten() -> T {
                    GenNum::<$bt>::from_s(2.30258509299404568401799145468436421)
                }
                #[inline(always)]
                fn ln_ln_two() -> T {
                    GenNum::<$bt>::from_s(-0.3665129205816643)
                }
                #[inline(always)]
                fn one_third() -> T {
                    GenNum::<$bt>::from_s(0.3333333333333333333333333333333333333333)
                }
                #[inline(always)]
                fn two_thirds() -> T {
                    GenNum::<$bt>::from_s(0.666666666666666666666666666666666666667)
                }
                fn golden_ratio() -> T {
                    GenNum::<$bt>::from_s(1.61803398874989484820458683436563811)
                }
            }
        )+
    }
}

impl_Consts_for! { f32, f64 }

// NOTE: can't define these functions without the indirection (trait `Consts`),
//       because Rust does not support implicit conversion.

/// Returns the epsilon constant for floating point types.
#[inline(always)]
pub fn epsilon<F: BaseFloat, T: GenFloat<F>>() -> T {
    GenNum::<F>::from_s(BaseFloat::epsilon())
}

/// Returns the Archimedes' constant π.
///
/// # Example
///
/// ```rust
/// use glm::*;
/// use glm::ext::*;
///
/// assert_eq!(DVec4::pi(), dvec4(pi(), pi(), pi(), pi()));
#[inline(always)]
pub fn pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::pi()
}

/// Returns π * 2.
#[inline(always)]
pub fn tau<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::tau()
}

/// Returns square root of π.
#[inline(always)]
pub fn root_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_pi()
}

/// Returns π / 2.
#[inline(always)]
pub fn half_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::half_pi()
}

/// Returns π / 3.
#[inline(always)]
pub fn one_third_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_third_pi()
}

/// Returns π / 4.
#[inline(always)]
pub fn quarter_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::quarter_pi()
}

/// Returns 1 / π.
#[inline(always)]
pub fn one_over_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_over_pi()
}

/// Returns 1 / tau.
#[inline(always)]
pub fn one_over_tau<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_over_tau()
}

/// Returns 2 / π.
#[inline(always)]
pub fn two_over_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::two_over_pi()
}

/// Returns 4 / π.
#[inline(always)]
pub fn four_over_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::four_over_pi()
}

/// Returns 2 / sqrt(π).
#[inline(always)]
pub fn two_over_root_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::two_over_root_pi()
}

/// Returns 1 / sqrt(2).
#[inline(always)]
pub fn one_over_root_two<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_over_root_two()
}

/// Returns sqrt(π / 2).
#[inline(always)]
pub fn root_half_pi<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_half_pi()
}

/// Returns sqrt(tau).
#[inline(always)]
pub fn root_tau<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_tau()
}

/// Returns sqrt(ln(4)).
#[inline(always)]
pub fn root_ln_four<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_ln_four()
}

/// Returns e constant.
#[inline(always)]
pub fn e<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::e()
}

/// Returns Euler's constant.
#[inline(always)]
pub fn euler<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::euler()
}

/// Returns sqrt(2).
#[inline(always)]
pub fn root_two<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_two()
}

/// Returns sqrt(3).
#[inline(always)]
pub fn root_three<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_three()
}

/// Returns sqrt(5).
#[inline(always)]
pub fn root_five<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::root_five()
}

/// Returns ln(2).
#[inline(always)]
pub fn ln_two<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::ln_two()
}

/// Returns ln(10).
#[inline(always)]
pub fn ln_ten<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::ln_ten()
}

/// Returns ln(ln(2)).
#[inline(always)]
pub fn ln_ln_two<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::ln_ln_two()
}

/// Returns 1 / 3.
#[inline(always)]
pub fn one_third<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::one_third()
}

/// Returns 2 / 3.
#[inline(always)]
pub fn two_thirds<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::two_thirds()
}

/// Returns the golden ratio constant.
pub fn golden_ratio<F: BaseFloat, T: Consts<F>>() -> T {
    Consts::golden_ratio()
}
<|endoftext|>


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

use log::warn;

pub fn walk<P: AsRef<Path>>(root: P) -> std::io::Result<Walk> {
    let metadata = std::fs::symlink_metadata(&root)?;

    Ok(Walk {
        root: Some(WalkEntry {
            path: root.as_ref().to_path_buf(),
            metadata: metadata,
        }),
        pending: vec!(list_dir(&root)?),
    })
}

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 Walk {
    // TODO: Add support for stopping at device boundaries.
    root: Option<WalkEntry>,
    pending: Vec<ListDir>,
}

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

impl Walk {

    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 Walk {

    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_empty() {
        let tempdir = tempfile::tempdir().unwrap();

        let mut iter = walk(&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_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(&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_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(&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_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(&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_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(&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_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(&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_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(&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_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(&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_with_unicode_names() {
        let tempdir = tempfile::tempdir().unwrap();
        File::create(tempdir.path().join("zażółć gęślą jaźń")).unwrap();

        let mut results = walk(&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_metadata_size() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::write(tempdir.path().join("foo"), b"123456789").unwrap();

        let mut results = walk(&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>Remove a spurious newline.<commit_after>use std::fs::Metadata;
use std::path::{Path, PathBuf};

use log::warn;

pub fn walk<P: AsRef<Path>>(root: P) -> std::io::Result<Walk> {
    let metadata = std::fs::symlink_metadata(&root)?;

    Ok(Walk {
        root: Some(WalkEntry {
            path: root.as_ref().to_path_buf(),
            metadata: metadata,
        }),
        pending: vec!(list_dir(&root)?),
    })
}

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 Walk {
    // TODO: Add support for stopping at device boundaries.
    root: Option<WalkEntry>,
    pending: Vec<ListDir>,
}

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

impl Walk {

    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 Walk {

    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_empty() {
        let tempdir = tempfile::tempdir().unwrap();

        let mut iter = walk(&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_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(&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_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(&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_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(&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_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(&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_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(&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_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(&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_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(&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_with_unicode_names() {
        let tempdir = tempfile::tempdir().unwrap();
        File::create(tempdir.path().join("zażółć gęślą jaźń")).unwrap();

        let mut results = walk(&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_metadata_size() {
        let tempdir = tempfile::tempdir().unwrap();
        std::fs::write(tempdir.path().join("foo"), b"123456789").unwrap();

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

use backend::StoreBackend;
use capnp;
use errors::HatError;
use hash;
use hat::insert_path_handler::InsertPathHandler;
use hat::walker;
use key;
use root_capnp;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::str;
use std::sync::mpsc;
use util::{FileIterator, FnBox, PathHandler};

fn try_a_few_times_then_panic<F>(mut f: F, msg: &str)
    where F: FnMut() -> bool
{
    for _ in 1 as i32..5 {
        if f() {
            return;
        }
    }
    panic!(msg.to_owned());
}

pub mod recover {
    use hash;
    use hash::tree;
    use hat::walker;
    use std::collections::VecDeque;
    use std::mem;
    use super::parse_dir_data;

    #[derive(Clone)]
    pub struct Node {
        pub href: tree::HashRef,
        pub childs: Option<Vec<tree::HashRef>>,
    }

    pub struct FileVisitor {
        tops: Vec<hash::Hash>,
        nodes: VecDeque<Node>,
    }

    impl FileVisitor {
        pub fn new() -> FileVisitor {
            FileVisitor {
                tops: vec![],
                nodes: VecDeque::new(),
            }
        }
        pub fn is_empty(&self) -> bool {
            self.tops.is_empty() && self.nodes.is_empty()
        }
        pub fn tops(&mut self) -> Vec<hash::Hash> {
            mem::replace(&mut self.tops, vec![])
        }
        pub fn nodes(&mut self) -> VecDeque<Node> {
            mem::replace(&mut self.nodes, VecDeque::new())
        }
    }

    impl tree::Visitor for FileVisitor {
        fn branch_enter(&mut self, href: &tree::HashRef, childs: &Vec<tree::HashRef>) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: Some(childs.clone()),
            });
            true
        }
        fn leaf_enter(&mut self, href: &tree::HashRef) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: None,
            });

            // Do not proceed to read the actual file data.
            false
        }
        fn leaf_leave(&mut self, _chunk: Vec<u8>, _href: &tree::HashRef) -> bool {
            unreachable!();
        }
    }

    impl walker::LikesFiles for FileVisitor {
        fn include_file(&mut self, file: &walker::FileEntry) -> bool {
            if file.meta.data_hash.is_some() {
                self.tops.push(file.hash_ref.hash.clone());
                true
            } else {
                false
            }
        }

        fn include_dir(&mut self, file: &walker::FileEntry) -> bool {
            if file.meta.data_hash.is_none() {
                self.tops.push(file.hash_ref.hash.clone());
                true
            } else {
                false
            }
        }
    }

    pub struct DirVisitor {
        nodes: VecDeque<Node>,
        files: Vec<walker::FileEntry>,
    }

    impl DirVisitor {
        pub fn new() -> DirVisitor {
            DirVisitor {
                nodes: VecDeque::new(),
                files: vec![],
            }
        }
        pub fn is_empty(&self) -> bool {
            self.nodes.is_empty()
        }
        pub fn nodes(&mut self) -> VecDeque<Node> {
            mem::replace(&mut self.nodes, VecDeque::new())
        }
    }

    impl walker::HasFiles for DirVisitor {
        fn files(&mut self) -> Vec<walker::FileEntry> {
            mem::replace(&mut self.files, vec![])
        }
    }

    impl tree::Visitor for DirVisitor {
        fn branch_enter(&mut self, href: &tree::HashRef, childs: &Vec<tree::HashRef>) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: Some(childs.clone()),
            });
            true
        }
        fn leaf_leave(&mut self, chunk: Vec<u8>, href: &tree::HashRef) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: None,
            });
            parse_dir_data(&chunk[..], &mut self.files).unwrap();
            true
        }
    }
}

fn parse_dir_data(chunk: &[u8], mut out: &mut Vec<walker::FileEntry>) -> Result<(), HatError> {
    if chunk.is_empty() {
        return Ok(());
    }

    use std::hash::{Hash, Hasher, SipHasher};

    fn hash<T: Hash>(t: &T) -> u64 {
        let mut s = SipHasher::new();
        t.hash(&mut s);
        s.finish()
    }

    let reader = capnp::serialize_packed::read_message(&mut &chunk[..],
                                                       capnp::message::ReaderOptions::new())
        .unwrap();

    let list = reader.get_root::<root_capnp::file_list::Reader>().unwrap();
    for f in list.get_files().unwrap().iter() {
        if f.get_name().unwrap().len() == 0 {
            // Empty entry at end.
            // TODO(jos): Can we get rid of these?
            break;
        }
        let entry = key::Entry {
            id: Some(f.get_id()),
            name: f.get_name().unwrap().to_owned(),
            created: match f.get_created().which().unwrap() {
                root_capnp::file::created::Unknown(()) => None,
                root_capnp::file::created::Timestamp(ts) => Some(ts),
            },
            modified: match f.get_modified().which().unwrap() {
                root_capnp::file::modified::Unknown(()) => None,
                root_capnp::file::modified::Timestamp(ts) => Some(ts),
            },
            accessed: match f.get_accessed().which().unwrap() {
                root_capnp::file::accessed::Unknown(()) => None,
                root_capnp::file::accessed::Timestamp(ts) => Some(ts),
            },
            data_hash: match f.get_content().which().unwrap() {
                root_capnp::file::content::Data(r) => {
                    Some(r.unwrap().get_hash().unwrap().to_owned())
                }
                root_capnp::file::content::Directory(_) => None,
            },
            // TODO(jos): Implement support for these remaining fields.
            user_id: None,
            group_id: None,
            permissions: None,
            data_length: None,
            parent_id: None,
        };
        let hash_ref = match f.get_content().which().unwrap() {
                root_capnp::file::content::Data(r) => {
                    hash::tree::HashRef::read_msg(&r.expect("File has no data reference"))
                }
                root_capnp::file::content::Directory(d) => {
                    hash::tree::HashRef::read_msg(&d.expect("Directory has no listing reference"))
                }
            }
            .unwrap();

        out.push(walker::FileEntry {
            hash_ref: hash_ref,
            meta: entry,
        });
    }
    Ok(())
}

pub struct Family<B> {
    pub name: String,
    pub key_store: key::Store<B>,
    pub key_store_process: Vec<key::StoreProcess<FileIterator, B>>,
}
impl<B: StoreBackend> Clone for Family<B> {
    fn clone(&self) -> Family<B> {
        Family {
            name: self.name.clone(),
            key_store: self.key_store.clone(),
            key_store_process: self.key_store_process.clone(),
        }
    }
}

impl<B: StoreBackend> Family<B> {
    pub fn snapshot_dir(&self, dir: PathBuf) {
        let handler = InsertPathHandler::new(self.key_store_process.clone());
        handler.recurse(PathBuf::from(&dir), None);
    }

    pub fn snapshot_direct(&self,
                           file: key::Entry,
                           is_directory: bool,
                           contents: Option<FileIterator>)
                           -> Result<u64, HatError> {
        let f = if is_directory {
            None
        } else {
            Some(Box::new(move |()| contents) as Box<FnBox<(), _>>)
        };
        match try!(self.key_store_process[0].send_reply(key::Msg::Insert(file, f))) {
            key::Reply::Id(id) => return Ok(id),
            _ => Err(From::from("Unexpected reply from key store")),
        }
    }

    pub fn flush(&self) -> Result<(), HatError> {
        for ks in &self.key_store_process {
            if let key::Reply::FlushOk = try!(ks.send_reply(key::Msg::Flush)) {
                continue;
            }
            return Err(From::from("Unexpected reply from key store"));
        }
        Ok(())
    }

  pub fn write_file_chunks<HTB: hash::tree::HashTreeBackend<Err=key::MsgError>>(
    &self, fd: &mut fs::File, tree: hash::tree::LeafIterator<HTB>)
  {
        for chunk in tree {
            try_a_few_times_then_panic(|| fd.write_all(&chunk[..]).is_ok(),
                                       "Could not write chunk.");
        }
        try_a_few_times_then_panic(|| fd.flush().is_ok(), "Could not flush file.");
    }

    pub fn checkout_in_dir(&self,
                           output_dir: PathBuf,
                           dir_id: Option<u64>)
                           -> Result<(), HatError> {
        let mut path = output_dir;
        for (entry, _ref, read_fn_opt) in try!(self.list_from_key_store(dir_id)).into_iter() {
            // Extend directory with filename:
            path.push(str::from_utf8(&entry.name[..]).unwrap());

            match read_fn_opt {
                None => {
                    // This is a directory, recurse!
                    fs::create_dir_all(&path).unwrap();
                    try!(self.checkout_in_dir(path.clone(), entry.id));
                }
                Some(read_fn) => {
                    // This is a file, write it
                    let mut fd = fs::File::create(&path).unwrap();
                    if let Some(tree) = try!(read_fn.init()) {
                        self.write_file_chunks(&mut fd, tree);
                    }
                }
            }

            // Prepare for next filename:
            path.pop();
        }

        Ok(())
    }

    pub fn list_from_key_store(&self,
                               dir_id: Option<u64>)
                               -> Result<Vec<key::DirElem<B>>, HatError> {
        match try!(self.key_store_process[0].send_reply(key::Msg::ListDir(dir_id))) {
            key::Reply::ListResult(ls) => Ok(ls),
            _ => Err(From::from("Unexpected result from key store")),
        }
    }

    pub fn fetch_dir_data<HTB: hash::tree::HashTreeBackend<Err = key::MsgError>>
        (&self,
         dir_hash: hash::tree::HashRef,
         backend: HTB)
         -> Result<Vec<(key::Entry, hash::tree::HashRef)>, HatError> {
        let it = try!(hash::tree::LeafIterator::new(backend, dir_hash))
            .expect("unable to open dir");

        let mut out = Vec::new();
        for chunk in it {
            if !chunk.is_empty() {
                try!(parse_dir_data(&chunk[..], &mut out));
            }
        }

        Ok(out.into_iter().map(|f| (f.meta, f.hash_ref)).collect())
    }

    pub fn commit(&mut self,
                  hash_ch: &mpsc::Sender<hash::Hash>)
                  -> Result<hash::tree::HashRef, HatError> {
        let mut top_tree = self.key_store.hash_tree_writer();
        try!(self.commit_to_tree(&mut top_tree, None, hash_ch));

        Ok(try!(top_tree.hash()))
    }

    pub fn commit_to_tree(&mut self,
                          tree: &mut hash::tree::SimpleHashTreeWriter<key::HashStoreBackend<B>>,
                          dir_id: Option<u64>,
                          hash_ch: &mpsc::Sender<hash::Hash>)
                          -> Result<(), HatError> {

        let files_at_a_time = 1024;
        let mut it = try!(self.list_from_key_store(dir_id)).into_iter();

        loop {
            let mut current_msg_is_empty = true;
            let mut file_block_msg = capnp::message::Builder::new_default();

            {
                let files_root = file_block_msg.init_root::<root_capnp::file_list::Builder>();
                let mut files = files_root.init_files(files_at_a_time as u32);

                for (idx, (entry, data_ref, _data_res_open)) in
                    it.by_ref()
                        .take(files_at_a_time)
                        .enumerate() {
                    assert!(idx < files_at_a_time);

                    current_msg_is_empty = false;
                    let mut file_msg = files.borrow().get(idx as u32);

                    file_msg.set_id(entry.id.unwrap_or(0));
                    file_msg.set_name(&entry.name);

                    match entry.created {
                        None => file_msg.borrow().init_created().set_unknown(()),
                        Some(ts) => file_msg.borrow().init_created().set_timestamp(ts),
                    }

                    match entry.modified {
                        None => file_msg.borrow().init_modified().set_unknown(()),
                        Some(ts) => file_msg.borrow().init_modified().set_timestamp(ts),
                    }

                    match entry.accessed {
                        None => file_msg.borrow().init_accessed().set_unknown(()),
                        Some(ts) => file_msg.borrow().init_accessed().set_timestamp(ts),
                    }

                    if let Some(hash_bytes) = entry.data_hash {
                        // This is a file, store its data hash:
                        let mut hash_ref_msg = capnp::message::Builder::new_default();
                        let mut hash_ref_root =
                            hash_ref_msg.init_root::<root_capnp::hash_ref::Builder>();

                        // Populate data hash and ChunkRef.
                        data_ref.expect("has data")
                            .populate_msg(hash_ref_root.borrow());
                        // Set as file content.
                        try!(file_msg.borrow()
                            .init_content()
                            .set_data(hash_ref_root.as_reader()));
                        hash_ch.send(hash::Hash { bytes: hash_bytes }).unwrap();
                    } else {
                        drop(data_ref);  // May not use data reference without hash.

                        // This is a directory, recurse!
                        let mut inner_tree = self.key_store.hash_tree_writer();
                        try!(self.commit_to_tree(&mut inner_tree, entry.id, hash_ch));
                        // Store a reference for the sub-tree in our tree:
                        let dir_hash_ref = try!(inner_tree.hash());

                        let mut hash_ref_msg = capnp::message::Builder::new_default();
                        let mut hash_ref_root =
                            hash_ref_msg.init_root::<root_capnp::hash_ref::Builder>();

                        // Populate directory hash and ChunkRef.
                        dir_hash_ref.populate_msg(hash_ref_root.borrow());
                        // Set as directory content.
                        try!(file_msg.borrow()
                            .init_content()
                            .set_directory(hash_ref_root.as_reader()));

                        hash_ch.send(dir_hash_ref.hash).unwrap();
                    }
                }
            }

            // Flush to our own tree when we have a decent amount.
            // The tree prevents large directories from clogging ram.
            if current_msg_is_empty {
                break;
            } else {
                let mut buf = vec![];
                try!(capnp::serialize_packed::write_message(&mut buf, &file_block_msg));
                try!(tree.append(&buf[..]));
            }
        }

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

use backend::StoreBackend;
use capnp;
use errors::HatError;
use hash;
use hat::insert_path_handler::InsertPathHandler;
use hat::walker;
use key;
use root_capnp;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::str;
use std::sync::mpsc;
use util::{FileIterator, FnBox, PathHandler};

fn try_a_few_times_then_panic<F>(mut f: F, msg: &str)
    where F: FnMut() -> bool
{
    for _ in 1 as i32..5 {
        if f() {
            return;
        }
    }
    panic!(msg.to_owned());
}

pub mod recover {
    use hash;
    use hash::tree;
    use hat::walker;
    use std::collections::VecDeque;
    use std::mem;
    use super::parse_dir_data;

    #[derive(Clone)]
    pub struct Node {
        pub href: tree::HashRef,
        pub childs: Option<Vec<tree::HashRef>>,
    }

    pub struct FileVisitor {
        tops: Vec<hash::Hash>,
        nodes: VecDeque<Node>,
    }

    impl FileVisitor {
        pub fn new() -> FileVisitor {
            FileVisitor {
                tops: vec![],
                nodes: VecDeque::new(),
            }
        }
        pub fn is_empty(&self) -> bool {
            self.tops.is_empty() && self.nodes.is_empty()
        }
        pub fn tops(&mut self) -> Vec<hash::Hash> {
            mem::replace(&mut self.tops, vec![])
        }
        pub fn nodes(&mut self) -> VecDeque<Node> {
            mem::replace(&mut self.nodes, VecDeque::new())
        }
    }

    impl tree::Visitor for FileVisitor {
        fn branch_enter(&mut self, href: &tree::HashRef, childs: &Vec<tree::HashRef>) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: Some(childs.clone()),
            });
            true
        }
        fn leaf_enter(&mut self, href: &tree::HashRef) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: None,
            });

            // Do not proceed to read the actual file data.
            false
        }
        fn leaf_leave(&mut self, _chunk: Vec<u8>, _href: &tree::HashRef) -> bool {
            unreachable!();
        }
    }

    impl walker::LikesFiles for FileVisitor {
        fn include_file(&mut self, file: &walker::FileEntry) -> bool {
            if file.meta.data_hash.is_some() {
                self.tops.push(file.hash_ref.hash.clone());
                true
            } else {
                false
            }
        }

        fn include_dir(&mut self, file: &walker::FileEntry) -> bool {
            if file.meta.data_hash.is_none() {
                self.tops.push(file.hash_ref.hash.clone());
                true
            } else {
                false
            }
        }
    }

    pub struct DirVisitor {
        nodes: VecDeque<Node>,
        files: Vec<walker::FileEntry>,
    }

    impl DirVisitor {
        pub fn new() -> DirVisitor {
            DirVisitor {
                nodes: VecDeque::new(),
                files: vec![],
            }
        }
        pub fn is_empty(&self) -> bool {
            self.nodes.is_empty()
        }
        pub fn nodes(&mut self) -> VecDeque<Node> {
            mem::replace(&mut self.nodes, VecDeque::new())
        }
    }

    impl walker::HasFiles for DirVisitor {
        fn files(&mut self) -> Vec<walker::FileEntry> {
            mem::replace(&mut self.files, vec![])
        }
    }

    impl tree::Visitor for DirVisitor {
        fn branch_enter(&mut self, href: &tree::HashRef, childs: &Vec<tree::HashRef>) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: Some(childs.clone()),
            });
            true
        }
        fn leaf_leave(&mut self, chunk: Vec<u8>, href: &tree::HashRef) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: None,
            });
            parse_dir_data(&chunk[..], &mut self.files).unwrap();
            true
        }
    }
}

fn parse_dir_data(chunk: &[u8], mut out: &mut Vec<walker::FileEntry>) -> Result<(), HatError> {
    if chunk.is_empty() {
        return Ok(());
    }

    let reader = capnp::serialize_packed::read_message(&mut &chunk[..],
                                                       capnp::message::ReaderOptions::new())
        .unwrap();

    let list = reader.get_root::<root_capnp::file_list::Reader>().unwrap();
    for f in list.get_files().unwrap().iter() {
        if f.get_name().unwrap().len() == 0 {
            // Empty entry at end.
            // TODO(jos): Can we get rid of these?
            break;
        }
        let entry = key::Entry {
            id: Some(f.get_id()),
            name: f.get_name().unwrap().to_owned(),
            created: match f.get_created().which().unwrap() {
                root_capnp::file::created::Unknown(()) => None,
                root_capnp::file::created::Timestamp(ts) => Some(ts),
            },
            modified: match f.get_modified().which().unwrap() {
                root_capnp::file::modified::Unknown(()) => None,
                root_capnp::file::modified::Timestamp(ts) => Some(ts),
            },
            accessed: match f.get_accessed().which().unwrap() {
                root_capnp::file::accessed::Unknown(()) => None,
                root_capnp::file::accessed::Timestamp(ts) => Some(ts),
            },
            data_hash: match f.get_content().which().unwrap() {
                root_capnp::file::content::Data(r) => {
                    Some(r.unwrap().get_hash().unwrap().to_owned())
                }
                root_capnp::file::content::Directory(_) => None,
            },
            // TODO(jos): Implement support for these remaining fields.
            user_id: None,
            group_id: None,
            permissions: None,
            data_length: None,
            parent_id: None,
        };
        let hash_ref = match f.get_content().which().unwrap() {
                root_capnp::file::content::Data(r) => {
                    hash::tree::HashRef::read_msg(&r.expect("File has no data reference"))
                }
                root_capnp::file::content::Directory(d) => {
                    hash::tree::HashRef::read_msg(&d.expect("Directory has no listing reference"))
                }
            }
            .unwrap();

        out.push(walker::FileEntry {
            hash_ref: hash_ref,
            meta: entry,
        });
    }
    Ok(())
}

pub struct Family<B> {
    pub name: String,
    pub key_store: key::Store<B>,
    pub key_store_process: Vec<key::StoreProcess<FileIterator, B>>,
}
impl<B: StoreBackend> Clone for Family<B> {
    fn clone(&self) -> Family<B> {
        Family {
            name: self.name.clone(),
            key_store: self.key_store.clone(),
            key_store_process: self.key_store_process.clone(),
        }
    }
}

impl<B: StoreBackend> Family<B> {
    pub fn snapshot_dir(&self, dir: PathBuf) {
        let handler = InsertPathHandler::new(self.key_store_process.clone());
        handler.recurse(PathBuf::from(&dir), None);
    }

    pub fn snapshot_direct(&self,
                           file: key::Entry,
                           is_directory: bool,
                           contents: Option<FileIterator>)
                           -> Result<u64, HatError> {
        let f = if is_directory {
            None
        } else {
            Some(Box::new(move |()| contents) as Box<FnBox<(), _>>)
        };
        match try!(self.key_store_process[0].send_reply(key::Msg::Insert(file, f))) {
            key::Reply::Id(id) => return Ok(id),
            _ => Err(From::from("Unexpected reply from key store")),
        }
    }

    pub fn flush(&self) -> Result<(), HatError> {
        for ks in &self.key_store_process {
            if let key::Reply::FlushOk = try!(ks.send_reply(key::Msg::Flush)) {
                continue;
            }
            return Err(From::from("Unexpected reply from key store"));
        }
        Ok(())
    }

  pub fn write_file_chunks<HTB: hash::tree::HashTreeBackend<Err=key::MsgError>>(
    &self, fd: &mut fs::File, tree: hash::tree::LeafIterator<HTB>)
  {
        for chunk in tree {
            try_a_few_times_then_panic(|| fd.write_all(&chunk[..]).is_ok(),
                                       "Could not write chunk.");
        }
        try_a_few_times_then_panic(|| fd.flush().is_ok(), "Could not flush file.");
    }

    pub fn checkout_in_dir(&self,
                           output_dir: PathBuf,
                           dir_id: Option<u64>)
                           -> Result<(), HatError> {
        let mut path = output_dir;
        for (entry, _ref, read_fn_opt) in try!(self.list_from_key_store(dir_id)).into_iter() {
            // Extend directory with filename:
            path.push(str::from_utf8(&entry.name[..]).unwrap());

            match read_fn_opt {
                None => {
                    // This is a directory, recurse!
                    fs::create_dir_all(&path).unwrap();
                    try!(self.checkout_in_dir(path.clone(), entry.id));
                }
                Some(read_fn) => {
                    // This is a file, write it
                    let mut fd = fs::File::create(&path).unwrap();
                    if let Some(tree) = try!(read_fn.init()) {
                        self.write_file_chunks(&mut fd, tree);
                    }
                }
            }

            // Prepare for next filename:
            path.pop();
        }

        Ok(())
    }

    pub fn list_from_key_store(&self,
                               dir_id: Option<u64>)
                               -> Result<Vec<key::DirElem<B>>, HatError> {
        match try!(self.key_store_process[0].send_reply(key::Msg::ListDir(dir_id))) {
            key::Reply::ListResult(ls) => Ok(ls),
            _ => Err(From::from("Unexpected result from key store")),
        }
    }

    pub fn fetch_dir_data<HTB: hash::tree::HashTreeBackend<Err = key::MsgError>>
        (&self,
         dir_hash: hash::tree::HashRef,
         backend: HTB)
         -> Result<Vec<(key::Entry, hash::tree::HashRef)>, HatError> {
        let it = try!(hash::tree::LeafIterator::new(backend, dir_hash))
            .expect("unable to open dir");

        let mut out = Vec::new();
        for chunk in it {
            if !chunk.is_empty() {
                try!(parse_dir_data(&chunk[..], &mut out));
            }
        }

        Ok(out.into_iter().map(|f| (f.meta, f.hash_ref)).collect())
    }

    pub fn commit(&mut self,
                  hash_ch: &mpsc::Sender<hash::Hash>)
                  -> Result<hash::tree::HashRef, HatError> {
        let mut top_tree = self.key_store.hash_tree_writer();
        try!(self.commit_to_tree(&mut top_tree, None, hash_ch));

        Ok(try!(top_tree.hash()))
    }

    pub fn commit_to_tree(&mut self,
                          tree: &mut hash::tree::SimpleHashTreeWriter<key::HashStoreBackend<B>>,
                          dir_id: Option<u64>,
                          hash_ch: &mpsc::Sender<hash::Hash>)
                          -> Result<(), HatError> {

        let files_at_a_time = 1024;
        let mut it = try!(self.list_from_key_store(dir_id)).into_iter();

        loop {
            let mut current_msg_is_empty = true;
            let mut file_block_msg = capnp::message::Builder::new_default();

            {
                let files_root = file_block_msg.init_root::<root_capnp::file_list::Builder>();
                let mut files = files_root.init_files(files_at_a_time as u32);

                for (idx, (entry, data_ref, _data_res_open)) in
                    it.by_ref()
                        .take(files_at_a_time)
                        .enumerate() {
                    assert!(idx < files_at_a_time);

                    current_msg_is_empty = false;
                    let mut file_msg = files.borrow().get(idx as u32);

                    file_msg.set_id(entry.id.unwrap_or(0));
                    file_msg.set_name(&entry.name);

                    match entry.created {
                        None => file_msg.borrow().init_created().set_unknown(()),
                        Some(ts) => file_msg.borrow().init_created().set_timestamp(ts),
                    }

                    match entry.modified {
                        None => file_msg.borrow().init_modified().set_unknown(()),
                        Some(ts) => file_msg.borrow().init_modified().set_timestamp(ts),
                    }

                    match entry.accessed {
                        None => file_msg.borrow().init_accessed().set_unknown(()),
                        Some(ts) => file_msg.borrow().init_accessed().set_timestamp(ts),
                    }

                    if let Some(hash_bytes) = entry.data_hash {
                        // This is a file, store its data hash:
                        let mut hash_ref_msg = capnp::message::Builder::new_default();
                        let mut hash_ref_root =
                            hash_ref_msg.init_root::<root_capnp::hash_ref::Builder>();

                        // Populate data hash and ChunkRef.
                        data_ref.expect("has data")
                            .populate_msg(hash_ref_root.borrow());
                        // Set as file content.
                        try!(file_msg.borrow()
                            .init_content()
                            .set_data(hash_ref_root.as_reader()));
                        hash_ch.send(hash::Hash { bytes: hash_bytes }).unwrap();
                    } else {
                        drop(data_ref);  // May not use data reference without hash.

                        // This is a directory, recurse!
                        let mut inner_tree = self.key_store.hash_tree_writer();
                        try!(self.commit_to_tree(&mut inner_tree, entry.id, hash_ch));
                        // Store a reference for the sub-tree in our tree:
                        let dir_hash_ref = try!(inner_tree.hash());

                        let mut hash_ref_msg = capnp::message::Builder::new_default();
                        let mut hash_ref_root =
                            hash_ref_msg.init_root::<root_capnp::hash_ref::Builder>();

                        // Populate directory hash and ChunkRef.
                        dir_hash_ref.populate_msg(hash_ref_root.borrow());
                        // Set as directory content.
                        try!(file_msg.borrow()
                            .init_content()
                            .set_directory(hash_ref_root.as_reader()));

                        hash_ch.send(dir_hash_ref.hash).unwrap();
                    }
                }
            }

            // Flush to our own tree when we have a decent amount.
            // The tree prevents large directories from clogging ram.
            if current_msg_is_empty {
                break;
            } else {
                let mut buf = vec![];
                try!(capnp::serialize_packed::write_message(&mut buf, &file_block_msg));
                try!(tree.append(&buf[..]));
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! The module contains the implementation of HTTP/2 frames.

/// A helper macro that unpacks a sequence of 4 bytes found in the buffer with
/// the given identifier, starting at the given offset, into the given integer
/// type. Obviously, the integer type should be able to support at least 4
/// bytes.
///
/// # Examples
///
/// ```rust
/// let buf: [u8; 4] = [0, 0, 0, 1];
/// assert_eq!(1u32, unpack_octets_4!(buf, 0, u32));
/// ```
macro_rules! unpack_octets_4 {
    ($buf:ident, $offset:expr, $tip:ty) => (
        (($buf[$offset + 0] as $tip) << 24) |
        (($buf[$offset + 1] as $tip) << 16) |
        (($buf[$offset + 2] as $tip) <<  8) |
        (($buf[$offset + 3] as $tip) <<  0)
    );
}

/// An alias for the 9-byte buffer that each HTTP/2 frame header must be stored
/// in.
type FrameHeaderBuffer = [u8; 9];
/// An alias for the 4-tuple representing the components of each HTTP/2 frame
/// header.
type FrameHeader = (u32, u8, u8, u32);

/// Deconstructs a `FrameHeader` into its corresponding 4 components,
/// represented as a 4-tuple: `(length, frame_type, flags, stream_id)`.
///
/// The frame `type` and `flags` components are returned as their original
/// octet representation, rather than reinterpreted.
fn unpack_header(header: &FrameHeaderBuffer) -> FrameHeader {
    let length: u32 = (
        ((header[0] as u32) << 16) |
        ((header[1] as u32) <<  8) |
        ((header[2] as u32) <<  0));
    let frame_type = header[3];
    let flags = header[4];
    let stream_id: u32 = unpack_octets_4!(header, 5, u32);

    (length, frame_type, flags, stream_id)
}

/// Constructs a buffer of 9 bytes that represents the given `FrameHeader`.
fn pack_header(header: &FrameHeader) -> FrameHeaderBuffer {
    let &(length, frame_type, flags, stream_id) = header;

    [
        (((length >> 16) & 0x000000FF) as u8),
        (((length >>  8) & 0x000000FF) as u8),
        (((length >>  0) & 0x000000FF) as u8),
        frame_type,
        flags,
        (((stream_id >> 24) & 0x000000FF) as u8),
        (((stream_id >> 16) & 0x000000FF) as u8),
        (((stream_id >>  8) & 0x000000FF) as u8),
        (((stream_id >>  0) & 0x000000FF) as u8),
    ]
}

/// An enum that lists all valid settings that can be sent in a SETTINGS
/// frame.
///
/// Each setting has a value that is a 32 bit unsigned integer (6.5.1.).
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
#[derive(Copy)]
pub enum HttpSetting {
    HeaderTableSize(u32),
    EnablePush(u32),
    MaxConcurrentStreams(u32),
    InitialWindowSize(u32),
    MaxFrameSize(u32),
    MaxHeaderListSize(u32),
}

impl HttpSetting {
    /// Creates a new `HttpSetting` with the correct variant corresponding to
    /// the given setting id, based on the settings IDs defined in section
    /// 6.5.2.
    pub fn from_id(id: u16, val: u32) -> Option<HttpSetting> {
        match id {
            1 => Some(HttpSetting::HeaderTableSize(val)),
            2 => Some(HttpSetting::EnablePush(val)),
            3 => Some(HttpSetting::MaxConcurrentStreams(val)),
            4 => Some(HttpSetting::InitialWindowSize(val)),
            5 => Some(HttpSetting::MaxFrameSize(val)),
            6 => Some(HttpSetting::MaxHeaderListSize(val)),
            _ => None,
        }
    }

    /// Creates a new `HttpSetting` by parsing the given buffer of 6 bytes,
    /// which contains the raw byte representation of the setting, according
    /// to the "SETTINGS format" defined in section 6.5.1.
    ///
    /// The `raw_setting` parameter should have length at least 6 bytes, since
    /// the length of the raw setting is exactly 6 bytes.
    ///
    /// # Panics
    ///
    /// If given a buffer shorter than 6 bytes, the function will panic.
    fn parse_setting(raw_setting: &[u8]) -> Option<HttpSetting> {
        let id: u16 = ((raw_setting[0] as u16) << 8) | (raw_setting[1] as u16);
        let val: u32 = unpack_octets_4!(raw_setting, 2, u32);

        HttpSetting::from_id(id, val)
    }

    /// Returns the setting ID as an unsigned 16 bit integer, as defined in
    /// section 6.5.2.
    pub fn get_id(&self) -> u16 {
        match self {
            &HttpSetting::HeaderTableSize(_) => 1,
            &HttpSetting::EnablePush(_) => 2,
            &HttpSetting::MaxConcurrentStreams(_) => 3,
            &HttpSetting::InitialWindowSize(_) => 4,
            &HttpSetting::MaxFrameSize(_) => 5,
            &HttpSetting::MaxHeaderListSize(_) => 6,
        }
    }

    /// Gets the setting value by unpacking it from the wrapped `u32`.
    pub fn get_val(&self) -> u32 {
        match self {
            &HttpSetting::HeaderTableSize(ref val) => val.clone(),
            &HttpSetting::EnablePush(ref val) => val.clone(),
            &HttpSetting::MaxConcurrentStreams(ref val) => val.clone(),
            &HttpSetting::InitialWindowSize(ref val) => val.clone(),
            &HttpSetting::MaxFrameSize(ref val) => val.clone(),
            &HttpSetting::MaxHeaderListSize(ref val) => val.clone(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{
        unpack_header,
        pack_header,
        HttpSetting,
    };

    /// Tests that the `unpack_header` function correctly returns the
    /// components of HTTP/2 frame headers.
    #[test]
    fn test_unpack_header() {
        {
            let header = [0; 9];
            assert_eq!((0, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 2, 3, 0, 0, 0, 4];
            assert_eq!((1, 2, 3, 4), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 200, 100, 0, 0, 0, 4];
            assert_eq!((1, 200, 100, 4), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 0, 0, 0, 0, 0, 0];
            assert_eq!((1, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 1, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!((256, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [1, 0, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!((256 * 256, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 0, 0, 0, 0, 0, 0, 0, 1];
            assert_eq!((0, 0, 0, 1), unpack_header(&header));
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1];
            assert_eq!(((1 << 24) - 1, 0, 0, 1), unpack_header(&header));
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1];
            assert_eq!(
                ((1 << 24) - 1, 0, 0, 1 + (1 << 8) + (1 << 16) + (1 << 24)),
                unpack_header(&header));
        }
    }

    /// Tests that the `pack_header` function correctly returns the buffer
    /// corresponding to components of HTTP/2 frame headers.
    #[test]
    fn test_pack_header() {
        {
            let header = [0; 9];
            assert_eq!(pack_header(&(0, 0, 0, 0)), header);
        }
        {
            let header = [0, 0, 1, 2, 3, 0, 0, 0, 4];
            assert_eq!(pack_header(&(1, 2, 3, 4)), header);
        }
        {
            let header = [0, 0, 1, 200, 100, 0, 0, 0, 4];
            assert_eq!(pack_header(&(1, 200, 100, 4)), header);
        }
        {
            let header = [0, 0, 1, 0, 0, 0, 0, 0, 0];
            assert_eq!(pack_header(&(1, 0, 0, 0)), header);
        }
        {
            let header = [0, 1, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!(pack_header(&(256, 0, 0, 0)), header);
        }
        {
            let header = [1, 0, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!(pack_header(&(256 * 256, 0, 0, 0)), header);
        }
        {
            let header = [0, 0, 0, 0, 0, 0, 0, 0, 1];
            assert_eq!(pack_header(&(0, 0, 0, 1)), header);
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1];
            assert_eq!(pack_header(&((1 << 24) - 1, 0, 0, 1)), header);
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1];
            let header_components = (
                (1 << 24) - 1, 0, 0, 1 + (1 << 8) + (1 << 16) + (1 << 24)
            );
            assert_eq!(pack_header(&header_components), header);
        }
    }

    /// Tests that the `HttpSetting::parse_setting` method correctly creates
    /// settings from raw bytes.
    #[test]
    fn test_setting_deserialize() {
        {
            let buf = [0, 1, 0, 0, 1, 0];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::HeaderTableSize(1 << 8));
        }
        {
            let buf = [0, 2, 0, 0, 0, 1];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::EnablePush(1));
        }
        {
            let buf = [0, 3, 0, 0, 0, 0];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::MaxConcurrentStreams(0));
        }
        {
            let buf = [0, 4, 0, 0, 0, 1];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::InitialWindowSize(1));
        }
        {
            let buf = [0, 5, 0, 0, 0, 255];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::MaxFrameSize((1 << 8) - 1));
        }
        {
            let buf = [0, 6, 0, 0, 0, 255];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::MaxHeaderListSize((1 << 8) - 1));
        }
        {
            let buf = [0, 7, 0, 0, 0, 255];

            let setting = HttpSetting::parse_setting(&buf);

            assert!(setting.is_none());
        }
        {
            let buf = [0, 0, 0, 0, 0, 255];

            let setting = HttpSetting::parse_setting(&buf);

            assert!(setting.is_none());
        }
    }
}
<commit_msg>Implement settings serialization to 6 byte buffers<commit_after>//! The module contains the implementation of HTTP/2 frames.

/// A helper macro that unpacks a sequence of 4 bytes found in the buffer with
/// the given identifier, starting at the given offset, into the given integer
/// type. Obviously, the integer type should be able to support at least 4
/// bytes.
///
/// # Examples
///
/// ```rust
/// let buf: [u8; 4] = [0, 0, 0, 1];
/// assert_eq!(1u32, unpack_octets_4!(buf, 0, u32));
/// ```
macro_rules! unpack_octets_4 {
    ($buf:ident, $offset:expr, $tip:ty) => (
        (($buf[$offset + 0] as $tip) << 24) |
        (($buf[$offset + 1] as $tip) << 16) |
        (($buf[$offset + 2] as $tip) <<  8) |
        (($buf[$offset + 3] as $tip) <<  0)
    );
}

/// An alias for the 9-byte buffer that each HTTP/2 frame header must be stored
/// in.
type FrameHeaderBuffer = [u8; 9];
/// An alias for the 4-tuple representing the components of each HTTP/2 frame
/// header.
type FrameHeader = (u32, u8, u8, u32);

/// Deconstructs a `FrameHeader` into its corresponding 4 components,
/// represented as a 4-tuple: `(length, frame_type, flags, stream_id)`.
///
/// The frame `type` and `flags` components are returned as their original
/// octet representation, rather than reinterpreted.
fn unpack_header(header: &FrameHeaderBuffer) -> FrameHeader {
    let length: u32 = (
        ((header[0] as u32) << 16) |
        ((header[1] as u32) <<  8) |
        ((header[2] as u32) <<  0));
    let frame_type = header[3];
    let flags = header[4];
    let stream_id: u32 = unpack_octets_4!(header, 5, u32);

    (length, frame_type, flags, stream_id)
}

/// Constructs a buffer of 9 bytes that represents the given `FrameHeader`.
fn pack_header(header: &FrameHeader) -> FrameHeaderBuffer {
    let &(length, frame_type, flags, stream_id) = header;

    [
        (((length >> 16) & 0x000000FF) as u8),
        (((length >>  8) & 0x000000FF) as u8),
        (((length >>  0) & 0x000000FF) as u8),
        frame_type,
        flags,
        (((stream_id >> 24) & 0x000000FF) as u8),
        (((stream_id >> 16) & 0x000000FF) as u8),
        (((stream_id >>  8) & 0x000000FF) as u8),
        (((stream_id >>  0) & 0x000000FF) as u8),
    ]
}

/// An enum that lists all valid settings that can be sent in a SETTINGS
/// frame.
///
/// Each setting has a value that is a 32 bit unsigned integer (6.5.1.).
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
#[derive(Copy)]
pub enum HttpSetting {
    HeaderTableSize(u32),
    EnablePush(u32),
    MaxConcurrentStreams(u32),
    InitialWindowSize(u32),
    MaxFrameSize(u32),
    MaxHeaderListSize(u32),
}

impl HttpSetting {
    /// Creates a new `HttpSetting` with the correct variant corresponding to
    /// the given setting id, based on the settings IDs defined in section
    /// 6.5.2.
    pub fn from_id(id: u16, val: u32) -> Option<HttpSetting> {
        match id {
            1 => Some(HttpSetting::HeaderTableSize(val)),
            2 => Some(HttpSetting::EnablePush(val)),
            3 => Some(HttpSetting::MaxConcurrentStreams(val)),
            4 => Some(HttpSetting::InitialWindowSize(val)),
            5 => Some(HttpSetting::MaxFrameSize(val)),
            6 => Some(HttpSetting::MaxHeaderListSize(val)),
            _ => None,
        }
    }

    /// Creates a new `HttpSetting` by parsing the given buffer of 6 bytes,
    /// which contains the raw byte representation of the setting, according
    /// to the "SETTINGS format" defined in section 6.5.1.
    ///
    /// The `raw_setting` parameter should have length at least 6 bytes, since
    /// the length of the raw setting is exactly 6 bytes.
    ///
    /// # Panics
    ///
    /// If given a buffer shorter than 6 bytes, the function will panic.
    fn parse_setting(raw_setting: &[u8]) -> Option<HttpSetting> {
        let id: u16 = ((raw_setting[0] as u16) << 8) | (raw_setting[1] as u16);
        let val: u32 = unpack_octets_4!(raw_setting, 2, u32);

        HttpSetting::from_id(id, val)
    }

    /// Returns the setting ID as an unsigned 16 bit integer, as defined in
    /// section 6.5.2.
    pub fn get_id(&self) -> u16 {
        match self {
            &HttpSetting::HeaderTableSize(_) => 1,
            &HttpSetting::EnablePush(_) => 2,
            &HttpSetting::MaxConcurrentStreams(_) => 3,
            &HttpSetting::InitialWindowSize(_) => 4,
            &HttpSetting::MaxFrameSize(_) => 5,
            &HttpSetting::MaxHeaderListSize(_) => 6,
        }
    }

    /// Gets the setting value by unpacking it from the wrapped `u32`.
    pub fn get_val(&self) -> u32 {
        match self {
            &HttpSetting::HeaderTableSize(ref val) => val.clone(),
            &HttpSetting::EnablePush(ref val) => val.clone(),
            &HttpSetting::MaxConcurrentStreams(ref val) => val.clone(),
            &HttpSetting::InitialWindowSize(ref val) => val.clone(),
            &HttpSetting::MaxFrameSize(ref val) => val.clone(),
            &HttpSetting::MaxHeaderListSize(ref val) => val.clone(),
        }
    }

    /// Serializes a setting into its "on-the-wire" representation of 6 octets,
    /// according to section 6.5.1.
    fn serialize(&self) -> [u8; 6] {
        let (id, val) = (self.get_id(), self.get_val());
        [
            ((id >> 8) & 0x00FF) as u8,
            ((id >> 0) & 0x00FF) as u8,
            (((val >> 24) & 0x000000FF) as u8),
            (((val >> 16) & 0x000000FF) as u8),
            (((val >>  8) & 0x000000FF) as u8),
            (((val >>  0) & 0x000000FF) as u8),
        ]
    }
}

#[cfg(test)]
mod tests {
    use super::{
        unpack_header,
        pack_header,
        HttpSetting,
    };

    /// Tests that the `unpack_header` function correctly returns the
    /// components of HTTP/2 frame headers.
    #[test]
    fn test_unpack_header() {
        {
            let header = [0; 9];
            assert_eq!((0, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 2, 3, 0, 0, 0, 4];
            assert_eq!((1, 2, 3, 4), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 200, 100, 0, 0, 0, 4];
            assert_eq!((1, 200, 100, 4), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 0, 0, 0, 0, 0, 0];
            assert_eq!((1, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 1, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!((256, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [1, 0, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!((256 * 256, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 0, 0, 0, 0, 0, 0, 0, 1];
            assert_eq!((0, 0, 0, 1), unpack_header(&header));
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1];
            assert_eq!(((1 << 24) - 1, 0, 0, 1), unpack_header(&header));
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1];
            assert_eq!(
                ((1 << 24) - 1, 0, 0, 1 + (1 << 8) + (1 << 16) + (1 << 24)),
                unpack_header(&header));
        }
    }

    /// Tests that the `pack_header` function correctly returns the buffer
    /// corresponding to components of HTTP/2 frame headers.
    #[test]
    fn test_pack_header() {
        {
            let header = [0; 9];
            assert_eq!(pack_header(&(0, 0, 0, 0)), header);
        }
        {
            let header = [0, 0, 1, 2, 3, 0, 0, 0, 4];
            assert_eq!(pack_header(&(1, 2, 3, 4)), header);
        }
        {
            let header = [0, 0, 1, 200, 100, 0, 0, 0, 4];
            assert_eq!(pack_header(&(1, 200, 100, 4)), header);
        }
        {
            let header = [0, 0, 1, 0, 0, 0, 0, 0, 0];
            assert_eq!(pack_header(&(1, 0, 0, 0)), header);
        }
        {
            let header = [0, 1, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!(pack_header(&(256, 0, 0, 0)), header);
        }
        {
            let header = [1, 0, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!(pack_header(&(256 * 256, 0, 0, 0)), header);
        }
        {
            let header = [0, 0, 0, 0, 0, 0, 0, 0, 1];
            assert_eq!(pack_header(&(0, 0, 0, 1)), header);
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1];
            assert_eq!(pack_header(&((1 << 24) - 1, 0, 0, 1)), header);
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1];
            let header_components = (
                (1 << 24) - 1, 0, 0, 1 + (1 << 8) + (1 << 16) + (1 << 24)
            );
            assert_eq!(pack_header(&header_components), header);
        }
    }

    /// Tests that the `HttpSetting::parse_setting` method correctly creates
    /// settings from raw bytes.
    #[test]
    fn test_setting_deserialize() {
        {
            let buf = [0, 1, 0, 0, 1, 0];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::HeaderTableSize(1 << 8));
        }
        {
            let buf = [0, 2, 0, 0, 0, 1];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::EnablePush(1));
        }
        {
            let buf = [0, 3, 0, 0, 0, 0];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::MaxConcurrentStreams(0));
        }
        {
            let buf = [0, 4, 0, 0, 0, 1];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::InitialWindowSize(1));
        }
        {
            let buf = [0, 5, 0, 0, 0, 255];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::MaxFrameSize((1 << 8) - 1));
        }
        {
            let buf = [0, 6, 0, 0, 0, 255];

            let setting = HttpSetting::parse_setting(&buf).unwrap();

            assert_eq!(setting, HttpSetting::MaxHeaderListSize((1 << 8) - 1));
        }
        {
            let buf = [0, 7, 0, 0, 0, 255];

            let setting = HttpSetting::parse_setting(&buf);

            assert!(setting.is_none());
        }
        {
            let buf = [0, 0, 0, 0, 0, 255];

            let setting = HttpSetting::parse_setting(&buf);

            assert!(setting.is_none());
        }
    }

    /// Tests that the `HttpSetting::serialize` method correctly creates
    /// a 6 byte buffer based on the given setting.
    #[test]
    fn test_setting_serialize() {
        {
            let buf = [0, 1, 0, 0, 1, 0];

            let setting = HttpSetting::HeaderTableSize(1 << 8);

            assert_eq!(buf, setting.serialize());
        }
        {
            let buf = [0, 2, 0, 0, 0, 1];

            let setting = HttpSetting::EnablePush(1);

            assert_eq!(buf, setting.serialize());
        }
        {
            let buf = [0, 3, 0, 0, 0, 0];

            let setting = HttpSetting::MaxConcurrentStreams(0);

            assert_eq!(buf, setting.serialize());
        }
        {
            let buf = [0, 4, 0, 0, 0, 1];

            let setting = HttpSetting::InitialWindowSize(1);

            assert_eq!(buf, setting.serialize());
        }
        {
            let buf = [0, 5, 0, 0, 0, 255];

            let setting = HttpSetting::MaxFrameSize((1 << 8) - 1);

            assert_eq!(buf, setting.serialize());
        }
        {
            let buf = [0, 6, 0, 0, 0, 255];

            let setting = HttpSetting::MaxHeaderListSize((1 << 8) - 1);

            assert_eq!(buf, setting.serialize());
        }
    }
}
<|endoftext|>