<commit_before>//! The Ref object is a helper over the link functionality, so one is able to create references to
//! files outside of the imag store.

use std::path::PathBuf;
use std::ops::Deref;
use std::ops::DerefMut;
use std::collections::BTreeMap;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Store;
use libimagerror::into::IntoError;

use toml::Value;

use error::RefErrorKind as REK;
use flags::RefFlags;
use result::Result;
use module_path::ModuleEntryPath;

pub struct Ref<'a>(FileLockEntry<'a>);

impl<'a> Ref<'a> {

    /// Try to get `si` as Ref object from the store
    pub fn get(store: &'a Store, si: StoreId) -> Result<Ref<'a>> {
        match store.get(si) {
            Err(e) => return Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
            Ok(None) => return Err(REK::RefNotInStore.into_error()),
            Ok(Some(fle)) => Ref::read_reference(&fle).map(|_| Ref(fle)),
        }
    }

    fn read_reference(fle: &FileLockEntry<'a>) -> Result<PathBuf> {
        match fle.get_header().read("ref.reference") {
            Ok(Some(Value::String(s))) => Ok(PathBuf::from(s)),
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
            Ok(None)    => Err(REK::HeaderFieldMissingError.into_error()),
            Err(e)      => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        }
    }

    /// Create a Ref object which refers to `pb`
    pub fn create(store: &'a Store, pb: PathBuf, flags: RefFlags) -> Result<Ref<'a>> {
        use std::fs::File;
        use std::io::Read;
        use crypto::sha1::Sha1;
        use crypto::digest::Digest;

        if !pb.exists() {
            return Err(REK::RefTargetDoesNotExist.into_error());
        }
        if flags.get_content_hashing() && pb.is_dir() {
            return Err(REK::RefTargetCannotBeHashed.into_error());
        }

        let (mut fle, content_hash, permissions, canonical_path) = { // scope to be able to fold
            try!(File::open(pb.clone())
                .map_err(Box::new)
                .map_err(|e| REK::RefTargetFileCannotBeOpened.into_error_with_cause(e))

                // If we were able to open this file,
                // we hash the contents of the file and return (file, hash)
                .and_then(|mut file| {
                    let opt_contenthash = if flags.get_content_hashing() {
                        let mut hasher = Sha1::new();
                        let mut s = String::new();
                        file.read_to_string(&mut s);
                        hasher.input_str(&s[..]);
                        Some(hasher.result_str())
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash))
                })

                // and then we get the permissions if we have to
                // and return (file, content hash, permissions)
                .and_then(|(file, opt_contenthash)| {
                    let opt_permissions = if flags.get_permission_tracking() {
                        Some(try!(file
                                  .metadata()
                                  .map(|md| md.permissions())
                                  .map_err(Box::new)
                                  .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e))
                        ))
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash, opt_permissions))
                })

                // and then we try to canonicalize the PathBuf, because we want to store a
                // canonicalized path
                // and return (file, content hash, permissions, canonicalized path)
                .and_then(|(file, opt_contenthash, opt_permissions)| {
                    pb.canonicalize()
                        .map(|can| (file, opt_contenthash, opt_permissions, can))
                        // if PathBuf::canonicalize() failed, build an error from the return value
                        .map_err(|e| REK::PathCanonicalizationError.into_error_with_cause(Box::new(e)))
                })

                // and then we hash the canonicalized path
                // and return (file, content hash, permissions, canonicalized path, path hash)
                .and_then(|(file, opt_contenthash, opt_permissions, can)| {
                    let path_hash = try!(Ref::hash_path(&can)
                        .map_err(Box::new)
                        .map_err(|e| REK::PathHashingError.into_error_with_cause(e))
                    );

                    Ok((file, opt_contenthash, opt_permissions, can, path_hash))
                })

                // and then we convert the PathBuf of the canonicalized path to a String to be able
                // to save it in the Ref FileLockEntry obj
                // and return
                // (file, content hash, permissions, canonicalized path as String, path hash)
                .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| {
                    match can.to_str().map(String::from) {
                        // UTF convert error in PathBuf::to_str(),
                        None      => Err(REK::PathUTF8Error.into_error()),
                        Some(can) => Ok((file, opt_conhash, opt_perm, can, path_hash))
                    }
                })

                // and then we create the FileLockEntry in the Store
                // and return (filelockentry, content hash, permissions, canonicalized path)
                .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| {
                    let fle = try!(store
                                   .create(ModuleEntryPath::new(path_hash))
                                   .map_err(Box::new)
                                   .map_err(|e| REK::StoreWriteError.into_error_with_cause(e))
                    );

                    Ok((fle, opt_conhash, opt_perm, can))
                })
            )
        };

        for tpl in [
                Some(("ref",             Value::Table(BTreeMap::new()))),
                Some(("ref.permissions", Value::Table(BTreeMap::new()))),

                Some(("ref.path", Value::String(canonical_path))),

                content_hash.map(|h| ("ref.content_hash", Value::String(h))),
                permissions.map(|p| ("ref.permissions.ro", Value::Boolean(p.readonly()))),
            ].into_iter()
        {
            match tpl {
                &Some((ref s, ref v)) => {
                    match fle.get_header_mut().insert(s, v.clone()) {
                        Ok(false) => {
                            let e = REK::HeaderFieldAlreadyExistsError.into_error();
                            let e = Box::new(e);
                            let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
                            return Err(e);
                        },
                        Err(e) => {
                            let e = Box::new(e);
                            let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
                            return Err(e);
                        },
                        _ => (),
                    }
                }
                &None => {
                    debug!("Not going to insert.");
                }
            }
        }

        Ok(Ref(fle))
    }

    /// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash
    /// algorithm on it
    fn hash_path(pb: &PathBuf) -> Result<String> {
        use std::io::Read;
        use crypto::sha1::Sha1;
        use crypto::digest::Digest;

        match pb.to_str() {
            Some(s) => {
                let mut hasher = Sha1::new();
                hasher.input_str(s);
                Ok(hasher.result_str())
            },
            None => return Err(REK::PathUTF8Error.into_error()),
        }
    }

    /// check whether the pointer the Ref represents still points to a file which exists
    pub fn fs_link_exists(&self) -> Result<bool> {
        self.fs_file().map(|pathbuf| pathbuf.exists())
    }

    /// Alias for `r.fs_link_exists() && r.deref().is_file()`
    pub fn is_ref_to_file(&self) -> bool {
        unimplemented!()
    }

    /// Alias for `r.fs_link_exists() && r.deref().is_dir()`
    pub fn is_ref_to_dir(&self) -> bool {
        unimplemented!()
    }

    /// Alias for `!Ref::fs_link_exists()`
    pub fn is_dangling(&self) -> Result<bool> {
        self.fs_link_exists().map(|b| !b)
    }

    /// check whether the pointer the Ref represents is valid
    /// This includes:
    ///     - Hashsum of the file is still the same as stored in the Ref
    ///     - file permissions are still valid
    pub fn fs_link_valid(&self) -> bool {
        unimplemented!()
    }

    /// Check whether the file permissions of the referenced file are equal to the stored
    /// permissions
    pub fn fs_link_valid_permissions(&self) -> bool {
        unimplemented!()
    }

    /// Check whether the Hashsum of the referenced file is equal to the stored hashsum
    pub fn fs_link_valid_hash(&self) -> bool {
        unimplemented!()
    }

    /// Update the Ref by re-checking the file from FS
    /// This errors if the file is not present or cannot be read()
    pub fn update_ref(&mut self) -> Result<()> {
        unimplemented!()
    }

    /// Get the path of the file which is reffered to by this Ref
    pub fn fs_file(&self) -> &PathBuf {
        unimplemented!()
    }

    /// Check whether there is a reference to the file at `pb`
    pub fn exists(store: &Store, pb: PathBuf) -> Result<bool> {
        unimplemented!()
    }

    /// Re-find a referenced file
    ///
    /// This function tries to re-find a ref by searching all directories in `search_roots` recursively
    /// for a file which matches the hash of the Ref `ref`.
    ///
    /// If `search_roots` is `None`, it starts at the filesystem root `/`.
    ///
    /// # Warning
    ///
    /// This option causes heavy I/O as it recursively searches the Filesystem.
    pub fn refind(&self, search_roots: Option<Vec<PathBuf>>) -> Option<PathBuf> {
        unimplemented!()
    }

}

impl<'a> Deref for Ref<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.0
    }

}

impl<'a> DerefMut for Ref<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.0
    }

}
<commit_msg>Impl Ref::fs_file()<commit_after>//! The Ref object is a helper over the link functionality, so one is able to create references to
//! files outside of the imag store.

use std::path::PathBuf;
use std::ops::Deref;
use std::ops::DerefMut;
use std::collections::BTreeMap;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Store;
use libimagerror::into::IntoError;

use toml::Value;

use error::RefErrorKind as REK;
use flags::RefFlags;
use result::Result;
use module_path::ModuleEntryPath;

pub struct Ref<'a>(FileLockEntry<'a>);

impl<'a> Ref<'a> {

    /// Try to get `si` as Ref object from the store
    pub fn get(store: &'a Store, si: StoreId) -> Result<Ref<'a>> {
        match store.get(si) {
            Err(e) => return Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
            Ok(None) => return Err(REK::RefNotInStore.into_error()),
            Ok(Some(fle)) => Ref::read_reference(&fle).map(|_| Ref(fle)),
        }
    }

    fn read_reference(fle: &FileLockEntry<'a>) -> Result<PathBuf> {
        match fle.get_header().read("ref.reference") {
            Ok(Some(Value::String(s))) => Ok(PathBuf::from(s)),
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
            Ok(None)    => Err(REK::HeaderFieldMissingError.into_error()),
            Err(e)      => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        }
    }

    /// Create a Ref object which refers to `pb`
    pub fn create(store: &'a Store, pb: PathBuf, flags: RefFlags) -> Result<Ref<'a>> {
        use std::fs::File;
        use std::io::Read;
        use crypto::sha1::Sha1;
        use crypto::digest::Digest;

        if !pb.exists() {
            return Err(REK::RefTargetDoesNotExist.into_error());
        }
        if flags.get_content_hashing() && pb.is_dir() {
            return Err(REK::RefTargetCannotBeHashed.into_error());
        }

        let (mut fle, content_hash, permissions, canonical_path) = { // scope to be able to fold
            try!(File::open(pb.clone())
                .map_err(Box::new)
                .map_err(|e| REK::RefTargetFileCannotBeOpened.into_error_with_cause(e))

                // If we were able to open this file,
                // we hash the contents of the file and return (file, hash)
                .and_then(|mut file| {
                    let opt_contenthash = if flags.get_content_hashing() {
                        let mut hasher = Sha1::new();
                        let mut s = String::new();
                        file.read_to_string(&mut s);
                        hasher.input_str(&s[..]);
                        Some(hasher.result_str())
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash))
                })

                // and then we get the permissions if we have to
                // and return (file, content hash, permissions)
                .and_then(|(file, opt_contenthash)| {
                    let opt_permissions = if flags.get_permission_tracking() {
                        Some(try!(file
                                  .metadata()
                                  .map(|md| md.permissions())
                                  .map_err(Box::new)
                                  .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e))
                        ))
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash, opt_permissions))
                })

                // and then we try to canonicalize the PathBuf, because we want to store a
                // canonicalized path
                // and return (file, content hash, permissions, canonicalized path)
                .and_then(|(file, opt_contenthash, opt_permissions)| {
                    pb.canonicalize()
                        .map(|can| (file, opt_contenthash, opt_permissions, can))
                        // if PathBuf::canonicalize() failed, build an error from the return value
                        .map_err(|e| REK::PathCanonicalizationError.into_error_with_cause(Box::new(e)))
                })

                // and then we hash the canonicalized path
                // and return (file, content hash, permissions, canonicalized path, path hash)
                .and_then(|(file, opt_contenthash, opt_permissions, can)| {
                    let path_hash = try!(Ref::hash_path(&can)
                        .map_err(Box::new)
                        .map_err(|e| REK::PathHashingError.into_error_with_cause(e))
                    );

                    Ok((file, opt_contenthash, opt_permissions, can, path_hash))
                })

                // and then we convert the PathBuf of the canonicalized path to a String to be able
                // to save it in the Ref FileLockEntry obj
                // and return
                // (file, content hash, permissions, canonicalized path as String, path hash)
                .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| {
                    match can.to_str().map(String::from) {
                        // UTF convert error in PathBuf::to_str(),
                        None      => Err(REK::PathUTF8Error.into_error()),
                        Some(can) => Ok((file, opt_conhash, opt_perm, can, path_hash))
                    }
                })

                // and then we create the FileLockEntry in the Store
                // and return (filelockentry, content hash, permissions, canonicalized path)
                .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| {
                    let fle = try!(store
                                   .create(ModuleEntryPath::new(path_hash))
                                   .map_err(Box::new)
                                   .map_err(|e| REK::StoreWriteError.into_error_with_cause(e))
                    );

                    Ok((fle, opt_conhash, opt_perm, can))
                })
            )
        };

        for tpl in [
                Some(("ref",             Value::Table(BTreeMap::new()))),
                Some(("ref.permissions", Value::Table(BTreeMap::new()))),

                Some(("ref.path", Value::String(canonical_path))),

                content_hash.map(|h| ("ref.content_hash", Value::String(h))),
                permissions.map(|p| ("ref.permissions.ro", Value::Boolean(p.readonly()))),
            ].into_iter()
        {
            match tpl {
                &Some((ref s, ref v)) => {
                    match fle.get_header_mut().insert(s, v.clone()) {
                        Ok(false) => {
                            let e = REK::HeaderFieldAlreadyExistsError.into_error();
                            let e = Box::new(e);
                            let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
                            return Err(e);
                        },
                        Err(e) => {
                            let e = Box::new(e);
                            let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
                            return Err(e);
                        },
                        _ => (),
                    }
                }
                &None => {
                    debug!("Not going to insert.");
                }
            }
        }

        Ok(Ref(fle))
    }

    /// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash
    /// algorithm on it
    fn hash_path(pb: &PathBuf) -> Result<String> {
        use std::io::Read;
        use crypto::sha1::Sha1;
        use crypto::digest::Digest;

        match pb.to_str() {
            Some(s) => {
                let mut hasher = Sha1::new();
                hasher.input_str(s);
                Ok(hasher.result_str())
            },
            None => return Err(REK::PathUTF8Error.into_error()),
        }
    }

    /// check whether the pointer the Ref represents still points to a file which exists
    pub fn fs_link_exists(&self) -> Result<bool> {
        self.fs_file().map(|pathbuf| pathbuf.exists())
    }

    /// Alias for `r.fs_link_exists() && r.deref().is_file()`
    pub fn is_ref_to_file(&self) -> bool {
        unimplemented!()
    }

    /// Alias for `r.fs_link_exists() && r.deref().is_dir()`
    pub fn is_ref_to_dir(&self) -> bool {
        unimplemented!()
    }

    /// Alias for `!Ref::fs_link_exists()`
    pub fn is_dangling(&self) -> Result<bool> {
        self.fs_link_exists().map(|b| !b)
    }

    /// check whether the pointer the Ref represents is valid
    /// This includes:
    ///     - Hashsum of the file is still the same as stored in the Ref
    ///     - file permissions are still valid
    pub fn fs_link_valid(&self) -> bool {
        unimplemented!()
    }

    /// Check whether the file permissions of the referenced file are equal to the stored
    /// permissions
    pub fn fs_link_valid_permissions(&self) -> bool {
        unimplemented!()
    }

    /// Check whether the Hashsum of the referenced file is equal to the stored hashsum
    pub fn fs_link_valid_hash(&self) -> bool {
        unimplemented!()
    }

    /// Update the Ref by re-checking the file from FS
    /// This errors if the file is not present or cannot be read()
    pub fn update_ref(&mut self) -> Result<()> {
        unimplemented!()
    }

    /// Get the path of the file which is reffered to by this Ref
    pub fn fs_file(&self) -> Result<PathBuf> {
        match self.0.get_header().read("ref.path") {
            Ok(Some(Value::String(ref s))) => Ok(PathBuf::from(s)),
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
            Ok(None)    => Err(REK::HeaderFieldMissingError.into_error()),
            Err(e)      => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        }
    }

    /// Check whether there is a reference to the file at `pb`
    pub fn exists(store: &Store, pb: PathBuf) -> Result<bool> {
        unimplemented!()
    }

    /// Re-find a referenced file
    ///
    /// This function tries to re-find a ref by searching all directories in `search_roots` recursively
    /// for a file which matches the hash of the Ref `ref`.
    ///
    /// If `search_roots` is `None`, it starts at the filesystem root `/`.
    ///
    /// # Warning
    ///
    /// This option causes heavy I/O as it recursively searches the Filesystem.
    pub fn refind(&self, search_roots: Option<Vec<PathBuf>>) -> Option<PathBuf> {
        unimplemented!()
    }

}

impl<'a> Deref for Ref<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.0
    }

}

impl<'a> DerefMut for Ref<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.0
    }

}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::path::Path;
use std::borrow::Borrow;
use std::ops::Deref;

use semver::Version;
use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId(PathBuf);

impl StoreId {

    pub fn storified(self, store: &Store) -> StoreId {
        if self.starts_with(store.path()) {
            debug!("Not storifying {:?}, because it is already.", self);
            self
        } else {
            debug!("Create new store id out of: {:?} and {:?}", store.path(), self);
            let mut new_id = store.path().clone();
            new_id.push(self);
            debug!("Created: '{:?}'", new_id);
            StoreId::from(new_id)
        }
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        self.0
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.0.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.0.to_string_lossy()),
        }
    }

}

impl Deref for StoreId {
    type Target = PathBuf;

    fn deref(&self) -> &PathBuf {
        &self.0
    }

}

impl From<PathBuf> for StoreId {

    fn from(pb: PathBuf) -> StoreId {
        StoreId(pb)
    }

}

impl From<String> for StoreId {

    fn from(string: String) -> StoreId {
        StoreId(string.into())
    }

}

impl AsRef<Path> for StoreId {

    fn as_ref(&self) -> &Path {
        self.0.as_ref()
    }

}

impl Borrow<Path> for StoreId {

    fn borrow(&self) -> &Path {
        self.0.borrow()
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        StoreId(self)
    }
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(SEK::StorePathLacksVersion.into());
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.starts_with('/') {
        path.push(&path_elem[1..]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    StoreId::from(self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<commit_msg>Make StoreId be two parts: base and id<commit_after>use std::path::PathBuf;
use std::path::Path;
use std::borrow::Borrow;
use std::ops::Deref;

use semver::Version;
use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    store_location: PathBuf,
    id: PathBuf,
}

impl StoreId {

    pub fn storified(self, store: &Store) -> StoreId {
        if self.starts_with(store.path()) {
            debug!("Not storifying {:?}, because it is already.", self);
            self
        } else {
            debug!("Create new store id out of: {:?} and {:?}", store.path(), self);
            let mut new_id = store.path().clone();
            new_id.push(self);
            debug!("Created: '{:?}'", new_id);
            StoreId::from(new_id)
        }
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        self.0
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.0.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.0.to_string_lossy()),
        }
    }

}

impl Deref for StoreId {
    type Target = PathBuf;

    fn deref(&self) -> &PathBuf {
        &self.0
    }

}

impl From<PathBuf> for StoreId {

    fn from(pb: PathBuf) -> StoreId {
        StoreId(pb)
    }

}

impl From<String> for StoreId {

    fn from(string: String) -> StoreId {
        StoreId(string.into())
    }

}

impl AsRef<Path> for StoreId {

    fn as_ref(&self) -> &Path {
        self.0.as_ref()
    }

}

impl Borrow<Path> for StoreId {

    fn borrow(&self) -> &Path {
        self.0.borrow()
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        StoreId(self)
    }
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(SEK::StorePathLacksVersion.into());
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.starts_with('/') {
        path.push(&path_elem[1..]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    StoreId::from(self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<|endoftext|>


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

use std::fmt;
use std::io;

use externalfiles::ExternalHtml;

#[deriving(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
    pub playground_url: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub ty: &'a str,
    pub root_path: &'a str,
}

pub fn render<T: fmt::Show, S: fmt::Show>(
    dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
    -> io::IoResult<()>
{
    write!(dst,
r##"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="The {krate} library documentation.">

    <title>{title}</title>

    <link rel="stylesheet" type="text/css" href="{root_path}main.css">

    {favicon}
    {in_header}

    {before_content}

        {logo}
        {sidebar}

        <form class="search-form js-only">

                <input class="search-input" name="search"
                       autocomplete="off"
                       placeholder="Click or press 'S' to search, '?' for more options..."
                       type="search">

        </form>

{content}

Keyboard shortcuts

?

Show this help dialog

S

Focus the search field

⇤

Move up in search results

⇥

Move down in search results

⏎

Go to active search result

Search tricks

                Prefix searches with a type followed by a colon (e.g.
                fn:) to restrict the search to a given type.

                Accepted types are: fn, mod,
                struct (or str), enum,
                trait, typedef (or
                tdef).

    {after_content}

    {play_js}

"##,
    content   = *t,
    root_path = page.root_path,
    ty        = page.ty,
    logo      = if layout.logo.len() == 0 {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    favicon   = if layout.favicon.len() == 0 {
        "".to_string()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    play_url  = layout.playground_url,
    play_js   = if layout.playground_url.len() == 0 {
        "".to_string()
    } else {
        format!(r#""#, page.root_path)
    },
    )
}

pub fn redirect(dst: &mut io::Writer, url: &str) -> io::IoResult<()> {
    write!(dst,
r##"<!DOCTYPE html>

    <meta http-equiv="refresh" content="0;URL={url}">

"##,
    url = url,
    )
}
<commit_msg>rustdoc: Add generator meta tag to API docs<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io;

use externalfiles::ExternalHtml;

#[deriving(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
    pub playground_url: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub ty: &'a str,
    pub root_path: &'a str,
}

pub fn render<T: fmt::Show, S: fmt::Show>(
    dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
    -> io::IoResult<()>
{
    write!(dst,
r##"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="The {krate} library documentation.">
    <meta name="generator" content="rustdoc">

    <title>{title}</title>

    <link rel="stylesheet" type="text/css" href="{root_path}main.css">

    {favicon}
    {in_header}

    {before_content}

        {logo}
        {sidebar}

        <form class="search-form js-only">

                <input class="search-input" name="search"
                       autocomplete="off"
                       placeholder="Click or press 'S' to search, '?' for more options..."
                       type="search">

        </form>

{content}

Keyboard shortcuts

?

Show this help dialog

S

Focus the search field

⇤

Move up in search results

⇥

Move down in search results

⏎

Go to active search result

Search tricks

                Prefix searches with a type followed by a colon (e.g.
                fn:) to restrict the search to a given type.

                Accepted types are: fn, mod,
                struct (or str), enum,
                trait, typedef (or
                tdef).

    {after_content}

    {play_js}

"##,
    content   = *t,
    root_path = page.root_path,
    ty        = page.ty,
    logo      = if layout.logo.len() == 0 {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    favicon   = if layout.favicon.len() == 0 {
        "".to_string()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    play_url  = layout.playground_url,
    play_js   = if layout.playground_url.len() == 0 {
        "".to_string()
    } else {
        format!(r#""#, page.root_path)
    },
    )
}

pub fn redirect(dst: &mut io::Writer, url: &str) -> io::IoResult<()> {
    write!(dst,
r##"<!DOCTYPE html>

    <meta http-equiv="refresh" content="0;URL={url}">

"##,
    url = url,
    )
}
<|endoftext|>


<commit_before>//! Metamethods for accesssing the registry values!

use super::super::super::registry;
use registry::RegistryAccess;

use hlua::any::AnyLuaValue;

use rustc_serialize::json::{Json, ToJson};
use std::ops::Deref;

pub fn index(table: AnyLuaValue, lua_key: AnyLuaValue)
             -> Result<AnyLuaValue, &'static str> {
    if let AnyLuaValue::LuaString(key) = lua_key {
        let maybe_json = registry::get_json(&key);
        if let Some(json_pair) = maybe_json {
            let (access, json) = json_pair;
            if access == RegistryAccess::Private {
                // TODO In lua_async: return nil
                Err("No value found for that key!")
            }
            else {
                Ok(convert_json(json.deref().to_json()))
            }
        }
        else {
            // Should be nil, nil doesn't seem to be included
            Err("No value found for that key!")
        }
    }
    else {
        Err("The registry can only be indexed with keys!")
    }
}

// Prevent lua from changing the registry?
pub fn new_index(table: AnyLuaValue, key: AnyLuaValue, val: AnyLuaValue)
                 -> Result<(), &'static str> {
    Err("You can't set the registry!")
}

fn convert_json(json: Json) -> AnyLuaValue {
    match json {
        Json::String(val) => AnyLuaValue::LuaString(val),
        Json::Boolean(val) => AnyLuaValue::LuaBoolean(val),
        Json::F64(val) => AnyLuaValue::LuaNumber(val),
        Json::I64(val) => AnyLuaValue::LuaNumber((val as i32) as f64),
        Json::U64(val) => AnyLuaValue::LuaNumber((val as u32) as f64),
        Json::Null => AnyLuaValue::LuaString("none".to_string()),
        Json::Array(vals) => {
            let mut count = 0f64;
            // Gotta love that 1-based indexing. Start at zero but increment for
            // the first one. It works here at least.
            AnyLuaValue::LuaArray(vals.into_iter().map(|v| {
                count += 1.0;
                (AnyLuaValue::LuaNumber(count), convert_json(v))
            }).collect())
        },
        Json::Object(vals) => {
            AnyLuaValue::LuaArray(vals.into_iter().map(|(key, val)| {
                (AnyLuaValue::LuaString(key), convert_json(val))
            }).collect())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::convert_json;
    use hlua::any::AnyLuaValue::*;
    use rustc_serialize::json::{Json, ToJson, Object};
    use std::collections::BTreeMap;

    #[test]
    fn convert_string() {
        let input = "Hello World".to_string();
        let json_input = Json::String(input.clone());
        assert_eq!(convert_json(json_input), LuaString(input));
    }
    #[test]
    fn convert_numbers() {
        let lua_number = LuaNumber(42f64);
        assert_eq!(convert_json(Json::F64(42f64)), lua_number);
        assert_eq!(convert_json(Json::I64(42i64)), lua_number);
        assert_eq!(convert_json(Json::U64(42u64)), lua_number);
    }

    #[test]
    fn convert_bool() {
        assert_eq!(convert_json(Json::Boolean(true)), LuaBoolean(true));
        assert_eq!(convert_json(Json::Boolean(false)), LuaBoolean(false));
    }

    #[test]
    fn convert_array() {
        let json = Json::Array(
            vec![Json::Boolean(true), Json::F64(11f64),
                 Json::String("Foo".to_string())]
        );
        let lua = LuaArray(vec![
                (LuaNumber(1f64), LuaBoolean(true)),
                (LuaNumber(2f64), LuaNumber(11f64)),
                (LuaNumber(3f64), LuaString("Foo".to_string()))
            ]);
        assert_eq!(convert_json(json), lua);
    }

    #[test]
    fn convert_object() {
        // { name="foo", point: {x=0, y=1}, valid=false }
        // The fields are emitted in alphabetical order thanks to Json's
        // internal BTreeMap representation.

        let mut json_tree: Object = BTreeMap::new();
        let mut point_tree: Object = BTreeMap::new();
        point_tree.insert("x".to_string(), Json::U64(0u64));
        point_tree.insert("y".to_string(), Json::U64(1u64));
        json_tree.insert("point".to_string(), Json::Object(point_tree));
        json_tree.insert("name".to_string(), Json::String("foo".to_string()));
        json_tree.insert("valid".to_string(), Json::Boolean(false));

        let lua = LuaArray(vec![
            (LuaString("name".to_string()), LuaString("foo".to_string())),
            (LuaString("point".to_string()), LuaArray(vec![
                (LuaString("x".to_string()), LuaNumber(0f64)),
                (LuaString("y".to_string()), LuaNumber(1f64))
            ])),
            (LuaString("valid".to_string()), LuaBoolean(false)),
        ]);

        assert_eq!(convert_json(Json::Object(json_tree)), lua);
    }
}
<commit_msg>Add support for LuaNil from hlua 0.1.8<commit_after>//! Metamethods for accesssing the registry values!

use super::super::super::registry;
use registry::RegistryAccess;

use hlua::any::AnyLuaValue;

use rustc_serialize::json::{Json, ToJson};
use std::ops::Deref;

pub fn index(table: AnyLuaValue, lua_key: AnyLuaValue)
             -> Result<AnyLuaValue, &'static str> {
    if let AnyLuaValue::LuaString(key) = lua_key {
        let maybe_json = registry::get_json(&key);
        if let Some(json_pair) = maybe_json {
            let (access, json) = json_pair;
            if access == RegistryAccess::Private {
                // TODO In lua_async: return nil
                Err("No value found for that key!")
            }
            else {
                Ok(convert_json(json.deref().to_json()))
            }
        }
        else {
            // Should be nil, nil doesn't seem to be included
            Err("No value found for that key!")
        }
    }
    else {
        Err("The registry can only be indexed with keys!")
    }
}

// Prevent lua from changing the registry?
pub fn new_index(table: AnyLuaValue, key: AnyLuaValue, val: AnyLuaValue)
                 -> Result<(), &'static str> {
    //Err("You can't set the registry!")
}

fn convert_json(json: Json) -> AnyLuaValue {
    match json {
        Json::String(val) => AnyLuaValue::LuaString(val),
        Json::Boolean(val) => AnyLuaValue::LuaBoolean(val),
        Json::F64(val) => AnyLuaValue::LuaNumber(val),
        Json::I64(val) => AnyLuaValue::LuaNumber((val as i32) as f64),
        Json::U64(val) => AnyLuaValue::LuaNumber((val as u32) as f64),
        Json::Null => AnyLuaValue::LuaNil,
        Json::Array(vals) => {
            let mut count = 0f64;
            // Gotta love that 1-based indexing. Start at zero but increment for
            // the first one. It works here at least.
            AnyLuaValue::LuaArray(vals.into_iter().map(|v| {
                count += 1.0;
                (AnyLuaValue::LuaNumber(count), convert_json(v))
            }).collect())
        },
        Json::Object(vals) => {
            AnyLuaValue::LuaArray(vals.into_iter().map(|(key, val)| {
                (AnyLuaValue::LuaString(key), convert_json(val))
            }).collect())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::convert_json;
    use hlua::any::AnyLuaValue::*;
    use rustc_serialize::json::{Json, ToJson, Object};
    use std::collections::BTreeMap;

    #[test]
    fn convert_string() {
        let input = "Hello World".to_string();
        let json_input = Json::String(input.clone());
        assert_eq!(convert_json(json_input), LuaString(input));
    }
    #[test]
    fn convert_numbers() {
        let lua_number = LuaNumber(42f64);
        assert_eq!(convert_json(Json::F64(42f64)), lua_number);
        assert_eq!(convert_json(Json::I64(42i64)), lua_number);
        assert_eq!(convert_json(Json::U64(42u64)), lua_number);
    }

    #[test]
    fn convert_bool() {
        assert_eq!(convert_json(Json::Boolean(true)), LuaBoolean(true));
        assert_eq!(convert_json(Json::Boolean(false)), LuaBoolean(false));
    }

    #[test]
    fn convert_array() {
        let json = Json::Array(
            vec![Json::Boolean(true), Json::F64(11f64),
                 Json::String("Foo".to_string())]
        );
        let lua = LuaArray(vec![
                (LuaNumber(1f64), LuaBoolean(true)),
                (LuaNumber(2f64), LuaNumber(11f64)),
                (LuaNumber(3f64), LuaString("Foo".to_string()))
            ]);
        assert_eq!(convert_json(json), lua);
    }

    #[test]
    fn convert_object() {
        // { name="foo", point: {x=0, y=1}, valid=false }
        // The fields are emitted in alphabetical order thanks to Json's
        // internal BTreeMap representation.

        let mut json_tree: Object = BTreeMap::new();
        let mut point_tree: Object = BTreeMap::new();
        point_tree.insert("x".to_string(), Json::U64(0u64));
        point_tree.insert("y".to_string(), Json::U64(1u64));
        json_tree.insert("point".to_string(), Json::Object(point_tree));
        json_tree.insert("name".to_string(), Json::String("foo".to_string()));
        json_tree.insert("valid".to_string(), Json::Boolean(false));

        let lua = LuaArray(vec![
            (LuaString("name".to_string()), LuaString("foo".to_string())),
            (LuaString("point".to_string()), LuaArray(vec![
                (LuaString("x".to_string()), LuaNumber(0f64)),
                (LuaString("y".to_string()), LuaNumber(1f64))
            ])),
            (LuaString("valid".to_string()), LuaBoolean(false)),
        ]);

        assert_eq!(convert_json(Json::Object(json_tree)), lua);
    }
}
<|endoftext|>


<commit_before>use basetypes::*;

#[derive(Debug)]
#[derive(Clone, Copy)]
#[derive(PartialOrd, Ord, PartialEq, Eq)]
pub struct Move(u32);

const M_SHIFT_SCORE: u32 = 26;
const M_SHIFT_INV_CAPTURED_PIECE: u32 = 23;
const M_SHIFT_PIECE: u32 = 20;
const M_SHIFT_ENPASSANT_FILE: u32 = 16;
const M_SHIFT_MOVE_TYPE: u32 = 14;
const M_SHIFT_ORIG_SQUARE: u32 = 8;
const M_SHIFT_DEST_SQUARE: u32 = 2;
const M_SHIFT_AUX_DATA: u32 = 0;

const M_MASK_SCORE: u32 = 0b111111 << M_SHIFT_SCORE;
const M_MASK_INV_CAPTURED_PIECE: u32 = 0b111 << M_SHIFT_INV_CAPTURED_PIECE;
const M_MASK_PIECE: u32 = 0b111 << M_SHIFT_PIECE;
const M_MASK_ENPASSANT_FILE: u32 = 0b1111 << M_SHIFT_ENPASSANT_FILE;
const M_MASK_MOVE_TYPE: u32 = 0b11 << M_SHIFT_MOVE_TYPE;
const M_MASK_ORIG_SQUARE: u32 = 0b111111 << M_SHIFT_ORIG_SQUARE;
const M_MASK_DEST_SQUARE: u32 = 0b111111 << M_SHIFT_DEST_SQUARE;
const M_MASK_AUX_DATA: u32 = 0b11 << M_SHIFT_AUX_DATA;

impl Move {
    #[inline(always)]
    pub fn new(score: usize,
               move_type: MoveType,
               piece: PieceType,
               orig_square: Square,
               dest_square: Square,
               captured_piece: PieceType,
               en_passant_file: File,
               aux_data: usize)
               -> Move {
        assert!(score <= 0b111111);
        assert!(move_type <= 0x11);
        assert!(piece < NO_PIECE);
        assert!(orig_square <= 63);
        assert!(dest_square <= 63);
        assert!(captured_piece != KING && captured_piece <= NO_PIECE);
        assert!(en_passant_file <= 0b1000);
        assert!(aux_data <= 0b11);
        Move((score << M_SHIFT_SCORE | (!captured_piece & 0b111) << M_SHIFT_INV_CAPTURED_PIECE |
              piece << M_SHIFT_PIECE | en_passant_file << M_SHIFT_ENPASSANT_FILE |
              move_type << M_SHIFT_MOVE_TYPE | orig_square << M_SHIFT_ORIG_SQUARE |
              dest_square << M_SHIFT_DEST_SQUARE |
              aux_data << M_SHIFT_AUX_DATA) as u32)
    }

    #[inline(always)]
    pub fn get_score(&self) -> usize {
        ((self.0 & M_MASK_SCORE) >> M_SHIFT_SCORE) as usize
    }

    #[inline(always)]
    pub fn set_score(&mut self, score: usize) {
        assert!(score <= 0b111111);
        self.0 |= (score << M_SHIFT_SCORE) as u32;
    }

    #[inline(always)]
    pub fn set_score_bit(&mut self, b: usize) {
        assert!(b <= 5);
        self.0 |= 1 << b << M_SHIFT_SCORE;
    }

    #[inline(always)]
    pub fn clear_score_bit(&mut self, b: usize) {
        assert!(b <= 5);
        self.0 &= !(1 << b << M_SHIFT_SCORE);
    }

    #[inline(always)]
    pub fn move_type(&self) -> MoveType {
        ((self.0 & M_MASK_MOVE_TYPE) >> M_SHIFT_MOVE_TYPE) as MoveType
    }

    #[inline(always)]
    pub fn piece(&self) -> PieceType {
        ((self.0 & M_MASK_PIECE) >> M_SHIFT_PIECE) as PieceType
    }

    #[inline(always)]
    pub fn orig_square(&self) -> Square {
        ((self.0 & M_MASK_ORIG_SQUARE) >> M_SHIFT_ORIG_SQUARE) as Square
    }

    #[inline(always)]
    pub fn dest_square(&self) -> Square {
        ((self.0 & M_MASK_DEST_SQUARE) >> M_SHIFT_DEST_SQUARE) as Square
    }

    #[inline(always)]
    pub fn captured_piece(&self) -> PieceType {
        ((!self.0 & M_MASK_INV_CAPTURED_PIECE) >> M_SHIFT_INV_CAPTURED_PIECE) as PieceType
    }

    #[inline(always)]
    pub fn en_passant_file(&self) -> File {
        ((self.0 & M_MASK_ENPASSANT_FILE) >> M_SHIFT_ENPASSANT_FILE) as File
    }

    #[inline(always)]
    pub fn aux_data(&self) -> usize {
        ((self.0 & M_MASK_AUX_DATA) >> M_SHIFT_AUX_DATA) as usize
    }

    #[inline(always)]
    pub fn promoted_piece(&self) -> PieceType {
        Move::piece_from_aux_data(self.aux_data())
    }

    #[inline(always)]
    pub fn piece_from_aux_data(pp_code: usize) -> PieceType {
        match pp_code {
            0 => QUEEN,
            1 => ROOK,
            2 => BISHOP,
            3 => KNIGHT,
            _ => panic!("invalid promoted piece code"),
        }
    }
}

pub struct MoveStack {
    stack: [Move; MOVE_STACK_SIZE],
    top_index: usize,
}

impl MoveStack {
    pub fn new() -> MoveStack {
        use std::mem::uninitialized;
        unsafe {
            MoveStack {
                stack: uninitialized(),
                top_index: 0,
            }
        }
    }

    #[inline(always)]
    pub fn push(&mut self, m: Move) {
        self.stack[self.top_index] = m;
        self.top_index += 1;
    }
}

<commit_msg>big comment about Move<commit_after>use basetypes::*;

// "Move" represents a move on the chessboard. It contains 3 types of
// information:
//
// 1. Information about the played move itself.
//
// 2. Information needed so as to be able to undo the move and restore
// the board into the exact same state as before.
//
// 3. The move score -- moves with higher score are tried
// first. Ideally the best move should have the highest score.
//
// "Move" is a 32-bit unsigned number. The lowest 16 bits contain the
// whole needed information about the move itself (type 1). And is
// laid out the following way:
//
//   15                                                           0
//  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//  |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
//  | Move  |    Origin square      |   Destination square  | Promo-|
//  | type  |       6 bits          |        6 bits         | ted   |
//  | 2 bits|   |   |   |   |   |   |   |   |   |   |   |   | piece |
//  |   |   |   |   |   |   |   |   |   |   |   |   |   |   | 2 bits|
//  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//
// There are 4 "move type"s: 0) normal move; 1) en-passant capture; 2)
// pawn promotion; 3) castling.
//
// The highest 16 bits contain the rest ot the info:
//
//   31                                                          16
//  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//  |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
//  |  Move score   | Captured  |  Played   | Cast- |   En-passant  |
//  |    4 bits     | piece     |  piece    | ling  |      file     |
//  |   |   |   |   | 3 bits|   |  3 bits   | rigths|     4 bits    |
//  |   |   |   |   |   |   |   |   |   |   | 2 bits|   |   |   |   |
//  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//
// "En-passant file" tells on what vertical line (if any) on the board
// there was a passing pawn before the move was played.
//
// Castling rights are a bit complex. The castling rights for the side
// that makes the move, before the move was made, are stored in the
// "Promoted piece" field. This is OK, because promoting a pawn never
// changes the moving player's castling rights. The castling rights
// for the opposite side are stored in "Castling rights" field. (A
// move can change the castling rights of the other side when a rook
// in the corner is captured.)
//
// When "Captured piece" is stored, its bits are inverted, so that
// MVV-LVA (Most valuable victim -- least valuable aggressor) ordering
// of the moves is preserved, even when the "Move score" field stays
// the same.
#[derive(Debug)]
#[derive(Clone, Copy)]
#[derive(PartialOrd, Ord, PartialEq, Eq)]
pub struct Move(u32);

const M_SHIFT_SCORE: u32 = 26;
const M_SHIFT_INV_CAPTURED_PIECE: u32 = 23;
const M_SHIFT_PIECE: u32 = 20;
const M_SHIFT_ENPASSANT_FILE: u32 = 16;
const M_SHIFT_MOVE_TYPE: u32 = 14;
const M_SHIFT_ORIG_SQUARE: u32 = 8;
const M_SHIFT_DEST_SQUARE: u32 = 2;
const M_SHIFT_AUX_DATA: u32 = 0;

const M_MASK_SCORE: u32 = 0b111111 << M_SHIFT_SCORE;
const M_MASK_INV_CAPTURED_PIECE: u32 = 0b111 << M_SHIFT_INV_CAPTURED_PIECE;
const M_MASK_PIECE: u32 = 0b111 << M_SHIFT_PIECE;
const M_MASK_ENPASSANT_FILE: u32 = 0b1111 << M_SHIFT_ENPASSANT_FILE;
const M_MASK_MOVE_TYPE: u32 = 0b11 << M_SHIFT_MOVE_TYPE;
const M_MASK_ORIG_SQUARE: u32 = 0b111111 << M_SHIFT_ORIG_SQUARE;
const M_MASK_DEST_SQUARE: u32 = 0b111111 << M_SHIFT_DEST_SQUARE;
const M_MASK_AUX_DATA: u32 = 0b11 << M_SHIFT_AUX_DATA;

impl Move {
    #[inline(always)]
    pub fn new(score: usize,
               move_type: MoveType,
               piece: PieceType,
               orig_square: Square,
               dest_square: Square,
               captured_piece: PieceType,
               en_passant_file: File,
               aux_data: usize)
               -> Move {
        assert!(score <= 0b111111);
        assert!(move_type <= 0x11);
        assert!(piece < NO_PIECE);
        assert!(orig_square <= 63);
        assert!(dest_square <= 63);
        assert!(captured_piece != KING && captured_piece <= NO_PIECE);
        assert!(en_passant_file <= 0b1000);
        assert!(aux_data <= 0b11);
        Move((score << M_SHIFT_SCORE | (!captured_piece & 0b111) << M_SHIFT_INV_CAPTURED_PIECE |
              piece << M_SHIFT_PIECE | en_passant_file << M_SHIFT_ENPASSANT_FILE |
              move_type << M_SHIFT_MOVE_TYPE | orig_square << M_SHIFT_ORIG_SQUARE |
              dest_square << M_SHIFT_DEST_SQUARE |
              aux_data << M_SHIFT_AUX_DATA) as u32)
    }

    #[inline(always)]
    pub fn get_score(&self) -> usize {
        ((self.0 & M_MASK_SCORE) >> M_SHIFT_SCORE) as usize
    }

    #[inline(always)]
    pub fn set_score(&mut self, score: usize) {
        assert!(score <= 0b111111);
        self.0 |= (score << M_SHIFT_SCORE) as u32;
    }

    #[inline(always)]
    pub fn set_score_bit(&mut self, b: usize) {
        assert!(b <= 5);
        self.0 |= 1 << b << M_SHIFT_SCORE;
    }

    #[inline(always)]
    pub fn clear_score_bit(&mut self, b: usize) {
        assert!(b <= 5);
        self.0 &= !(1 << b << M_SHIFT_SCORE);
    }

    #[inline(always)]
    pub fn move_type(&self) -> MoveType {
        ((self.0 & M_MASK_MOVE_TYPE) >> M_SHIFT_MOVE_TYPE) as MoveType
    }

    #[inline(always)]
    pub fn piece(&self) -> PieceType {
        ((self.0 & M_MASK_PIECE) >> M_SHIFT_PIECE) as PieceType
    }

    #[inline(always)]
    pub fn orig_square(&self) -> Square {
        ((self.0 & M_MASK_ORIG_SQUARE) >> M_SHIFT_ORIG_SQUARE) as Square
    }

    #[inline(always)]
    pub fn dest_square(&self) -> Square {
        ((self.0 & M_MASK_DEST_SQUARE) >> M_SHIFT_DEST_SQUARE) as Square
    }

    #[inline(always)]
    pub fn captured_piece(&self) -> PieceType {
        ((!self.0 & M_MASK_INV_CAPTURED_PIECE) >> M_SHIFT_INV_CAPTURED_PIECE) as PieceType
    }

    #[inline(always)]
    pub fn en_passant_file(&self) -> File {
        ((self.0 & M_MASK_ENPASSANT_FILE) >> M_SHIFT_ENPASSANT_FILE) as File
    }

    #[inline(always)]
    pub fn aux_data(&self) -> usize {
        ((self.0 & M_MASK_AUX_DATA) >> M_SHIFT_AUX_DATA) as usize
    }

    #[inline(always)]
    pub fn promoted_piece(&self) -> PieceType {
        Move::piece_from_aux_data(self.aux_data())
    }

    #[inline(always)]
    pub fn piece_from_aux_data(pp_code: usize) -> PieceType {
        match pp_code {
            0 => QUEEN,
            1 => ROOK,
            2 => BISHOP,
            3 => KNIGHT,
            _ => panic!("invalid promoted piece code"),
        }
    }
}

pub struct MoveStack {
    stack: [Move; MOVE_STACK_SIZE],
    top_index: usize,
}

impl MoveStack {
    pub fn new() -> MoveStack {
        use std::mem::uninitialized;
        unsafe {
            MoveStack {
                stack: uninitialized(),
                top_index: 0,
            }
        }
    }

    #[inline(always)]
    pub fn push(&mut self, m: Move) {
        self.stack[self.top_index] = m;
        self.top_index += 1;
    }
}

<|endoftext|>


<commit_before>extern crate regex;

use std::io::Read;

use hyper::Client;
use hyper::header::UserAgent;
use hyper::status::StatusCode;
use regex::Captures;
use regex::Regex;
use rustc_serialize::json::Json;

use handler::MessageHandler;
use handler::HandlerResult;
use message::IncomingMessage;

/// Respond to github issue links with the title and hyperlink
pub struct GithubIssueLinker;

impl GithubIssueLinker {
    pub fn new() -> GithubIssueLinker {
        GithubIssueLinker
    }

    pub fn can_handle(&self, msg: &str) -> bool {
        let re = regex!(r"https://github.com/(?P<owner>\w|\w\w|\w[\w-]+\w)/(?P<repo>[\w_-]+)/issues/(?P<issue>\d+)");
        re.is_match(msg)
    }

    pub fn get_captures<'a>(&self, msg: &'a str) -> Option<Captures<'a>> {
        let re = regex!(r"https://github.com/(?P<owner>\w|\w\w|\w[\w-]+\w)/(?P<repo>[\w_-]+)/issues/(?P<issue>\d+)");
        re.captures(msg)
    }
}

impl MessageHandler for GithubIssueLinker {
    fn name(&self) -> &str {
        "GithubIssueLinker"
    }

    fn handle(&self, incoming: &IncomingMessage) -> HandlerResult {
        if !self.can_handle(incoming.get_contents()) {
            return Ok(())
        }

        let captures = self.get_captures(incoming.get_contents()).unwrap();
        let owner = captures.name("owner").unwrap();
        let repo = captures.name("repo").unwrap();
        let issue = captures.name("issue").unwrap();

        let mut client = Client::new();
        let url = format!("https://api.github.com/repos/{}/{}/issues/{}", owner, repo, issue);
        let mut res = client.get(&url)
            .header(UserAgent("chatbot.rs".to_owned()))
            .send().unwrap();

        // Read the Response.
        if res.status == StatusCode::Ok {
            let mut body = String::new();
            res.read_to_string(&mut body).unwrap();

            let data = Json::from_str(body.as_ref()).unwrap();
            let obj = data.as_object().unwrap();

            let html_url = obj.get("html_url").unwrap().as_string().unwrap();
            let title = obj.get("title").unwrap().as_string().unwrap();

            let outgoing = format!("{} ({})", title, html_url);
            incoming.reply(outgoing).unwrap();
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use handler::GithubIssueLinker;
    use message::AdapterMsg;
    use message::IncomingMessage;
    use handler::MessageHandler;
    use std::sync::mpsc::channel;

    #[test]
    #[allow(unused_variables)]
    fn test_create() {
        let handler = GithubIssueLinker::new();
    }

    #[test]
    fn test_valid_urls() {
        let handler = GithubIssueLinker::new();

        assert!(handler.can_handle("https://github.com/jwilm/chatbot/issues/123"));
        assert!(handler.can_handle("https://github.com/NaMespacE/ano_ther-repo/issues/123"));
        assert!(!handler.can_handle("https://github.com/-hyphen/word/issues/123"));
        assert!(!handler.can_handle("https://github.com/hyphen-/word/issues/123"));
        assert!(!handler.can_handle("https://github.com/hyphens--/word/issues/123"));
    }

    #[test]
    fn test_response() {
        let handler = GithubIssueLinker::new();
        let msg = "words and words https://github.com/rust-lang/rust/issues/1";
        let (tx, rx) = channel();
        let inc = IncomingMessage::new(handler.name().to_owned(),
            None, None, None, msg.to_owned(), tx);

        handler.handle(&inc).unwrap();

        match rx.recv().unwrap() {
            AdapterMsg::Outgoing(_) => {
                assert!(true);
            },
            _ => panic!("Did not receive message from handler")
        };
    }
}
<commit_msg>Remove unused import<commit_after>extern crate regex;

use std::io::Read;

use hyper::Client;
use hyper::header::UserAgent;
use hyper::status::StatusCode;
use regex::Captures;
use rustc_serialize::json::Json;

use handler::MessageHandler;
use handler::HandlerResult;
use message::IncomingMessage;

/// Respond to github issue links with the title and hyperlink
pub struct GithubIssueLinker;

impl GithubIssueLinker {
    pub fn new() -> GithubIssueLinker {
        GithubIssueLinker
    }

    pub fn can_handle(&self, msg: &str) -> bool {
        let re = regex!(r"https://github.com/(?P<owner>\w|\w\w|\w[\w-]+\w)/(?P<repo>[\w_-]+)/issues/(?P<issue>\d+)");
        re.is_match(msg)
    }

    pub fn get_captures<'a>(&self, msg: &'a str) -> Option<Captures<'a>> {
        let re = regex!(r"https://github.com/(?P<owner>\w|\w\w|\w[\w-]+\w)/(?P<repo>[\w_-]+)/issues/(?P<issue>\d+)");
        re.captures(msg)
    }
}

impl MessageHandler for GithubIssueLinker {
    fn name(&self) -> &str {
        "GithubIssueLinker"
    }

    fn handle(&self, incoming: &IncomingMessage) -> HandlerResult {
        if !self.can_handle(incoming.get_contents()) {
            return Ok(())
        }

        let captures = self.get_captures(incoming.get_contents()).unwrap();
        let owner = captures.name("owner").unwrap();
        let repo = captures.name("repo").unwrap();
        let issue = captures.name("issue").unwrap();

        let mut client = Client::new();
        let url = format!("https://api.github.com/repos/{}/{}/issues/{}", owner, repo, issue);
        let mut res = client.get(&url)
            .header(UserAgent("chatbot.rs".to_owned()))
            .send().unwrap();

        // Read the Response.
        if res.status == StatusCode::Ok {
            let mut body = String::new();
            res.read_to_string(&mut body).unwrap();

            let data = Json::from_str(body.as_ref()).unwrap();
            let obj = data.as_object().unwrap();

            let html_url = obj.get("html_url").unwrap().as_string().unwrap();
            let title = obj.get("title").unwrap().as_string().unwrap();

            let outgoing = format!("{} ({})", title, html_url);
            incoming.reply(outgoing).unwrap();
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use handler::GithubIssueLinker;
    use message::AdapterMsg;
    use message::IncomingMessage;
    use handler::MessageHandler;
    use std::sync::mpsc::channel;

    #[test]
    #[allow(unused_variables)]
    fn test_create() {
        let handler = GithubIssueLinker::new();
    }

    #[test]
    fn test_valid_urls() {
        let handler = GithubIssueLinker::new();

        assert!(handler.can_handle("https://github.com/jwilm/chatbot/issues/123"));
        assert!(handler.can_handle("https://github.com/NaMespacE/ano_ther-repo/issues/123"));
        assert!(!handler.can_handle("https://github.com/-hyphen/word/issues/123"));
        assert!(!handler.can_handle("https://github.com/hyphen-/word/issues/123"));
        assert!(!handler.can_handle("https://github.com/hyphens--/word/issues/123"));
    }

    #[test]
    fn test_response() {
        let handler = GithubIssueLinker::new();
        let msg = "words and words https://github.com/rust-lang/rust/issues/1";
        let (tx, rx) = channel();
        let inc = IncomingMessage::new(handler.name().to_owned(),
            None, None, None, msg.to_owned(), tx);

        handler.handle(&inc).unwrap();

        match rx.recv().unwrap() {
            AdapterMsg::Outgoing(_) => {
                assert!(true);
            },
            _ => panic!("Did not receive message from handler")
        };
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "rustc_ser_type")]
use serialize::json::{Json, ToJson};
#[cfg(feature = "serde_type")]
use serde_json::value::{self, Value as Json};

use helpers::HelperDef;
use registry::Registry;
use context::Context;
use render::{Renderable, RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper {
    #[cfg(feature = "rustc_ser_type")]
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let value = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();

                rc.promote_local_vars();

                debug!("each value {:?}", value.value());
                let rendered = match value.value() {
                    &Json::Array(ref list) => {
                        let len = list.len();
                        for i in 0..len {
                            rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
                            rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
                            rc.set_local_var("@index".to_string(), i.to_json());

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]", path, inner_path, i);
                                debug!("each value {:?}", new_path);
                                rc.set_path(new_path);
                            }
                            // FIXME: context for literal

                            try!(t.render(c, r, rc));
                        }
                        Ok(())
                    }
                    &Json::Object(ref obj) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), k.to_json());

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]", path, inner_path, k);
                                rc.set_path(new_path);
                            }

                            try!(t.render(c, r, rc));
                        }

                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }

    #[cfg(feature = "serde_type")]
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let value = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();

                rc.promote_local_vars();

                debug!("each value {:?}", value.value);
                let rendered = match value.value {
                    Json::Array(ref list) => {
                        let len = list.len();
                        for i in 0..len {
                            rc.set_local_var("@first".to_string(), value::to_value(&(i == 0usize)));
                            rc.set_local_var("@last".to_string(), value::to_value(&(i == len - 1)));
                            rc.set_local_var("@index".to_string(), value::to_value(&i));

                            if let Some(ref inner_path) = value.path {
                                let new_path = format!("{}/{}.[{}]", path, inner_path, i);
                                debug!("each value {:?}", new_path);
                                rc.set_path(new_path);
                            }
                            try!(t.render(c, r, rc));
                        }
                        Ok(())
                    }
                    Json::Object(ref obj) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), value::to_value(&first));
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), value::to_value(&k));
                            if let Some(ref inner_path) = value.path {
                                let new_path = format!("{}/{}.[{}]", path, inner_path, k);
                                debug!("each value {:?}", new_path);
                                rc.set_path(new_path);
                            }

                            try!(t.render(c, r, rc));
                        }

                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::Template;
    use registry::Registry;

    use std::collections::BTreeMap;

    #[test]
    fn test_each() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:\
                                    {{this}}|{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(r0.ok().unwrap(),
                   "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m: BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    fn test_nested_array() {
        let t0 = Template::compile("{{#each this.[0]}}{{this}}{{/each}}".to_owned()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let t0 = Template::compile("{{#each this}}{{@key}}-{{value}}\n{{/each}}".to_owned())
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0",
                                   &({
                                       let mut rv = BTreeMap::new();
                                       rv.insert("foo".to_owned(), {
                                           let mut rv = BTreeMap::new();
                                           rv.insert("value".to_owned(), "bar".to_owned());
                                           rv
                                       });
                                       rv.insert("".to_owned(), {
                                           let mut rv = BTreeMap::new();
                                           rv.insert("value".to_owned(), "baz".to_owned());
                                           rv
                                       });
                                       rv
                                   }))
                           .unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }
}
<commit_msg>(fix) fixes serde branch<commit_after>#[cfg(feature = "rustc_ser_type")]
use serialize::json::{Json, ToJson};
#[cfg(feature = "serde_type")]
use serde_json::value::{self, Value as Json};

use helpers::HelperDef;
use registry::Registry;
use context::Context;
use render::{Renderable, RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper {
    #[cfg(feature = "rustc_ser_type")]
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let value = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();

                rc.promote_local_vars();

                debug!("each value {:?}", value.value());
                let rendered = match value.value() {
                    &Json::Array(ref list) => {
                        let len = list.len();
                        for i in 0..len {
                            rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
                            rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
                            rc.set_local_var("@index".to_string(), i.to_json());

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]", path, inner_path, i);
                                debug!("each value {:?}", new_path);
                                rc.set_path(new_path);
                            }
                            // FIXME: context for literal

                            try!(t.render(c, r, rc));
                        }
                        Ok(())
                    }
                    &Json::Object(ref obj) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), k.to_json());

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]", path, inner_path, k);
                                rc.set_path(new_path);
                            }

                            try!(t.render(c, r, rc));
                        }

                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }

    #[cfg(feature = "serde_type")]
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let value = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();

                rc.promote_local_vars();

                debug!("each value {:?}", value.value());
                let rendered = match value.value() {
                    &Json::Array(ref list) => {
                        let len = list.len();
                        for i in 0..len {
                            rc.set_local_var("@first".to_string(), value::to_value(&(i == 0usize)));
                            rc.set_local_var("@last".to_string(), value::to_value(&(i == len - 1)));
                            rc.set_local_var("@index".to_string(), value::to_value(&i));

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]", path, inner_path, i);
                                debug!("each value {:?}", new_path);
                                rc.set_path(new_path);
                            }
                            try!(t.render(c, r, rc));
                        }
                        Ok(())
                    }
                    &Json::Object(ref obj) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), value::to_value(&first));
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), value::to_value(&k));
                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]", path, inner_path, k);
                                debug!("each value {:?}", new_path);
                                rc.set_path(new_path);
                            }

                            try!(t.render(c, r, rc));
                        }

                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::Template;
    use registry::Registry;

    use std::collections::BTreeMap;

    #[test]
    fn test_each() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:\
                                    {{this}}|{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(r0.ok().unwrap(),
                   "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m: BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    fn test_nested_array() {
        let t0 = Template::compile("{{#each this.[0]}}{{this}}{{/each}}".to_owned()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let t0 = Template::compile("{{#each this}}{{@key}}-{{value}}\n{{/each}}".to_owned())
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0",
                                   &({
                                       let mut rv = BTreeMap::new();
                                       rv.insert("foo".to_owned(), {
                                           let mut rv = BTreeMap::new();
                                           rv.insert("value".to_owned(), "bar".to_owned());
                                           rv
                                       });
                                       rv.insert("".to_owned(), {
                                           let mut rv = BTreeMap::new();
                                           rv.insert("value".to_owned(), "baz".to_owned());
                                           rv
                                       });
                                       rv
                                   }))
                           .unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }
}
<|endoftext|>


<commit_before>use serialize::json::{Json, ToJson};

use helpers::{HelperDef};
use registry::{Registry};
use context::{Context};
use render::{Renderable, RenderContext, RenderError, render_error, Helper};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper{
    fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
        let param = try!(h.param(0).ok_or_else(|| render_error("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();
                let value = c.navigate(&path, param);

                rc.promote_local_vars();

                debug!("each value {}", value);
                let rendered = match *value {
                    Json::Array (ref list) => {
                        let len = list.len();
                        for i in 0..len {
                            rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
                            rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
                            rc.set_local_var("@index".to_string(), i.to_json());

                            let new_path = format!("{}/{}.[{}]", path, param, i);
                            debug!("each value {}", new_path);
                            rc.set_path(new_path);
                            try!(t.render(c, r, rc));
                        }
                        Ok(())
                    },
                    Json::Object(ref obj) => {
                        let mut first:bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), k.to_json());
                            let new_path = format!("{}/{}/{}", path, param, k);
                            rc.set_path(new_path);
                            try!(t.render(c, r, rc));
                        }

                        Ok(())
                    },
                    _ => {
                        Err(render_error("Param is not an iteratable."))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            },
            None => Ok(())
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};

    use std::collections::BTreeMap;

    #[test]
    fn test_each() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}".to_string()).ok().unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(r0.ok().unwrap(), "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m :BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    fn test_nested_array() {
        let t0 = Template::compile("{{#each this.[0]}}{{this}}{{/each}}".to_owned()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }
}
<commit_msg>Testcase for empty-keys bug with #each<commit_after>use serialize::json::{Json, ToJson};

use helpers::{HelperDef};
use registry::{Registry};
use context::{Context};
use render::{Renderable, RenderContext, RenderError, render_error, Helper};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper{
    fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
        let param = try!(h.param(0).ok_or_else(|| render_error("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();
                let value = c.navigate(&path, param);

                rc.promote_local_vars();

                debug!("each value {}", value);
                let rendered = match *value {
                    Json::Array (ref list) => {
                        let len = list.len();
                        for i in 0..len {
                            rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
                            rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
                            rc.set_local_var("@index".to_string(), i.to_json());

                            let new_path = format!("{}/{}.[{}]", path, param, i);
                            debug!("each value {}", new_path);
                            rc.set_path(new_path);
                            try!(t.render(c, r, rc));
                        }
                        Ok(())
                    },
                    Json::Object(ref obj) => {
                        let mut first:bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), k.to_json());
                            let new_path = format!("{}/{}/{}", path, param, k);
                            rc.set_path(new_path);
                            try!(t.render(c, r, rc));
                        }

                        Ok(())
                    },
                    _ => {
                        Err(render_error("Param is not an iteratable."))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            },
            None => Ok(())
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};

    use std::collections::BTreeMap;

    #[test]
    fn test_each() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}".to_string()).ok().unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(r0.ok().unwrap(), "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m :BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    fn test_nested_array() {
        let t0 = Template::compile("{{#each this.[0]}}{{this}}{{/each}}".to_owned()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let t0 = Template::compile("{{#each this}}{{@key}}-{{value}}\n{{/each}}".to_owned()).unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0", &({
            let mut rv = BTreeMap::new();
            rv.insert("foo".to_owned(), {
                let mut rv = BTreeMap::new();
                rv.insert("value".to_owned(), "bar".to_owned());
                rv
            });
            rv.insert("".to_owned(), {
                let mut rv = BTreeMap::new();
                rv.insert("value".to_owned(), "baz".to_owned());
                rv
            });
            rv
        })).unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }
}
<|endoftext|>


<commit_before>//! This will contain some good documentation about the LRS crate
//!
//! For now I guess enjoy this emoji of a cup 🍵

mod terms;
pub use terms::*;

mod equation;
pub use equation::*;
<commit_msg>Documentation and very simple unit tests. Also macros...<commit_after>//! This will contain some good documentation about the LRS crate
//!
//! For now I guess enjoy this emoji of a cup 🍵

mod terms;
pub use terms::*;

mod equation;
pub use equation::*;

/* Unit tests below */

macro_rules! symbol {
    ($v:expr, $s:expr) => ( Symbol { val: $v, state: $s } );
}

#[test]
fn lrs_symbol_create() {
    let s = symbol!('A', true);
    assert!(s.val == 'A');
    assert!(s.state == true);
}

#[test]
fn lrs_term_create() {
    let s = symbol!('A', true);
    let t = Term::new(s);

    assert!(t.contains(&symbol!('A', true)));
}<|endoftext|>