<commit_before>use std::ops::{Neg, Add, AddAssign, Sub, SubAssign, Mul, MulAssign};
use std::cmp::Ordering;
use rand::{Rand, Rng};
use serde::{Serialize, Deserialize};

// The field size.
const P: u128 = (1 << 127) - 1;

// A finite field element.
//
// It is consistent iff 0 <= self.0 <= P.
// Note that this implies that the zero element has two internal representations.
#[derive(Clone, Copy, Default, Debug)]
pub struct Fp(u128);

impl Serialize for Fp {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ::serde::Serializer
    {
        use serde::ser::SerializeTuple;

        // TODO serde currently does not support u128 natively
        let (h, l) = as_limbs(u128::from(*self));
        let mut tup = serializer.serialize_tuple(2)?;
        tup.serialize_element(&h)?;
        tup.serialize_element(&l)?;
        tup.end()
    }
}

impl<'de> Deserialize<'de> for Fp {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<Fp, D::Error>
        where D: ::serde::Deserializer<'de>
    {
        use serde::de;

        // TODO serde currently does not support u128 natively
        struct Visitor;
        impl<'de> ::serde::de::Visitor<'de> for Visitor {
            type Value = Fp;

            fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                formatter.write_str("a pair (h, l) of u64 representing an u128 x = h||l \
                                    such that 0 <= x < p where p = 2**127 - 1")
            }

            fn visit_seq<A>(self, mut a: A) -> Result<Fp, A::Error>
                where A: de::SeqAccess<'de>
            {
                let h: u64 = a.next_element()?.ok_or(de::Error::invalid_length(0, &self))?;
                let l: u64 = a.next_element()?.ok_or(de::Error::invalid_length(1, &self))?;
                let x = ((h as u128) << 64) | (l as u128);
                if x >= P {
                    let unexp_str = format!("the u128 with value {:x}", x);
                    let unexp = de::Unexpected::Other(&unexp_str);
                    return Err(de::Error::invalid_value(unexp, &self));
                }
                Ok(Fp::from_u127(x))
            }
        }

        deserializer.deserialize_tuple(2, Visitor { })
    }
}

#[inline]
fn as_limbs(x: u128) -> (u64, u64) {
    ((x >> 64) as u64, x as u64)
}

trait Reduce: Sized {
    fn reduce_once(self) -> u128;

    #[inline]
    fn reduce_once_assert(self) -> u128 {
        let red: u128 = self.reduce_once();
        debug_assert!(red <= P);
        red
    }
}

impl Reduce for u128 {
    #[inline]
    fn reduce_once(self) -> u128 {
        (self & P) + (self >> 127)
    }
}

impl Reduce for (u128, u128) {
    #[inline]
    fn reduce_once(self) -> u128 {
        let (h, l) = self;
        // shift = (h, l) >> 127
        let shift = (h << 1) | (l >> 127);
        (l & P) + shift
    }
}

impl Fp {
    #[inline]
    pub fn from_u127(x: u128) -> Self {
        // x == P is explicitly allowed.
        // This introduces a negligible bias towards the zero element
        // if x is uniformly random from {0,1}^127.
        debug_assert!(x <= P);
        Fp(x)
    }

    #[inline]
    pub fn from_u128_discard_msb(x: u128) -> Self {
        Self::from_u127(x & P)
    }

    #[inline]
    pub fn prime() -> u128 {
        P
    }
}

impl From<Fp> for u128 {
    #[inline]
    fn from(x: Fp) -> u128 {
        if x.0 == P { 0 } else { x.0 }
    }
}

impl Rand for Fp {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Self {
        Self::from_u128_discard_msb(rng.gen::<u128>())
    }

}

impl Neg for Fp {
    type Output = Self;
    #[inline]
    fn neg(self) -> Self {
        Fp(P - self.0)
    }
}

impl Add for Fp {
    type Output = Self;
    #[inline]
    fn add(self, other: Self) -> Self {
        Fp((self.0 + other.0).reduce_once_assert())
    }
}

impl AddAssign for Fp {
    #[inline]
    fn add_assign(&mut self, other: Self) {
        *self = *self + other
    }
}

impl Sub for Fp {
    type Output = Self;
    #[inline]
    fn sub(self, other: Self) -> Self {
        self + (-other)
    }
}

impl SubAssign for Fp {
    #[inline]
    fn sub_assign(&mut self, other: Self) {
        *self = *self - other
    }
}

impl Mul for Fp {
    type Output = Self;
    #[inline]
    fn mul(self, other: Self) -> Self {
        let (sh, sl) = as_limbs(self.0);
        let (oh, ol) = as_limbs(other.0);

        // (64 bits * 63 bits) + (64 bits * 63 bits) = 128 bits
        let m: u128 = (sh as u128 * ol as u128) + (oh as u128 * sl as u128);
        let (mh, ml) = as_limbs(m);

        // (64 bits * 64 bits) + 128 bits = 129 bits
        let (rl, carry) = (sl as u128 * ol as u128).overflowing_add((ml as u128) << 64);

        // (63 bits * 63 bits) + 64 bits + 1 bit = 127 bits
        let rh: u128 = (sh as u128 * oh as u128) + (mh as u128) + (carry as u128);

        Fp((rh, rl).reduce_once().reduce_once_assert())
    }
}

impl MulAssign for Fp {
    #[inline]
    fn mul_assign(&mut self, other: Self) {
        *self = *self * other
    }
}

impl PartialEq for Fp {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        u128::from(*self) == u128::from(*other)
    }
}

impl Eq for Fp {}

impl PartialOrd for Fp {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        u128::from(*self).partial_cmp(&u128::from(*other))
    }
}

impl Ord for Fp {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(&other).unwrap()
    }
}

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

    #[test]
    fn neg() {
        assert_eq!(-Fp(0), Fp(0));
        assert_eq!(-Fp(5), Fp(P - 5));
    }

    #[test]
    fn add() {
        assert_eq!(Fp(7) + Fp(5), Fp(12));
        assert_eq!(Fp(P - 2) + Fp(5), Fp(3));
        assert_eq!(
            Fp(75661398932549814984099328258351945610) + Fp(154440289138086217180118920884960981429),
            Fp(59960504610166800432530945427428821312)
        );
    }

    #[test]
    fn sub() {
        assert_eq!(Fp(7) - Fp(5), Fp(2));
        assert_eq!(Fp(4) - Fp(8), Fp(P - 4));
    }

    #[test]
    fn mul() {
        assert_eq!(Fp(4) * Fp(3), Fp(12));
        assert_eq!(Fp(P) * Fp(291298091), Fp(0));
        assert_eq!(
            Fp(14766549069271113692204649107775507741) * Fp(153613967287097206589234951623852979690),
            Fp(113548737858505840193892055835373785352)
        );
        // Two reductions are necessary for the following example.
        assert_eq!(
            Fp(75661398932549814984099328258351945610) * Fp(154440289138086217180118920884960981429),
            Fp(109146875586984049909139102289297416971)
        );
    }

    #[test]
    fn eq() {
        assert_eq!(Fp(0), Fp(P));
        assert!(Fp(17) != Fp(4));
        assert!(Fp(0) != Fp(4));
        assert!(Fp(P) != Fp(17));
    }

    #[test]
    fn assign() {
        let mut a = Fp(17);

        a += Fp(3);
        assert_eq!(a, Fp(20));

        a -= Fp(5);
        assert_eq!(a, Fp(15));

        a *= Fp(2);
        assert_eq!(a, Fp(30));
    }
}
<commit_msg>Add test for Fp ordering<commit_after>use std::ops::{Neg, Add, AddAssign, Sub, SubAssign, Mul, MulAssign};
use std::cmp::Ordering;
use rand::{Rand, Rng};
use serde::{Serialize, Deserialize};

// The field size.
const P: u128 = (1 << 127) - 1;

// A finite field element.
//
// It is consistent iff 0 <= self.0 <= P.
// Note that this implies that the zero element has two internal representations.
#[derive(Clone, Copy, Default, Debug)]
pub struct Fp(u128);

impl Serialize for Fp {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ::serde::Serializer
    {
        use serde::ser::SerializeTuple;

        // TODO serde currently does not support u128 natively
        let (h, l) = as_limbs(u128::from(*self));
        let mut tup = serializer.serialize_tuple(2)?;
        tup.serialize_element(&h)?;
        tup.serialize_element(&l)?;
        tup.end()
    }
}

impl<'de> Deserialize<'de> for Fp {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<Fp, D::Error>
        where D: ::serde::Deserializer<'de>
    {
        use serde::de;

        // TODO serde currently does not support u128 natively
        struct Visitor;
        impl<'de> ::serde::de::Visitor<'de> for Visitor {
            type Value = Fp;

            fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                formatter.write_str("a pair (h, l) of u64 representing an u128 x = h||l \
                                    such that 0 <= x < p where p = 2**127 - 1")
            }

            fn visit_seq<A>(self, mut a: A) -> Result<Fp, A::Error>
                where A: de::SeqAccess<'de>
            {
                let h: u64 = a.next_element()?.ok_or(de::Error::invalid_length(0, &self))?;
                let l: u64 = a.next_element()?.ok_or(de::Error::invalid_length(1, &self))?;
                let x = ((h as u128) << 64) | (l as u128);
                if x >= P {
                    let unexp_str = format!("the u128 with value {:x}", x);
                    let unexp = de::Unexpected::Other(&unexp_str);
                    return Err(de::Error::invalid_value(unexp, &self));
                }
                Ok(Fp::from_u127(x))
            }
        }

        deserializer.deserialize_tuple(2, Visitor { })
    }
}

#[inline]
fn as_limbs(x: u128) -> (u64, u64) {
    ((x >> 64) as u64, x as u64)
}

trait Reduce: Sized {
    fn reduce_once(self) -> u128;

    #[inline]
    fn reduce_once_assert(self) -> u128 {
        let red: u128 = self.reduce_once();
        debug_assert!(red <= P);
        red
    }
}

impl Reduce for u128 {
    #[inline]
    fn reduce_once(self) -> u128 {
        (self & P) + (self >> 127)
    }
}

impl Reduce for (u128, u128) {
    #[inline]
    fn reduce_once(self) -> u128 {
        let (h, l) = self;
        // shift = (h, l) >> 127
        let shift = (h << 1) | (l >> 127);
        (l & P) + shift
    }
}

impl Fp {
    #[inline]
    pub fn from_u127(x: u128) -> Self {
        // x == P is explicitly allowed.
        // This introduces a negligible bias towards the zero element
        // if x is uniformly random from {0,1}^127.
        debug_assert!(x <= P);
        Fp(x)
    }

    #[inline]
    pub fn from_u128_discard_msb(x: u128) -> Self {
        Self::from_u127(x & P)
    }

    #[inline]
    pub fn prime() -> u128 {
        P
    }
}

impl From<Fp> for u128 {
    #[inline]
    fn from(x: Fp) -> u128 {
        if x.0 == P { 0 } else { x.0 }
    }
}

impl Rand for Fp {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Self {
        Self::from_u128_discard_msb(rng.gen::<u128>())
    }

}

impl Neg for Fp {
    type Output = Self;
    #[inline]
    fn neg(self) -> Self {
        Fp(P - self.0)
    }
}

impl Add for Fp {
    type Output = Self;
    #[inline]
    fn add(self, other: Self) -> Self {
        Fp((self.0 + other.0).reduce_once_assert())
    }
}

impl AddAssign for Fp {
    #[inline]
    fn add_assign(&mut self, other: Self) {
        *self = *self + other
    }
}

impl Sub for Fp {
    type Output = Self;
    #[inline]
    fn sub(self, other: Self) -> Self {
        self + (-other)
    }
}

impl SubAssign for Fp {
    #[inline]
    fn sub_assign(&mut self, other: Self) {
        *self = *self - other
    }
}

impl Mul for Fp {
    type Output = Self;
    #[inline]
    fn mul(self, other: Self) -> Self {
        let (sh, sl) = as_limbs(self.0);
        let (oh, ol) = as_limbs(other.0);

        // (64 bits * 63 bits) + (64 bits * 63 bits) = 128 bits
        let m: u128 = (sh as u128 * ol as u128) + (oh as u128 * sl as u128);
        let (mh, ml) = as_limbs(m);

        // (64 bits * 64 bits) + 128 bits = 129 bits
        let (rl, carry) = (sl as u128 * ol as u128).overflowing_add((ml as u128) << 64);

        // (63 bits * 63 bits) + 64 bits + 1 bit = 127 bits
        let rh: u128 = (sh as u128 * oh as u128) + (mh as u128) + (carry as u128);

        Fp((rh, rl).reduce_once().reduce_once_assert())
    }
}

impl MulAssign for Fp {
    #[inline]
    fn mul_assign(&mut self, other: Self) {
        *self = *self * other
    }
}

impl PartialEq for Fp {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        u128::from(*self) == u128::from(*other)
    }
}

impl Eq for Fp {}

impl PartialOrd for Fp {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        u128::from(*self).partial_cmp(&u128::from(*other))
    }
}

impl Ord for Fp {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(&other).unwrap()
    }
}

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

    #[test]
    fn neg() {
        assert_eq!(-Fp(0), Fp(0));
        assert_eq!(-Fp(5), Fp(P - 5));
    }

    #[test]
    fn add() {
        assert_eq!(Fp(7) + Fp(5), Fp(12));
        assert_eq!(Fp(P - 2) + Fp(5), Fp(3));
        assert_eq!(
            Fp(75661398932549814984099328258351945610) + Fp(154440289138086217180118920884960981429),
            Fp(59960504610166800432530945427428821312)
        );
    }

    #[test]
    fn sub() {
        assert_eq!(Fp(7) - Fp(5), Fp(2));
        assert_eq!(Fp(4) - Fp(8), Fp(P - 4));
    }

    #[test]
    fn mul() {
        assert_eq!(Fp(4) * Fp(3), Fp(12));
        assert_eq!(Fp(P) * Fp(291298091), Fp(0));
        assert_eq!(
            Fp(14766549069271113692204649107775507741) * Fp(153613967287097206589234951623852979690),
            Fp(113548737858505840193892055835373785352)
        );
        // Two reductions are necessary for the following example.
        assert_eq!(
            Fp(75661398932549814984099328258351945610) * Fp(154440289138086217180118920884960981429),
            Fp(109146875586984049909139102289297416971)
        );
    }

    #[test]
    fn eq() {
        assert_eq!(Fp(0), Fp(P));
        assert!(Fp(17) != Fp(4));
        assert!(Fp(0) != Fp(4));
        assert!(Fp(P) != Fp(17));
    }

    #[test]
    fn ord() {
        assert!(Fp(0) < Fp(1));
        assert!(Fp(17) > Fp(0));
        assert!(Fp(P) < Fp(1));
        assert!(Fp(23) > Fp(P));
    }

    #[test]
    fn assign() {
        let mut a = Fp(17);

        a += Fp(3);
        assert_eq!(a, Fp(20));

        a -= Fp(5);
        assert_eq!(a, Fp(15));

        a *= Fp(2);
        assert_eq!(a, Fp(30));
    }
}
<|endoftext|>


<commit_before>use super::CrateVersion;
use serde_json;
use std::path::Path;

use git2::{
    build::RepoBuilder, Delta, DiffFormat, Error as GitError, ErrorClass, Object, ObjectType, Oid,
    Reference, Repository, Tree,
};
use std::str;

static INDEX_GIT_URL: &str = "https://github.com/rust-lang/crates.io-index";
static LAST_SEEN_REFNAME: &str = "refs/heads/crates-index-diff_last-seen";
static EMPTY_TREE_HASH: &str = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
static LINE_ADDED_INDICATOR: char = '+';

/// A wrapper for a repository of the crates.io index.
pub struct Index {
    /// The name and path of the reference used to keep track of the last seen state of the
    /// crates.io repository. The default value is `refs/heads/crates-index-diff_last-seen`.
    pub seen_ref_name: &'static str,
    /// The crates.io repository.
    repo: Repository,
}

/// Options for use in `Index::from_path_or_cloned_with_options`
pub struct CloneOptions {
    pub repository_url: String,
}

impl Default for CloneOptions {
    fn default() -> Self {
        CloneOptions {
            repository_url: INDEX_GIT_URL.into(),
        }
    }
}

impl Index {
    /// Return the crates.io repository.
    pub fn repository(&self) -> &Repository {
        &self.repo
    }

    /// Return the reference pointing to the state we have seen after calling `fetch_changes()`.
    pub fn last_seen_reference(&self) -> Result<Reference, GitError> {
        self.repo.find_reference(self.seen_ref_name)
    }

    /// Return a new `Index` instance from the given `path`, which should contain a bare or non-bare
    /// clone of the `crates.io` index.
    /// If the directory does not contain the repository or does not exist, it will be cloned from
    /// the official location automatically (with complete history).
    ///
    /// An error will occour if the repository exists and the remote URL does not match the given repository URL.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use crates_index_diff::{CloneOptions, Index};
    ///
    /// # let path = tempdir::TempDir::new("index").unwrap();
    /// let mut options = CloneOptions {
    ///   repository_url: "https://github.com/rust-lang/staging.crates.io-index".into(),
    ///   ..Default::default()
    /// };
    ///
    ///
    /// let index = Index::from_path_or_cloned_with_options(path, options)?;
    /// # Ok::<(), git2::Error>(())
    /// ```
    pub fn from_path_or_cloned_with_options(
        path: impl AsRef<Path>,
        options: CloneOptions,
    ) -> Result<Index, GitError> {
        let mut repo_did_exist = true;
        let repo = Repository::open(path.as_ref()).or_else(|err| {
            if err.class() == ErrorClass::Repository {
                repo_did_exist = false;
                RepoBuilder::new()
                    .bare(true)
                    .clone(&options.repository_url, path.as_ref())
            } else {
                Err(err)
            }
        })?;

        if repo_did_exist {
            let remote = repo.find_remote("origin")?;
            let actual_remote_url = remote
                .url()
                .ok_or_else(|| GitError::from_str("did not obtain URL of remote named 'origin'"))?;
            if actual_remote_url != options.repository_url {
                return Err(GitError::from_str(&format!(
                    "Actual 'origin' remote url {:#?} did not match desired one at {:#?}",
                    actual_remote_url, options.repository_url
                )));
            }
        }

        Ok(Index {
            repo,
            seen_ref_name: LAST_SEEN_REFNAME,
        })
    }

    /// Return a new `Index` instance from the given `path`, which should contain a bare or non-bare
    /// clone of the `crates.io` index.
    /// If the directory does not contain the repository or does not exist, it will be cloned from
    /// the official location automatically (with complete history).
    pub fn from_path_or_cloned(path: impl AsRef<Path>) -> Result<Index, GitError> {
        Index::from_path_or_cloned_with_options(path, CloneOptions::default())
    }

    /// As `peek_changes_with_options`, but without the options.
    pub fn peek_changes(&self) -> Result<(Vec<CrateVersion>, git2::Oid), GitError> {
        self.peek_changes_with_options(None)
    }

    /// Return all `CrateVersion`s that are observed between the last time `fetch_changes(…)` was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will not be created or updated.
    /// The second field in the returned tuple is the commit object to which the changes were provided.
    /// If one would set the `last_seen_reference()` to that object, the effect is exactly the same
    /// as if `fetch_changes(…)` had been called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn peek_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<(Vec<CrateVersion>, git2::Oid), GitError> {
        let from = self
            .last_seen_reference()
            .and_then(|r| {
                r.target().ok_or_else(|| {
                    GitError::from_str("last-seen reference did not have a valid target")
                })
            })
            .or_else(|_| Oid::from_str(EMPTY_TREE_HASH))?;
        let to = {
            self.repo.find_remote("origin").and_then(|mut r| {
                r.fetch(&["refs/heads/*:refs/remotes/origin/*"], options, None)
            })?;
            let latest_fetched_commit_oid =
                self.repo.refname_to_id("refs/remotes/origin/master")?;
            latest_fetched_commit_oid
        };

        Ok((
            self.changes_from_objects(
                &self.repo.find_object(from, None)?,
                &self.repo.find_object(to, None)?,
            )?,
            to,
        ))
    }

    /// As `fetch_changes_with_options`, but without the options.
    pub fn fetch_changes(&self) -> Result<Vec<CrateVersion>, GitError> {
        self.fetch_changes_with_options(None)
    }

    /// Return all `CrateVersion`s that are observed between the last time this method was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will be created or adjusted to point to the latest fetched
    /// state, which causes this method to have a different result each time it is called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn fetch_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<Vec<CrateVersion>, GitError> {
        let (changes, to) = self.peek_changes_with_options(options)?;
        self.set_last_seen_reference(to)?;
        Ok(changes)
    }

    /// Set the last seen reference to the given Oid. It will be created if it does not yet exists.
    pub fn set_last_seen_reference(&self, to: Oid) -> Result<(), GitError> {
        self.last_seen_reference()
            .and_then(|mut seen_ref| {
                seen_ref.set_target(to, "updating seen-ref head to latest fetched commit")
            })
            .or_else(|_err| {
                self.repo.reference(
                    self.seen_ref_name,
                    to,
                    true,
                    "creating seen-ref at latest fetched commit",
                )
            })?;
        Ok(())
    }

    /// Return all `CreateVersion`s observed between `from` and `to`. Both parameter are ref-specs
    /// pointing to either a commit or a tree.
    /// Learn more about specifying revisions
    /// in the
    /// [official documentation](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html)
    pub fn changes(
        &self,
        from: impl AsRef<str>,
        to: impl AsRef<str>,
    ) -> Result<Vec<CrateVersion>, GitError> {
        self.changes_from_objects(
            &self.repo.revparse_single(from.as_ref())?,
            &self.repo.revparse_single(to.as_ref())?,
        )
    }

    /// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
    /// to either `Commit`s or `Tree`s.
    pub fn changes_from_objects(
        &self,
        from: &Object,
        to: &Object,
    ) -> Result<Vec<CrateVersion>, GitError> {
        fn into_tree<'a>(repo: &'a Repository, obj: &Object) -> Result<Tree<'a>, GitError> {
            repo.find_tree(match obj.kind() {
                Some(ObjectType::Commit) => obj
                    .as_commit()
                    .expect("object of kind commit yields commit")
                    .tree_id(),
                _ =>
                /* let it possibly fail later */
                {
                    obj.id()
                }
            })
        }
        let diff = self.repo.diff_tree_to_tree(
            Some(&into_tree(&self.repo, from)?),
            Some(&into_tree(&self.repo, to)?),
            None,
        )?;
        let mut res: Vec<CrateVersion> = Vec::new();
        diff.print(DiffFormat::Patch, |delta, _, diffline| {
            if diffline.origin() != LINE_ADDED_INDICATOR {
                return true;
            }

            if !match delta.status() {
                Delta::Added | Delta::Modified => true,
                _ => false,
            } {
                return true;
            }

            if let Ok(c) = serde_json::from_slice(diffline.content()) {
                res.push(c)
            }
            true
        })
        .map(|_| res)
    }
}
<commit_msg>Pass FetchOptions for cloning<commit_after>use super::CrateVersion;
use serde_json;
use std::path::Path;

use git2::{
    build::RepoBuilder, Delta, DiffFormat, Error as GitError, ErrorClass, Object, ObjectType, Oid,
    Reference, Repository, Tree,
};
use std::str;

static INDEX_GIT_URL: &str = "https://github.com/rust-lang/crates.io-index";
static LAST_SEEN_REFNAME: &str = "refs/heads/crates-index-diff_last-seen";
static EMPTY_TREE_HASH: &str = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
static LINE_ADDED_INDICATOR: char = '+';

/// A wrapper for a repository of the crates.io index.
pub struct Index {
    /// The name and path of the reference used to keep track of the last seen state of the
    /// crates.io repository. The default value is `refs/heads/crates-index-diff_last-seen`.
    pub seen_ref_name: &'static str,
    /// The crates.io repository.
    repo: Repository,
}

/// Options for use in `Index::from_path_or_cloned_with_options`
pub struct CloneOptions<'a> {
    pub repository_url: String,
    pub fetch_options: Option<git2::FetchOptions<'a>>,
}

impl<'a> Default for CloneOptions<'a> {
    fn default() -> Self {
        CloneOptions {
            repository_url: INDEX_GIT_URL.into(),
            fetch_options: None,
        }
    }
}

impl Index {
    /// Return the crates.io repository.
    pub fn repository(&self) -> &Repository {
        &self.repo
    }

    /// Return the reference pointing to the state we have seen after calling `fetch_changes()`.
    pub fn last_seen_reference(&self) -> Result<Reference, GitError> {
        self.repo.find_reference(self.seen_ref_name)
    }

    /// Return a new `Index` instance from the given `path`, which should contain a bare or non-bare
    /// clone of the `crates.io` index.
    /// If the directory does not contain the repository or does not exist, it will be cloned from
    /// the official location automatically (with complete history).
    ///
    /// An error will occour if the repository exists and the remote URL does not match the given repository URL.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use crates_index_diff::{CloneOptions, Index};
    ///
    /// # let path = tempdir::TempDir::new("index").unwrap();
    /// let mut options = CloneOptions {
    ///   repository_url: "https://github.com/rust-lang/staging.crates.io-index".into(),
    ///   ..Default::default()
    /// };
    ///
    ///
    /// let index = Index::from_path_or_cloned_with_options(path, options)?;
    /// # Ok::<(), git2::Error>(())
    /// ```
    pub fn from_path_or_cloned_with_options(
        path: impl AsRef<Path>,
        CloneOptions {
            repository_url,
            fetch_options,
        }: CloneOptions,
    ) -> Result<Index, GitError> {
        let mut repo_did_exist = true;
        let repo = Repository::open(path.as_ref()).or_else(|err| {
            if err.class() == ErrorClass::Repository {
                repo_did_exist = false;
                let mut builder = RepoBuilder::new();
                if let Some(fo) = fetch_options {
                    builder.fetch_options(fo);
                }
                builder.bare(true).clone(&repository_url, path.as_ref())
            } else {
                Err(err)
            }
        })?;

        if repo_did_exist {
            let remote = repo.find_remote("origin")?;
            let actual_remote_url = remote
                .url()
                .ok_or_else(|| GitError::from_str("did not obtain URL of remote named 'origin'"))?;
            if actual_remote_url != repository_url {
                return Err(GitError::from_str(&format!(
                    "Actual 'origin' remote url {:#?} did not match desired one at {:#?}",
                    actual_remote_url, repository_url
                )));
            }
        }

        Ok(Index {
            repo,
            seen_ref_name: LAST_SEEN_REFNAME,
        })
    }

    /// Return a new `Index` instance from the given `path`, which should contain a bare or non-bare
    /// clone of the `crates.io` index.
    /// If the directory does not contain the repository or does not exist, it will be cloned from
    /// the official location automatically (with complete history).
    pub fn from_path_or_cloned(path: impl AsRef<Path>) -> Result<Index, GitError> {
        Index::from_path_or_cloned_with_options(path, CloneOptions::default())
    }

    /// As `peek_changes_with_options`, but without the options.
    pub fn peek_changes(&self) -> Result<(Vec<CrateVersion>, git2::Oid), GitError> {
        self.peek_changes_with_options(None)
    }

    /// Return all `CrateVersion`s that are observed between the last time `fetch_changes(…)` was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will not be created or updated.
    /// The second field in the returned tuple is the commit object to which the changes were provided.
    /// If one would set the `last_seen_reference()` to that object, the effect is exactly the same
    /// as if `fetch_changes(…)` had been called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn peek_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<(Vec<CrateVersion>, git2::Oid), GitError> {
        let from = self
            .last_seen_reference()
            .and_then(|r| {
                r.target().ok_or_else(|| {
                    GitError::from_str("last-seen reference did not have a valid target")
                })
            })
            .or_else(|_| Oid::from_str(EMPTY_TREE_HASH))?;
        let to = {
            self.repo.find_remote("origin").and_then(|mut r| {
                r.fetch(&["refs/heads/*:refs/remotes/origin/*"], options, None)
            })?;
            let latest_fetched_commit_oid =
                self.repo.refname_to_id("refs/remotes/origin/master")?;
            latest_fetched_commit_oid
        };

        Ok((
            self.changes_from_objects(
                &self.repo.find_object(from, None)?,
                &self.repo.find_object(to, None)?,
            )?,
            to,
        ))
    }

    /// As `fetch_changes_with_options`, but without the options.
    pub fn fetch_changes(&self) -> Result<Vec<CrateVersion>, GitError> {
        self.fetch_changes_with_options(None)
    }

    /// Return all `CrateVersion`s that are observed between the last time this method was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will be created or adjusted to point to the latest fetched
    /// state, which causes this method to have a different result each time it is called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn fetch_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<Vec<CrateVersion>, GitError> {
        let (changes, to) = self.peek_changes_with_options(options)?;
        self.set_last_seen_reference(to)?;
        Ok(changes)
    }

    /// Set the last seen reference to the given Oid. It will be created if it does not yet exists.
    pub fn set_last_seen_reference(&self, to: Oid) -> Result<(), GitError> {
        self.last_seen_reference()
            .and_then(|mut seen_ref| {
                seen_ref.set_target(to, "updating seen-ref head to latest fetched commit")
            })
            .or_else(|_err| {
                self.repo.reference(
                    self.seen_ref_name,
                    to,
                    true,
                    "creating seen-ref at latest fetched commit",
                )
            })?;
        Ok(())
    }

    /// Return all `CreateVersion`s observed between `from` and `to`. Both parameter are ref-specs
    /// pointing to either a commit or a tree.
    /// Learn more about specifying revisions
    /// in the
    /// [official documentation](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html)
    pub fn changes(
        &self,
        from: impl AsRef<str>,
        to: impl AsRef<str>,
    ) -> Result<Vec<CrateVersion>, GitError> {
        self.changes_from_objects(
            &self.repo.revparse_single(from.as_ref())?,
            &self.repo.revparse_single(to.as_ref())?,
        )
    }

    /// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
    /// to either `Commit`s or `Tree`s.
    pub fn changes_from_objects(
        &self,
        from: &Object,
        to: &Object,
    ) -> Result<Vec<CrateVersion>, GitError> {
        fn into_tree<'a>(repo: &'a Repository, obj: &Object) -> Result<Tree<'a>, GitError> {
            repo.find_tree(match obj.kind() {
                Some(ObjectType::Commit) => obj
                    .as_commit()
                    .expect("object of kind commit yields commit")
                    .tree_id(),
                _ =>
                /* let it possibly fail later */
                {
                    obj.id()
                }
            })
        }
        let diff = self.repo.diff_tree_to_tree(
            Some(&into_tree(&self.repo, from)?),
            Some(&into_tree(&self.repo, to)?),
            None,
        )?;
        let mut res: Vec<CrateVersion> = Vec::new();
        diff.print(DiffFormat::Patch, |delta, _, diffline| {
            if diffline.origin() != LINE_ADDED_INDICATOR {
                return true;
            }

            if !match delta.status() {
                Delta::Added | Delta::Modified => true,
                _ => false,
            } {
                return true;
            }

            if let Ok(c) = serde_json::from_slice(diffline.content()) {
                res.push(c)
            }
            true
        })
        .map(|_| res)
    }
}
<|endoftext|>


<commit_before>use std;
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
use std::ops::{Add, Sub};

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct GlobalSectorNumber(pub usize);

impl GlobalSectorNumber {
    pub fn to_msf_index(self) -> Result<MsfIndex, MsfParseError> {
        let mut temp_sectors = self.0;
        let m = temp_sectors / (60 * 75);
        temp_sectors -= m * 60 * 75;
        let s = temp_sectors / 75;
        temp_sectors -= s * 75;
        let f = temp_sectors;
        debug!("MsfIndex::from_sectors({}) -> ({},{},{})", self.0, m, s, f);
        MsfIndex::new(m as u8, s as u8, f as u8)
    }
}

impl Add for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn add(self, rhs: GlobalSectorNumber) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 + rhs.0)
    }
}

impl Sub for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn sub(self, rhs: GlobalSectorNumber) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 - rhs.0)
    }
}

impl Add<LocalSectorNumber> for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn add(self, rhs: LocalSectorNumber) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 + rhs.0)
    }
}

impl Add<usize> for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn add(self, rhs: usize) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 + rhs)
    }
}

impl Sub<usize> for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn sub(self, rhs: usize) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 - rhs)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct LocalSectorNumber(pub usize);

impl LocalSectorNumber {
    pub fn to_byte_offset(self) -> usize {
        self.0 * 2352
    }

    pub fn to_msf_index(self) -> Result<MsfIndex, MsfParseError> {
        let mut temp_sectors = self.0;
        let m = temp_sectors / (60 * 75);
        temp_sectors -= m * 60 * 75;
        let s = temp_sectors / 75;
        temp_sectors -= s * 75;
        let f = temp_sectors;
        debug!("MsfIndex::from_sectors({}) -> ({},{},{})", self.0, m, s, f);
        MsfIndex::new(m as u8, s as u8, f as u8)
    }
}

impl Add for LocalSectorNumber {
    type Output = LocalSectorNumber;
    #[inline]
    fn add(self, rhs: LocalSectorNumber) -> LocalSectorNumber {
        LocalSectorNumber(self.0 + rhs.0)
    }
}

impl Sub for LocalSectorNumber {
    type Output = LocalSectorNumber;
    #[inline]
    fn sub(self, rhs: LocalSectorNumber) -> LocalSectorNumber {
        LocalSectorNumber(self.0 - rhs.0)
    }
}

impl Add<usize> for LocalSectorNumber {
    type Output = LocalSectorNumber;
    #[inline]
    fn add(self, rhs: usize) -> LocalSectorNumber {
        LocalSectorNumber(self.0 + rhs)
    }
}

impl Sub<usize> for LocalSectorNumber {
    type Output = LocalSectorNumber;
    #[inline]
    fn sub(self, rhs: usize) -> LocalSectorNumber {
        LocalSectorNumber(self.0 - rhs)
    }
}

#[derive(Debug, PartialEq)]
pub enum MsfParseError {
    ParseIntError(std::num::ParseIntError),
    OutOfRangeError,
    InvalidMsfError
}

impl Error for MsfParseError {
    fn description(&self) -> &str {
        "Could not parse MSF Timestamp"
    }

    fn cause(&self) -> Option<&Error> {
        use MsfParseError::*;
        match *self {
            ParseIntError(ref inner_err) => Some(inner_err),
            _ => None
        }
    }
}

impl fmt::Display for MsfParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl From<std::num::ParseIntError> for MsfParseError {
    fn from(err: std::num::ParseIntError) -> MsfParseError {
        MsfParseError::ParseIntError(err)
    }
}

// MsfIndex(minutes, seconds, frame), not BCD encoded
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MsfIndex(u8, u8, u8);

impl MsfIndex {
    pub fn new(m: u8, s: u8, f: u8) -> Result<MsfIndex, MsfParseError> {
        if m > 99 || s > 59 || f > 74 {
            Err(MsfParseError::OutOfRangeError)
        } else {
            Ok(MsfIndex(m,s,f))
        }
    }

    pub fn from_bcd_values(m_bcd: u8, s_bcd: u8, f_bcd: u8) -> Result<MsfIndex, MsfParseError> {
        if (m_bcd & 0xf0) > 0x90 || (m_bcd & 0x0f) > 0x09 ||
           (s_bcd & 0xf0) > 0x90 || (s_bcd & 0x0f) > 0x09 ||
           (f_bcd & 0xf0) > 0x90 || (f_bcd & 0x0f) > 0x09 {
            Err(MsfParseError::OutOfRangeError)
        } else {
            let m = (m_bcd >> 4) * 10 + (m_bcd & 0x0f);
            let s = (s_bcd >> 4) * 10 + (s_bcd & 0x0f);
            let f = (f_bcd >> 4) * 10 + (f_bcd & 0x0f);
            debug!("from_bcd_values: Converted (0x{:x}, 0x{:x}, 0x{:x}) to ({}, {}, {})",
                   m_bcd, s_bcd, f_bcd, m, s, f);
            MsfIndex::new(m,s,f)
        }
    }

    pub fn try_from_str(s: &str) -> Result<MsfIndex, MsfParseError> {
        let s = s.trim();
        let colon_matches = s.split(":").collect::<Vec<&str>>();
        debug!("{:?}", colon_matches);
        if colon_matches.len() == 3 {
            let (m, s, f) = (
                colon_matches[0].parse()?,
                colon_matches[1].parse()?,
                colon_matches[2].parse()?
            );
            MsfIndex::new(m, s, f)
        } else {
            Err(MsfParseError::InvalidMsfError)
        }
    }

    pub fn to_sector_number(&self) -> usize {
        let MsfIndex(m,s,f) = *self;
        m as usize * 60 * 75 + s as usize * 75 + f as usize
    }

    pub fn to_bcd_values(&self) -> (u8, u8, u8) {
        let MsfIndex(m,s,f) = *self;
        let m_bcd = ((m / 10) << 4) + (m % 10);
        let s_bcd = ((s / 10) << 4) + (s % 10);
        let f_bcd = ((f / 10) << 4) + (f % 10);
        debug!("Converted from ({}, {}, {}) to (0x{:x}, 0x{:x}, 0x{:x})",
               m, s, f, m_bcd, s_bcd, f_bcd);
        (m_bcd, s_bcd, f_bcd)
    }
}

impl fmt::Display for MsfIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {}, {})", self.0, self.1, self.2)
    }
}

impl Ord for MsfIndex {
    fn cmp(&self, other: &MsfIndex) -> Ordering {
        let self_sector = self.to_sector_number();
        let other_sector = &other.to_sector_number();
        self_sector.cmp(other_sector)
    }
}

impl PartialOrd for MsfIndex {
    fn partial_cmp(&self, other: &MsfIndex) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

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

    #[test]
    fn msf_index_range() {
        assert_eq!(MsfIndex::new(0, 0, 0).unwrap(), MsfIndex(0, 0, 0));
        assert_eq!(MsfIndex::new(13, 37, 42).unwrap(), MsfIndex(13, 37, 42));
        assert_eq!(MsfIndex::new(99, 59, 74).unwrap(), MsfIndex(99, 59, 74));

        assert_eq!(MsfIndex::new(99, 59, 75), Err(MsfParseError::OutOfRangeError));
        assert_eq!(MsfIndex::new(99, 60, 74), Err(MsfParseError::OutOfRangeError));
        assert_eq!(MsfIndex::new(100, 59, 74), Err(MsfParseError::OutOfRangeError));
    }
}
<commit_msg>Fix tests for MsfIndex<commit_after>use std;
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
use std::ops::{Add, Sub};

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct GlobalSectorNumber(pub usize);

impl GlobalSectorNumber {
    pub fn to_msf_index(self) -> Result<MsfIndex, MsfParseError> {
        let mut temp_sectors = self.0;
        let m = temp_sectors / (60 * 75);
        temp_sectors -= m * 60 * 75;
        let s = temp_sectors / 75;
        temp_sectors -= s * 75;
        let f = temp_sectors;
        debug!("MsfIndex::from_sectors({}) -> ({},{},{})", self.0, m, s, f);
        MsfIndex::new(m as u8, s as u8, f as u8)
    }
}

impl Add for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn add(self, rhs: GlobalSectorNumber) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 + rhs.0)
    }
}

impl Sub for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn sub(self, rhs: GlobalSectorNumber) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 - rhs.0)
    }
}

impl Add<LocalSectorNumber> for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn add(self, rhs: LocalSectorNumber) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 + rhs.0)
    }
}

impl Add<usize> for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn add(self, rhs: usize) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 + rhs)
    }
}

impl Sub<usize> for GlobalSectorNumber {
    type Output = GlobalSectorNumber;
    #[inline]
    fn sub(self, rhs: usize) -> GlobalSectorNumber {
        GlobalSectorNumber(self.0 - rhs)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct LocalSectorNumber(pub usize);

impl LocalSectorNumber {
    pub fn to_byte_offset(self) -> usize {
        self.0 * 2352
    }

    pub fn to_msf_index(self) -> Result<MsfIndex, MsfParseError> {
        let mut temp_sectors = self.0;
        let m = temp_sectors / (60 * 75);
        temp_sectors -= m * 60 * 75;
        let s = temp_sectors / 75;
        temp_sectors -= s * 75;
        let f = temp_sectors;
        debug!("MsfIndex::from_sectors({}) -> ({},{},{})", self.0, m, s, f);
        MsfIndex::new(m as u8, s as u8, f as u8)
    }
}

impl Add for LocalSectorNumber {
    type Output = LocalSectorNumber;
    #[inline]
    fn add(self, rhs: LocalSectorNumber) -> LocalSectorNumber {
        LocalSectorNumber(self.0 + rhs.0)
    }
}

impl Sub for LocalSectorNumber {
    type Output = LocalSectorNumber;
    #[inline]
    fn sub(self, rhs: LocalSectorNumber) -> LocalSectorNumber {
        LocalSectorNumber(self.0 - rhs.0)
    }
}

impl Add<usize> for LocalSectorNumber {
    type Output = LocalSectorNumber;
    #[inline]
    fn add(self, rhs: usize) -> LocalSectorNumber {
        LocalSectorNumber(self.0 + rhs)
    }
}

impl Sub<usize> for LocalSectorNumber {
    type Output = LocalSectorNumber;
    #[inline]
    fn sub(self, rhs: usize) -> LocalSectorNumber {
        LocalSectorNumber(self.0 - rhs)
    }
}

#[derive(Debug, PartialEq)]
pub enum MsfParseError {
    ParseIntError(std::num::ParseIntError),
    OutOfRangeError,
    InvalidMsfError
}

impl Error for MsfParseError {
    fn description(&self) -> &str {
        "Could not parse MSF Timestamp"
    }

    fn cause(&self) -> Option<&Error> {
        use MsfParseError::*;
        match *self {
            ParseIntError(ref inner_err) => Some(inner_err),
            _ => None
        }
    }
}

impl fmt::Display for MsfParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl From<std::num::ParseIntError> for MsfParseError {
    fn from(err: std::num::ParseIntError) -> MsfParseError {
        MsfParseError::ParseIntError(err)
    }
}

// MsfIndex(minutes, seconds, frame), not BCD encoded
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MsfIndex(u8, u8, u8);

impl MsfIndex {
    pub fn new(m: u8, s: u8, f: u8) -> Result<MsfIndex, MsfParseError> {
        if m > 99 || s > 59 || f > 74 {
            Err(MsfParseError::OutOfRangeError)
        } else {
            Ok(MsfIndex(m,s,f))
        }
    }

    pub fn from_bcd_values(m_bcd: u8, s_bcd: u8, f_bcd: u8) -> Result<MsfIndex, MsfParseError> {
        if (m_bcd & 0xf0) > 0x90 || (m_bcd & 0x0f) > 0x09 ||
           (s_bcd & 0xf0) > 0x90 || (s_bcd & 0x0f) > 0x09 ||
           (f_bcd & 0xf0) > 0x90 || (f_bcd & 0x0f) > 0x09 {
            Err(MsfParseError::OutOfRangeError)
        } else {
            let m = (m_bcd >> 4) * 10 + (m_bcd & 0x0f);
            let s = (s_bcd >> 4) * 10 + (s_bcd & 0x0f);
            let f = (f_bcd >> 4) * 10 + (f_bcd & 0x0f);
            debug!("from_bcd_values: Converted (0x{:x}, 0x{:x}, 0x{:x}) to ({}, {}, {})",
                   m_bcd, s_bcd, f_bcd, m, s, f);
            MsfIndex::new(m,s,f)
        }
    }

    pub fn try_from_str(s: &str) -> Result<MsfIndex, MsfParseError> {
        let s = s.trim();
        let colon_matches = s.split(":").collect::<Vec<&str>>();
        debug!("{:?}", colon_matches);
        if colon_matches.len() == 3 {
            let (m, s, f) = (
                colon_matches[0].parse()?,
                colon_matches[1].parse()?,
                colon_matches[2].parse()?
            );
            MsfIndex::new(m, s, f)
        } else {
            Err(MsfParseError::InvalidMsfError)
        }
    }

    pub fn to_sector_number(&self) -> usize {
        let MsfIndex(m,s,f) = *self;
        m as usize * 60 * 75 + s as usize * 75 + f as usize
    }

    pub fn to_bcd_values(&self) -> (u8, u8, u8) {
        let MsfIndex(m,s,f) = *self;
        let m_bcd = ((m / 10) << 4) + (m % 10);
        let s_bcd = ((s / 10) << 4) + (s % 10);
        let f_bcd = ((f / 10) << 4) + (f % 10);
        debug!("Converted from ({}, {}, {}) to (0x{:x}, 0x{:x}, 0x{:x})",
               m, s, f, m_bcd, s_bcd, f_bcd);
        (m_bcd, s_bcd, f_bcd)
    }
}

impl fmt::Display for MsfIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {}, {})", self.0, self.1, self.2)
    }
}

impl Ord for MsfIndex {
    fn cmp(&self, other: &MsfIndex) -> Ordering {
        let self_sector = self.to_sector_number();
        let other_sector = &other.to_sector_number();
        self_sector.cmp(other_sector)
    }
}

impl PartialOrd for MsfIndex {
    fn partial_cmp(&self, other: &MsfIndex) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

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

    #[test]
    fn msf_index_range() {
        assert_eq!(MsfIndex::new(0, 0, 0).unwrap(), MsfIndex(0, 0, 0));
        assert_eq!(MsfIndex::new(13, 37, 42).unwrap(), MsfIndex(13, 37, 42));
        assert_eq!(MsfIndex::new(99, 59, 74).unwrap(), MsfIndex(99, 59, 74));

        assert_eq!(MsfIndex::new(99, 59, 75), Err(MsfParseError::OutOfRangeError));
        assert_eq!(MsfIndex::new(99, 60, 74), Err(MsfParseError::OutOfRangeError));
        assert_eq!(MsfIndex::new(100, 59, 74), Err(MsfParseError::OutOfRangeError));
    }
}
<|endoftext|>


<commit_before>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level<T> {
    tiles: Grid<Option<T>>,
}

impl<T> Level<T> {
    pub fn new(width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(None ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<T>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: T) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut T> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level<T> where F: FnOnce(&mut Level<T>) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level<T> {
    type Output= Option<T>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_end_tiles(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(ref n) = level[(x,y)] {
                if let &Tile::Floor = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }
    let mut filled_deadend = false;
    for &(x,y) in &deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Wall;
            filled_deadend = true;
        }
    }
    filled_deadend
}

pub fn is_deadend(level: &Level, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(Tile::Floor) = level[coord] {
            paths += 1;
        }
	}
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<commit_msg>I broke the master. sorry<commit_after>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level<T> {
    tiles: Grid<Option<T>>,
}

impl<T> Level<T> {
    pub fn new(width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(None ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<T>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: T) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut T> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level<T> where F: FnOnce(&mut Level<T>) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level<T> {
    type Output= Option<T>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<T>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level<T> {
    type Output= Option<T>;

    fn index(&self, vec: Vec2<usize>) -> &Option<T>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_end_tiles(level: &mut Level<Tile>) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(ref n) = level[(x,y)] {
                if let &Tile::Floor = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }
    let mut filled_deadend = false;
    for &(x,y) in &deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Wall;
            filled_deadend = true;
        }
    }
    filled_deadend
}

pub fn is_deadend(level: &Level<Tile>, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(Tile::Floor) = level[coord] {
            paths += 1;
        }
	}
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<|endoftext|>


<commit_before>mod lexer {
    extern mod core;

    enum TokenType {
        COMMAND,
        EXIT,
        PIPE,
        EOF,
    }

    pub struct Token {
        text: ~str,
        ttype: TokenType,
    }

    pub struct Lexer {
        input: ~str,
        mut currentChar: char,
        mut index: int,
    }
}
<commit_msg>Lexing stuff<commit_after>mod lexer {
    extern mod core;

    enum TokenType {
        COMMAND,
        ARGUMENT,
        EXIT,
        PIPE,
        SEMICOLON,
        EOF,
    }

    pub struct Token {
        text: ~str,
        ttype: TokenType,
    }

    impl to_str::ToStr for Token {
        fn to_str(&self) -> ~str {
            copy self.text
        }
    }

    pub struct Lexer {
        input: ~str,
        currentChar: char,
        index: uint,
        eof: bool,
    }

    impl Lexer {

        pub fn consume(&mut self) {
            self.index += 1;
            if (self.index >= str::len(self.input)) {
                self.eof = true;
            } else {
                self.currentChar = str::char_at(self.input, self.index);
            }
        }

        pub fn whitespace(&mut self) {
            while (char::is_whitespace(self.currentChar) && !self.eof) {
                self.consume();
            }
        }

        pub fn command(&mut self) -> Token {
            let start = self.index;
            while (char::is_alphanumeric(self.currentChar) && !self.eof) {
                self.consume();
            }
            Token {text: str::slice(self.input, start, self.index).to_owned(), ttype: COMMAND}
        }

        pub fn next_token(&mut self) -> Token {
            while !self.eof {
                match self.currentChar {
                    ' ' | '\n' | '\r' | '\t' => {
                        self.whitespace();
                        loop;
                    }
                    ';' => {
                        self.consume();
                        return Token {text: ~";", ttype: SEMICOLON};
                    }
                    '|' => {
                        self.consume();
                        return Token {text: ~"|", ttype: PIPE};
                    }
                    _ => {
                        return self.command();
                    }
                }
            }
            return Token {text: ~" ", ttype: EOF};
        }

    }
    pub fn main() {
        let mut lex = Lexer { input: ~"te;st st2ring|", index: 0, currentChar: 't', eof: false };
        let mut t = lex.next_token();
        loop {
            match t.ttype {
                EOF => return,
                _   => {
                    io::println(t.to_str());
                    t = lex.next_token();
                }
            }

        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Chars, CharsError};
use std::borrow::Cow;
use std::fmt;
use std::char;

use num::Num;

use error::{ParserError, ParserErrorKind, StreamError};

/// Token types
#[derive(PartialEq)]
pub enum Token {
    /// `(`
    OpenParen,
    /// `)`
    CloseParen,
    /// `[`
    OpenBracket,
    /// `]`
    CloseBracket,
    /// `#(`
    OpenVectorParen,
    /// `#vu8(`
    OpenBytesParen,
    /// `.`
    Dot,
    /// `'`
    Quote,
    /// `\``
    QuasiQuote,
    /// `,`
    Comma,
    /// `,@`
    UnquoteSplicing,
    Identifier(Cow<'static, str>),
    /// `#t`
    True,
    /// `#f`
    False,
    /// `#\<String>`
    Character(String),
    String(String),
    Numeric(String),
    /// End of character stream
    EOF
}

impl fmt::Debug for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Token::OpenParen => write!(f, "OpenParen"),
            Token::OpenVectorParen => write!(f, "OpenVectorParen"),
            Token::OpenBytesParen => write!(f, "OpenBytesParen"),
            Token::CloseParen => write!(f, "CloseParen"),
            Token::OpenBracket => write!(f, "OpenBracket"),
            Token::CloseBracket => write!(f, "CloseBracket"),
            Token::Dot => write!(f, "Dot"),
            Token::Quote => write!(f, "Quote"),
            Token::QuasiQuote => write!(f, "QuasiQuote"),
            Token::Comma => write!(f, "Comma"),
            Token::UnquoteSplicing => write!(f, "UnquoteSplicing"),
            Token::Identifier(ref name) => write!(f, "Identifier({})", name),
            Token::True => write!(f, "#t"),
            Token::False => write!(f, "#f"),
            Token::Character(ref name) => write!(f, "#\\{}", name),
            Token::Numeric(ref rep) => rep.fmt(f),
            Token::String(ref rep) => write!(f, "{:?}", rep),
            Token::EOF => write!(f, "EOF"),
        }
    }
}

/// TokenWrapper provides positional information to each token
pub struct TokenWrapper {
    pub line: usize,
    pub column: usize,
    pub token: Token
}

fn wrap(line: usize, column: usize, t: Token) -> TokenWrapper {
    TokenWrapper {
        line: line,
        column: column,
        token: t
    }
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\t' | '\n' | '\x0b' | '\x0c' | '\r' | ' ' | '\u{0085}' => true,
        _ => c.is_whitespace()
    }
}

fn is_initial(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' => true,
        _ => false
    }
}

fn is_subsequent(c: char) -> bool {
    if is_initial(c) {
        true
    } else {
        match c {
            '0'...'9' | '+' | '-' | '.' | '@' => true,
            _ => false
        }
    }
}

fn is_delim(c: char) -> bool {
    match c {
        '(' | ')' | '[' | ']' | '"' | ';' | '#' => true,
        _ => c.is_whitespace()
    }
}

/// Lexer transforms character stream into a token stream
pub struct Lexer<R> {
    line: usize,
    column: usize,
    stream: Chars<R>,
    lookahead_buf: Option<char>,
}

macro_rules! try_consume {
    ($this:ident) => (
        match $this.consume() {
            Some(Ok(c)) => c,
            Some(Err(e)) => return Err($this.make_error(ParserErrorKind::UnderlyingError(StreamError(e)))),
            None => return Err($this.make_error(ParserErrorKind::UnexpectedEOF))
        }
    )
}

impl <R: Read + Sized> Lexer<R> {
    /// Creates new Lexer from io::Buffer
    pub fn new(stream: R) -> Lexer<R> {
        Lexer {
            line: 1,
            column: 1,
            stream: stream.chars(),
            lookahead_buf: None,
        }
    }

    pub fn lex_token(&mut self) -> Result<TokenWrapper, ParserError> {
        try!(self.consume_whitespace());

        let line = self.line;
        let col = self.column;

        let token = try!(self.lex());

        try!(self.consume_whitespace());

        Ok(wrap(line, col, token))
    }

    /// return next token
    fn lex(&mut self) -> Result<Token, ParserError> {
        let c = match try!(self.consume_eof()) {
            Some(c) => c,
            None => return Ok(Token::EOF)
        };

        let end_of_token = try!(self.is_end_of_token());

        if is_initial(c) {
            let mut init = String::new();
            init.push(c);
            self.lex_ident(init).map(|s| Token::Identifier(Cow::Owned(s)))
        } else if c == '+' {
            if end_of_token {
                Ok(Token::Identifier(Cow::Borrowed("+")))
            } else {
                self.lex_numeric("+".to_string()).map(Token::Numeric)
            }
        } else if c == '-' {
            if end_of_token {
                Ok(Token::Identifier(Cow::Borrowed("-")))
            } else {
                match try!(self.lookahead()) {
                    Some('>') => self.lex_ident("-".to_string()).map(|s| Token::Identifier(Cow::Owned(s))),
                    Some(_) => self.lex_numeric("-".to_string()).map(Token::Numeric),
                    None => Ok(Token::Identifier(Cow::Borrowed("-")))
                }
            }
        } else if c == ',' {
            match try!(self.lookahead()) {
                Some('@') => {
                    self.consume().expect("lookahead buffer error");
                    Ok(Token::UnquoteSplicing)
                },
                _ => Ok(Token::Comma)
            }
        } else if c == '(' {
            Ok(Token::OpenParen)
        } else if c == ')' {
            Ok(Token::CloseParen)
        } else if c == '[' {
            Ok(Token::OpenBracket)
        } else if c == ']' {
            Ok(Token::CloseBracket)
        } else if c == '.' {
            if end_of_token {
                Ok(Token::Dot)
            } else {
                let rest_prefix = try!(self.read_while(|c| !is_delim(c)));
                if rest_prefix == ".." {
                    Ok(Token::Identifier(Cow::Borrowed("...")))
                } else {
                    Err(self.make_error(ParserErrorKind::InvalidToken(format!("{}{}", c, rest_prefix))))
                }
            }
        } else if c == '\'' {
            Ok(Token::Quote)
        } else if c == '`' {
            Ok(Token::QuasiQuote)
        } else if c == '#' {
            let c0 = try!(self.consume());
            match c0 {
                't' | 'T' => Ok(Token::True),
                'f' | 'F' => Ok(Token::False),
                'b' | 'B' | 'o' | 'O' | 'd' | 'D' | 'x' | 'X' | 'i' | 'I' | 'e' | 'E' => {
                    let s = format!("{}{}", c, c0);
                    self.lex_numeric(s).map(Token::Numeric)
                },
                'v' | 'u' => {
                    let rest_prefix = try!(self.read_while(|c| !is_delim(c)));
                    let delim = try!(self.consume());
                    let prefix = format!("{}{}{}", c0, rest_prefix, delim);
                    match prefix.as_ref() {
                        "vu8(" | "u8(" =>
                            Ok(Token::OpenBytesParen),
                        _ =>
                            Err(self.make_error(ParserErrorKind::InvalidToken(prefix)))
                    }
                },
                '\\' => self.lex_char().map(Token::Character),
                '(' => Ok(Token::OpenVectorParen),
                _ => Err(self.make_error(ParserErrorKind::InvalidToken(format!("#{}", c))))
            }
        } else if c == '"' {
            self.lex_string().map(Token::String)
        } else if c.is_numeric() {
            let s = format!("{}", c);
            self.lex_numeric(s).map(Token::Numeric)
        } else {
            Err(self.make_error(ParserErrorKind::InvalidCharacter(c)))
        }
    }

    fn is_end_of_token(&mut self) -> Result<bool, ParserError> {
        match try!(self.lookahead()) {
            Some(c) => Ok(is_whitespace(c) || is_delim(c)),
            None => Ok(true)
        }
    }

    fn lex_ident(&mut self, initial: String) -> Result<String, ParserError> {
        let mut s = initial;
        let sub = try!(self.read_while(is_subsequent));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn lex_char(&mut self) -> Result<String, ParserError> {
        let c = try!(self.consume());
        let mut s = String::new();
        s.push(c);
        let sub = try!(self.read_while(|c| c.is_alphanumeric()));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn lex_string(&mut self) -> Result<String, ParserError> {
        let mut s = String::new();
        loop {
            match try!(self.consume()) {
                '"' => return Ok(s),
                '\\' => match try!(self.consume()) {
                    'a' => s.push('\x07'),
                    'b' => s.push('\x08'),
                    't' => s.push('\t'),
                    'n' => s.push('\n'),
                    'v' => s.push('\x0b'),
                    'f' => s.push('\x0c'),
                    'r' => s.push('\r'),
                    '"' => s.push('"'),
                    '\\' => s.push('\\'),
                    'x' => {
                        let hex_str = try!(self.read_while(|c| c != ';'));
                        if try!(self.consume()) != ';' {
                            panic!("read_while error");
                        }
                        if hex_str.len() == 0 {
                            return Err(self.make_error(ParserErrorKind::InvalidStringEscape(hex_str)))
                        }
                        let code = match Num::from_str_radix(hex_str.as_ref(), 16) {
                            Ok(n) => n,
                            Err(_) => return Err(self.make_error(ParserErrorKind::InvalidStringEscape(hex_str)))
                        };
                        match char::from_u32(code) {
                            Some(c) => s.push(c),
                            None => return Err(self.make_error(ParserErrorKind::InvalidUnicodeRange(code)))
                        }
                    },
                    c =>
                        if c.is_whitespace() {
                            try!(self.read_while(|c| c != '\n' && c.is_whitespace()));
                            if c != '\n' {
                                if let '\n' = try!(self.consume()) {
                                    try!(self.read_while(|c| c != '\n' && c.is_whitespace()));
                                } else {
                                    return Err(self.make_error(ParserErrorKind::InvalidStringLiteral))
                                }
                            }
                        } else {
                            return Err(self.make_error(ParserErrorKind::InvalidStringEscape(format!("{}", c))))
                        }
                },
                c => s.push(c),
            }
        }
    }

    fn lex_numeric(&mut self, init: String) -> Result<String, ParserError> {
        let mut s = init;
        let sub = try!(self.read_while(|c| !is_delim(c)));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn make_error(&self, kind: ParserErrorKind) -> ParserError {
        ParserError {
            line: self.line,
            column: self.column,
            kind: kind
        }
    }

    fn lookahead(&mut self) -> Result<Option<char>, CharsError> {
        match self.lookahead_buf {
            Some(c) => Ok(Some(c)),
            None => {
                match self.stream.next() {
                    Some(Ok(ch)) => {
                        self.lookahead_buf = Some(ch);
                        Ok(Some(ch))
                    },
                    Some(Err(e)) => {
                        Err(e)
                    },
                    None => {
                        Ok(None)
                    }
                }
            }
        }
    }

    fn advance(&mut self, c: char) {
        if c == '\n' {
            self.line += 1;
            self.column = 1;
        } else {
            self.column += 1;
        }
    }

    fn read_while<F>(&mut self, f: F) -> Result<String, ParserError> where
        F: Fn(char) -> bool
    {
        let mut s = match self.lookahead_buf {
            None => String::new(),
            Some(c) => if f(c) {
                self.lookahead_buf = None;
                self.advance(c);
                let mut s = String::new();
                s.push(c);
                s
            } else {
                return Ok(String::new());
            }
        };

        loop {
            match self.stream.next() {
                Some(Ok(c)) => if f(c) {
                    self.advance(c);
                    s.push(c);
                } else {
                    self.lookahead_buf = Some(c);
                    return Ok(s);
                },
                Some(Err(e)) =>
                    return Err(self.make_error(ParserErrorKind::UnderlyingError(StreamError(e)))),
                None => return Ok(s)
            }
        }
    }

    fn consume_eof(&mut self) -> Result<Option<char>, CharsError> {
        let c = match self.lookahead_buf {
            Some(c) => {
                self.lookahead_buf = None;
                Some(Ok(c))
            },
            None => self.stream.next()
        };

        match c {
            Some(Ok(ch)) => {
                self.advance(ch);
                Ok(Some(ch))
            },
            Some(Err(e)) => Err(e),
            None => Ok(None)
        }
    }

    fn consume(&mut self) -> Result<char, ParserError> {
        match try!(self.consume_eof()) {
            Some(c) => Ok(c),
            None => return Err(self.make_error(ParserErrorKind::UnexpectedEOF))
        }
    }

    fn consume_whitespace(&mut self) -> Result<bool, ParserError> {
        let mut consumed = false;
        loop {
            let whitespace = try!(self.read_while(is_whitespace));
            consumed = consumed || whitespace.len() > 0;
            if let Some(';') = try!(self.lookahead()) {
                consumed = true;
                try!(self.read_while(|c| c != '\n'));
                if self.lookahead_buf.is_some() {
                    self.lookahead_buf = None;
                }
            } else {
                return Ok(consumed);
            }
        }
    }
}
<commit_msg>Whitespace lexer doesn't need to return a value<commit_after>use std::io::{Read, Chars, CharsError};
use std::borrow::Cow;
use std::fmt;
use std::char;

use num::Num;

use error::{ParserError, ParserErrorKind, StreamError};

/// Token types
#[derive(PartialEq)]
pub enum Token {
    /// `(`
    OpenParen,
    /// `)`
    CloseParen,
    /// `[`
    OpenBracket,
    /// `]`
    CloseBracket,
    /// `#(`
    OpenVectorParen,
    /// `#vu8(`
    OpenBytesParen,
    /// `.`
    Dot,
    /// `'`
    Quote,
    /// `\``
    QuasiQuote,
    /// `,`
    Comma,
    /// `,@`
    UnquoteSplicing,
    Identifier(Cow<'static, str>),
    /// `#t`
    True,
    /// `#f`
    False,
    /// `#\<String>`
    Character(String),
    String(String),
    Numeric(String),
    /// End of character stream
    EOF
}

impl fmt::Debug for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Token::OpenParen => write!(f, "OpenParen"),
            Token::OpenVectorParen => write!(f, "OpenVectorParen"),
            Token::OpenBytesParen => write!(f, "OpenBytesParen"),
            Token::CloseParen => write!(f, "CloseParen"),
            Token::OpenBracket => write!(f, "OpenBracket"),
            Token::CloseBracket => write!(f, "CloseBracket"),
            Token::Dot => write!(f, "Dot"),
            Token::Quote => write!(f, "Quote"),
            Token::QuasiQuote => write!(f, "QuasiQuote"),
            Token::Comma => write!(f, "Comma"),
            Token::UnquoteSplicing => write!(f, "UnquoteSplicing"),
            Token::Identifier(ref name) => write!(f, "Identifier({})", name),
            Token::True => write!(f, "#t"),
            Token::False => write!(f, "#f"),
            Token::Character(ref name) => write!(f, "#\\{}", name),
            Token::Numeric(ref rep) => rep.fmt(f),
            Token::String(ref rep) => write!(f, "{:?}", rep),
            Token::EOF => write!(f, "EOF"),
        }
    }
}

/// TokenWrapper provides positional information to each token
pub struct TokenWrapper {
    pub line: usize,
    pub column: usize,
    pub token: Token
}

fn wrap(line: usize, column: usize, t: Token) -> TokenWrapper {
    TokenWrapper {
        line: line,
        column: column,
        token: t
    }
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\t' | '\n' | '\x0b' | '\x0c' | '\r' | ' ' | '\u{0085}' => true,
        _ => c.is_whitespace()
    }
}

fn is_initial(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' => true,
        _ => false
    }
}

fn is_subsequent(c: char) -> bool {
    if is_initial(c) {
        true
    } else {
        match c {
            '0'...'9' | '+' | '-' | '.' | '@' => true,
            _ => false
        }
    }
}

fn is_delim(c: char) -> bool {
    match c {
        '(' | ')' | '[' | ']' | '"' | ';' | '#' => true,
        _ => c.is_whitespace()
    }
}

/// Lexer transforms character stream into a token stream
pub struct Lexer<R> {
    line: usize,
    column: usize,
    stream: Chars<R>,
    lookahead_buf: Option<char>,
}

macro_rules! try_consume {
    ($this:ident) => (
        match $this.consume() {
            Some(Ok(c)) => c,
            Some(Err(e)) => return Err($this.make_error(ParserErrorKind::UnderlyingError(StreamError(e)))),
            None => return Err($this.make_error(ParserErrorKind::UnexpectedEOF))
        }
    )
}

impl <R: Read + Sized> Lexer<R> {
    /// Creates new Lexer from io::Buffer
    pub fn new(stream: R) -> Lexer<R> {
        Lexer {
            line: 1,
            column: 1,
            stream: stream.chars(),
            lookahead_buf: None,
        }
    }

    pub fn lex_token(&mut self) -> Result<TokenWrapper, ParserError> {
        try!(self.consume_whitespace());

        let line = self.line;
        let col = self.column;

        let token = try!(self.lex());

        try!(self.consume_whitespace());

        Ok(wrap(line, col, token))
    }

    /// return next token
    fn lex(&mut self) -> Result<Token, ParserError> {
        let c = match try!(self.consume_eof()) {
            Some(c) => c,
            None => return Ok(Token::EOF)
        };

        let end_of_token = try!(self.is_end_of_token());

        if is_initial(c) {
            let mut init = String::new();
            init.push(c);
            self.lex_ident(init).map(|s| Token::Identifier(Cow::Owned(s)))
        } else if c == '+' {
            if end_of_token {
                Ok(Token::Identifier(Cow::Borrowed("+")))
            } else {
                self.lex_numeric("+".to_string()).map(Token::Numeric)
            }
        } else if c == '-' {
            if end_of_token {
                Ok(Token::Identifier(Cow::Borrowed("-")))
            } else {
                match try!(self.lookahead()) {
                    Some('>') => self.lex_ident("-".to_string()).map(|s| Token::Identifier(Cow::Owned(s))),
                    Some(_) => self.lex_numeric("-".to_string()).map(Token::Numeric),
                    None => Ok(Token::Identifier(Cow::Borrowed("-")))
                }
            }
        } else if c == ',' {
            match try!(self.lookahead()) {
                Some('@') => {
                    self.consume().expect("lookahead buffer error");
                    Ok(Token::UnquoteSplicing)
                },
                _ => Ok(Token::Comma)
            }
        } else if c == '(' {
            Ok(Token::OpenParen)
        } else if c == ')' {
            Ok(Token::CloseParen)
        } else if c == '[' {
            Ok(Token::OpenBracket)
        } else if c == ']' {
            Ok(Token::CloseBracket)
        } else if c == '.' {
            if end_of_token {
                Ok(Token::Dot)
            } else {
                let rest_prefix = try!(self.read_while(|c| !is_delim(c)));
                if rest_prefix == ".." {
                    Ok(Token::Identifier(Cow::Borrowed("...")))
                } else {
                    Err(self.make_error(ParserErrorKind::InvalidToken(format!("{}{}", c, rest_prefix))))
                }
            }
        } else if c == '\'' {
            Ok(Token::Quote)
        } else if c == '`' {
            Ok(Token::QuasiQuote)
        } else if c == '#' {
            let c0 = try!(self.consume());
            match c0 {
                't' | 'T' => Ok(Token::True),
                'f' | 'F' => Ok(Token::False),
                'b' | 'B' | 'o' | 'O' | 'd' | 'D' | 'x' | 'X' | 'i' | 'I' | 'e' | 'E' => {
                    let s = format!("{}{}", c, c0);
                    self.lex_numeric(s).map(Token::Numeric)
                },
                'v' | 'u' => {
                    let rest_prefix = try!(self.read_while(|c| !is_delim(c)));
                    let delim = try!(self.consume());
                    let prefix = format!("{}{}{}", c0, rest_prefix, delim);
                    match prefix.as_ref() {
                        "vu8(" | "u8(" =>
                            Ok(Token::OpenBytesParen),
                        _ =>
                            Err(self.make_error(ParserErrorKind::InvalidToken(prefix)))
                    }
                },
                '\\' => self.lex_char().map(Token::Character),
                '(' => Ok(Token::OpenVectorParen),
                _ => Err(self.make_error(ParserErrorKind::InvalidToken(format!("#{}", c))))
            }
        } else if c == '"' {
            self.lex_string().map(Token::String)
        } else if c.is_numeric() {
            let s = format!("{}", c);
            self.lex_numeric(s).map(Token::Numeric)
        } else {
            Err(self.make_error(ParserErrorKind::InvalidCharacter(c)))
        }
    }

    fn is_end_of_token(&mut self) -> Result<bool, ParserError> {
        match try!(self.lookahead()) {
            Some(c) => Ok(is_whitespace(c) || is_delim(c)),
            None => Ok(true)
        }
    }

    fn lex_ident(&mut self, initial: String) -> Result<String, ParserError> {
        let mut s = initial;
        let sub = try!(self.read_while(is_subsequent));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn lex_char(&mut self) -> Result<String, ParserError> {
        let c = try!(self.consume());
        let mut s = String::new();
        s.push(c);
        let sub = try!(self.read_while(|c| c.is_alphanumeric()));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn lex_string(&mut self) -> Result<String, ParserError> {
        let mut s = String::new();
        loop {
            match try!(self.consume()) {
                '"' => return Ok(s),
                '\\' => match try!(self.consume()) {
                    'a' => s.push('\x07'),
                    'b' => s.push('\x08'),
                    't' => s.push('\t'),
                    'n' => s.push('\n'),
                    'v' => s.push('\x0b'),
                    'f' => s.push('\x0c'),
                    'r' => s.push('\r'),
                    '"' => s.push('"'),
                    '\\' => s.push('\\'),
                    'x' => {
                        let hex_str = try!(self.read_while(|c| c != ';'));
                        if try!(self.consume()) != ';' {
                            panic!("read_while error");
                        }
                        if hex_str.len() == 0 {
                            return Err(self.make_error(ParserErrorKind::InvalidStringEscape(hex_str)))
                        }
                        let code = match Num::from_str_radix(hex_str.as_ref(), 16) {
                            Ok(n) => n,
                            Err(_) => return Err(self.make_error(ParserErrorKind::InvalidStringEscape(hex_str)))
                        };
                        match char::from_u32(code) {
                            Some(c) => s.push(c),
                            None => return Err(self.make_error(ParserErrorKind::InvalidUnicodeRange(code)))
                        }
                    },
                    c =>
                        if c.is_whitespace() {
                            try!(self.read_while(|c| c != '\n' && c.is_whitespace()));
                            if c != '\n' {
                                if let '\n' = try!(self.consume()) {
                                    try!(self.read_while(|c| c != '\n' && c.is_whitespace()));
                                } else {
                                    return Err(self.make_error(ParserErrorKind::InvalidStringLiteral))
                                }
                            }
                        } else {
                            return Err(self.make_error(ParserErrorKind::InvalidStringEscape(format!("{}", c))))
                        }
                },
                c => s.push(c),
            }
        }
    }

    fn lex_numeric(&mut self, init: String) -> Result<String, ParserError> {
        let mut s = init;
        let sub = try!(self.read_while(|c| !is_delim(c)));
        s.push_str(sub.as_ref());
        return Ok(s);
    }

    fn make_error(&self, kind: ParserErrorKind) -> ParserError {
        ParserError {
            line: self.line,
            column: self.column,
            kind: kind
        }
    }

    fn lookahead(&mut self) -> Result<Option<char>, CharsError> {
        match self.lookahead_buf {
            Some(c) => Ok(Some(c)),
            None => {
                match self.stream.next() {
                    Some(Ok(ch)) => {
                        self.lookahead_buf = Some(ch);
                        Ok(Some(ch))
                    },
                    Some(Err(e)) => {
                        Err(e)
                    },
                    None => {
                        Ok(None)
                    }
                }
            }
        }
    }

    fn advance(&mut self, c: char) {
        if c == '\n' {
            self.line += 1;
            self.column = 1;
        } else {
            self.column += 1;
        }
    }

    fn read_while<F>(&mut self, f: F) -> Result<String, ParserError> where
        F: Fn(char) -> bool
    {
        let mut s = match self.lookahead_buf {
            None => String::new(),
            Some(c) => if f(c) {
                self.lookahead_buf = None;
                self.advance(c);
                let mut s = String::new();
                s.push(c);
                s
            } else {
                return Ok(String::new());
            }
        };

        loop {
            match self.stream.next() {
                Some(Ok(c)) => if f(c) {
                    self.advance(c);
                    s.push(c);
                } else {
                    self.lookahead_buf = Some(c);
                    return Ok(s);
                },
                Some(Err(e)) =>
                    return Err(self.make_error(ParserErrorKind::UnderlyingError(StreamError(e)))),
                None => return Ok(s)
            }
        }
    }

    fn consume_eof(&mut self) -> Result<Option<char>, CharsError> {
        let c = match self.lookahead_buf {
            Some(c) => {
                self.lookahead_buf = None;
                Some(Ok(c))
            },
            None => self.stream.next()
        };

        match c {
            Some(Ok(ch)) => {
                self.advance(ch);
                Ok(Some(ch))
            },
            Some(Err(e)) => Err(e),
            None => Ok(None)
        }
    }

    fn consume(&mut self) -> Result<char, ParserError> {
        match try!(self.consume_eof()) {
            Some(c) => Ok(c),
            None => return Err(self.make_error(ParserErrorKind::UnexpectedEOF))
        }
    }

    fn consume_whitespace(&mut self) -> Result<(), ParserError> {
        loop {
            try!(self.read_while(is_whitespace));
            if let Some(';') = try!(self.lookahead()) {
                try!(self.read_while(|c| c != '\n'));
                if self.lookahead_buf.is_some() {
                    self.lookahead_buf = None;
                }
            } else {
                return Ok(());
            }
        }
    }
}
<|endoftext|>


<commit_before>use regex::{Captures, Regex};
use peruse::slice_parsers::*;
use peruse::string_parsers::*;

use grammar::*;
use std::str::FromStr;

//type Lexer = SliceParser<I=str, O=Token>;

pub fn token() -> Box<SliceParser<I=str, O=Vec<Token>>> {

  fn lt(s: &str, t: Token) -> RegexLiteralParser<Token> {
    str_lit((String::from_str(r"^[ \t]*") + s).as_str(), t)
  }

  let ident = capture(r"^[ \t]*([a-zA-Z]\w*)[ \t]*", |caps| Token::Ident(String::from_str(caps.at(1).unwrap())));

  let number = capture(r"^[ \t]*(\d+)[ \t]*", |caps| Token::Number(FromStr::from_str(caps.at(1).unwrap()).unwrap()));

  let lits = one_of(vec![
    lt("out",         Token::OutputCmd),
    lt("if",          Token::IfKeyword),
    lt("else",        Token::ElseKeyword),
    lt("while",       Token::WhileKeyword),
    lt(r"\r?\n\s*",   Token::NewLine),
    lt(r"\(\s*",      Token::OpenParen),
    lt(r"\)",         Token::CloseParen),
    lt(r"\}",         Token::CloseBrace),
    lt("==",          Token::Cmp(Comparator::CEq)),
    lt("!=",          Token::Cmp(Comparator::CNeq)),
    lt(">=",          Token::Cmp(Comparator::CGeq)),
    lt(r"\{\s*",      Token::OpenBrace),
    lt("<=",          Token::Cmp(Comparator::CLeq)),
    lt(">",           Token::Cmp(Comparator::CGt)),
    lt("<",           Token::Cmp(Comparator::CLt)),
    lt(r"\+",         Token::PlusSign),
    lt("-",           Token::MinusSign),
    lt("=",           Token::Equals),
    lt(r"\*",         Token::MultSign),
    lt("/",           Token::DivideSign),
    lt(r"%",           Token::ModuloSign)
  ]);

  let options = lits.or(number).or(ident).repeat();
  Box::new(options)

}
<commit_msg>Added missing unwraps<commit_after>use regex::{Captures, Regex};
use peruse::slice_parsers::*;
use peruse::string_parsers::*;

use grammar::*;
use std::str::FromStr;

//type Lexer = SliceParser<I=str, O=Token>;

pub fn token() -> Box<SliceParser<I=str, O=Vec<Token>>> {

  fn lt(s: &str, t: Token) -> RegexLiteralParser<Token> {
    str_lit((String::from_str(r"^[ \t]*").unwrap() + s).as_str(), t)
  }

  let ident = capture(r"^[ \t]*([a-zA-Z]\w*)[ \t]*", |caps| Token::Ident(String::from_str(caps.at(1).unwrap()).unwrap()));

  let number = capture(r"^[ \t]*(\d+)[ \t]*", |caps| Token::Number(FromStr::from_str(caps.at(1).unwrap()).unwrap()));

  let lits = one_of(vec![
    lt("out",         Token::OutputCmd),
    lt("if",          Token::IfKeyword),
    lt("else",        Token::ElseKeyword),
    lt("while",       Token::WhileKeyword),
    lt(r"\r?\n\s*",   Token::NewLine),
    lt(r"\(\s*",      Token::OpenParen),
    lt(r"\)",         Token::CloseParen),
    lt(r"\}",         Token::CloseBrace),
    lt("==",          Token::Cmp(Comparator::CEq)),
    lt("!=",          Token::Cmp(Comparator::CNeq)),
    lt(">=",          Token::Cmp(Comparator::CGeq)),
    lt(r"\{\s*",      Token::OpenBrace),
    lt("<=",          Token::Cmp(Comparator::CLeq)),
    lt(">",           Token::Cmp(Comparator::CGt)),
    lt("<",           Token::Cmp(Comparator::CLt)),
    lt(r"\+",         Token::PlusSign),
    lt("-",           Token::MinusSign),
    lt("=",           Token::Equals),
    lt(r"\*",         Token::MultSign),
    lt("/",           Token::DivideSign),
    lt(r"%",           Token::ModuloSign)
  ]);

  let options = lits.or(number).or(ident).repeat();
  Box::new(options)

}
<|endoftext|>


<commit_before>use std;
use common::*;
use arena::*;
use layout;

pub struct ReaderOptions {
    traversalLimitInWords : u64,
    nestingLimit : uint
}

pub static DEFAULT_READER_OPTIONS : ReaderOptions =
    ReaderOptions { traversalLimitInWords : 8 * 1024 * 1024, nestingLimit : 64 };

pub struct MessageReader<'self> {
    segments : &'self [ &'self [u8]],
    options : ReaderOptions,
//    arena : ReaderArena<'self>
}

type SegmentId = u32;

impl <'self> MessageReader<'self> {

    #[inline(always)]
    pub fn getSegment(&self, id : uint) -> &'self [u8] {
        self.segments[id]
    }

    #[inline(always)]
    pub fn getSegmentReader<'a>(&'a self, id : SegmentId) -> SegmentReader<'a> {
        SegmentReader { messageReader : self, segment : self.getSegment(id as uint) }
    }

    #[inline(always)]
    pub fn getOptions<'a>(&'a self) -> &'a ReaderOptions {
        return &self.options;
    }

    pub fn getRoot<'a>(&'a mut self) -> layout::StructReader<'a> {
        let segment = self.getSegmentReader(0);

        return layout::StructReader::readRoot(0, segment,
                                              self.options.nestingLimit as int);
    }

}

pub enum AllocationStrategy {
    FIXED_SIZE,
    GROW_HEURISTICALLY
}

pub static SUGGESTED_FIRST_SEGMENT_WORDS : uint = 1024;
pub static SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy = GROW_HEURISTICALLY;

pub struct MessageBuilder {
    nextSize : uint,
    allocationStrategy : AllocationStrategy,
    segments : ~[@mut SegmentBuilder]
}

impl MessageBuilder {

/*
    pub fn new(firstSegment : ~[u8], allocationStrategy : AllocationStrategy)
        -> @MessageBuilder {
        @MessageBuilder {
            nextSize : firstSegment.len(),
            allocationStrategy : allocationStrategy,
            firstSegment : firstSegment,
            moreSegments : ~[]
        }
    }
*/

    pub fn new_default() -> @mut MessageBuilder {
        let result = @mut MessageBuilder {
            nextSize : SUGGESTED_FIRST_SEGMENT_WORDS,
            allocationStrategy : SUGGESTED_ALLOCATION_STRATEGY,
            segments : ~[]
        };
        result.segments.push(
            @mut SegmentBuilder::new(result, SUGGESTED_FIRST_SEGMENT_WORDS * BYTES_PER_WORD));

        result
    }

    pub fn allocateSegment(@mut self, minimumSize : uint) -> @mut SegmentBuilder {
        let size = std::cmp::max(minimumSize, self.nextSize);
        let result  = @mut SegmentBuilder::new(self, size);
        self.segments.push(result);

        match self.allocationStrategy {
            GROW_HEURISTICALLY => { self.nextSize += size; }
            _ => { }
        }

        result
    }

    pub fn getSegmentWithAvailable(@mut self, minimumAvailable : WordCount)
        -> @mut SegmentBuilder {
        if (self.segments.last().available() >= minimumAvailable) {

            return self.segments[self.segments.len()];

        } else {

            return self.allocateSegment(minimumAvailable);

        }
    }

    pub fn initRoot(&self, size : layout::StructSize) -> layout::StructBuilder {
        layout::StructBuilder::initRoot(self.segments[0], 0, size)
    }
}<commit_msg>avoid that instance, but it happens elsewhere<commit_after>use std;
use common::*;
use arena::*;
use layout;

pub struct ReaderOptions {
    traversalLimitInWords : u64,
    nestingLimit : uint
}

pub static DEFAULT_READER_OPTIONS : ReaderOptions =
    ReaderOptions { traversalLimitInWords : 8 * 1024 * 1024, nestingLimit : 64 };

pub struct MessageReader<'self> {
    segments : &'self [ &'self [u8]],
    options : ReaderOptions,
//    arena : ReaderArena<'self>
}

type SegmentId = u32;

impl <'self> MessageReader<'self> {

    #[inline(always)]
    pub fn getSegment(&self, id : uint) -> &'self [u8] {
        self.segments[id]
    }

    #[inline(always)]
    pub fn getSegmentReader<'a>(&'a self, id : SegmentId) -> SegmentReader<'a> {
        SegmentReader { messageReader : self, segment : self.getSegment(id as uint) }
    }

    #[inline(always)]
    pub fn getOptions<'a>(&'a self) -> &'a ReaderOptions {
        return &self.options;
    }

    pub fn getRoot<'a>(&'a mut self) -> layout::StructReader<'a> {
        let segment = self.getSegmentReader(0);

        return layout::StructReader::readRoot(0, segment,
                                              self.options.nestingLimit as int);
    }

}

pub enum AllocationStrategy {
    FIXED_SIZE,
    GROW_HEURISTICALLY
}

pub static SUGGESTED_FIRST_SEGMENT_WORDS : uint = 1024;
pub static SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy = GROW_HEURISTICALLY;

pub struct MessageBuilder {
    nextSize : uint,
    allocationStrategy : AllocationStrategy,
    segments : ~[@mut SegmentBuilder]
}

impl MessageBuilder {

/*
    pub fn new(firstSegment : ~[u8], allocationStrategy : AllocationStrategy)
        -> @MessageBuilder {
        @MessageBuilder {
            nextSize : firstSegment.len(),
            allocationStrategy : allocationStrategy,
            firstSegment : firstSegment,
            moreSegments : ~[]
        }
    }
*/

    pub fn new_default() -> @mut MessageBuilder {
        let result = @mut MessageBuilder {
            nextSize : SUGGESTED_FIRST_SEGMENT_WORDS,
            allocationStrategy : SUGGESTED_ALLOCATION_STRATEGY,
            segments : ~[]
        };
        let builder =
            @mut SegmentBuilder::new(result, SUGGESTED_FIRST_SEGMENT_WORDS * BYTES_PER_WORD);
        result.segments.push(builder);

        result
    }

    pub fn allocateSegment(@mut self, minimumSize : uint) -> @mut SegmentBuilder {
        let size = std::cmp::max(minimumSize, self.nextSize);
        let result  = @mut SegmentBuilder::new(self, size);
        self.segments.push(result);

        match self.allocationStrategy {
            GROW_HEURISTICALLY => { self.nextSize += size; }
            _ => { }
        }

        result
    }

    pub fn getSegmentWithAvailable(@mut self, minimumAvailable : WordCount)
        -> @mut SegmentBuilder {
        if (self.segments.last().available() >= minimumAvailable) {

            return self.segments[self.segments.len()];

        } else {

            return self.allocateSegment(minimumAvailable);

        }
    }

    pub fn initRoot(&self, size : layout::StructSize) -> layout::StructBuilder {
        layout::StructBuilder::initRoot(self.segments[0], 0, size)
    }
}<|endoftext|>