<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::collections::BTreeMap;
use std::fs::File;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::Store;

use toml::Value;

use error::RefErrorKind as REK;
use error::RefError as RE;
use error::ResultExt;
use error::Result;
use flags::RefFlags;
use hasher::*;
use module_path::ModuleEntryPath;
use util::*;

pub trait RefStore {

    /// Check whether there is a reference to the file at `pb`
    fn exists(&self, pb: PathBuf) -> Result<bool>;

    /// Get a Ref object from the store by hash.
    ///
    /// Returns None if the hash cannot be found.
    fn get_by_hash<'a>(&'a self, hash: String) -> Result<Option<FileLockEntry<'a>>>;

    /// Delete a ref by hash
    ///
    /// If the returned Result contains an error, the ref might not be deleted.
    fn delete_by_hash(&self, hash: String) -> Result<()>;

    /// Create a Ref object which refers to `pb`
    fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result<FileLockEntry<'a>>;

    fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, h: H)
        -> Result<FileLockEntry<'a>>;

    /// Get all reference objects
    fn all_references(&self) -> Result<StoreIdIterator>;

}

impl RefStore for Store {

    /// Check whether there is a reference to the file at `pb`
    fn exists(&self, pb: PathBuf) -> Result<bool> {
        pb.canonicalize()
            .chain_err(|| REK::PathCanonicalizationError)
            .and_then(|c| hash_path(&c))
            .chain_err(|| REK::PathHashingError)
            .and_then(|hash| {
                self.retrieve_for_module("ref").map(|iter| (hash, iter)).map_err(From::from)
            })
            .and_then(|(hash, possible_refs)| {
                // This is kind of a manual Iterator::filter() call what we do here, but with the
                // actual ::filter method we cannot return the error in a nice way, so we do it
                // manually here. If you can come up with a better version of this, feel free to
                // take this note as a todo.
                for r in possible_refs {
                    let contains_hash = try!(r.to_str()
                        .chain_err(|| REK::TypeConversionError)
                        .map(|s| s.contains(&hash[..]))
                    );

                    if !contains_hash {
                        continue;
                    }

                    match self.get(r.clone())? {
                        Some(fle) => {
                            if read_reference(&fle).map(|path| path == pb).unwrap_or(false) {
                                return Ok(true)
                            }
                        },

                        None => {
                            let e = format!("Failed to get from store: {}", r);
                            return Err(e).map_err(From::from)
                        },
                    }
                }

                Ok(false)
            })
    }

    /// Get a Ref object from the store by hash.
    ///
    /// Returns None if the hash cannot be found.
    fn get_by_hash<'a>(&'a self, hash: String) -> Result<Option<FileLockEntry<'a>>> {
        ModuleEntryPath::new(hash)
            .into_storeid()
            .and_then(|id| self.get(id))
            .map_err(From::from)
    }

    /// Delete a ref by hash
    ///
    /// If the returned Result contains an error, the ref might not be deleted.
    fn delete_by_hash(&self, hash: String) -> Result<()> {
        ModuleEntryPath::new(hash)
            .into_storeid()
            .and_then(|id| self.delete(id))
            .map_err(From::from)
    }

    /// Create a Ref object which refers to `pb`
    fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result<FileLockEntry<'a>> {
        self.create_with_hasher(pb, flags, DefaultHasher::new())
    }

    fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, mut h: H)
        -> Result<FileLockEntry<'a>>
    {
        use toml_query::insert::TomlValueInsertExt;

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

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

                // 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() {
                        Some(try!(h.create_hash(&pb, &mut file)))
                    } 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())
                                  .chain_err(|| REK::RefTargetCannotReadPermissions)
                        ))
                    } else {
                        None
                    };

                    Ok((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(|(opt_contenthash, opt_permissions)| {
                    pb.canonicalize()
                        .map(|can| (opt_contenthash, opt_permissions, can))
                        // if PathBuf::canonicalize() failed, build an error from the return value
                        .chain_err(|| REK::PathCanonicalizationError)
                })

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

                    Ok((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(|(opt_conhash, opt_perm, can, path_hash)| {
                    match can.to_str().map(String::from) {
                        // UTF convert error in PathBuf::to_str(),
                        None      => Err(RE::from_kind(REK::PathUTF8Error)),
                        Some(can) => Ok((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(|(opt_conhash, opt_perm, can, path_hash)| {
                    let fle = try!(self.create(ModuleEntryPath::new(path_hash)));
                    Ok((fle, opt_conhash, opt_perm, can))
                })
            )
        };

        for tpl in [
                Some((String::from("ref"),              Value::Table(BTreeMap::new()))),
                Some((String::from("ref.permissions"),  Value::Table(BTreeMap::new()))),
                Some((String::from("ref.path"),         Value::String(canonical_path))),
                Some((String::from("ref.content_hash"), Value::Table(BTreeMap::new()))),

                content_hash.map(|hash| {
                    (format!("ref.content_hash.{}", h.hash_name()), Value::String(hash))
                }),
                permissions.map(|p| {
                    (String::from("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(Some(_)) => {
                            let e = RE::from_kind(REK::HeaderFieldAlreadyExistsError);
                            return Err(e).chain_err(|| REK::HeaderFieldWriteError);
                        },
                        Ok(None) => {
                            // Okay, we just inserted a new header value...
                        },
                        Err(e) => return Err(e).chain_err(|| REK::HeaderFieldWriteError),
                    }
                }
                &None => {
                    debug!("Not going to insert.");
                }
            }
        }

        Ok(fle)
    }

    fn all_references(&self) -> Result<StoreIdIterator> {
        self.retrieve_for_module("ref").map_err(From::from)
    }
}

<commit_msg>Add RefStore::get_by_partial_hash()<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::collections::BTreeMap;
use std::fs::File;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::Store;

use toml::Value;

use error::RefErrorKind as REK;
use error::RefError as RE;
use error::ResultExt;
use error::Result;
use flags::RefFlags;
use hasher::*;
use module_path::ModuleEntryPath;
use util::*;

pub trait RefStore {

    /// Check whether there is a reference to the file at `pb`
    fn exists(&self, pb: PathBuf) -> Result<bool>;

    /// Get a Ref object from the store by hash.
    ///
    /// Returns None if the hash cannot be found.
    fn get_by_hash<'a>(&'a self, hash: String) -> Result<Option<FileLockEntry<'a>>>;

    /// Get a Ref object from the store by (eventually partial) hash.
    ///
    /// If the hash is complete, `RefStore::get_by_hash()` should be used as it is cheaper.
    /// If the hash comes from user input and thus might be abbreviated, this function can be used.
    fn get_by_partitial_hash<'a>(&'a self, hash: &String) -> Result<Option<FileLockEntry<'a>>>;

    /// Delete a ref by hash
    ///
    /// If the returned Result contains an error, the ref might not be deleted.
    fn delete_by_hash(&self, hash: String) -> Result<()>;

    /// Create a Ref object which refers to `pb`
    fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result<FileLockEntry<'a>>;

    fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, h: H)
        -> Result<FileLockEntry<'a>>;

    /// Get all reference objects
    fn all_references(&self) -> Result<StoreIdIterator>;

}

impl RefStore for Store {

    /// Check whether there is a reference to the file at `pb`
    fn exists(&self, pb: PathBuf) -> Result<bool> {
        pb.canonicalize()
            .chain_err(|| REK::PathCanonicalizationError)
            .and_then(|c| hash_path(&c))
            .chain_err(|| REK::PathHashingError)
            .and_then(|hash| {
                self.retrieve_for_module("ref").map(|iter| (hash, iter)).map_err(From::from)
            })
            .and_then(|(hash, possible_refs)| {
                // This is kind of a manual Iterator::filter() call what we do here, but with the
                // actual ::filter method we cannot return the error in a nice way, so we do it
                // manually here. If you can come up with a better version of this, feel free to
                // take this note as a todo.
                for r in possible_refs {
                    let contains_hash = try!(r.to_str()
                        .chain_err(|| REK::TypeConversionError)
                        .map(|s| s.contains(&hash[..]))
                    );

                    if !contains_hash {
                        continue;
                    }

                    match self.get(r.clone())? {
                        Some(fle) => {
                            if read_reference(&fle).map(|path| path == pb).unwrap_or(false) {
                                return Ok(true)
                            }
                        },

                        None => {
                            let e = format!("Failed to get from store: {}", r);
                            return Err(e).map_err(From::from)
                        },
                    }
                }

                Ok(false)
            })
    }

    /// Get a Ref object from the store by hash.
    ///
    /// Returns None if the hash cannot be found.
    fn get_by_hash<'a>(&'a self, hash: String) -> Result<Option<FileLockEntry<'a>>> {
        ModuleEntryPath::new(hash)
            .into_storeid()
            .and_then(|id| self.get(id))
            .map_err(From::from)
    }

    /// Get a Ref object from the store by (eventually partial) hash.
    ///
    /// If the hash is complete, `RefStore::get_by_hash()` should be used as it is cheaper.
    /// If the hash comes from user input and thus might be abbreviated, this function can be used.
    fn get_by_partitial_hash<'a>(&'a self, hash: &String) -> Result<Option<FileLockEntry<'a>>> {
        for id in self.retrieve_for_module("ref")? {
            let components_have_hash = id
                .components()
                .any(|c| c.as_os_str().to_str().map(|s| s.contains(hash)).unwrap_or(false));

            if components_have_hash {
                return self.get(id).map_err(From::from);
            }
        }
        Ok(None)
    }

    /// Delete a ref by hash
    ///
    /// If the returned Result contains an error, the ref might not be deleted.
    fn delete_by_hash(&self, hash: String) -> Result<()> {
        ModuleEntryPath::new(hash)
            .into_storeid()
            .and_then(|id| self.delete(id))
            .map_err(From::from)
    }

    /// Create a Ref object which refers to `pb`
    fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result<FileLockEntry<'a>> {
        self.create_with_hasher(pb, flags, DefaultHasher::new())
    }

    fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, mut h: H)
        -> Result<FileLockEntry<'a>>
    {
        use toml_query::insert::TomlValueInsertExt;

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

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

                // 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() {
                        Some(try!(h.create_hash(&pb, &mut file)))
                    } 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())
                                  .chain_err(|| REK::RefTargetCannotReadPermissions)
                        ))
                    } else {
                        None
                    };

                    Ok((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(|(opt_contenthash, opt_permissions)| {
                    pb.canonicalize()
                        .map(|can| (opt_contenthash, opt_permissions, can))
                        // if PathBuf::canonicalize() failed, build an error from the return value
                        .chain_err(|| REK::PathCanonicalizationError)
                })

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

                    Ok((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(|(opt_conhash, opt_perm, can, path_hash)| {
                    match can.to_str().map(String::from) {
                        // UTF convert error in PathBuf::to_str(),
                        None      => Err(RE::from_kind(REK::PathUTF8Error)),
                        Some(can) => Ok((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(|(opt_conhash, opt_perm, can, path_hash)| {
                    let fle = try!(self.create(ModuleEntryPath::new(path_hash)));
                    Ok((fle, opt_conhash, opt_perm, can))
                })
            )
        };

        for tpl in [
                Some((String::from("ref"),              Value::Table(BTreeMap::new()))),
                Some((String::from("ref.permissions"),  Value::Table(BTreeMap::new()))),
                Some((String::from("ref.path"),         Value::String(canonical_path))),
                Some((String::from("ref.content_hash"), Value::Table(BTreeMap::new()))),

                content_hash.map(|hash| {
                    (format!("ref.content_hash.{}", h.hash_name()), Value::String(hash))
                }),
                permissions.map(|p| {
                    (String::from("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(Some(_)) => {
                            let e = RE::from_kind(REK::HeaderFieldAlreadyExistsError);
                            return Err(e).chain_err(|| REK::HeaderFieldWriteError);
                        },
                        Ok(None) => {
                            // Okay, we just inserted a new header value...
                        },
                        Err(e) => return Err(e).chain_err(|| REK::HeaderFieldWriteError),
                    }
                }
                &None => {
                    debug!("Not going to insert.");
                }
            }
        }

        Ok(fle)
    }

    fn all_references(&self) -> Result<StoreIdIterator> {
        self.retrieve_for_module("ref").map_err(From::from)
    }
}

<|endoftext|>


<commit_before>//! # Virtual File System
//!
//! VFS stores all files read by rust-analyzer. Reading file contents from VFS
//! always returns the same contents, unless VFS was explicitly modified with
//! [`set_file_contents`]. All changes to VFS are logged, and can be retrieved via
//! [`take_changes`] method. The pack of changes is then pushed to `salsa` and
//! triggers incremental recomputation.
//!
//! Files in VFS are identified with [`FileId`]s -- interned paths. The notion of
//! the path, [`VfsPath`] is somewhat abstract: at the moment, it is represented
//! as an [`std::path::PathBuf`] internally, but this is an implementation detail.
//!
//! VFS doesn't do IO or file watching itself. For that, see the [`loader`]
//! module. [`loader::Handle`] is an object-safe trait which abstracts both file
//! loading and file watching. [`Handle`] is dynamically configured with a set of
//! directory entries which should be scanned and watched. [`Handle`] then
//! asynchronously pushes file changes. Directory entries are configured in
//! free-form via list of globs, it's up to the [`Handle`] to interpret the globs
//! in any specific way.
//!
//! VFS stores a flat list of files. [`FileSet`] can partition this list of files
//! into disjoint sets of files. Traversal-like operations (including getting
//! the neighbor file by the relative path) are handled by the [`FileSet`].
//! [`FileSet`]s are also pushed to salsa and cause it to re-check `mod foo;`
//! declarations when files are created or deleted.
//!
//! [`file_set::FileSet`] and [`loader::Entry`] play similar, but different roles.
//! Both specify the "set of paths/files", one is geared towards file watching,
//! the other towards salsa changes. In particular, single [`file_set::FileSet`]
//! may correspond to several [`loader::Entry`]. For example, a crate from
//! crates.io which uses code generation would have two [`Entries`] -- for sources
//! in `~/.cargo`, and for generated code in `./target/debug/build`. It will
//! have a single [`FileSet`] which unions the two sources.
//!
//! [`set_file_contents`]: Vfs::set_file_contents
//! [`take_changes`]: Vfs::take_changes
//! [`FileSet`]: file_set::FileSet
//! [`Handle`]: loader::Handle
//! [`Entries`]: loader::Entry
mod anchored_path;
pub mod file_set;
pub mod loader;
mod path_interner;
mod vfs_path;

use std::{fmt, mem};

use crate::path_interner::PathInterner;

pub use crate::{
    anchored_path::{AnchoredPath, AnchoredPathBuf},
    vfs_path::VfsPath,
};
pub use paths::{AbsPath, AbsPathBuf};

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

#[derive(Default)]
pub struct Vfs {
    interner: PathInterner,
    data: Vec<Option<Vec<u8>>>,
    changes: Vec<ChangedFile>,
}

pub struct ChangedFile {
    pub file_id: FileId,
    pub change_kind: ChangeKind,
}

impl ChangedFile {
    pub fn exists(&self) -> bool {
        self.change_kind != ChangeKind::Delete
    }
    pub fn is_created_or_deleted(&self) -> bool {
        matches!(self.change_kind, ChangeKind::Create | ChangeKind::Delete)
    }
}

#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum ChangeKind {
    Create,
    Modify,
    Delete,
}

impl Vfs {
    pub fn len(&self) -> usize {
        self.data.len()
    }
    pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
        self.interner.get(path).filter(|&it| self.get(it).is_some())
    }
    pub fn file_path(&self, file_id: FileId) -> VfsPath {
        self.interner.lookup(file_id).clone()
    }
    pub fn file_contents(&self, file_id: FileId) -> &[u8] {
        self.get(file_id).as_deref().unwrap()
    }
    pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
        (0..self.data.len())
            .map(|it| FileId(it as u32))
            .filter(move |&file_id| self.get(file_id).is_some())
            .map(move |file_id| {
                let path = self.interner.lookup(file_id);
                (file_id, path)
            })
    }
    pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool {
        let file_id = self.alloc_file_id(path);
        let change_kind = match (&self.get(file_id), &contents) {
            (None, None) => return false,
            (None, Some(_)) => ChangeKind::Create,
            (Some(_), None) => ChangeKind::Delete,
            (Some(old), Some(new)) if old == new => return false,
            (Some(_), Some(_)) => ChangeKind::Modify,
        };

        *self.get_mut(file_id) = contents;
        self.changes.push(ChangedFile { file_id, change_kind });
        true
    }
    pub fn has_changes(&self) -> bool {
        !self.changes.is_empty()
    }
    pub fn take_changes(&mut self) -> Vec<ChangedFile> {
        mem::take(&mut self.changes)
    }
    fn alloc_file_id(&mut self, path: VfsPath) -> FileId {
        let file_id = self.interner.intern(path);
        let idx = file_id.0 as usize;
        let len = self.data.len().max(idx + 1);
        self.data.resize_with(len, || None);
        file_id
    }
    fn get(&self, file_id: FileId) -> &Option<Vec<u8>> {
        &self.data[file_id.0 as usize]
    }
    fn get_mut(&mut self, file_id: FileId) -> &mut Option<Vec<u8>> {
        &mut self.data[file_id.0 as usize]
    }
}

impl fmt::Debug for Vfs {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Vfs").field("n_files", &self.data.len()).finish()
    }
}
<commit_msg>Use `file_set::FileSet` and `FileSet` consistently in doc<commit_after>//! # Virtual File System
//!
//! VFS stores all files read by rust-analyzer. Reading file contents from VFS
//! always returns the same contents, unless VFS was explicitly modified with
//! [`set_file_contents`]. All changes to VFS are logged, and can be retrieved via
//! [`take_changes`] method. The pack of changes is then pushed to `salsa` and
//! triggers incremental recomputation.
//!
//! Files in VFS are identified with [`FileId`]s -- interned paths. The notion of
//! the path, [`VfsPath`] is somewhat abstract: at the moment, it is represented
//! as an [`std::path::PathBuf`] internally, but this is an implementation detail.
//!
//! VFS doesn't do IO or file watching itself. For that, see the [`loader`]
//! module. [`loader::Handle`] is an object-safe trait which abstracts both file
//! loading and file watching. [`Handle`] is dynamically configured with a set of
//! directory entries which should be scanned and watched. [`Handle`] then
//! asynchronously pushes file changes. Directory entries are configured in
//! free-form via list of globs, it's up to the [`Handle`] to interpret the globs
//! in any specific way.
//!
//! VFS stores a flat list of files. [`file_set::FileSet`] can partition this list
//! of files into disjoint sets of files. Traversal-like operations (including
//! getting the neighbor file by the relative path) are handled by the [`FileSet`].
//! [`FileSet`]s are also pushed to salsa and cause it to re-check `mod foo;`
//! declarations when files are created or deleted.
//!
//! [`FileSet`] and [`loader::Entry`] play similar, but different roles.
//! Both specify the "set of paths/files", one is geared towards file watching,
//! the other towards salsa changes. In particular, single [`FileSet`]
//! may correspond to several [`loader::Entry`]. For example, a crate from
//! crates.io which uses code generation would have two [`Entries`] -- for sources
//! in `~/.cargo`, and for generated code in `./target/debug/build`. It will
//! have a single [`FileSet`] which unions the two sources.
//!
//! [`set_file_contents`]: Vfs::set_file_contents
//! [`take_changes`]: Vfs::take_changes
//! [`FileSet`]: file_set::FileSet
//! [`Handle`]: loader::Handle
//! [`Entries`]: loader::Entry
mod anchored_path;
pub mod file_set;
pub mod loader;
mod path_interner;
mod vfs_path;

use std::{fmt, mem};

use crate::path_interner::PathInterner;

pub use crate::{
    anchored_path::{AnchoredPath, AnchoredPathBuf},
    vfs_path::VfsPath,
};
pub use paths::{AbsPath, AbsPathBuf};

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

#[derive(Default)]
pub struct Vfs {
    interner: PathInterner,
    data: Vec<Option<Vec<u8>>>,
    changes: Vec<ChangedFile>,
}

pub struct ChangedFile {
    pub file_id: FileId,
    pub change_kind: ChangeKind,
}

impl ChangedFile {
    pub fn exists(&self) -> bool {
        self.change_kind != ChangeKind::Delete
    }
    pub fn is_created_or_deleted(&self) -> bool {
        matches!(self.change_kind, ChangeKind::Create | ChangeKind::Delete)
    }
}

#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum ChangeKind {
    Create,
    Modify,
    Delete,
}

impl Vfs {
    pub fn len(&self) -> usize {
        self.data.len()
    }
    pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
        self.interner.get(path).filter(|&it| self.get(it).is_some())
    }
    pub fn file_path(&self, file_id: FileId) -> VfsPath {
        self.interner.lookup(file_id).clone()
    }
    pub fn file_contents(&self, file_id: FileId) -> &[u8] {
        self.get(file_id).as_deref().unwrap()
    }
    pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
        (0..self.data.len())
            .map(|it| FileId(it as u32))
            .filter(move |&file_id| self.get(file_id).is_some())
            .map(move |file_id| {
                let path = self.interner.lookup(file_id);
                (file_id, path)
            })
    }
    pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool {
        let file_id = self.alloc_file_id(path);
        let change_kind = match (&self.get(file_id), &contents) {
            (None, None) => return false,
            (None, Some(_)) => ChangeKind::Create,
            (Some(_), None) => ChangeKind::Delete,
            (Some(old), Some(new)) if old == new => return false,
            (Some(_), Some(_)) => ChangeKind::Modify,
        };

        *self.get_mut(file_id) = contents;
        self.changes.push(ChangedFile { file_id, change_kind });
        true
    }
    pub fn has_changes(&self) -> bool {
        !self.changes.is_empty()
    }
    pub fn take_changes(&mut self) -> Vec<ChangedFile> {
        mem::take(&mut self.changes)
    }
    fn alloc_file_id(&mut self, path: VfsPath) -> FileId {
        let file_id = self.interner.intern(path);
        let idx = file_id.0 as usize;
        let len = self.data.len().max(idx + 1);
        self.data.resize_with(len, || None);
        file_id
    }
    fn get(&self, file_id: FileId) -> &Option<Vec<u8>> {
        &self.data[file_id.0 as usize]
    }
    fn get_mut(&mut self, file_id: FileId) -> &mut Option<Vec<u8>> {
        &mut self.data[file_id.0 as usize]
    }
}

impl fmt::Debug for Vfs {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Vfs").field("n_files", &self.data.len()).finish()
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate cc;

use std::env;
use std::path::PathBuf;

fn main() {
    cc::Build::new()
        .flag("-std=c11")
        .flag("-march=native")
        .flag("-O3")
        .file("CRoaring/roaring.c")
        .compile("libroaring.a");

    let bindings = bindgen::Builder::default()
        .blacklist_type("max_align_t")
        .header("CRoaring/roaring.h")
        .generate_inline_functions(true)
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("croaring-sys.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>Build CRoaring with flags if compiler supports them<commit_after>extern crate bindgen;
extern crate cc;

use std::env;
use std::path::PathBuf;

fn main() {
    cc::Build::new()
        .flag_if_supported("-std=c11")
        .flag_if_supported("-march=native")
        .flag_if_supported("-O3")
        .file("CRoaring/roaring.c")
        .compile("libroaring.a");

    let bindings = bindgen::Builder::default()
        .blacklist_type("max_align_t")
        .header("CRoaring/roaring.h")
        .generate_inline_functions(true)
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("croaring-sys.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>use memory::MemSegment;
use screen::Screen;
use cart::Cart;
use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

mod ppu_reg;
use ppu::ppu_reg::*;

mod ppu_memory;
use ppu::ppu_memory::*;

mod sprite_rendering;
use ppu::sprite_rendering::*;

mod background_rendering;

pub const SCREEN_WIDTH: usize = 256;
pub const SCREEN_HEIGHT: usize = 240;
pub const SCREEN_BUFFER_SIZE: usize = SCREEN_WIDTH * SCREEN_HEIGHT;

#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(C)]
pub struct Color(u8);
impl Color {
    fn from_bits_truncate(val: u8) -> Color {
        Color(val & 0b0011_1111)
    }

    pub fn bits(&self) -> u8 {
        self.0
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PaletteSet {
    Background,
    Sprite,
}

impl PaletteSet {
    fn table(&self) -> u16 {
        match *self {
            PaletteSet::Background => 0x00,
            PaletteSet::Sprite => 0x10,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PaletteIndex {
    pub set: PaletteSet,
    pub palette_id: u8,
    pub color_id: u8,
}

impl PaletteIndex {
    fn to_addr(self) -> u16 {
        let mut addr: u16 = 0x3F00;
        addr = addr | self.set.table();
        addr = addr | (self.palette_id as u16 & 0x03) << 2;
        addr = addr | self.color_id as u16 & 0x03;
        addr
    }

    fn is_transparent(&self) -> bool {
        self.color_id == 0
    }
}

#[derive(Debug, Copy, Clone)]
pub struct TilePattern {
    lo: u8,
    hi: u8,
}

impl Default for TilePattern {
    fn default() -> TilePattern {
        TilePattern{
            lo: 0,
            hi: 0,
        }
    }
}

pub struct PPU {
    reg: PPUReg,
    ppudata_read_buffer: u8,
    ppu_mem: PPUMemory,

    screen: Box<Screen>,
    screen_buffer: [Color; SCREEN_BUFFER_SIZE],

    sprite_data: SpriteRenderer,

    global_cyc: u64,
    cyc: u16,
    sl: i16,
    frame: u32,
}

#[derive(Copy, Debug, PartialEq, Clone)]
pub enum StepResult {
    NMI,
    Continue,
}

impl PPU {
    pub fn new(cart: Rc<RefCell<Cart>>, screen: Box<Screen>) -> PPU {
        PPU {
            reg: Default::default(),
            ppudata_read_buffer: 0,
            ppu_mem: PPUMemory::new(cart),
            screen_buffer: [Color::from_bits_truncate(0x00); SCREEN_BUFFER_SIZE],
            screen: screen,

            sprite_data: Default::default(),

            global_cyc: 0,
            cyc: 0,
            sl: 241,
            frame: 0,
        }
    }

    pub fn run_to(&mut self, cpu_cycle: u64) -> StepResult {
        let mut hit_nmi = false;
        while self.global_cyc < (cpu_cycle * 3) {
            self.tick_cycle();
            hit_nmi |= self.run_cycle();
        }

        if hit_nmi {
            StepResult::NMI
        } else {
            StepResult::Continue
        }
    }

    fn tick_cycle(&mut self) {
        self.global_cyc += 1;
        self.cyc += 1;
        if self.cyc == 341 {
            self.cyc = 0;
            self.sl += 1;
            if self.sl == 261 {
                self.sl = -1;
                self.frame += 1;
            }
        }
    }

    fn run_cycle(&mut self) -> bool {
        match (self.cyc, self.sl) {
            (c, -1) => self.prerender_scanline(c),
            (c, sl @ 0...239) => self.visible_scanline(c, sl),
            (_, 240) => (), //Post-render idle scanline
            (1, 241) => return self.start_vblank(),
            (_, 241...260) => (), //VBlank lines
            _ => (),
        }
        false
    }

    fn prerender_scanline(&mut self, cycle: u16) {
        if cycle == 0 {
            self.reg.ppustat.remove(VBLANK);
        }
    }

    fn visible_scanline(&mut self, pixel: u16, scanline: i16) {
        // Nothing here yet
        self.visible_scanline_sprite(pixel, scanline);
        if pixel >= 256 {
            return;
        }
        let x = pixel as usize;
        let y = scanline as usize;
        self.screen_buffer[y * SCREEN_WIDTH + x] = self.get_pixel(pixel, scanline as u16);
    }

    fn get_pixel(&mut self, px: u16, sl: u16) -> Color {
        let (priority, sprite_pal_idx) = self.get_sprite_pixel(px);
        let background_pal_idx = self.get_background_pixel(px, sl);

        let pal_idx = match (background_pal_idx, priority, sprite_pal_idx) {
            (bck, _, spr) if spr.is_transparent() => bck,
            (bck, _, spr) if bck.is_transparent() => spr,
            (_, SpritePriority::Foreground, spr) => spr,
            (bck, SpritePriority::Background, _) => bck,
        };
        self.read_palette(pal_idx)
    }

    fn start_vblank(&mut self) -> bool {
        let buf = &self.screen_buffer;
        self.screen.draw(buf);
        if self.frame > 0 {
            self.reg.ppustat.insert(VBLANK);
            self.reg.ppuctrl.generate_vblank_nmi()
        } else {
            false
        }
    }

    fn read_palette(&mut self, idx: PaletteIndex) -> Color {
        let bits = self.ppu_mem.read(idx.to_addr());
        Color::from_bits_truncate(bits)
    }

    fn read_tile_pattern(&mut self, tile_id: u8, fine_y_scroll: u16, tile_table: u16) -> TilePattern {
        let lo_addr = self.get_tile_addr(tile_id, 0, fine_y_scroll, tile_table);
        let hi_addr = self.get_tile_addr(tile_id, 8, fine_y_scroll, tile_table);
        TilePattern{
            lo: self.ppu_mem.read(lo_addr),
            hi: self.ppu_mem.read(hi_addr),
        }
    }

    fn get_tile_addr(&self, tile_id: u8, plane: u8, fine_y_scroll: u16, tile_table: u16) -> u16 {
        let mut tile_addr = 0u16;
        tile_addr |= fine_y_scroll;
        tile_addr |= plane as u16; //Plane must be 0 for low or 8 for high
        tile_addr |= (tile_id as u16) << 4;
        tile_addr |= tile_table; //Table must be 0x0000 or 0x1000
        tile_addr
    }

    fn get_color_in_pattern(&self, pattern: TilePattern, fine_x: u32) -> u8 {
        let lo = pattern.lo;
        let hi = pattern.hi;
        let shift = 0x07 - fine_x;
        let color_id_lo = lo.wrapping_shr(shift) & 0x01;
        let color_id_hi = (hi.wrapping_shr(shift) & 0x01) << 1;
        color_id_lo | color_id_hi
    }

    #[cfg(feature="cputrace")]
    pub fn cycle(&self) -> u16 {
        self.cyc
    }

    #[cfg(feature="cputrace")]
    pub fn scanline(&self) -> i16 {
        self.sl
    }

    #[cfg(feature="cputrace")]
    pub fn vram_addr(&self) -> u16 {
        self.reg.ppuaddr
    }
}

impl MemSegment for PPU {
    fn read(&mut self, idx: u16) -> u8 {
        match idx % 8 {
            0x0004 => self.sprite_data.read(self.reg.oamaddr as u16),
            0x0007 => {
                let addr = self.reg.ppuaddr;
                match addr {
                    0x0000...0x3EFF => {
                        let old_buffer = self.ppudata_read_buffer;
                        self.ppudata_read_buffer = self.ppu_mem.read(addr);
                        self.reg.incr_ppuaddr();
                        old_buffer
                    }
                    0x3F00...0x3FFF => {
                        let read_result = self.ppu_mem.read(addr);
                        self.reg.incr_ppuaddr();
                        self.ppudata_read_buffer = self.ppu_mem.read_bypass_palette(addr);
                        read_result
                    }
                    x => invalid_address!(x),
                }
            }
            _ => self.reg.read(idx),
        }
    }

    fn write(&mut self, idx: u16, val: u8) {
        match idx % 8 {
            0x0004 => {
                self.sprite_data.write(self.reg.oamaddr as u16, val);
                self.reg.incr_oamaddr();
            }
            0x0007 => {
                self.ppu_mem.write(self.reg.ppuaddr, val);
                self.reg.incr_ppuaddr();
            }
            _ => self.reg.write(idx, val),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use mappers::{Mapper, MapperParams};
    use std::rc::Rc;
    use std::cell::RefCell;
    use cart::Cart;
    use screen::DummyScreen;
    use ppu::ppu_reg::PPUCtrl;
    use memory::MemSegment;

    pub fn create_test_ppu() -> PPU {
        create_test_ppu_with_rom(vec![0u8; 0x1000])
    }

    pub fn create_test_ppu_with_rom(chr_rom: Vec<u8>) -> PPU {
        let mapper = Mapper::new(0, MapperParams::simple(vec![0u8; 0x1000], chr_rom));
        let cart = Cart::new(mapper);
        PPU::new(Rc::new(RefCell::new(cart)), Box::new(DummyScreen::new()))
    }

    #[test]
    fn reading_oamdata_doesnt_increment_oamaddr() {
        let mut ppu = create_test_ppu();
        ppu.reg.oamaddr = 0;
        ppu.read(0x2004);
        assert_eq!(ppu.reg.oamaddr, 0);
    }

    #[test]
    fn writing_oamdata_increments_oamaddr() {
        let mut ppu = create_test_ppu();
        ppu.reg.oamaddr = 0;
        ppu.write(0x2004, 12);
        assert_eq!(ppu.reg.oamaddr, 1);
        ppu.reg.oamaddr = 255;
        ppu.write(0x2004, 12);
        assert_eq!(ppu.reg.oamaddr, 0);
    }

    #[test]
    fn ppu_can_read_chr_rom() {
        let mut chr_rom = vec![0u8; 0x2000];
        chr_rom[0x0ABC] = 12;
        chr_rom[0x0DBA] = 212;
        let mut ppu = create_test_ppu_with_rom(chr_rom);

        ppu.reg.ppuaddr = 0x0ABC;
        ppu.read(0x2007);//Dummy Read
        assert_eq!(ppu.read(0x2007), 12);

        ppu.reg.ppuaddr = 0x0DBA;
        ppu.read(0x2007);//Dummy Read
        assert_eq!(ppu.read(0x2007), 212);
    }

    #[test]
    fn ppu_can_read_write_vram() {
        let mut ppu = create_test_ppu();

        ppu.reg.ppuaddr = 0x2ABC;
        ppu.write(0x2007, 12);
        ppu.reg.ppuaddr = 0x2ABC;
        ppu.read(0x2007);//Dummy read
        assert_eq!(ppu.read(0x2007), 12);

        ppu.reg.ppuaddr = 0x2DBA;
        ppu.write(0x2007, 212);
        ppu.reg.ppuaddr = 0x2DBA;
        ppu.read(0x2007);//Dummy Read
        assert_eq!(ppu.read(0x2007), 212);

        // Mirroring
        ppu.reg.ppuaddr = 0x2EFC;
        ppu.write(0x2007, 128);
        ppu.reg.ppuaddr = 0x3EFC;
        ppu.read(0x2007);//Dummy Read
        assert_eq!(ppu.read(0x2007), 128);
    }

    #[test]
    fn ppu_needs_no_dummy_read_for_palette_data() {
        let mut ppu = create_test_ppu();
        ppu.reg.ppuaddr = 0x3F16;
        ppu.write(0x2007, 21);
        ppu.reg.ppuaddr = 0x3F16;
        assert_eq!(ppu.read(0x2007), 21);
    }

    #[test]
    fn accessing_ppudata_increments_ppuaddr() {
        let mut ppu = create_test_ppu();
        ppu.reg.ppuaddr = 0x2000;
        ppu.read(0x2007);
        assert_eq!(ppu.reg.ppuaddr, 0x2001);
        ppu.write(0x2007, 0);
        assert_eq!(ppu.reg.ppuaddr, 0x2002);
    }

    #[test]
    fn accessing_ppudata_increments_ppuaddr_by_32_when_ctrl_flag_is_set() {
        let mut ppu = create_test_ppu();
        ppu.reg.ppuctrl = PPUCtrl::new(0b0000_0100);
        ppu.reg.ppuaddr = 0x2000;
        ppu.read(0x2007);
        assert_eq!(ppu.reg.ppuaddr, 0x2020);
        ppu.write(0x2007, 0);
        assert_eq!(ppu.reg.ppuaddr, 0x2040);
    }
}
<commit_msg>Add skipping the last pixel of the prerender scanline on odd frames.<commit_after>use memory::MemSegment;
use screen::Screen;
use cart::Cart;
use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

mod ppu_reg;
use ppu::ppu_reg::*;

mod ppu_memory;
use ppu::ppu_memory::*;

mod sprite_rendering;
use ppu::sprite_rendering::*;

mod background_rendering;

pub const SCREEN_WIDTH: usize = 256;
pub const SCREEN_HEIGHT: usize = 240;
pub const SCREEN_BUFFER_SIZE: usize = SCREEN_WIDTH * SCREEN_HEIGHT;

#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(C)]
pub struct Color(u8);
impl Color {
    fn from_bits_truncate(val: u8) -> Color {
        Color(val & 0b0011_1111)
    }

    pub fn bits(&self) -> u8 {
        self.0
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PaletteSet {
    Background,
    Sprite,
}

impl PaletteSet {
    fn table(&self) -> u16 {
        match *self {
            PaletteSet::Background => 0x00,
            PaletteSet::Sprite => 0x10,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PaletteIndex {
    pub set: PaletteSet,
    pub palette_id: u8,
    pub color_id: u8,
}

impl PaletteIndex {
    fn to_addr(self) -> u16 {
        let mut addr: u16 = 0x3F00;
        addr = addr | self.set.table();
        addr = addr | (self.palette_id as u16 & 0x03) << 2;
        addr = addr | self.color_id as u16 & 0x03;
        addr
    }

    fn is_transparent(&self) -> bool {
        self.color_id == 0
    }
}

#[derive(Debug, Copy, Clone)]
pub struct TilePattern {
    lo: u8,
    hi: u8,
}

impl Default for TilePattern {
    fn default() -> TilePattern {
        TilePattern{
            lo: 0,
            hi: 0,
        }
    }
}

pub struct PPU {
    reg: PPUReg,
    ppudata_read_buffer: u8,
    ppu_mem: PPUMemory,

    screen: Box<Screen>,
    screen_buffer: [Color; SCREEN_BUFFER_SIZE],

    sprite_data: SpriteRenderer,

    global_cyc: u64,
    cyc: u16,
    sl: i16,
    frame: u32,
}

#[derive(Copy, Debug, PartialEq, Clone)]
pub enum StepResult {
    NMI,
    Continue,
}

impl PPU {
    pub fn new(cart: Rc<RefCell<Cart>>, screen: Box<Screen>) -> PPU {
        PPU {
            reg: Default::default(),
            ppudata_read_buffer: 0,
            ppu_mem: PPUMemory::new(cart),
            screen_buffer: [Color::from_bits_truncate(0x00); SCREEN_BUFFER_SIZE],
            screen: screen,

            sprite_data: Default::default(),

            global_cyc: 0,
            cyc: 0,
            sl: 241,
            frame: 0,
        }
    }

    pub fn run_to(&mut self, cpu_cycle: u64) -> StepResult {
        let mut hit_nmi = false;
        while self.global_cyc < (cpu_cycle * 3) {
            self.tick_cycle();
            hit_nmi |= self.run_cycle();
        }

        if hit_nmi {
            StepResult::NMI
        } else {
            StepResult::Continue
        }
    }

    fn tick_cycle(&mut self) {
        self.global_cyc += 1;
        self.cyc += 1;
        if self.cyc == 341 {
            self.cyc = 0;
            self.sl += 1;
            if self.sl == 261 {
                self.sl = -1;
                self.frame += 1;
            }
        }
    }

    fn run_cycle(&mut self) -> bool {
        match (self.cyc, self.sl) {
            (c, -1) => self.prerender_scanline(c),
            (c, sl @ 0...239) => self.visible_scanline(c, sl),
            (_, 240) => (), //Post-render idle scanline
            (1, 241) => return self.start_vblank(),
            (_, 241...260) => (), //VBlank lines
            _ => (),
        }
        false
    }

    fn prerender_scanline(&mut self, cycle: u16) {
        if cycle == 0 {
            self.reg.ppustat.remove(VBLANK);
        }
        if cycle == 339 && self.frame % 2 == 1 {
            self.tick_cycle()
        }
    }

    fn visible_scanline(&mut self, pixel: u16, scanline: i16) {
        // Nothing here yet
        self.visible_scanline_sprite(pixel, scanline);
        if pixel >= 256 {
            return;
        }
        let x = pixel as usize;
        let y = scanline as usize;
        self.screen_buffer[y * SCREEN_WIDTH + x] = self.get_pixel(pixel, scanline as u16);
    }

    fn get_pixel(&mut self, px: u16, sl: u16) -> Color {
        let (priority, sprite_pal_idx) = self.get_sprite_pixel(px);
        let background_pal_idx = self.get_background_pixel(px, sl);

        let pal_idx = match (background_pal_idx, priority, sprite_pal_idx) {
            (bck, _, spr) if spr.is_transparent() => bck,
            (bck, _, spr) if bck.is_transparent() => spr,
            (_, SpritePriority::Foreground, spr) => spr,
            (bck, SpritePriority::Background, _) => bck,
        };
        self.read_palette(pal_idx)
    }

    fn start_vblank(&mut self) -> bool {
        let buf = &self.screen_buffer;
        self.screen.draw(buf);
        if self.frame > 0 {
            self.reg.ppustat.insert(VBLANK);
            self.reg.ppuctrl.generate_vblank_nmi()
        } else {
            false
        }
    }

    fn read_palette(&mut self, idx: PaletteIndex) -> Color {
        let bits = self.ppu_mem.read(idx.to_addr());
        Color::from_bits_truncate(bits)
    }

    fn read_tile_pattern(&mut self, tile_id: u8, fine_y_scroll: u16, tile_table: u16) -> TilePattern {
        let lo_addr = self.get_tile_addr(tile_id, 0, fine_y_scroll, tile_table);
        let hi_addr = self.get_tile_addr(tile_id, 8, fine_y_scroll, tile_table);
        TilePattern{
            lo: self.ppu_mem.read(lo_addr),
            hi: self.ppu_mem.read(hi_addr),
        }
    }

    fn get_tile_addr(&self, tile_id: u8, plane: u8, fine_y_scroll: u16, tile_table: u16) -> u16 {
        let mut tile_addr = 0u16;
        tile_addr |= fine_y_scroll;
        tile_addr |= plane as u16; //Plane must be 0 for low or 8 for high
        tile_addr |= (tile_id as u16) << 4;
        tile_addr |= tile_table; //Table must be 0x0000 or 0x1000
        tile_addr
    }

    fn get_color_in_pattern(&self, pattern: TilePattern, fine_x: u32) -> u8 {
        let lo = pattern.lo;
        let hi = pattern.hi;
        let shift = 0x07 - fine_x;
        let color_id_lo = lo.wrapping_shr(shift) & 0x01;
        let color_id_hi = (hi.wrapping_shr(shift) & 0x01) << 1;
        color_id_lo | color_id_hi
    }

    #[cfg(feature="cputrace")]
    pub fn cycle(&self) -> u16 {
        self.cyc
    }

    #[cfg(feature="cputrace")]
    pub fn scanline(&self) -> i16 {
        self.sl
    }

    #[cfg(feature="cputrace")]
    pub fn vram_addr(&self) -> u16 {
        self.reg.ppuaddr
    }
}

impl MemSegment for PPU {
    fn read(&mut self, idx: u16) -> u8 {
        match idx % 8 {
            0x0004 => self.sprite_data.read(self.reg.oamaddr as u16),
            0x0007 => {
                let addr = self.reg.ppuaddr;
                match addr {
                    0x0000...0x3EFF => {
                        let old_buffer = self.ppudata_read_buffer;
                        self.ppudata_read_buffer = self.ppu_mem.read(addr);
                        self.reg.incr_ppuaddr();
                        old_buffer
                    }
                    0x3F00...0x3FFF => {
                        let read_result = self.ppu_mem.read(addr);
                        self.reg.incr_ppuaddr();
                        self.ppudata_read_buffer = self.ppu_mem.read_bypass_palette(addr);
                        read_result
                    }
                    x => invalid_address!(x),
                }
            }
            _ => self.reg.read(idx),
        }
    }

    fn write(&mut self, idx: u16, val: u8) {
        match idx % 8 {
            0x0004 => {
                self.sprite_data.write(self.reg.oamaddr as u16, val);
                self.reg.incr_oamaddr();
            }
            0x0007 => {
                self.ppu_mem.write(self.reg.ppuaddr, val);
                self.reg.incr_ppuaddr();
            }
            _ => self.reg.write(idx, val),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use mappers::{Mapper, MapperParams};
    use std::rc::Rc;
    use std::cell::RefCell;
    use cart::Cart;
    use screen::DummyScreen;
    use ppu::ppu_reg::PPUCtrl;
    use memory::MemSegment;

    pub fn create_test_ppu() -> PPU {
        create_test_ppu_with_rom(vec![0u8; 0x1000])
    }

    pub fn create_test_ppu_with_rom(chr_rom: Vec<u8>) -> PPU {
        let mapper = Mapper::new(0, MapperParams::simple(vec![0u8; 0x1000], chr_rom));
        let cart = Cart::new(mapper);
        PPU::new(Rc::new(RefCell::new(cart)), Box::new(DummyScreen::new()))
    }

    #[test]
    fn reading_oamdata_doesnt_increment_oamaddr() {
        let mut ppu = create_test_ppu();
        ppu.reg.oamaddr = 0;
        ppu.read(0x2004);
        assert_eq!(ppu.reg.oamaddr, 0);
    }

    #[test]
    fn writing_oamdata_increments_oamaddr() {
        let mut ppu = create_test_ppu();
        ppu.reg.oamaddr = 0;
        ppu.write(0x2004, 12);
        assert_eq!(ppu.reg.oamaddr, 1);
        ppu.reg.oamaddr = 255;
        ppu.write(0x2004, 12);
        assert_eq!(ppu.reg.oamaddr, 0);
    }

    #[test]
    fn ppu_can_read_chr_rom() {
        let mut chr_rom = vec![0u8; 0x2000];
        chr_rom[0x0ABC] = 12;
        chr_rom[0x0DBA] = 212;
        let mut ppu = create_test_ppu_with_rom(chr_rom);

        ppu.reg.ppuaddr = 0x0ABC;
        ppu.read(0x2007);//Dummy Read
        assert_eq!(ppu.read(0x2007), 12);

        ppu.reg.ppuaddr = 0x0DBA;
        ppu.read(0x2007);//Dummy Read
        assert_eq!(ppu.read(0x2007), 212);
    }

    #[test]
    fn ppu_can_read_write_vram() {
        let mut ppu = create_test_ppu();

        ppu.reg.ppuaddr = 0x2ABC;
        ppu.write(0x2007, 12);
        ppu.reg.ppuaddr = 0x2ABC;
        ppu.read(0x2007);//Dummy read
        assert_eq!(ppu.read(0x2007), 12);

        ppu.reg.ppuaddr = 0x2DBA;
        ppu.write(0x2007, 212);
        ppu.reg.ppuaddr = 0x2DBA;
        ppu.read(0x2007);//Dummy Read
        assert_eq!(ppu.read(0x2007), 212);

        // Mirroring
        ppu.reg.ppuaddr = 0x2EFC;
        ppu.write(0x2007, 128);
        ppu.reg.ppuaddr = 0x3EFC;
        ppu.read(0x2007);//Dummy Read
        assert_eq!(ppu.read(0x2007), 128);
    }

    #[test]
    fn ppu_needs_no_dummy_read_for_palette_data() {
        let mut ppu = create_test_ppu();
        ppu.reg.ppuaddr = 0x3F16;
        ppu.write(0x2007, 21);
        ppu.reg.ppuaddr = 0x3F16;
        assert_eq!(ppu.read(0x2007), 21);
    }

    #[test]
    fn accessing_ppudata_increments_ppuaddr() {
        let mut ppu = create_test_ppu();
        ppu.reg.ppuaddr = 0x2000;
        ppu.read(0x2007);
        assert_eq!(ppu.reg.ppuaddr, 0x2001);
        ppu.write(0x2007, 0);
        assert_eq!(ppu.reg.ppuaddr, 0x2002);
    }

    #[test]
    fn accessing_ppudata_increments_ppuaddr_by_32_when_ctrl_flag_is_set() {
        let mut ppu = create_test_ppu();
        ppu.reg.ppuctrl = PPUCtrl::new(0b0000_0100);
        ppu.reg.ppuaddr = 0x2000;
        ppu.read(0x2007);
        assert_eq!(ppu.reg.ppuaddr, 0x2020);
        ppu.write(0x2007, 0);
        assert_eq!(ppu.reg.ppuaddr, 0x2040);
    }
}
<|endoftext|>


<commit_before>use world::World;

use std::{thread, time};

#[derive(Clone, Debug)]
pub enum CommandType {
    Move,
    TurnLeft,
    PickBeeper,
    PutBeeper,
}

#[derive(Clone, Debug)]
pub enum CommandError {
    CommandError(CommandType),
}

#[derive(Debug)]
pub struct Program {
    commands: Vec<CommandType>,
}

impl Program {
    pub fn new(commands: Vec<CommandType>) -> Program {
        Program { commands }
    }

    pub fn start(&self, world: &mut World) {
        let one_second = time::Duration::from_secs(1);
        let five_seconds = time::Duration::from_secs(5);

        self.clean_terminal();
        self.render_start_info();
        self.render(world);

        for (index, command) in self.commands.iter().enumerate() {
            let step_number = index + 1;
            // set timer
            thread::sleep(one_second);

            if let Err(err) = self.execute(command, world) {
                println!("There was an error in program execution on step {}, {:?}, continuing...", step_number, err);
                thread::sleep(five_seconds);
                continue;
            }

            self.clean_terminal();
            self.render_header(step_number);
            self.render(world);
        }

        println!("Program execution done.");
    }

    fn render_start_info(&self) {
        println!("Program loaded, executing...");
    }

    fn render_header(&self, step_number: usize) {
        println!("Executing step {}", step_number);
    }

    fn render(&self, world: &mut World) {
        println!("karel info {:?}", world.get_robot().info());
        println!("tiles {}", world.render());
    }

    fn clean_terminal(&self) {
        print!("{esc}[2J{esc}[1;1H", esc = 27 as char);
    }

    fn execute(&self, command: &CommandType, world: &mut World) -> Result<(), CommandError> {
        let owned_command = command.to_owned();

        let command_successful = match owned_command {
            CommandType::Move => world.move_robot(),
            CommandType::TurnLeft => world.get_robot().turn_left(),
            CommandType::PickBeeper => world.pick_beeper(),
            CommandType::PutBeeper => world.put_beeper(),
        };

        if !command_successful {
            return Err(CommandError::CommandError(owned_command));
        }

        Ok(())
    }
}
<commit_msg>feat: improve the execution information<commit_after>use world::World;

use std::{thread, time};

#[derive(Clone, Debug)]
pub enum CommandType {
    Move,
    TurnLeft,
    PickBeeper,
    PutBeeper,
}

#[derive(Clone, Debug)]
pub enum CommandError {
    CommandError(CommandType),
}

#[derive(Debug)]
pub struct Program {
    commands: Vec<CommandType>,
}

impl Program {
    pub fn new(commands: Vec<CommandType>) -> Program {
        Program { commands }
    }

    pub fn start(&self, world: &mut World) {
        let one_second = time::Duration::from_secs(1);
        let five_seconds = time::Duration::from_secs(5);

        self.clean_terminal();
        self.render_start_info();
        self.render(world);

        for (index, command) in self.commands.iter().enumerate() {
            let command_number = index + 1;
            // set timer
            thread::sleep(one_second);
            self.clean_terminal();

            if let Err(err) = self.execute(command, world) {
                println!("There was an error in program execution on command {}, {:?}, continuing...", command_number, err);
                thread::sleep(five_seconds);
            }

            self.render_header(command_number, command);
            self.render(world);
        }

        println!("Program execution done.");
    }

    fn render_start_info(&self) {
        println!("Program loaded, executing...");
    }

    fn render_header(&self, command_number: usize, command: &CommandType) {
        println!("Executed command {}: {:?}", command_number, &command);
    }

    fn render(&self, world: &mut World) {
        println!("karel info {:?}", world.get_robot().info());
        println!("tiles {}", world.render());
    }

    fn clean_terminal(&self) {
        print!("{esc}[2J{esc}[1;1H", esc = 27 as char);
    }

    fn execute(&self, command: &CommandType, world: &mut World) -> Result<(), CommandError> {
        let owned_command = command.to_owned();

        let command_successful = match owned_command {
            CommandType::Move => world.move_robot(),
            CommandType::TurnLeft => world.get_robot().turn_left(),
            CommandType::PickBeeper => world.pick_beeper(),
            CommandType::PutBeeper => world.put_beeper(),
        };

        if !command_successful {
            return Err(CommandError::CommandError(owned_command));
        }

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


<commit_before>// Copyright 2015-2017 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

#[repr(C)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
/// The payload's programming language.
pub enum Language {
    C,
    Php,
    Rust,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectConfig {
    pub language: Language,
    pub auth_server: String,
    pub auth_api_port: u32,
    pub auth_update_port: u32,
}
<commit_msg>Add build_server to project conf<commit_after>// Copyright 2015-2017 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

#[repr(C)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
/// The payload's programming language.
pub enum Language {
    C,
    Php,
    Rust,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectConfig {
    pub language: Language,
    pub auth_server: String,
    pub auth_api_port: u32,
    pub auth_update_port: u32,
    pub build_server: Option<String>,
}
<|endoftext|>


<commit_before>pub trait EventHandler<T> {
    fn handle_event(&mut self, event: T);
}

pub trait EventDemultiplexer {
    type Event;
    fn select(&mut self) -> Option<Self::Event>;
}

pub trait Reactor {
    type Event;
    fn handle_events(&mut self);
    fn register_handler(&mut self, handler: Box<EventHandler<Self::Event>>);
    fn remove_handler(&mut self, handler: &EventHandler<Self::Event>);
}
<commit_msg>reactor: bring back the Handler types<commit_after>pub trait EventHandler<T> {
    type Handler;
    fn handle_event(&mut self, event: T);
    fn handler(&self) -> Self::Handler;
}

pub trait EventDemultiplexer {
    type Event;
    fn select(&mut self) -> Option<Self::Event>;
}

pub trait Reactor {
    type Event: Event;
    type Handler;
    fn handle_events(&mut self);
    fn register_handler(&mut self, handler: Box<EventHandler<Self::Event, Handler=Self::Handler>>);
    fn remove_handler(&mut self, handler: &EventHandler<Self::Event, Handler=Self::Handler>);
}

pub trait Event {
    type Handler;
    fn handler(&self) -> Self::Handler;
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::str::{Words, Split, FromStr};
use cgmath::{Vector3, Vector2};
use core::types::{ZInt};
use visualizer::types::{VertexCoord, TextureCoord, Normal};
use core::fs;

struct Face {
    vertex: [ZInt; 3],
    texture: [ZInt; 3],
    normal: [ZInt; 3],
}

pub struct Model {
    coords: Vec<VertexCoord>,
    normals: Vec<Normal>,
    texture_coords: Vec<TextureCoord>,
    faces: Vec<Face>,
}

fn parse_word<T: FromStr>(words: &mut Words) -> T {
    let str = words.next().expect("Can not read next word");
    str.parse().expect("Can not convert from string")
}

fn parse_charsplit<T: FromStr>(words: &mut Split<char>) -> T {
    let str = words.next().expect("Can not read next word");
    str.parse().expect("Can not convert from string")
}

impl Model {
    pub fn new(path: &Path) -> Model {
        let mut obj = Model {
            coords: Vec::new(),
            normals: Vec::new(),
            texture_coords: Vec::new(),
            faces: Vec::new(),
        };
        obj.read(path);
        obj
    }

    fn read_v(words: &mut Words) -> VertexCoord {
        VertexCoord{v: Vector3 {
            x: parse_word(words),
            y: parse_word(words),
            z: parse_word(words),
        }}
    }

    fn read_vn(words: &mut Words) -> Normal {
        Normal{v: Vector3 {
            x: parse_word(words),
            y: parse_word(words),
            z: parse_word(words),
        }}
    }

    fn read_vt(words: &mut Words) -> TextureCoord {
        TextureCoord{v: Vector2 {
            x: parse_word(words),
            y: 1.0 - parse_word(words), // flip
        }}
    }

    fn read_f(words: &mut Words) -> Face {
        let mut face = Face {
            vertex: [0, 0, 0],
            texture: [0, 0, 0],
            normal: [0, 0, 0],
        };
        let mut i = 0;
        for group in *words {
            let mut w = group.split('/');
            face.vertex[i] = parse_charsplit(&mut w);
            face.texture[i] = parse_charsplit(&mut w);
            face.normal[i] = parse_charsplit(&mut w);
            i += 1;
        }
        face
    }

    fn read_line(&mut self, line: &str) {
        let mut words = line.words();
        fn is_correct_tag(tag: &str) -> bool {
            tag.len() != 0 && tag.char_at(0) != '#'
        }
        match words.next() {
            Some(tag) if is_correct_tag(tag) => {
                let w = &mut words;
                match tag {
                    "v" => self.coords.push(Model::read_v(w)),
                    "vn" => self.normals.push(Model::read_vn(w)),
                    "vt" => self.texture_coords.push(Model::read_vt(w)),
                    "f" => self.faces.push(Model::read_f(w)),
                    _ => {},
                }
            }
            _ => {},
        };
    }

    fn read(&mut self, path: &Path) {
        for line in fs::load(path).lines() {
            match line {
                Ok(line) => self.read_line(line.as_slice()),
                Err(msg) => panic!("Obj: read error: {}", msg),
            }
        }
    }

    pub fn build(&self) -> Vec<VertexCoord> {
        let mut mesh = Vec::new();
        for face in self.faces.iter() {
            for i in range(0, 3) {
                let vertex_id = face.vertex[i] as usize - 1;
                mesh.push(self.coords[vertex_id].clone());
            }
        }
        mesh
    }

    pub fn build_tex_coord(&self) -> Vec<TextureCoord> {
        let mut tex_coords = Vec::new();
        for face in self.faces.iter() {
            for i in range(0, 3) {
                let texture_coord_id = face.texture[i] as usize - 1;
                tex_coords.push(self.texture_coords[texture_coord_id].clone());
            }
        }
        tex_coords
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Updated from Rust eaf4c5c78 2015-02-02 15:04:54<commit_after>// See LICENSE file for copyright and license details.

use std::str::{Words, Split, FromStr};
use cgmath::{Vector3, Vector2};
use core::types::{ZInt};
use visualizer::types::{VertexCoord, TextureCoord, Normal};
use core::fs;

struct Face {
    vertex: [ZInt; 3],
    texture: [ZInt; 3],
    normal: [ZInt; 3],
}

pub struct Model {
    coords: Vec<VertexCoord>,
    normals: Vec<Normal>,
    texture_coords: Vec<TextureCoord>,
    faces: Vec<Face>,
}

fn parse_word<T: FromStr>(words: &mut Words) -> T {
    let str = words.next().expect("Can not read next word");
    str.parse().ok().expect("Can not convert from string")
}

fn parse_charsplit<T: FromStr>(words: &mut Split<char>) -> T {
    let str = words.next().expect("Can not read next word");
    str.parse().ok().expect("Can not convert from string")
}

impl Model {
    pub fn new(path: &Path) -> Model {
        let mut obj = Model {
            coords: Vec::new(),
            normals: Vec::new(),
            texture_coords: Vec::new(),
            faces: Vec::new(),
        };
        obj.read(path);
        obj
    }

    fn read_v(words: &mut Words) -> VertexCoord {
        VertexCoord{v: Vector3 {
            x: parse_word(words),
            y: parse_word(words),
            z: parse_word(words),
        }}
    }

    fn read_vn(words: &mut Words) -> Normal {
        Normal{v: Vector3 {
            x: parse_word(words),
            y: parse_word(words),
            z: parse_word(words),
        }}
    }

    fn read_vt(words: &mut Words) -> TextureCoord {
        TextureCoord{v: Vector2 {
            x: parse_word(words),
            y: 1.0 - parse_word(words), // flip
        }}
    }

    fn read_f(words: &mut Words) -> Face {
        let mut face = Face {
            vertex: [0, 0, 0],
            texture: [0, 0, 0],
            normal: [0, 0, 0],
        };
        let mut i = 0;
        for group in words.by_ref() {
            let mut w = group.split('/');
            face.vertex[i] = parse_charsplit(&mut w);
            face.texture[i] = parse_charsplit(&mut w);
            face.normal[i] = parse_charsplit(&mut w);
            i += 1;
        }
        face
    }

    fn read_line(&mut self, line: &str) {
        let mut words = line.words();
        fn is_correct_tag(tag: &str) -> bool {
            tag.len() != 0 && tag.char_at(0) != '#'
        }
        match words.next() {
            Some(tag) if is_correct_tag(tag) => {
                let w = &mut words;
                match tag {
                    "v" => self.coords.push(Model::read_v(w)),
                    "vn" => self.normals.push(Model::read_vn(w)),
                    "vt" => self.texture_coords.push(Model::read_vt(w)),
                    "f" => self.faces.push(Model::read_f(w)),
                    _ => {},
                }
            }
            _ => {},
        };
    }

    fn read(&mut self, path: &Path) {
        for line in fs::load(path).lines() {
            match line {
                Ok(line) => self.read_line(line.as_slice()),
                Err(msg) => panic!("Obj: read error: {}", msg),
            }
        }
    }

    pub fn build(&self) -> Vec<VertexCoord> {
        let mut mesh = Vec::new();
        for face in self.faces.iter() {
            for i in range(0, 3) {
                let vertex_id = face.vertex[i] as usize - 1;
                mesh.push(self.coords[vertex_id].clone());
            }
        }
        mesh
    }

    pub fn build_tex_coord(&self) -> Vec<TextureCoord> {
        let mut tex_coords = Vec::new();
        for face in self.faces.iter() {
            for i in range(0, 3) {
                let texture_coord_id = face.texture[i] as usize - 1;
                tex_coords.push(self.texture_coords[texture_coord_id].clone());
            }
        }
        tex_coords
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use crate::fmt;
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map};
use crate::ops::Try;

/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
/// This `struct` is created by [`Iterator::flat_map`]. See its documentation
/// for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FlatMap<I, U: IntoIterator, F> {
    inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>,
}

impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
    pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
        FlatMap { inner: FlattenCompat::new(iter.map(f)) }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Clone, U, F: Clone> Clone for FlatMap<I, U, F>
where
    U: Clone + IntoIterator<IntoIter: Clone>,
{
    fn clone(&self) -> Self {
        FlatMap { inner: self.inner.clone() }
    }
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, U, F> fmt::Debug for FlatMap<I, U, F>
where
    U: IntoIterator<IntoIter: fmt::Debug>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FlatMap").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        self.inner.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.fold(init, fold)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
    U: IntoIterator<IntoIter: DoubleEndedIterator>,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        self.inner.next_back()
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.rfold(init, fold)
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
where
    I: FusedIterator,
    U: IntoIterator,
    F: FnMut(I::Item) -> U,
{
}

/// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators.
///
/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flatten`]: Iterator::flatten()
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iterator_flatten", since = "1.29.0")]
pub struct Flatten<I: Iterator<Item: IntoIterator>> {
    inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
}

impl<I: Iterator<Item: IntoIterator>> Flatten<I> {
    pub(in super::super) fn new(iter: I) -> Flatten<I> {
        Flatten { inner: FlattenCompat::new(iter) }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> fmt::Debug for Flatten<I>
where
    I: fmt::Debug + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: fmt::Debug + Iterator,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Flatten").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Clone for Flatten<I>
where
    I: Clone + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Clone + Iterator,
{
    fn clone(&self) -> Self {
        Flatten { inner: self.inner.clone() }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Iterator for Flatten<I>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        self.inner.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.fold(init, fold)
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> DoubleEndedIterator for Flatten<I>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        self.inner.next_back()
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.rfold(init, fold)
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> FusedIterator for Flatten<I>
where
    I: FusedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
}

/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
struct FlattenCompat<I, U> {
    iter: Fuse<I>,
    frontiter: Option<U>,
    backiter: Option<U>,
}
impl<I, U> FlattenCompat<I, U>
where
    I: Iterator,
{
    /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
    fn new(iter: I) -> FlattenCompat<I, U> {
        FlattenCompat { iter: iter.fuse(), frontiter: None, backiter: None }
    }
}

impl<I, U> Iterator for FlattenCompat<I, U>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.frontiter {
                match inner.next() {
                    None => self.frontiter = None,
                    elt @ Some(_) => return elt,
                }
            }
            match self.iter.next() {
                None => return self.backiter.as_mut()?.next(),
                Some(inner) => self.frontiter = Some(inner.into_iter()),
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let lo = flo.saturating_add(blo);
        match (self.iter.size_hint(), fhi, bhi) {
            ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
            _ => (lo, None),
        }
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            frontiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_fold(acc, &mut *fold);
                *frontiter = Some(mid);
                r
            }
        }

        if let Some(ref mut front) = self.frontiter {
            init = front.try_fold(init, &mut fold)?;
        }
        self.frontiter = None;

        init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
        self.frontiter = None;

        if let Some(ref mut back) = self.backiter {
            init = back.try_fold(init, &mut fold)?;
        }
        self.backiter = None;

        try { init }
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: Iterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.fold(acc, &mut *fold)
        }

        self.frontiter
            .into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .fold(init, flatten(fold))
    }
}

impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.backiter {
                match inner.next_back() {
                    None => self.backiter = None,
                    elt @ Some(_) => return elt,
                }
            }
            match self.iter.next_back() {
                None => return self.frontiter.as_mut()?.next_back(),
                next => self.backiter = next.map(IntoIterator::into_iter),
            }
        }
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            backiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a
        where
            T::IntoIter: DoubleEndedIterator,
        {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_rfold(acc, &mut *fold);
                *backiter = Some(mid);
                r
            }
        }

        if let Some(ref mut back) = self.backiter {
            init = back.try_rfold(init, &mut fold)?;
        }
        self.backiter = None;

        init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
        self.backiter = None;

        if let Some(ref mut front) = self.frontiter {
            init = front.try_rfold(init, &mut fold)?;
        }
        self.frontiter = None;

        try { init }
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: DoubleEndedIterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.rfold(acc, &mut *fold)
        }

        self.frontiter
            .into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .rfold(init, flatten(fold))
    }
}
<commit_msg>Manually fuse the inner iterator in FlattenCompat<commit_after>use crate::fmt;
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map};
use crate::ops::Try;

/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
/// This `struct` is created by [`Iterator::flat_map`]. See its documentation
/// for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FlatMap<I, U: IntoIterator, F> {
    inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>,
}

impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
    pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
        FlatMap { inner: FlattenCompat::new(iter.map(f)) }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Clone, U, F: Clone> Clone for FlatMap<I, U, F>
where
    U: Clone + IntoIterator<IntoIter: Clone>,
{
    fn clone(&self) -> Self {
        FlatMap { inner: self.inner.clone() }
    }
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, U, F> fmt::Debug for FlatMap<I, U, F>
where
    U: IntoIterator<IntoIter: fmt::Debug>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FlatMap").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        self.inner.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.fold(init, fold)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
    U: IntoIterator<IntoIter: DoubleEndedIterator>,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        self.inner.next_back()
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.rfold(init, fold)
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
where
    I: FusedIterator,
    U: IntoIterator,
    F: FnMut(I::Item) -> U,
{
}

/// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators.
///
/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flatten`]: Iterator::flatten()
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iterator_flatten", since = "1.29.0")]
pub struct Flatten<I: Iterator<Item: IntoIterator>> {
    inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
}

impl<I: Iterator<Item: IntoIterator>> Flatten<I> {
    pub(in super::super) fn new(iter: I) -> Flatten<I> {
        Flatten { inner: FlattenCompat::new(iter) }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> fmt::Debug for Flatten<I>
where
    I: fmt::Debug + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: fmt::Debug + Iterator,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Flatten").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Clone for Flatten<I>
where
    I: Clone + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Clone + Iterator,
{
    fn clone(&self) -> Self {
        Flatten { inner: self.inner.clone() }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Iterator for Flatten<I>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        self.inner.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.fold(init, fold)
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> DoubleEndedIterator for Flatten<I>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        self.inner.next_back()
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.rfold(init, fold)
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> FusedIterator for Flatten<I>
where
    I: FusedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
}

/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
struct FlattenCompat<I, U> {
    iter: Fuse<I>,
    frontiter: Option<U>,
    backiter: Option<U>,
}
impl<I, U> FlattenCompat<I, U>
where
    I: Iterator,
{
    /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
    fn new(iter: I) -> FlattenCompat<I, U> {
        FlattenCompat { iter: iter.fuse(), frontiter: None, backiter: None }
    }
}

impl<I, U> Iterator for FlattenCompat<I, U>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.frontiter {
                match inner.next() {
                    None => self.frontiter = None,
                    elt @ Some(_) => return elt,
                }
            }
            match self.iter.next() {
                None => match self.backiter.as_mut()?.next() {
                    None => {
                        self.backiter = None;
                        return None;
                    }
                    elt @ Some(_) => return elt,
                },
                Some(inner) => self.frontiter = Some(inner.into_iter()),
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let lo = flo.saturating_add(blo);
        match (self.iter.size_hint(), fhi, bhi) {
            ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
            _ => (lo, None),
        }
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            frontiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_fold(acc, &mut *fold);
                *frontiter = Some(mid);
                r
            }
        }

        if let Some(ref mut front) = self.frontiter {
            init = front.try_fold(init, &mut fold)?;
        }
        self.frontiter = None;

        init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
        self.frontiter = None;

        if let Some(ref mut back) = self.backiter {
            init = back.try_fold(init, &mut fold)?;
        }
        self.backiter = None;

        try { init }
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: Iterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.fold(acc, &mut *fold)
        }

        self.frontiter
            .into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .fold(init, flatten(fold))
    }
}

impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.backiter {
                match inner.next_back() {
                    None => self.backiter = None,
                    elt @ Some(_) => return elt,
                }
            }
            match self.iter.next_back() {
                None => match self.frontiter.as_mut()?.next_back() {
                    None => {
                        self.frontiter = None;
                        return None;
                    }
                    elt @ Some(_) => return elt,
                },
                next => self.backiter = next.map(IntoIterator::into_iter),
            }
        }
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            backiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a
        where
            T::IntoIter: DoubleEndedIterator,
        {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_rfold(acc, &mut *fold);
                *backiter = Some(mid);
                r
            }
        }

        if let Some(ref mut back) = self.backiter {
            init = back.try_rfold(init, &mut fold)?;
        }
        self.backiter = None;

        init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
        self.backiter = None;

        if let Some(ref mut front) = self.frontiter {
            init = front.try_rfold(init, &mut fold)?;
        }
        self.frontiter = None;

        try { init }
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: DoubleEndedIterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.rfold(acc, &mut *fold)
        }

        self.frontiter
            .into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .rfold(init, flatten(fold))
    }
}
<|endoftext|>


<commit_before>pub mod vec;
pub mod merge;
pub mod union;

pub trait Set {
    type T;
    type E;
    type I: Iterator<Item = Result<Self::T, Self::E>>;

    fn size(&self) -> usize;
    fn get(&self, index: usize) -> Result<&Self::T, Self::E>;
    fn add(&mut self, item: Self::T) -> Result<(), Self::E>;
    fn into_iter(self) -> Self::I;
}

pub trait SetManager {
    type S: Set;
    type E;

    fn make_set(&mut self, size_hint: Option<usize>) -> Result<Self::S, Self::E>;
    fn reserve(&mut self, set: &mut Self::S, additional: usize) -> Result<(), Self::E>;
}

pub trait SetManagerMut {
    type SM: SetManager;

    fn set_manager_mut(&mut self) -> &mut Self::SM;
}
<commit_msg>add default `reserve` method<commit_after>pub mod vec;
pub mod merge;
pub mod union;

pub trait Set {
    type T;
    type E;
    type I: Iterator<Item = Result<Self::T, Self::E>>;

    fn size(&self) -> usize;
    fn get(&self, index: usize) -> Result<&Self::T, Self::E>;
    fn add(&mut self, item: Self::T) -> Result<(), Self::E>;
    fn into_iter(self) -> Self::I;
}

pub trait SetManager {
    type S: Set;
    type E;

    fn make_set(&mut self, size_hint: Option<usize>) -> Result<Self::S, Self::E>;

    fn reserve(&mut self, _set: &mut Self::S, _additional: usize) -> Result<(), Self::E> {
        // default is to do nothing
        Ok(())
    }
}

pub trait SetManagerMut {
    type SM: SetManager;

    fn set_manager_mut(&mut self) -> &mut Self::SM;
}
<|endoftext|>


<commit_before>use crate::paths::TargetDir;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

pub(crate) fn target_dir(out_dir: &Path) -> TargetDir {
    try_target_dir(out_dir).map_or(TargetDir::Unknown, TargetDir::Path)
}

fn try_target_dir(out_dir: &Path) -> Option<PathBuf> {
    let cargo = option_env!("CARGO").unwrap_or("cargo");
    let output = Command::new(cargo)
        .current_dir(out_dir)
        .arg("metadata")
        .arg("--no-deps")
        .arg("--format-version=1")
        .output()
        .ok()?;

    // Cargo only outputs utf8 encoded JSON.
    let mut metadata = str::from_utf8(&output.stdout).ok()?;

    let key_pattern = "\"target_directory\":";
    let key_index = metadata.rfind(key_pattern)?;
    metadata = &metadata[key_index + key_pattern.len()..];
    let open_quote_index = metadata.find('"')?;
    metadata = &metadata[open_quote_index + 1..];
    let close_quote_index = metadata.find('"')?;
    let string = &metadata[..close_quote_index];
    let target_directory = string.replace("\\\\", "\\");
    Some(PathBuf::from(target_directory))
}
<commit_msg>Recognize CARGO_TARGET_DIR env var if set<commit_after>use crate::paths::TargetDir;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

pub(crate) fn target_dir(out_dir: &Path) -> TargetDir {
    try_target_dir(out_dir).map_or(TargetDir::Unknown, TargetDir::Path)
}

fn try_target_dir(out_dir: &Path) -> Option<PathBuf> {
    if let Some(target_dir) = env::var_os("CARGO_TARGET_DIR") {
        return Some(PathBuf::from(target_dir));
    }

    let cargo = option_env!("CARGO").unwrap_or("cargo");
    let output = Command::new(cargo)
        .current_dir(out_dir)
        .arg("metadata")
        .arg("--no-deps")
        .arg("--format-version=1")
        .output()
        .ok()?;

    // Cargo only outputs utf8 encoded JSON.
    let mut metadata = str::from_utf8(&output.stdout).ok()?;

    let key_pattern = "\"target_directory\":";
    let key_index = metadata.rfind(key_pattern)?;
    metadata = &metadata[key_index + key_pattern.len()..];
    let open_quote_index = metadata.find('"')?;
    metadata = &metadata[open_quote_index + 1..];
    let close_quote_index = metadata.find('"')?;
    let string = &metadata[..close_quote_index];
    let target_directory = string.replace("\\\\", "\\");
    Some(PathBuf::from(target_directory))
}
<|endoftext|>