<commit_before>#![crate_name = "foo"]

#![feature(staged_api)]

#[stable(feature = "bar", since = "OLD 1.0")]
pub trait Bar {}

#[stable(feature = "baz", since = "OLD 1.0")]
pub trait Baz {}

pub struct Foo;

// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0'
#[stable(feature = "foobar", since = "NEW 2.0")]
impl Bar for Foo {}

// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0'
#[stable(feature = "foobaz", since = "OLD 1.0")]
impl Baz for Foo {}
<commit_msg>Update rustdoc test to make it work with newly added rustc passes<commit_after>#![stable(feature = "bar", since = "OLD 1.0")]
#![crate_name = "foo"]

#![feature(staged_api)]

#[stable(feature = "bar", since = "OLD 1.0")]
pub trait Bar {}

#[stable(feature = "baz", since = "OLD 1.0")]
pub trait Baz {}

#[stable(feature = "baz", since = "OLD 1.0")]
pub struct Foo;

// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0'
#[stable(feature = "foobar", since = "NEW 2.0")]
impl Bar for Foo {}

// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0'
#[stable(feature = "foobaz", since = "OLD 1.0")]
impl Baz for Foo {}
<|endoftext|>


<commit_before>use sdl2::mixer::Music;
use rand::thread_rng;
use std::path::PathBuf;
use rand::Rng;

pub struct Playlist {
    tracks: Vec<Music<'static>>,
    current_track: usize,
    pub shuffle: bool,
    pub loop_music: bool,
}

impl Playlist {
    pub fn new() -> Playlist {
        Playlist {
            tracks: Vec::new(),
            current_track: 0,
            shuffle: false,
            loop_music: false,
        }
    }

    pub fn start(&mut self) {
        if self.shuffle {
            self.shuffle();
        }
        self.play_track(0).expect("No tracks present.");
    }

    fn shuffle(&mut self) {
        if self.tracks.len() > 1 {
            let mut new_tracks = Vec::new();

            // Make sure the new first track is never the previous last track.  Keeps from hearing
            // the same song twice in a row.
            new_tracks.push(unborrow!(self.tracks.remove(thread_rng().gen_range(0, self.tracks.len()-1))));
            while self.tracks.len() > 0 {
                new_tracks.push(unborrow!(self.tracks.remove(thread_rng().gen_range(0, self.tracks.len()))));
            }
            self.tracks = new_tracks;
        }
    }

    pub fn next_track(&mut self) {
        if self.current_track < self.tracks.len() - 1 {
            unborrow!(self.play_track(self.current_track + 1))
                .expect("Track index invalid.");
        } else if self.loop_music {
            if self.shuffle {
                self.shuffle();
            }
            self.play_track(0).expect("Track index invalid.");
        } else {
            Music::halt();
        }
    }

    /// Returns err if track is not a valid index into self.tracks
    pub fn play_track(&mut self, track: usize) -> Result<(), String> {
        if track < self.tracks.len() {
            self.current_track = track;
            self.tracks[track].play(1)?;
            return Ok(());
        } else {
            return Err("Track index invalid.".to_string());
        }
    }

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

    pub fn add_track(&mut self, path: &str) -> Result<(), String> {
        let mut file_path = PathBuf::from("assets");
        file_path.push("music");
        file_path.push(path);
        self.tracks.push(Music::from_file(file_path)?);
        Ok(())
    }
}

pub fn advance_if_needed(playlist: &mut Playlist) {
    if !Music::is_playing() {
        playlist.next_track();
    }
}
<commit_msg>Improve playlist with proper starting and stopping<commit_after>use sdl2::mixer::Music;
use rand::thread_rng;
use std::path::PathBuf;
use rand::Rng;

pub struct Playlist {
    tracks: Vec<Music<'static>>,
    current_track: usize,
    pub shuffle: bool,
    pub loop_music: bool,
    started: bool,
}

impl Playlist {
    pub fn new() -> Playlist {
        Playlist {
            tracks: Vec::new(),
            current_track: 0,
            shuffle: false,
            loop_music: false,
            started: false,
        }
    }

    /// Start playing this playlist.
    ///
    /// Will not auto advance songs unless this playlist is attached to App::audio.playlist
    pub fn start(&mut self) {
        if self.shuffle {
            self.shuffle();
        }
        self.started = true;
        self.play_track(0).expect("No tracks present.");
    }

    pub fn stop(&mut self) {
        if self.started {
            self.started = false;
            Music::halt();
        }
    }

    fn shuffle(&mut self) {
        if self.tracks.len() > 1 {
            let mut new_tracks = Vec::new();

            // Make sure the new first track is never the previous last track.  Keeps from hearing
            // the same song twice in a row.
            new_tracks.push(unborrow!(self.tracks.remove(thread_rng().gen_range(0, self.tracks.len()-1))));
            while self.tracks.len() > 0 {
                new_tracks.push(unborrow!(self.tracks.remove(thread_rng().gen_range(0, self.tracks.len()))));
            }
            self.tracks = new_tracks;
        }
    }

    pub fn next_track(&mut self) {
        if self.current_track < self.tracks.len() - 1 {
            unborrow!(self.play_track(self.current_track + 1))
                .expect("Track index invalid.");
        } else if self.loop_music {
            if self.shuffle {
                self.shuffle();
            }
            self.play_track(0).expect("Track index invalid.");
        } else {
            Music::halt();
        }
    }

    /// Returns err if track is not a valid index into self.tracks
    pub fn play_track(&mut self, track: usize) -> Result<(), String> {
        if track < self.tracks.len() {
            self.current_track = track;
            self.tracks[track].play(1)?;
            return Ok(());
        } else {
            return Err("Track index invalid.".to_string());
        }
    }

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

    pub fn add_track(&mut self, path: &str) -> Result<(), String> {
        let mut file_path = PathBuf::from("assets");
        file_path.push("music");
        file_path.push(path);
        self.tracks.push(Music::from_file(file_path)?);
        Ok(())
    }
}

pub fn advance_if_needed(playlist: &mut Playlist) {
    if playlist.started {
        if !Music::is_playing() {
            playlist.next_track();
        }
    }
}
<|endoftext|>


<commit_before>use std::iter;
use std::fmt::Write;
use std::rc::Rc;

use ::forktable::ForkTable;

pub mod ast;
pub mod types;
pub mod annotations;

use ast::*;
use self::annotations::*;
use self::types::Type;

/// A symbol table is a `ForkTable` mapping `String`s to `Type` annotations.
///
/// This table should be forked upon entering a new scope.
pub type SymbolTable<'a>
    = ForkTable<'a, String, SymbolAnnotation<'a>>;

macro_rules! indent {
    ($to:expr) => ( iter::repeat('\t')
                        .take($to)
                        .collect::<String>() )
}

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait ASTNode: Sized {

    /// Pretty-print the AST node as an S-expression at the desired
    /// indentation level.]
    ///
    /// Note that this prints the desugared form and may not be a perfect
    /// match for the original source code.
    fn to_sexpr(&self, level: usize) -> String;

}

pub trait AnnotateTypes<'a>: Sized {

    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
        unimplemented!() //TODO: implement
    }
}

impl<'a, S> ASTNode for Form<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Form::Define(ref form) => form.to_sexpr(level)
          , Form::Let(ref form) => form.to_sexpr(level)
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => fun.to_sexpr(level)
        }
    }

}

impl<'a> AnnotateTypes<'a> for Unscoped<'a, Form<'a, UnscopedState>> {
    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
        unimplemented!() //TODO: implement
    }
}

impl ASTNode for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}

impl<'a, S> ASTNode for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot.to_sexpr(level)
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> ASTNode for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                       , indent!(level)
                       , bindings.iter()
                                 .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level));
                                    s
                                 })
                       , body.iter()
                             .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1));
                                s
                             })
                       )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> ASTNode for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> ASTNode for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a> AnnotateTypes<'a> for Unscoped<'a, DefForm<'a, UnscopedState>> {
    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self>{
        unimplemented!() //TODO: implement
    }
}

impl ASTNode for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

#[derive(Clone,Debug,PartialEq)]
pub struct SymbolAnnotation<'a> {
    /// The type of the symbol
    pub ty: Type,
    /// An optional proven value for the symbol.
    ///
    /// This should be defined iff the symbol signifies a constant value
    /// or a constant expression, or if we were able to prove that the value
    /// remains constant within the current scope.
    pub proven_value: Option<Rc<Expr<'a, ScopedState>>>
}
<commit_msg>Add `to_sexpr()` for more let forms<commit_after>use std::iter;
use std::fmt::Write;
use std::rc::Rc;

use ::forktable::ForkTable;

pub mod ast;
pub mod types;
pub mod annotations;

use ast::*;
use self::annotations::*;
use self::types::Type;

/// A symbol table is a `ForkTable` mapping `String`s to `Type` annotations.
///
/// This table should be forked upon entering a new scope.
pub type SymbolTable<'a>
    = ForkTable<'a, String, SymbolAnnotation<'a>>;

macro_rules! indent {
    ($to:expr) => ( iter::repeat('\t')
                        .take($to)
                        .collect::<String>() )
}

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait ASTNode: Sized {

    /// Pretty-print the AST node as an S-expression at the desired
    /// indentation level.]
    ///
    /// Note that this prints the desugared form and may not be a perfect
    /// match for the original source code.
    fn to_sexpr(&self, level: usize) -> String;

}

pub trait AnnotateTypes<'a>: Sized {

    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
        unimplemented!() //TODO: implement
    }
}

impl<'a, S> ASTNode for Form<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Form::Define(ref form) => form.to_sexpr(level)
          , Form::Let(ref form) => form.to_sexpr(level)
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => fun.to_sexpr(level)
        }
    }

}

impl<'a> AnnotateTypes<'a> for Unscoped<'a, Form<'a, UnscopedState>> {
    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
        unimplemented!() //TODO: implement
    }
}

impl ASTNode for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}

impl<'a, S> ASTNode for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot.to_sexpr(level)
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> ASTNode for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level));
                                    s
                                 })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                              write!(s, "{}", expr.to_sexpr(level + 1));
                              s
                          })
                       )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level));
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1)); s
                            })
                          )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level));
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1)); s
                            })
                          )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> ASTNode for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> ASTNode for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a> AnnotateTypes<'a> for Unscoped<'a, DefForm<'a, UnscopedState>> {
    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self>{
        unimplemented!() //TODO: implement
    }
}

impl ASTNode for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

#[derive(Clone,Debug,PartialEq)]
pub struct SymbolAnnotation<'a> {
    /// The type of the symbol
    pub ty: Type,
    /// An optional proven value for the symbol.
    ///
    /// This should be defined iff the symbol signifies a constant value
    /// or a constant expression, or if we were able to prove that the value
    /// remains constant within the current scope.
    pub proven_value: Option<Rc<Expr<'a, ScopedState>>>
}
<|endoftext|>


<commit_before>use std::fs::{File, Permissions, set_permissions};
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};

use zip::ZipArchive;

use quire::validate as V;
use builder::context::Context;
use capsule::download::maybe_download_and_check_hashsum;
use build_step::{BuildStep, VersionError, StepError, Digest, Config, Guard};
use file_util::{Dir, copy_stream};

#[derive(RustcEncodable, RustcDecodable, Debug, Clone)]
pub struct Unzip {
    pub url: String,
    pub sha256: Option<String>,
    pub path: PathBuf,
    pub subdir: PathBuf,
}

impl Unzip {
    pub fn config() -> V::Structure<'static> {
        V::Structure::new()
        .member("url", V::Scalar::new())
        .member("sha256", V::Scalar::new().optional())
        .member("path", V::Directory::new().absolute(true).default("/"))
        .member("subdir", V::Directory::new().default("").absolute(false))
    }
}

pub fn unzip_file(_ctx: &mut Context, src: &Path, dst: &Path,
    subdir: &Path)
    -> Result<(), String>
{
    let file = try_msg!(File::open(src),
        "Cannot open archive: {err}");

    let mut zip = try_msg!(ZipArchive::new(file),
        "Error when unpacking zip archive: {err}");

    let no_subdir = &subdir == &Path::new("") || &subdir == &Path::new(".");
    let mut found_subdir = no_subdir;
    for i in 0..zip.len() {
        let mut fin = zip.by_index(i).unwrap();
        let fin_name = String::from(fin.name());
        let fin_path = PathBuf::from(&fin_name);
        let fout_path = if no_subdir {
            dst.join(&fin_path)
        } else if fin_path.starts_with(subdir) {
            found_subdir = true;
            dst.join(try_msg!(fin_path.strip_prefix(subdir), "{err}"))
        } else {
            continue;
        };
        if &fout_path == &Path::new("") {
            continue;
        }
        if fin_name.ends_with("/") {
            try_msg!(Dir::new(&fout_path).recursive(true).create(),
                "Error creating dir: {err}");
        } else {
            let mut fout = try_msg!(File::create(&fout_path),
                "Error creating file: {err}");
            try_msg!(copy_stream(&mut fin, &mut fout),
                "Error unpacking file: {err}");
        }
        if let Some(mode) = fin.unix_mode() {
            let perms = Permissions::from_mode(mode);
            try_msg!(set_permissions(&fout_path, perms),
                 "Error setting permissions: {err}");
        }
    }

    if found_subdir {
        Ok(())
    } else {
        Err(format!("{:?} is not found in archive", subdir))
    }
}

impl BuildStep for Unzip {
    fn name(&self) -> &'static str { "Unzip" }
    fn hash(&self, _cfg: &Config, hash: &mut Digest)
        -> Result<(), VersionError>
    {
        if let Some(ref sha) = self.sha256 {
            hash.field("hash", sha);
        } else {
            hash.field("url", &self.url);
        }
        hash.field("path", &self.path);
        hash.field("subdir", &self.subdir);
        Ok(())
    }
    fn build(&self, guard: &mut Guard, build: bool)
        -> Result<(), StepError>
    {
        if build {
            info!("Unzipping file: {}", self.url);

            let fpath = PathBuf::from("/vagga/root")
                .join(self.path.strip_prefix("/").unwrap());
            let (filename, _) = maybe_download_and_check_hashsum(
                &mut guard.ctx.capsule, &self.url, self.sha256.clone())?;

            unzip_file(&mut guard.ctx, &filename, &fpath, &self.subdir)?;
        }
        Ok(())
    }
    fn is_dependent_on(&self) -> Option<&str> {
        None
    }
}
<commit_msg>Create parent directory for files in zip (fixes #397)<commit_after>use std::collections::HashSet;
use std::fs::{File, Permissions, set_permissions};
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};

use zip::ZipArchive;

use quire::validate as V;
use builder::context::Context;
use capsule::download::maybe_download_and_check_hashsum;
use build_step::{BuildStep, VersionError, StepError, Digest, Config, Guard};
use file_util::{Dir, copy_stream};

#[derive(RustcEncodable, RustcDecodable, Debug, Clone)]
pub struct Unzip {
    pub url: String,
    pub sha256: Option<String>,
    pub path: PathBuf,
    pub subdir: PathBuf,
}

impl Unzip {
    pub fn config() -> V::Structure<'static> {
        V::Structure::new()
        .member("url", V::Scalar::new())
        .member("sha256", V::Scalar::new().optional())
        .member("path", V::Directory::new().absolute(true).default("/"))
        .member("subdir", V::Directory::new().default("").absolute(false))
    }
}

pub fn unzip_file(_ctx: &mut Context, src: &Path, dst: &Path,
    subdir: &Path)
    -> Result<(), String>
{
    let file = try_msg!(File::open(src),
        "Cannot open archive: {err}");

    let mut zip = try_msg!(ZipArchive::new(file),
        "Error when unpacking zip archive: {err}");

    let no_subdir = &subdir == &Path::new("") || &subdir == &Path::new(".");
    let mut dirs = HashSet::new();
    let mut found_subdir = no_subdir;
    for i in 0..zip.len() {
        let mut fin = zip.by_index(i).unwrap();
        let fin_name = String::from(fin.name());
        let fin_path = PathBuf::from(&fin_name);
        let fout_path = if no_subdir {
            dst.join(&fin_path)
        } else if fin_path.starts_with(subdir) {
            found_subdir = true;
            dst.join(try_msg!(fin_path.strip_prefix(subdir), "{err}"))
        } else {
            continue;
        };
        if &fout_path == &Path::new("") {
            continue;
        }
        if fin_name.ends_with("/") {
            dirs.insert(fout_path.clone());
            try_msg!(Dir::new(&fout_path).recursive(true).create(),
                "Error creating dir: {err}");
        } else {
            let fout_base = fout_path.parent().unwrap();
            if !dirs.contains(fout_base) {
                try_msg!(Dir::new(&fout_base).recursive(true).create(),
                    "Error creating dir: {err}");
                dirs.insert(fout_base.to_path_buf());
            }
            let mut fout = try_msg!(File::create(&fout_path),
                "Error creating file: {err}");
            try_msg!(copy_stream(&mut fin, &mut fout),
                "Error unpacking file: {err}");
        }
        if let Some(mode) = fin.unix_mode() {
            let perms = Permissions::from_mode(mode);
            try_msg!(set_permissions(&fout_path, perms),
                 "Error setting permissions: {err}");
        }
    }

    if found_subdir {
        Ok(())
    } else {
        Err(format!("{:?} is not found in archive", subdir))
    }
}

impl BuildStep for Unzip {
    fn name(&self) -> &'static str { "Unzip" }
    fn hash(&self, _cfg: &Config, hash: &mut Digest)
        -> Result<(), VersionError>
    {
        if let Some(ref sha) = self.sha256 {
            hash.field("hash", sha);
        } else {
            hash.field("url", &self.url);
        }
        hash.field("path", &self.path);
        hash.field("subdir", &self.subdir);
        Ok(())
    }
    fn build(&self, guard: &mut Guard, build: bool)
        -> Result<(), StepError>
    {
        if build {
            info!("Unzipping file: {}", self.url);

            let fpath = PathBuf::from("/vagga/root")
                .join(self.path.strip_prefix("/").unwrap());
            let (filename, _) = maybe_download_and_check_hashsum(
                &mut guard.ctx.capsule, &self.url, self.sha256.clone())?;

            unzip_file(&mut guard.ctx, &filename, &fpath, &self.subdir)?;
        }
        Ok(())
    }
    fn is_dependent_on(&self) -> Option<&str> {
        None
    }
}
<|endoftext|>


<commit_before>use crate::*;
use fixed_len_vec::typenum::{Unsigned, U1024, U8, U8192};
use serde_derive::{Deserialize, Serialize};
use std::fmt::Debug;

pub trait EthSpec:
    'static + Default + Sync + Send + Clone + Debug + PartialEq + serde::de::DeserializeOwned
{
    type ShardCount: Unsigned + Clone + Sync + Send + Debug + PartialEq;
    type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send + Debug + PartialEq;
    type LatestRandaoMixesLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
    type LatestActiveIndexRootsLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
    type LatestSlashedExitLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;

    fn spec() -> ChainSpec;

    /// Returns the `SLOTS_PER_EPOCH` constant for this specification.
    ///
    /// Spec v0.6.1
    fn slots_per_epoch() -> u64 {
        Self::spec().slots_per_epoch
    }

    /// Returns the `SLOTS_PER_EPOCH` constant for this specification.
    ///
    /// Spec v0.6.1
    fn genesis_epoch() -> Epoch {
        Self::spec().genesis_epoch
    }

    /// Returns the `SHARD_COUNT` constant for this specification.
    ///
    /// Spec v0.5.1
    fn shard_count() -> usize {
        Self::ShardCount::to_usize()
    }

    /// Returns the `SLOTS_PER_HISTORICAL_ROOT` constant for this specification.
    ///
    /// Spec v0.5.1
    fn slots_per_historical_root() -> usize {
        Self::SlotsPerHistoricalRoot::to_usize()
    }

    /// Returns the `LATEST_RANDAO_MIXES_LENGTH` constant for this specification.
    ///
    /// Spec v0.5.1
    fn latest_randao_mixes_length() -> usize {
        Self::LatestRandaoMixesLength::to_usize()
    }

    /// Returns the `LATEST_ACTIVE_INDEX_ROOTS` constant for this specification.
    ///
    /// Spec v0.5.1
    fn latest_active_index_roots() -> usize {
        Self::LatestActiveIndexRootsLength::to_usize()
    }

    /// Returns the `LATEST_SLASHED_EXIT_LENGTH` constant for this specification.
    ///
    /// Spec v0.5.1
    fn latest_slashed_exit_length() -> usize {
        Self::LatestSlashedExitLength::to_usize()
    }
}

/// Ethereum Foundation specifications.
///
/// Spec v0.5.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct FoundationEthSpec;

impl EthSpec for FoundationEthSpec {
    type ShardCount = U1024;
    type SlotsPerHistoricalRoot = U8192;
    type LatestRandaoMixesLength = U8192;
    type LatestActiveIndexRootsLength = U8192;
    type LatestSlashedExitLength = U8192;

    fn spec() -> ChainSpec {
        ChainSpec::foundation()
    }
}

pub type FoundationBeaconState = BeaconState<FoundationEthSpec>;

/// Ethereum Foundation specifications, modified to be suitable for < 1000 validators.
///
/// Spec v0.5.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct FewValidatorsEthSpec;

impl EthSpec for FewValidatorsEthSpec {
    type ShardCount = U8;
    type SlotsPerHistoricalRoot = U8192;
    type LatestRandaoMixesLength = U8192;
    type LatestActiveIndexRootsLength = U8192;
    type LatestSlashedExitLength = U8192;

    fn spec() -> ChainSpec {
        ChainSpec::few_validators()
    }
}

pub type FewValidatorsBeaconState = BeaconState<FewValidatorsEthSpec>;

/// Specifications suitable for a small-scale (< 1000 validators) lighthouse testnet.
///
/// Spec v0.5.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct LighthouseTestnetEthSpec;

impl EthSpec for LighthouseTestnetEthSpec {
    type ShardCount = U8;
    type SlotsPerHistoricalRoot = U8192;
    type LatestRandaoMixesLength = U8192;
    type LatestActiveIndexRootsLength = U8192;
    type LatestSlashedExitLength = U8192;

    fn spec() -> ChainSpec {
        ChainSpec::lighthouse_testnet()
    }
}

pub type LighthouseTestnetBeaconState = BeaconState<LighthouseTestnetEthSpec>;
<commit_msg>Add a "minimum_validator_count" to EthSpec<commit_after>use crate::*;
use fixed_len_vec::typenum::{Unsigned, U1024, U8, U8192};
use serde_derive::{Deserialize, Serialize};
use std::fmt::Debug;

pub trait EthSpec:
    'static + Default + Sync + Send + Clone + Debug + PartialEq + serde::de::DeserializeOwned
{
    type ShardCount: Unsigned + Clone + Sync + Send + Debug + PartialEq;
    type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send + Debug + PartialEq;
    type LatestRandaoMixesLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
    type LatestActiveIndexRootsLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
    type LatestSlashedExitLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;

    fn spec() -> ChainSpec;

    /// Returns the minimum number of validators required for this spec.
    ///
    /// This is the _absolute_ minimum, the number required to make the chain operate in the most
    /// basic sense. This count is not required to provide any security guarantees regarding
    /// decentralization, entropy, etc.
    fn minimum_validator_count() -> usize {
        Self::slots_per_epoch() as usize
    }

    /// Returns the `SLOTS_PER_EPOCH` constant for this specification.
    ///
    /// Spec v0.6.1
    fn slots_per_epoch() -> u64 {
        Self::spec().slots_per_epoch
    }

    /// Returns the `SLOTS_PER_EPOCH` constant for this specification.
    ///
    /// Spec v0.6.1
    fn genesis_epoch() -> Epoch {
        Self::spec().genesis_epoch
    }

    /// Returns the `SHARD_COUNT` constant for this specification.
    ///
    /// Spec v0.5.1
    fn shard_count() -> usize {
        Self::ShardCount::to_usize()
    }

    /// Returns the `SLOTS_PER_HISTORICAL_ROOT` constant for this specification.
    ///
    /// Spec v0.5.1
    fn slots_per_historical_root() -> usize {
        Self::SlotsPerHistoricalRoot::to_usize()
    }

    /// Returns the `LATEST_RANDAO_MIXES_LENGTH` constant for this specification.
    ///
    /// Spec v0.5.1
    fn latest_randao_mixes_length() -> usize {
        Self::LatestRandaoMixesLength::to_usize()
    }

    /// Returns the `LATEST_ACTIVE_INDEX_ROOTS` constant for this specification.
    ///
    /// Spec v0.5.1
    fn latest_active_index_roots() -> usize {
        Self::LatestActiveIndexRootsLength::to_usize()
    }

    /// Returns the `LATEST_SLASHED_EXIT_LENGTH` constant for this specification.
    ///
    /// Spec v0.5.1
    fn latest_slashed_exit_length() -> usize {
        Self::LatestSlashedExitLength::to_usize()
    }
}

/// Ethereum Foundation specifications.
///
/// Spec v0.5.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct FoundationEthSpec;

impl EthSpec for FoundationEthSpec {
    type ShardCount = U1024;
    type SlotsPerHistoricalRoot = U8192;
    type LatestRandaoMixesLength = U8192;
    type LatestActiveIndexRootsLength = U8192;
    type LatestSlashedExitLength = U8192;

    fn spec() -> ChainSpec {
        ChainSpec::foundation()
    }
}

pub type FoundationBeaconState = BeaconState<FoundationEthSpec>;

/// Ethereum Foundation specifications, modified to be suitable for < 1000 validators.
///
/// Spec v0.5.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct FewValidatorsEthSpec;

impl EthSpec for FewValidatorsEthSpec {
    type ShardCount = U8;
    type SlotsPerHistoricalRoot = U8192;
    type LatestRandaoMixesLength = U8192;
    type LatestActiveIndexRootsLength = U8192;
    type LatestSlashedExitLength = U8192;

    fn spec() -> ChainSpec {
        ChainSpec::few_validators()
    }
}

pub type FewValidatorsBeaconState = BeaconState<FewValidatorsEthSpec>;

/// Specifications suitable for a small-scale (< 1000 validators) lighthouse testnet.
///
/// Spec v0.5.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct LighthouseTestnetEthSpec;

impl EthSpec for LighthouseTestnetEthSpec {
    type ShardCount = U8;
    type SlotsPerHistoricalRoot = U8192;
    type LatestRandaoMixesLength = U8192;
    type LatestActiveIndexRootsLength = U8192;
    type LatestSlashedExitLength = U8192;

    fn spec() -> ChainSpec {
        ChainSpec::lighthouse_testnet()
    }
}

pub type LighthouseTestnetBeaconState = BeaconState<LighthouseTestnetEthSpec>;
<|endoftext|>


<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::result::Result as RResult;
use std::ops::Deref;

use toml::Value;

use error::RuntimeErrorKind as REK;
use libimagerror::into::IntoError;

generate_error_module!(
    generate_error_types!(ConfigError, ConfigErrorKind,
        TOMLParserError => "TOML Parsing error",
        NoConfigFileFound   => "No config file found",

        ConfigOverrideError => "Config override error",
        ConfigOverrideKeyNotAvailable => "Key not available",
        ConfigOverrideTypeNotMatching => "Configuration Type not matching"

    );
);

pub use self::error::{ConfigError, ConfigErrorKind};

/// Result type of this module. Either `T` or `ConfigError`
pub type Result<T> = RResult<T, ConfigError>;

/// `Configuration` object
///
/// Holds all config variables which are globally available plus the configuration object from the
/// config parser, which can be accessed.
#[derive(Debug)]
pub struct Configuration {

    /// The plain configuration object for direct access if necessary
    config: Value,

    /// The verbosity the program should run with
    verbosity: bool,

    /// The editor which should be used
    editor: Option<String>,

    ///The options the editor should get when opening some file
    editor_opts: String,
}

impl Configuration {

    /// Get a new configuration object.
    ///
    /// The passed runtimepath is used for searching the configuration file, whereas several file
    /// names are tested. If that does not work, the home directory and the XDG basedir are tested
    /// with all variants.
    ///
    /// If that doesn't work either, an error is returned.
    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = get_verbosity(&cfg);
            let editor      = get_editor(&cfg);
            let editor_opts = get_editor_opts(&cfg);

            debug!("Building configuration");
            debug!("  - verbosity  : {:?}", verbosity);
            debug!("  - editor     : {:?}", editor);
            debug!("  - editor-opts: {}", editor_opts);

            Configuration {
                config: cfg,
                verbosity: verbosity,
                editor: editor,
                editor_opts: editor_opts,
            }
        })
    }

    /// Get the Editor setting from the configuration
    pub fn editor(&self) -> Option<&String> {
        self.editor.as_ref()
    }

    #[allow(dead_code)] // Why do I actually need this annotation on a pub function?
    /// Get the underlying configuration TOML object
    pub fn config(&self) -> &Value {
        &self.config
    }

    /// Get the configuration of the store, if any.
    pub fn store_config(&self) -> Option<&Value> {
        match self.config {
            Value::Table(ref tabl) => tabl.get("store"),
            _ => None,
        }
    }

    /// Override the configuration.
    /// The `v` parameter is expected to contain 'key=value' pairs where the key is a path in the
    /// TOML tree, the value to be an appropriate value.
    ///
    /// The override fails if the configuration which is about to be overridden does not exist or
    /// the `value` part cannot be converted to the type of the configuration value.
    ///
    /// If `v` is empty, this is considered to be a successful `override_config()` call.
    pub fn override_config(&mut self, v: Vec<String>) -> Result<()> {
        use libimagutil::key_value_split::*;
        use libimagutil::iter::*;
        use self::error::ConfigErrorKind as CEK;
        use self::error::MapErrInto;
        use libimagerror::into::IntoError;
        use libimagstore::toml_ext::TomlValueExt;

        v.into_iter()
            .map(|s| { debug!("Trying to process '{}'", s); s })
            .filter_map(|s| {
                match s.into_kv() {
                    Some(kv) => Some(kv.into()),
                    None => {
                        warn!("Could split at '=' - will be ignore override");
                        None
                    }
                }
            })
            .map(|(k, v)| {
                self.config
                    .read(&k[..])
                    .map_err_into(CEK::TOMLParserError)
                    .map(|toml| match toml {
                        Some(value) => {
                            match into_value(value, v) {
                                Some(v) => {
                                    info!("Successfully overridden: {} = {}", k, v);
                                    Ok(v)
                                },
                                None => Err(CEK::ConfigOverrideTypeNotMatching.into_error()),
                            }
                        },
                        None => Err(CEK::ConfigOverrideKeyNotAvailable.into_error()),
                    })
            })
            .fold_result(|i| i)
            .map_err(Box::new)
            .map_err(|e| CEK::ConfigOverrideError.into_error_with_cause(e))
    }
}

/// Tries to convert the String `s` into the same type as `value`.
///
/// Returns None if string cannot be converted.
///
/// Arrays and Tables are not supported and will yield `None`.
fn into_value(value: Value, s: String) -> Option<Value> {
    use std::str::FromStr;

    match value {
        Value::String(_) => Some(Value::String(s)),
        Value::Integer(_) => FromStr::from_str(&s[..]).ok().map(|i| Value::Integer(i)),
        Value::Float(_) => FromStr::from_str(&s[..]).ok().map(|f| Value::Float(f)),
        Value::Boolean(_) => {
            if s == "true" { Some(Value::Boolean(true)) }
            else if s == "false" { Some(Value::Boolean(false)) }
            else { None }
        }
        Value::Datetime(_) => Value::try_from(s).ok(),
        _ => None,
    }
}

impl Deref for Configuration {
    type Target = Value;

    fn deref(&self) -> &Value {
        &self.config
    }

}

fn get_verbosity(v: &Value) -> bool {
    match *v {
        Value::Table(ref t) => t.get("verbose")
                .map_or(false, |v| match *v { Value::Boolean(b) => b, _ => false, }),
        _ => false,
    }
}

fn get_editor(v: &Value) -> Option<String> {
    match *v {
        Value::Table(ref t) => t.get("editor")
                .and_then(|v| match *v { Value::String(ref s) => Some(s.clone()), _ => None, }),
        _ => None,
    }
}

fn get_editor_opts(v: &Value) -> String {
    match *v {
        Value::Table(ref t) => t.get("editor-opts")
                .and_then(|v| match *v { Value::String(ref s) => Some(s.clone()), _ => None, })
                .unwrap_or_default(),
        _ => String::new(),
    }
}

/// Helper to fetch the config file
///
/// Tests several variants for the config file path and uses the first one which works.
fn fetch_config(rtp: &PathBuf) -> Result<Value> {
    use std::env;
    use std::fs::File;
    use std::io::Read;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;
    use self::error::MapErrInto;

    let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
    let modifier = |base: &PathBuf, v: &'static str| {
        let mut base = base.clone();
        base.push(String::from(v));
        base
    };

    vec![
        vec![rtp.clone()],
        gen_vars(rtp.clone(), variants.clone(), &modifier),

        env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
                        .unwrap_or(vec![]),

        xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
                                    .unwrap_or(vec![]),
    ].iter()
        .flatten()
        .filter(|path| path.exists() && path.is_file())
        .map(|path| {
            debug!("Reading {:?}", path);
            let content = {
                let mut s = String::new();
                let f = File::open(path);
                if f.is_err() {
                    return None
                }
                let mut f = f.unwrap();
                f.read_to_string(&mut s).ok();
                s
            };

            trace!("Contents of config file: \n---\n{}\n---", content);

            let toml = ::toml::de::from_str(&content[..])
                .map_err_into(ConfigErrorKind::TOMLParserError)
                .map_err(Box::new)
                .map_err(|e| REK::Instantiate.into_error_with_cause(e));

            Some(toml)
        })
        .filter_map(|x| x)
        .filter(|loaded| loaded.is_ok())
        .map(|inner| Value::Table(inner.unwrap()))
        .nth(0)
        .ok_or(ConfigErrorKind::NoConfigFileFound.into())
}
<commit_msg>Try to remove annotation<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::result::Result as RResult;
use std::ops::Deref;

use toml::Value;

use error::RuntimeErrorKind as REK;
use libimagerror::into::IntoError;

generate_error_module!(
    generate_error_types!(ConfigError, ConfigErrorKind,
        TOMLParserError => "TOML Parsing error",
        NoConfigFileFound   => "No config file found",

        ConfigOverrideError => "Config override error",
        ConfigOverrideKeyNotAvailable => "Key not available",
        ConfigOverrideTypeNotMatching => "Configuration Type not matching"

    );
);

pub use self::error::{ConfigError, ConfigErrorKind};

/// Result type of this module. Either `T` or `ConfigError`
pub type Result<T> = RResult<T, ConfigError>;

/// `Configuration` object
///
/// Holds all config variables which are globally available plus the configuration object from the
/// config parser, which can be accessed.
#[derive(Debug)]
pub struct Configuration {

    /// The plain configuration object for direct access if necessary
    config: Value,

    /// The verbosity the program should run with
    verbosity: bool,

    /// The editor which should be used
    editor: Option<String>,

    ///The options the editor should get when opening some file
    editor_opts: String,
}

impl Configuration {

    /// Get a new configuration object.
    ///
    /// The passed runtimepath is used for searching the configuration file, whereas several file
    /// names are tested. If that does not work, the home directory and the XDG basedir are tested
    /// with all variants.
    ///
    /// If that doesn't work either, an error is returned.
    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = get_verbosity(&cfg);
            let editor      = get_editor(&cfg);
            let editor_opts = get_editor_opts(&cfg);

            debug!("Building configuration");
            debug!("  - verbosity  : {:?}", verbosity);
            debug!("  - editor     : {:?}", editor);
            debug!("  - editor-opts: {}", editor_opts);

            Configuration {
                config: cfg,
                verbosity: verbosity,
                editor: editor,
                editor_opts: editor_opts,
            }
        })
    }

    /// Get the Editor setting from the configuration
    pub fn editor(&self) -> Option<&String> {
        self.editor.as_ref()
    }

    /// Get the underlying configuration TOML object
    pub fn config(&self) -> &Value {
        &self.config
    }

    /// Get the configuration of the store, if any.
    pub fn store_config(&self) -> Option<&Value> {
        match self.config {
            Value::Table(ref tabl) => tabl.get("store"),
            _ => None,
        }
    }

    /// Override the configuration.
    /// The `v` parameter is expected to contain 'key=value' pairs where the key is a path in the
    /// TOML tree, the value to be an appropriate value.
    ///
    /// The override fails if the configuration which is about to be overridden does not exist or
    /// the `value` part cannot be converted to the type of the configuration value.
    ///
    /// If `v` is empty, this is considered to be a successful `override_config()` call.
    pub fn override_config(&mut self, v: Vec<String>) -> Result<()> {
        use libimagutil::key_value_split::*;
        use libimagutil::iter::*;
        use self::error::ConfigErrorKind as CEK;
        use self::error::MapErrInto;
        use libimagerror::into::IntoError;
        use libimagstore::toml_ext::TomlValueExt;

        v.into_iter()
            .map(|s| { debug!("Trying to process '{}'", s); s })
            .filter_map(|s| {
                match s.into_kv() {
                    Some(kv) => Some(kv.into()),
                    None => {
                        warn!("Could split at '=' - will be ignore override");
                        None
                    }
                }
            })
            .map(|(k, v)| {
                self.config
                    .read(&k[..])
                    .map_err_into(CEK::TOMLParserError)
                    .map(|toml| match toml {
                        Some(value) => {
                            match into_value(value, v) {
                                Some(v) => {
                                    info!("Successfully overridden: {} = {}", k, v);
                                    Ok(v)
                                },
                                None => Err(CEK::ConfigOverrideTypeNotMatching.into_error()),
                            }
                        },
                        None => Err(CEK::ConfigOverrideKeyNotAvailable.into_error()),
                    })
            })
            .fold_result(|i| i)
            .map_err(Box::new)
            .map_err(|e| CEK::ConfigOverrideError.into_error_with_cause(e))
    }
}

/// Tries to convert the String `s` into the same type as `value`.
///
/// Returns None if string cannot be converted.
///
/// Arrays and Tables are not supported and will yield `None`.
fn into_value(value: Value, s: String) -> Option<Value> {
    use std::str::FromStr;

    match value {
        Value::String(_) => Some(Value::String(s)),
        Value::Integer(_) => FromStr::from_str(&s[..]).ok().map(|i| Value::Integer(i)),
        Value::Float(_) => FromStr::from_str(&s[..]).ok().map(|f| Value::Float(f)),
        Value::Boolean(_) => {
            if s == "true" { Some(Value::Boolean(true)) }
            else if s == "false" { Some(Value::Boolean(false)) }
            else { None }
        }
        Value::Datetime(_) => Value::try_from(s).ok(),
        _ => None,
    }
}

impl Deref for Configuration {
    type Target = Value;

    fn deref(&self) -> &Value {
        &self.config
    }

}

fn get_verbosity(v: &Value) -> bool {
    match *v {
        Value::Table(ref t) => t.get("verbose")
                .map_or(false, |v| match *v { Value::Boolean(b) => b, _ => false, }),
        _ => false,
    }
}

fn get_editor(v: &Value) -> Option<String> {
    match *v {
        Value::Table(ref t) => t.get("editor")
                .and_then(|v| match *v { Value::String(ref s) => Some(s.clone()), _ => None, }),
        _ => None,
    }
}

fn get_editor_opts(v: &Value) -> String {
    match *v {
        Value::Table(ref t) => t.get("editor-opts")
                .and_then(|v| match *v { Value::String(ref s) => Some(s.clone()), _ => None, })
                .unwrap_or_default(),
        _ => String::new(),
    }
}

/// Helper to fetch the config file
///
/// Tests several variants for the config file path and uses the first one which works.
fn fetch_config(rtp: &PathBuf) -> Result<Value> {
    use std::env;
    use std::fs::File;
    use std::io::Read;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;
    use self::error::MapErrInto;

    let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
    let modifier = |base: &PathBuf, v: &'static str| {
        let mut base = base.clone();
        base.push(String::from(v));
        base
    };

    vec![
        vec![rtp.clone()],
        gen_vars(rtp.clone(), variants.clone(), &modifier),

        env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
                        .unwrap_or(vec![]),

        xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
                                    .unwrap_or(vec![]),
    ].iter()
        .flatten()
        .filter(|path| path.exists() && path.is_file())
        .map(|path| {
            debug!("Reading {:?}", path);
            let content = {
                let mut s = String::new();
                let f = File::open(path);
                if f.is_err() {
                    return None
                }
                let mut f = f.unwrap();
                f.read_to_string(&mut s).ok();
                s
            };

            trace!("Contents of config file: \n---\n{}\n---", content);

            let toml = ::toml::de::from_str(&content[..])
                .map_err_into(ConfigErrorKind::TOMLParserError)
                .map_err(Box::new)
                .map_err(|e| REK::Instantiate.into_error_with_cause(e));

            Some(toml)
        })
        .filter_map(|x| x)
        .filter(|loaded| loaded.is_ok())
        .map(|inner| Value::Table(inner.unwrap()))
        .nth(0)
        .ok_or(ConfigErrorKind::NoConfigFileFound.into())
}
<|endoftext|>


<commit_before>use super::{EXT, INIT_PY};
use backend::{Environment, PackageProcessor, PackageUtils};
use backend::errors::*;
use core::{Loc, RpDecl, RpEnumBody, RpInterfaceBody, RpPackage, RpTupleBody, RpTypeBody,
           RpVersionedPackage};
use python_backend::PythonBackend;
use python_file_spec::PythonFileSpec;
use std::collections::BTreeMap;
use std::fs::{self, File};
use std::path::{Path, PathBuf};

pub struct PythonCompiler<'el> {
    pub out_path: PathBuf,
    pub backend: &'el PythonBackend,
}

impl<'el> PythonCompiler<'el> {
    pub fn compile(&self) -> Result<()> {
        let files = self.populate_files()?;
        self.write_files(files)
    }
}

impl<'el> PackageProcessor<'el> for PythonCompiler<'el> {
    type Out = PythonFileSpec<'el>;

    fn ext(&self) -> &str {
        EXT
    }

    fn env(&self) -> &'el Environment {
        &self.backend.env
    }

    fn out_path(&self) -> &Path {
        &self.out_path
    }

    fn processed_package(&self, package: &RpVersionedPackage) -> RpPackage {
        self.backend.package(package)
    }

    fn process_tuple(&self, out: &mut Self::Out, body: &'el Loc<RpTupleBody>) -> Result<()> {
        self.backend.process_tuple(out, body)
    }

    fn process_enum(&self, out: &mut Self::Out, body: &'el Loc<RpEnumBody>) -> Result<()> {
        self.backend.process_enum(out, body)
    }

    fn process_type(&self, out: &mut Self::Out, body: &'el Loc<RpTypeBody>) -> Result<()> {
        self.backend.process_type(out, body)
    }

    fn process_interface(
        &self,
        out: &mut Self::Out,
        body: &'el Loc<RpInterfaceBody>,
    ) -> Result<()> {
        self.backend.process_interface(out, body)
    }

    fn populate_files(&self) -> Result<BTreeMap<RpVersionedPackage, PythonFileSpec<'el>>> {
        let mut enums = Vec::new();

        let mut files = self.do_populate_files(|decl| {
            if let RpDecl::Enum(ref body) = **decl {
                enums.push(body);
            }

            Ok(())
        })?;

        for body in enums {
            if let Some(ref mut file_spec) = files.get_mut(&body.name.package) {
                file_spec.0.push(self.backend.enum_variants(&body)?);
            } else {
                return Err(format!("no such package: {}", &body.name.package).into());
            }
        }

        Ok(files)
    }

    fn resolve_full_path(&self, package: &RpPackage) -> Result<PathBuf> {
        let mut full_path = self.out_path().to_owned();
        let mut iter = package.parts.iter().peekable();

        while let Some(part) = iter.next() {
            full_path = full_path.join(part);

            if iter.peek().is_none() {
                continue;
            }

            if !full_path.is_dir() {
                debug!("+dir: {}", full_path.display());
                fs::create_dir_all(&full_path)?;
            }

            let init_path = full_path.join(INIT_PY);

            if !init_path.is_file() {
                debug!("+init: {}", init_path.display());
                File::create(init_path)?;
            }
        }

        // path to final file
        full_path.set_extension(self.ext());
        Ok(full_path)
    }
}
<commit_msg>[python] more documentation<commit_after>use super::{EXT, INIT_PY};
use backend::{Environment, PackageProcessor, PackageUtils};
use backend::errors::*;
use core::{Loc, RpDecl, RpEnumBody, RpInterfaceBody, RpPackage, RpTupleBody, RpTypeBody,
           RpVersionedPackage};
use python_backend::PythonBackend;
use python_file_spec::PythonFileSpec;
use std::collections::BTreeMap;
use std::fs::{self, File};
use std::path::{Path, PathBuf};

pub struct PythonCompiler<'el> {
    pub out_path: PathBuf,
    pub backend: &'el PythonBackend,
}

impl<'el> PythonCompiler<'el> {
    pub fn compile(&self) -> Result<()> {
        self.write_files(self.populate_files()?)
    }
}

impl<'el> PackageProcessor<'el> for PythonCompiler<'el> {
    type Out = PythonFileSpec<'el>;

    fn ext(&self) -> &str {
        EXT
    }

    fn env(&self) -> &'el Environment {
        &self.backend.env
    }

    fn out_path(&self) -> &Path {
        &self.out_path
    }

    fn processed_package(&self, package: &RpVersionedPackage) -> RpPackage {
        self.backend.package(package)
    }

    fn process_tuple(&self, out: &mut Self::Out, body: &'el Loc<RpTupleBody>) -> Result<()> {
        self.backend.process_tuple(out, body)
    }

    fn process_enum(&self, out: &mut Self::Out, body: &'el Loc<RpEnumBody>) -> Result<()> {
        self.backend.process_enum(out, body)
    }

    fn process_type(&self, out: &mut Self::Out, body: &'el Loc<RpTypeBody>) -> Result<()> {
        self.backend.process_type(out, body)
    }

    fn process_interface(
        &self,
        out: &mut Self::Out,
        body: &'el Loc<RpInterfaceBody>,
    ) -> Result<()> {
        self.backend.process_interface(out, body)
    }

    fn populate_files(&self) -> Result<BTreeMap<RpVersionedPackage, PythonFileSpec<'el>>> {
        let mut enums = Vec::new();

        let mut files = self.do_populate_files(|decl| {
            if let RpDecl::Enum(ref body) = **decl {
                enums.push(body);
            }

            Ok(())
        })?;

        // Process picked up enums.
        // These are added to the end of the file to declare enums:
        // https://docs.python.org/3/library/enum.html
        for body in enums {
            if let Some(ref mut file_spec) = files.get_mut(&body.name.package) {
                file_spec.0.push(self.backend.enum_variants(&body)?);
            } else {
                return Err(
                    format!("missing file for package: {}", &body.name.package).into(),
                );
            }
        }

        Ok(files)
    }

    fn resolve_full_path(&self, package: &RpPackage) -> Result<PathBuf> {
        let mut full_path = self.out_path().to_owned();
        let mut iter = package.parts.iter().peekable();

        while let Some(part) = iter.next() {
            full_path = full_path.join(part);

            if iter.peek().is_none() {
                continue;
            }

            if !full_path.is_dir() {
                debug!("+dir: {}", full_path.display());
                fs::create_dir_all(&full_path)?;
            }

            let init_path = full_path.join(INIT_PY);

            if !init_path.is_file() {
                debug!("+init: {}", init_path.display());
                File::create(init_path)?;
            }
        }

        full_path.set_extension(self.ext());
        Ok(full_path)
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::iter;
use std::path::{Component, Path, PathBuf};

use filetime::FileTime;

use crate::util::errors::{CargoResult, CargoResultExt, Internal};

pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
    let err = match env::join_paths(paths.iter()) {
        Ok(paths) => return Ok(paths),
        Err(e) => e,
    };
    let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
    let err = failure::Error::from(err);
    let explain = Internal::new(failure::format_err!(
        "failed to join path array: {:?}",
        paths
    ));
    let err = failure::Error::from(err.context(explain));
    let more_explain = format!(
        "failed to join search paths together\n\
         Does ${} have an unterminated quote character?",
        env
    );
    Err(err.context(more_explain).into())
}

pub fn dylib_path_envvar() -> &'static str {
    if cfg!(windows) {
        "PATH"
    } else if cfg!(target_os = "macos") {
        "DYLD_LIBRARY_PATH"
    } else {
        "LD_LIBRARY_PATH"
    }
}

pub fn dylib_path() -> Vec<PathBuf> {
    match env::var_os(dylib_path_envvar()) {
        Some(var) => env::split_paths(&var).collect(),
        None => Vec::new(),
    }
}

pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => {
                ret.push(component.as_os_str());
            }
            Component::CurDir => {}
            Component::ParentDir => {
                ret.pop();
            }
            Component::Normal(c) => {
                ret.push(c);
            }
        }
    }
    ret
}

pub fn without_prefix<'a>(long_path: &'a Path, prefix: &'a Path) -> Option<&'a Path> {
    let mut a = long_path.components();
    let mut b = prefix.components();
    loop {
        match b.next() {
            Some(y) => match a.next() {
                Some(x) if x == y => continue,
                _ => return None,
            },
            None => return Some(a.as_path()),
        }
    }
}

pub fn resolve_executable(exec: &Path) -> CargoResult<PathBuf> {
    if exec.components().count() == 1 {
        let paths = env::var_os("PATH").ok_or_else(|| failure::format_err!("no PATH"))?;
        let candidates = env::split_paths(&paths).flat_map(|path| {
            let candidate = path.join(&exec);
            let with_exe = if env::consts::EXE_EXTENSION == "" {
                None
            } else {
                Some(candidate.with_extension(env::consts::EXE_EXTENSION))
            };
            iter::once(candidate).chain(with_exe)
        });
        for candidate in candidates {
            if candidate.is_file() {
                // PATH may have a component like "." in it, so we still need to
                // canonicalize.
                return Ok(candidate.canonicalize()?);
            }
        }

        failure::bail!("no executable for `{}` found in PATH", exec.display())
    } else {
        Ok(exec.canonicalize()?)
    }
}

pub fn read(path: &Path) -> CargoResult<String> {
    match String::from_utf8(read_bytes(path)?) {
        Ok(s) => Ok(s),
        Err(_) => failure::bail!("path at `{}` was not valid utf-8", path.display()),
    }
}

pub fn read_bytes(path: &Path) -> CargoResult<Vec<u8>> {
    let res = (|| -> CargoResult<_> {
        let mut ret = Vec::new();
        let mut f = File::open(path)?;
        if let Ok(m) = f.metadata() {
            ret.reserve(m.len() as usize + 1);
        }
        f.read_to_end(&mut ret)?;
        Ok(ret)
    })()
    .chain_err(|| format!("failed to read `{}`", path.display()))?;
    Ok(res)
}

pub fn write(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = File::create(path)?;
        f.write_all(contents)?;
        Ok(())
    })()
    .chain_err(|| format!("failed to write `{}`", path.display()))?;
    Ok(())
}

pub fn write_if_changed<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let contents = contents.as_ref();
        let mut f = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)?;
        let mut orig = Vec::new();
        f.read_to_end(&mut orig)?;
        if orig != contents {
            f.set_len(0)?;
            f.seek(io::SeekFrom::Start(0))?;
            f.write_all(contents)?;
        }
        Ok(())
    })()
    .chain_err(|| format!("failed to write `{}`", path.as_ref().display()))?;
    Ok(())
}

pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = OpenOptions::new()
            .write(true)
            .append(true)
            .create(true)
            .open(path)?;

        f.write_all(contents)?;
        Ok(())
    })()
    .chain_err(|| format!("failed to write `{}`", path.display()))?;
    Ok(())
}

pub fn mtime(path: &Path) -> CargoResult<FileTime> {
    let meta = fs::metadata(path).chain_err(|| format!("failed to stat `{}`", path.display()))?;
    Ok(FileTime::from_last_modification_time(&meta))
}

#[cfg(unix)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    use std::os::unix::prelude::*;
    Ok(path.as_os_str().as_bytes())
}
#[cfg(windows)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    match path.as_os_str().to_str() {
        Some(s) => Ok(s.as_bytes()),
        None => Err(failure::format_err!(
            "invalid non-unicode path: {}",
            path.display()
        )),
    }
}

#[cfg(unix)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::ffi::OsStr;
    use std::os::unix::prelude::*;
    Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(windows)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::str;
    match str::from_utf8(bytes) {
        Ok(s) => Ok(PathBuf::from(s)),
        Err(..) => Err(failure::format_err!("invalid non-unicode path")),
    }
}

pub fn ancestors(path: &Path) -> PathAncestors<'_> {
    PathAncestors::new(path)
}

pub struct PathAncestors<'a> {
    current: Option<&'a Path>,
    stop_at: Option<PathBuf>,
}

impl<'a> PathAncestors<'a> {
    fn new(path: &Path) -> PathAncestors<'_> {
        PathAncestors {
            current: Some(path),
            //HACK: avoid reading `~/.cargo/config` when testing Cargo itself.
            stop_at: env::var("__CARGO_TEST_ROOT").ok().map(PathBuf::from),
        }
    }
}

impl<'a> Iterator for PathAncestors<'a> {
    type Item = &'a Path;

    fn next(&mut self) -> Option<&'a Path> {
        if let Some(path) = self.current {
            self.current = path.parent();

            if let Some(ref stop_at) = self.stop_at {
                if path == stop_at {
                    self.current = None;
                }
            }

            Some(path)
        } else {
            None
        }
    }
}

pub fn remove_dir_all<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_dir_all(p.as_ref())
}

fn _remove_dir_all(p: &Path) -> CargoResult<()> {
    if p.symlink_metadata()?.file_type().is_symlink() {
        return remove_file(p);
    }
    let entries = p
        .read_dir()
        .chain_err(|| format!("failed to read directory `{}`", p.display()))?;
    for entry in entries {
        let entry = entry?;
        let path = entry.path();
        if entry.file_type()?.is_dir() {
            remove_dir_all(&path)?;
        } else {
            remove_file(&path)?;
        }
    }
    remove_dir(&p)
}

pub fn remove_dir<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_dir(p.as_ref())
}

fn _remove_dir(p: &Path) -> CargoResult<()> {
    fs::remove_dir(p).chain_err(|| format!("failed to remove directory `{}`", p.display()))?;
    Ok(())
}

pub fn remove_file<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_file(p.as_ref())
}

fn _remove_file(p: &Path) -> CargoResult<()> {
    let mut err = match fs::remove_file(p) {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if err.kind() == io::ErrorKind::PermissionDenied && set_not_readonly(p).unwrap_or(false) {
        match fs::remove_file(p) {
            Ok(()) => return Ok(()),
            Err(e) => err = e,
        }
    }

    Err(err).chain_err(|| format!("failed to remove file `{}`", p.display()))?;
    Ok(())
}

fn set_not_readonly(p: &Path) -> io::Result<bool> {
    let mut perms = p.metadata()?.permissions();
    if !perms.readonly() {
        return Ok(false);
    }
    perms.set_readonly(false);
    fs::set_permissions(p, perms)?;
    Ok(true)
}
<commit_msg>use DYLD_FALLBACK_LIBRARY_PATH for dylib_path_envvar on macOS<commit_after>use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::iter;
use std::path::{Component, Path, PathBuf};

use filetime::FileTime;

use crate::util::errors::{CargoResult, CargoResultExt, Internal};

pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
    let err = match env::join_paths(paths.iter()) {
        Ok(paths) => return Ok(paths),
        Err(e) => e,
    };
    let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
    let err = failure::Error::from(err);
    let explain = Internal::new(failure::format_err!(
        "failed to join path array: {:?}",
        paths
    ));
    let err = failure::Error::from(err.context(explain));
    let more_explain = format!(
        "failed to join search paths together\n\
         Does ${} have an unterminated quote character?",
        env
    );
    Err(err.context(more_explain).into())
}

pub fn dylib_path_envvar() -> &'static str {
    if cfg!(windows) {
        "PATH"
    } else if cfg!(target_os = "macos") {
        // When loading and linking a dynamic library or bundle, dlopen
        // searches in LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, PWD, and
        // DYLD_FALLBACK_LIBRARY_PATH.
        // In the Mach-O format, a dynamic library has an "install path."
        // Clients linking against the library record this path, and the
        // dynamic linker, dyld, uses it to locate the library.
        // dyld searches DYLD_LIBRARY_PATH *before* the install path.
        // dyld searches DYLD_FALLBACK_LIBRARY_PATH only if it cannot
        // find the library in the install path.
        // Setting DYLD_LIBRARY_PATH can easily have unintended
        // consequences.
        "DYLD_FALLBACK_LIBRARY_PATH"
    } else {
        "LD_LIBRARY_PATH"
    }
}

pub fn dylib_path() -> Vec<PathBuf> {
    match env::var_os(dylib_path_envvar()) {
        Some(var) => env::split_paths(&var).collect(),
        None => Vec::new(),
    }
}

pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => {
                ret.push(component.as_os_str());
            }
            Component::CurDir => {}
            Component::ParentDir => {
                ret.pop();
            }
            Component::Normal(c) => {
                ret.push(c);
            }
        }
    }
    ret
}

pub fn without_prefix<'a>(long_path: &'a Path, prefix: &'a Path) -> Option<&'a Path> {
    let mut a = long_path.components();
    let mut b = prefix.components();
    loop {
        match b.next() {
            Some(y) => match a.next() {
                Some(x) if x == y => continue,
                _ => return None,
            },
            None => return Some(a.as_path()),
        }
    }
}

pub fn resolve_executable(exec: &Path) -> CargoResult<PathBuf> {
    if exec.components().count() == 1 {
        let paths = env::var_os("PATH").ok_or_else(|| failure::format_err!("no PATH"))?;
        let candidates = env::split_paths(&paths).flat_map(|path| {
            let candidate = path.join(&exec);
            let with_exe = if env::consts::EXE_EXTENSION == "" {
                None
            } else {
                Some(candidate.with_extension(env::consts::EXE_EXTENSION))
            };
            iter::once(candidate).chain(with_exe)
        });
        for candidate in candidates {
            if candidate.is_file() {
                // PATH may have a component like "." in it, so we still need to
                // canonicalize.
                return Ok(candidate.canonicalize()?);
            }
        }

        failure::bail!("no executable for `{}` found in PATH", exec.display())
    } else {
        Ok(exec.canonicalize()?)
    }
}

pub fn read(path: &Path) -> CargoResult<String> {
    match String::from_utf8(read_bytes(path)?) {
        Ok(s) => Ok(s),
        Err(_) => failure::bail!("path at `{}` was not valid utf-8", path.display()),
    }
}

pub fn read_bytes(path: &Path) -> CargoResult<Vec<u8>> {
    let res = (|| -> CargoResult<_> {
        let mut ret = Vec::new();
        let mut f = File::open(path)?;
        if let Ok(m) = f.metadata() {
            ret.reserve(m.len() as usize + 1);
        }
        f.read_to_end(&mut ret)?;
        Ok(ret)
    })()
    .chain_err(|| format!("failed to read `{}`", path.display()))?;
    Ok(res)
}

pub fn write(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = File::create(path)?;
        f.write_all(contents)?;
        Ok(())
    })()
    .chain_err(|| format!("failed to write `{}`", path.display()))?;
    Ok(())
}

pub fn write_if_changed<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let contents = contents.as_ref();
        let mut f = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)?;
        let mut orig = Vec::new();
        f.read_to_end(&mut orig)?;
        if orig != contents {
            f.set_len(0)?;
            f.seek(io::SeekFrom::Start(0))?;
            f.write_all(contents)?;
        }
        Ok(())
    })()
    .chain_err(|| format!("failed to write `{}`", path.as_ref().display()))?;
    Ok(())
}

pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = OpenOptions::new()
            .write(true)
            .append(true)
            .create(true)
            .open(path)?;

        f.write_all(contents)?;
        Ok(())
    })()
    .chain_err(|| format!("failed to write `{}`", path.display()))?;
    Ok(())
}

pub fn mtime(path: &Path) -> CargoResult<FileTime> {
    let meta = fs::metadata(path).chain_err(|| format!("failed to stat `{}`", path.display()))?;
    Ok(FileTime::from_last_modification_time(&meta))
}

#[cfg(unix)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    use std::os::unix::prelude::*;
    Ok(path.as_os_str().as_bytes())
}
#[cfg(windows)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    match path.as_os_str().to_str() {
        Some(s) => Ok(s.as_bytes()),
        None => Err(failure::format_err!(
            "invalid non-unicode path: {}",
            path.display()
        )),
    }
}

#[cfg(unix)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::ffi::OsStr;
    use std::os::unix::prelude::*;
    Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(windows)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::str;
    match str::from_utf8(bytes) {
        Ok(s) => Ok(PathBuf::from(s)),
        Err(..) => Err(failure::format_err!("invalid non-unicode path")),
    }
}

pub fn ancestors(path: &Path) -> PathAncestors<'_> {
    PathAncestors::new(path)
}

pub struct PathAncestors<'a> {
    current: Option<&'a Path>,
    stop_at: Option<PathBuf>,
}

impl<'a> PathAncestors<'a> {
    fn new(path: &Path) -> PathAncestors<'_> {
        PathAncestors {
            current: Some(path),
            //HACK: avoid reading `~/.cargo/config` when testing Cargo itself.
            stop_at: env::var("__CARGO_TEST_ROOT").ok().map(PathBuf::from),
        }
    }
}

impl<'a> Iterator for PathAncestors<'a> {
    type Item = &'a Path;

    fn next(&mut self) -> Option<&'a Path> {
        if let Some(path) = self.current {
            self.current = path.parent();

            if let Some(ref stop_at) = self.stop_at {
                if path == stop_at {
                    self.current = None;
                }
            }

            Some(path)
        } else {
            None
        }
    }
}

pub fn remove_dir_all<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_dir_all(p.as_ref())
}

fn _remove_dir_all(p: &Path) -> CargoResult<()> {
    if p.symlink_metadata()?.file_type().is_symlink() {
        return remove_file(p);
    }
    let entries = p
        .read_dir()
        .chain_err(|| format!("failed to read directory `{}`", p.display()))?;
    for entry in entries {
        let entry = entry?;
        let path = entry.path();
        if entry.file_type()?.is_dir() {
            remove_dir_all(&path)?;
        } else {
            remove_file(&path)?;
        }
    }
    remove_dir(&p)
}

pub fn remove_dir<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_dir(p.as_ref())
}

fn _remove_dir(p: &Path) -> CargoResult<()> {
    fs::remove_dir(p).chain_err(|| format!("failed to remove directory `{}`", p.display()))?;
    Ok(())
}

pub fn remove_file<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_file(p.as_ref())
}

fn _remove_file(p: &Path) -> CargoResult<()> {
    let mut err = match fs::remove_file(p) {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if err.kind() == io::ErrorKind::PermissionDenied && set_not_readonly(p).unwrap_or(false) {
        match fs::remove_file(p) {
            Ok(()) => return Ok(()),
            Err(e) => err = e,
        }
    }

    Err(err).chain_err(|| format!("failed to remove file `{}`", p.display()))?;
    Ok(())
}

fn set_not_readonly(p: &Path) -> io::Result<bool> {
    let mut perms = p.metadata()?.permissions();
    if !perms.readonly() {
        return Ok(false);
    }
    perms.set_readonly(false);
    fs::set_permissions(p, perms)?;
    Ok(true)
}
<|endoftext|>


<commit_before> // aux-build:priv_dep.rs
 // aux-build:pub_dep.rs
 // compile-flags: --extern-private priv_dep
#![deny(exported_private_dependencies)]

// This crate is a private dependency
extern crate priv_dep;
// This crate is a public dependenct
extern crate pub_dep;

use priv_dep::{OtherType, OtherTrait};
use pub_dep::PubType;

// Type from private dependency used in private
// type - this is fine
struct PrivateType {
    field: OtherType
}

pub struct PublicType {
    pub field: OtherType,
    //~^ ERROR type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface
    //~| WARNING this was previously accepted
    priv_field: OtherType, // Private field - this is fine
    pub other_field: PubType // Type from public dependency - this is fine
}

impl PublicType {
    pub fn pub_fn(param: OtherType) {}
    //~^ ERROR type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface
    //~| WARNING this was previously accepted

    fn priv_fn(param: OtherType) {}
}

pub trait MyPubTrait {
    type Foo: OtherTrait;
}
//~^^^ ERROR trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface
//~| WARNING this was previously accepted

fn main() {}
<commit_msg>Test allowing individual struct field<commit_after> // aux-build:priv_dep.rs
 // aux-build:pub_dep.rs
 // compile-flags: --extern-private priv_dep
#![deny(exported_private_dependencies)]

// This crate is a private dependency
extern crate priv_dep;
// This crate is a public dependenct
extern crate pub_dep;

use priv_dep::{OtherType, OtherTrait};
use pub_dep::PubType;

// Type from private dependency used in private
// type - this is fine
struct PrivateType {
    field: OtherType
}

pub struct PublicType {
    pub field: OtherType,
    //~^ ERROR type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface
    //~| WARNING this was previously accepted
    priv_field: OtherType, // Private field - this is fine
    pub other_field: PubType // Type from public dependency - this is fine
}

impl PublicType {
    pub fn pub_fn(param: OtherType) {}
    //~^ ERROR type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface
    //~| WARNING this was previously accepted

    fn priv_fn(param: OtherType) {}
}

pub trait MyPubTrait {
    type Foo: OtherTrait;
}
//~^^^ ERROR trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface
//~| WARNING this was previously accepted

pub struct AllowedPrivType {
    #[allow(exported_private_dependencies)]
    pub allowed: OtherType
}

fn main() {}
<|endoftext|>


<commit_before>//! base_db defines basic database traits. The concrete DB is defined by ide.
mod input;
mod change;
pub mod fixture;

use std::{panic, sync::Arc};

use rustc_hash::FxHashSet;
use syntax::{ast, Parse, SourceFile, TextRange, TextSize};

pub use crate::{
    change::Change,
    input::{
        CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
        Edition, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroId,
        ProcMacroKind, SourceRoot, SourceRootId,
    },
};
pub use salsa::{self, Cancelled};
pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath};

#[macro_export]
macro_rules! impl_intern_key {
    ($name:ident) => {
        impl $crate::salsa::InternKey for $name {
            fn from_intern_id(v: $crate::salsa::InternId) -> Self {
                $name(v)
            }
            fn as_intern_id(&self) -> $crate::salsa::InternId {
                self.0
            }
        }
    };
}

pub trait Upcast<T: ?Sized> {
    fn upcast(&self) -> &T;
}

#[derive(Clone, Copy, Debug)]
pub struct FilePosition {
    pub file_id: FileId,
    pub offset: TextSize,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct FileRange {
    pub file_id: FileId,
    pub range: TextRange,
}

pub const DEFAULT_LRU_CAP: usize = 128;

pub trait FileLoader {
    /// Text of the file.
    fn file_text(&self, file_id: FileId) -> Arc<String>;
    fn resolve_path(&self, path: AnchoredPath) -> Option<FileId>;
    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
}

/// Database which stores all significant input facts: source code and project
/// model. Everything else in rust-analyzer is derived from these queries.
#[salsa::query_group(SourceDatabaseStorage)]
pub trait SourceDatabase: FileLoader + std::fmt::Debug {
    // Parses the file into the syntax tree.
    #[salsa::invoke(parse_query)]
    fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;

    /// The crate graph.
    #[salsa::input]
    fn crate_graph(&self) -> Arc<CrateGraph>;
}

fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
    let _p = profile::span("parse_query").detail(|| format!("{:?}", file_id));
    let text = db.file_text(file_id);
    SourceFile::parse(&*text)
}

/// We don't want to give HIR knowledge of source roots, hence we extract these
/// methods into a separate DB.
#[salsa::query_group(SourceDatabaseExtStorage)]
pub trait SourceDatabaseExt: SourceDatabase {
    #[salsa::input]
    fn file_text(&self, file_id: FileId) -> Arc<String>;
    /// Path to a file, relative to the root of its source root.
    /// Source root of the file.
    #[salsa::input]
    fn file_source_root(&self, file_id: FileId) -> SourceRootId;
    /// Contents of the source root.
    #[salsa::input]
    fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;

    fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
}

fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
    let graph = db.crate_graph();
    let res = graph
        .iter()
        .filter(|&krate| {
            let root_file = graph[krate].root_file_id;
            db.file_source_root(root_file) == id
        })
        .collect();
    Arc::new(res)
}

/// Silly workaround for cyclic deps between the traits
pub struct FileLoaderDelegate<T>(pub T);

impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
    fn file_text(&self, file_id: FileId) -> Arc<String> {
        SourceDatabaseExt::file_text(self.0, file_id)
    }
    fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
        // FIXME: this *somehow* should be platform agnostic...
        let source_root = self.0.file_source_root(path.anchor);
        let source_root = self.0.source_root(source_root);
        source_root.file_set.resolve_path(path)
    }

    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
        let _p = profile::span("relevant_crates");
        let source_root = self.0.file_source_root(file_id);
        self.0.source_root_crates(source_root)
    }
}
<commit_msg>Add `crate_limits` query to `SourceDatabase`<commit_after>//! base_db defines basic database traits. The concrete DB is defined by ide.
mod input;
mod change;
pub mod fixture;

use std::{panic, sync::Arc};

use rustc_hash::FxHashSet;
use syntax::{ast, Parse, SourceFile, TextRange, TextSize};

pub use crate::{
    change::Change,
    input::{
        CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
        Edition, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroId,
        ProcMacroKind, SourceRoot, SourceRootId,
    },
};
pub use salsa::{self, Cancelled};
pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath};

#[macro_export]
macro_rules! impl_intern_key {
    ($name:ident) => {
        impl $crate::salsa::InternKey for $name {
            fn from_intern_id(v: $crate::salsa::InternId) -> Self {
                $name(v)
            }
            fn as_intern_id(&self) -> $crate::salsa::InternId {
                self.0
            }
        }
    };
}

pub trait Upcast<T: ?Sized> {
    fn upcast(&self) -> &T;
}

#[derive(Clone, Copy, Debug)]
pub struct FilePosition {
    pub file_id: FileId,
    pub offset: TextSize,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct FileRange {
    pub file_id: FileId,
    pub range: TextRange,
}

pub const DEFAULT_LRU_CAP: usize = 128;

pub trait FileLoader {
    /// Text of the file.
    fn file_text(&self, file_id: FileId) -> Arc<String>;
    fn resolve_path(&self, path: AnchoredPath) -> Option<FileId>;
    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
}

/// Database which stores all significant input facts: source code and project
/// model. Everything else in rust-analyzer is derived from these queries.
#[salsa::query_group(SourceDatabaseStorage)]
pub trait SourceDatabase: FileLoader + std::fmt::Debug {
    // Parses the file into the syntax tree.
    #[salsa::invoke(parse_query)]
    fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;

    /// The crate graph.
    #[salsa::input]
    fn crate_graph(&self) -> Arc<CrateGraph>;

    #[salsa::transparent]
    fn crate_limits(&self, crate_id: CrateId) -> CrateLimits;
}

pub struct CrateLimits {
    /// The maximum depth for potentially infinitely-recursive compile-time operations like macro expansion or auto-dereference.
    pub recursion_limit: u32,
}

fn crate_limits(_db: &dyn SourceDatabase, _crate_id: CrateId) -> CrateLimits {
    CrateLimits {
        // 128 is the default in rustc.
        recursion_limit: 128,
    }
}

fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
    let _p = profile::span("parse_query").detail(|| format!("{:?}", file_id));
    let text = db.file_text(file_id);
    SourceFile::parse(&*text)
}

/// We don't want to give HIR knowledge of source roots, hence we extract these
/// methods into a separate DB.
#[salsa::query_group(SourceDatabaseExtStorage)]
pub trait SourceDatabaseExt: SourceDatabase {
    #[salsa::input]
    fn file_text(&self, file_id: FileId) -> Arc<String>;
    /// Path to a file, relative to the root of its source root.
    /// Source root of the file.
    #[salsa::input]
    fn file_source_root(&self, file_id: FileId) -> SourceRootId;
    /// Contents of the source root.
    #[salsa::input]
    fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;

    fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
}

fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
    let graph = db.crate_graph();
    let res = graph
        .iter()
        .filter(|&krate| {
            let root_file = graph[krate].root_file_id;
            db.file_source_root(root_file) == id
        })
        .collect();
    Arc::new(res)
}

/// Silly workaround for cyclic deps between the traits
pub struct FileLoaderDelegate<T>(pub T);

impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
    fn file_text(&self, file_id: FileId) -> Arc<String> {
        SourceDatabaseExt::file_text(self.0, file_id)
    }
    fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
        // FIXME: this *somehow* should be platform agnostic...
        let source_root = self.0.file_source_root(path.anchor);
        let source_root = self.0.source_root(source_root);
        source_root.file_set.resolve_path(path)
    }

    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
        let _p = profile::span("relevant_crates");
        let source_root = self.0.file_source_root(file_id);
        self.0.source_root_crates(source_root)
    }
}
<|endoftext|>