<commit_before>use std::io;
use std::path::{PathBuf, Path};
use std::fs::File;
use std::cmp::{Ordering, PartialEq, Ord};
use std::collections::HashMap;
use object::{Object, File as OFile};
use memmap::MmapOptions;
use gimli::*;
use rustc_demangle::demangle;
use cargo::core::Workspace;

use config::Config;
use source_analysis::*;
use traces::*;

/// Describes a function as `low_pc`, `high_pc` and bool representing `is_test`.
type FuncDesc = (u64, u64, FunctionType);

#[derive(Clone, Copy, PartialEq)]
enum FunctionType {
    Generated,
    Test,
    Standard
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
pub enum LineType {
    /// Generated test main. Shouldn't be traced.
    TestMain,
    /// Entry of function known to be a test
    TestEntry(u64),
    /// Entry of function. May or may not be test
    FunctionEntry(u64),
    /// Standard statement
    Statement,
    /// Condition
    Condition,
    /// Unknown type
    Unknown,
    /// Unused meta-code
    UnusedGeneric,
}

#[derive(Debug, Clone, Eq, PartialOrd)]
pub struct TracerData {
    pub path: PathBuf,
    pub line: u64,
    pub address: Option<u64>,
    pub trace_type: LineType,
    pub hits: u64,
}

impl PartialEq for TracerData {
    fn eq(&self, other: &TracerData) -> bool {
        (self.path == other.path) && (self.line == other.line)
    }
}

impl Ord for TracerData {

    fn cmp(&self, other: &TracerData) -> Ordering {
        if self == other {
            Ordering::Equal
        } else if self.path == other.path {
            if self.line > other.line {
                Ordering::Greater
            } else {
                Ordering::Less
            }
        } else if self.path > other.path {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

fn generate_func_desc<R, Offset>(die: &DebuggingInformationEntry<R, Offset>,
                                 debug_str: &DebugStr<R>) -> Result<FuncDesc>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut func_type = FunctionType::Standard;
    let low = die.attr_value(DW_AT_low_pc)?;
    let high = die.attr_value(DW_AT_high_pc)?;
    let linkage = die.attr_value(DW_AT_linkage_name)?;

    // Low is a program counter address so stored in an Addr
    let low = match low {
        Some(AttributeValue::Addr(x)) => x,
        _ => 0u64,
    };
    // High is an offset from the base pc, therefore is u64 data.
    let high = match high {
        Some(AttributeValue::Udata(x)) => x,
        _ => 0u64,
    };
    if let Some(AttributeValue::DebugStrRef(offset)) = linkage {
        let name = debug_str.get_str(offset)
            .and_then(|r| r.to_string().map(|s| s.to_string()))
            .unwrap_or("".into());
        let name = demangle(name.as_ref()).to_string();
        // Simplest test is whether it's in tests namespace.
        // Rust guidelines recommend all tests are in a tests module.
        func_type = if name.contains("tests::") {
            FunctionType::Test
        } else if name.contains("__test::main") {
            FunctionType::Generated
        } else {
            FunctionType::Standard
        };
    }
    Ok((low, high, func_type))
}

/// Finds all function entry points and returns a vector
/// This will identify definite tests, but may be prone to false negatives.
fn get_entry_points<R, Offset>(debug_info: &CompilationUnitHeader<R, Offset>,
                               debug_abbrev: &Abbreviations,
                               debug_str: &DebugStr<R>) -> Vec<FuncDesc>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut result:Vec<FuncDesc> = Vec::new();
    let mut cursor = debug_info.entries(debug_abbrev);
    // skip compilation unit root.
    let _ = cursor.next_entry();
    while let Ok(Some((_, node))) = cursor.next_dfs() {
        // Function DIE
        if node.tag() == DW_TAG_subprogram {

            if let Ok(fd) = generate_func_desc(node, debug_str) {
                result.push(fd);
            }
        }
    }
    result
}

fn get_addresses_from_program<R, Offset>(prog: IncompleteLineNumberProgram<R>,
                                         entries: &[(u64, LineType)],
                                         project: &Path) -> Result<Vec<TracerData>>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut result: Vec<TracerData> = Vec::new();
    let ( cprog, seq) = prog.sequences()?;
    for s in seq {
        let mut temp_store : Vec<TracerData> = Vec::new();
        let mut sm = cprog.resume_from(&s);
         while let Ok(Some((header, &ln_row))) = sm.next_row() {
            if let Some(file) = ln_row.file(header) {
                let mut path = PathBuf::new();

                if let Some(dir) = file.directory(header) {
                    if let Ok(temp) = dir.to_string() {
                        path.push(temp.as_ref());
                    }
                }
                if let Ok(p) = path.canonicalize() {
                    path = p;
                }
                let is_target = path.starts_with(project.join("target"));
                // Fix relative paths and determine if in target directory
                // Source in target directory shouldn't be covered as it's either
                // autogenerated or resulting from the projects Cargo.lock
                let is_target = if path.is_relative() {
                    path.starts_with("target")
                } else {
                    path.starts_with(project.join("target"))
                };
                // Source is part of project so we cover it.
                if !is_target && path.starts_with(project) {
                    let force_test = path.starts_with(project.join("tests"));
                    if let Some(file) = ln_row.file(header) {
                        // If we can't map to line, we can't trace it.
                        let line = match ln_row.line() {
                            Some(l) => l,
                            None => continue,
                        };

                        let file = file.path_name();

                        if let Ok(file) = file.to_string() {
                            path.push(file.as_ref());
                            if !path.is_file() {
                                // Not really a source file!
                                continue;
                            }
                            let address = ln_row.address();

                            let desc = entries.iter()
                                              .filter(|&&(addr, _)| addr == address )
                                              .map(|&(_, t)| t)
                                              .nth(0)
                                              .unwrap_or(LineType::Unknown);
                            temp_store.push( TracerData {
                                path: path,
                                line: line,
                                address: Some(address),
                                trace_type: desc,
                                hits: 0u64
                            });
                        }
                    }
                }
            }
        }
        if !temp_store.is_empty() {
            temp_store.sort();
            temp_store.dedup();
            result.append(&mut temp_store);
        }
    }
    Ok(result)
}

fn get_line_addresses(endian: RunTimeEndian,
                      project: &Path,
                      obj: &OFile,
                      analysis: &HashMap<PathBuf, LineAnalysis>,
                      config: &Config) -> Result<Vec<TracerData>>  {
    let mut result: Vec<TracerData> = Vec::new();
    let debug_info = obj.section_data_by_name(".debug_info").unwrap_or(&[]);
    let debug_info = DebugInfo::new(debug_info, endian);
    let debug_abbrev = obj.section_data_by_name(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = DebugAbbrev::new(debug_abbrev, endian);
    let debug_strings = obj.section_data_by_name(".debug_str").unwrap_or(&[]);
    let debug_strings = DebugStr::new(debug_strings, endian);

    let mut iter = debug_info.units();
    while let Ok(Some(cu)) = iter.next() {
        let addr_size = cu.address_size();
        let abbr = match cu.abbreviations(&debug_abbrev) {
            Ok(a) => a,
            _ => continue,
        };
        let entries = get_entry_points(&cu, &abbr, &debug_strings)
            .iter()
            .map(|&(a, b, c)| {
                match c {
                    FunctionType::Test => (a, LineType::TestEntry(b)),
                    FunctionType::Standard => (a, LineType::FunctionEntry(b)),
                    FunctionType::Generated => (a, LineType::TestMain),
                }
            }).collect::<Vec<_>>();
        if let Ok(Some((_, root))) = cu.entries(&abbr).next_dfs() {
            let offset = match root.attr_value(DW_AT_stmt_list) {
                Ok(Some(AttributeValue::DebugLineRef(o))) => o,
                _ => continue,
            };
            let debug_line = obj.section_data_by_name(".debug_line").unwrap_or(&[]);
            let debug_line = DebugLine::new(debug_line, endian);

            let prog = debug_line.program(offset, addr_size, None, None)?;
            if let Ok(mut addresses) = get_addresses_from_program(prog, &entries, project) {
                result.append(&mut addresses);
            }
        }
    }
    // Due to rust being a higher level language multiple instructions may map
    // to the same line. This prunes these to just the first instruction address
    let mut result = result.iter()
                           .filter(|x| !(config.ignore_tests && x.path.starts_with(project.join("tests"))))
                           .filter(|x| !(config.exclude_path(&x.path)))
                           .filter(|x| !analysis.should_ignore(x.path.as_ref(), &(x.line as usize)))
                           .filter(|x| x.trace_type != LineType::TestMain)
                           .cloned()
                           .collect::<Vec<TracerData>>();

    let addresses = result.iter()
                          .map(|x| x.address.unwrap())
                          .collect::<Vec<_>>();
    // TODO Probably a more idiomatic way to do this.
    {
        let test_entries = result.iter_mut()
                                 .filter(|x| match x.trace_type {
                                     LineType::TestEntry(_) => true,
                                     _ => false,
                                 });

        for test_entry in test_entries {
            let endpoint = match test_entry.trace_type {
                LineType::TestEntry(x) => x,
                _ => continue,
            };
            let addr = test_entry.address.unwrap();
            let max_address = addresses.iter()
                                       .fold(0, |acc, x| {
                                           if x > &(addr + acc) && (x-addr) <= endpoint {
                                               *x - addr
                                           } else {
                                               acc
                                           }
                                       });
            test_entry.trace_type = LineType::TestEntry(max_address);
        }
    }
    for (file, ref line_analysis) in analysis.iter() {
        if config.exclude_path(file) {
            continue;
        }
        for line in &line_analysis.cover {
            let line64 = *line as u64;
            let contain = result.iter().any(|ref x| &x.path == file && line64 == x.line);
            if !contain && !line_analysis.should_ignore(line) {
                result.push(TracerData {
                    line: line64,
                    path: file.to_path_buf(),
                    address: None,
                    hits: 0,
                    trace_type: LineType::UnusedGeneric,
                });
            }
        }
    }
    Ok(result)
}

pub fn generate_tracemap<'a>(project: &Workspace, test: &Path, config: &'a Config) -> io::Result<TraceMap<'a>> {
    let manifest = project.root();
    let file = File::open(test)?;
    let file = unsafe {
        MmapOptions::new().map(&file)?
    };
    if let Ok(obj) = OFile::parse(&*file) {
        let analysis = get_line_analysis(project, config);
        let endian = if obj.is_little_endian() {
            RunTimeEndian::Little
        } else {
            RunTimeEndian::Big
        };
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}

/// Generates a list of lines we want to trace the coverage of. Used to instrument the
/// traces into the test executable
pub fn generate_tracer_data(project: &Workspace, test: &Path, config: &Config) -> io::Result<Vec<TracerData>> {
    let manifest = project.root();
    let file = File::open(test)?;
    let file = unsafe {
        MmapOptions::new().map(&file)?
    };
    if let Ok(obj) = OFile::parse(&*file) {
        let analysis = get_line_analysis(project, config);
        let endian = if obj.is_little_endian() {
            RunTimeEndian::Little
        } else {
            RunTimeEndian::Big
        };
        get_line_addresses(endian,
                           manifest,
                           &obj,
                           &analysis,
                           config)
            .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Error while parsing"))
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}

<commit_msg>Moved debug lines<commit_after>use std::io;
use std::path::{PathBuf, Path};
use std::fs::File;
use std::cmp::{Ordering, PartialEq, Ord};
use std::collections::HashMap;
use object::{Object, File as OFile};
use memmap::MmapOptions;
use gimli::*;
use rustc_demangle::demangle;
use cargo::core::Workspace;

use config::Config;
use source_analysis::*;
use traces::*;

/// Describes a function as `low_pc`, `high_pc` and bool representing `is_test`.
type FuncDesc = (u64, u64, FunctionType);

#[derive(Clone, Copy, PartialEq)]
enum FunctionType {
    Generated,
    Test,
    Standard
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
pub enum LineType {
    /// Generated test main. Shouldn't be traced.
    TestMain,
    /// Entry of function known to be a test
    TestEntry(u64),
    /// Entry of function. May or may not be test
    FunctionEntry(u64),
    /// Standard statement
    Statement,
    /// Condition
    Condition,
    /// Unknown type
    Unknown,
    /// Unused meta-code
    UnusedGeneric,
}

#[derive(Clone, PartialEq, Eq, Hash)]
struct SourceLocation {
    pub path: PathBuf,
    pub line: u64,
}

#[derive(Debug, Clone, Eq, PartialOrd)]
pub struct TracerData {
    pub path: PathBuf,
    pub line: u64,
    pub address: Option<u64>,
    pub trace_type: LineType,
    pub hits: u64,
}

impl PartialEq for TracerData {
    fn eq(&self, other: &TracerData) -> bool {
        (self.path == other.path) && (self.line == other.line)
    }
}

impl Ord for TracerData {

    fn cmp(&self, other: &TracerData) -> Ordering {
        if self == other {
            Ordering::Equal
        } else if self.path == other.path {
            if self.line > other.line {
                Ordering::Greater
            } else {
                Ordering::Less
            }
        } else if self.path > other.path {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

fn generate_func_desc<R, Offset>(die: &DebuggingInformationEntry<R, Offset>,
                                 debug_str: &DebugStr<R>) -> Result<FuncDesc>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut func_type = FunctionType::Standard;
    let low = die.attr_value(DW_AT_low_pc)?;
    let high = die.attr_value(DW_AT_high_pc)?;
    let linkage = die.attr_value(DW_AT_linkage_name)?;

    // Low is a program counter address so stored in an Addr
    let low = match low {
        Some(AttributeValue::Addr(x)) => x,
        _ => 0u64,
    };
    // High is an offset from the base pc, therefore is u64 data.
    let high = match high {
        Some(AttributeValue::Udata(x)) => x,
        _ => 0u64,
    };
    if let Some(AttributeValue::DebugStrRef(offset)) = linkage {
        let name = debug_str.get_str(offset)
            .and_then(|r| r.to_string().map(|s| s.to_string()))
            .unwrap_or("".into());
        let name = demangle(name.as_ref()).to_string();
        // Simplest test is whether it's in tests namespace.
        // Rust guidelines recommend all tests are in a tests module.
        func_type = if name.contains("tests::") {
            FunctionType::Test
        } else if name.contains("__test::main") {
            FunctionType::Generated
        } else {
            FunctionType::Standard
        };
    }
    Ok((low, high, func_type))
}

/// Finds all function entry points and returns a vector
/// This will identify definite tests, but may be prone to false negatives.
fn get_entry_points<R, Offset>(debug_info: &CompilationUnitHeader<R, Offset>,
                               debug_abbrev: &Abbreviations,
                               debug_str: &DebugStr<R>) -> Vec<FuncDesc>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut result:Vec<FuncDesc> = Vec::new();
    let mut cursor = debug_info.entries(debug_abbrev);
    // skip compilation unit root.
    let _ = cursor.next_entry();
    while let Ok(Some((_, node))) = cursor.next_dfs() {
        // Function DIE
        if node.tag() == DW_TAG_subprogram {

            if let Ok(fd) = generate_func_desc(node, debug_str) {
                result.push(fd);
            }
        }
    }
    result
}

fn get_addresses_from_program<R, Offset>(prog: IncompleteLineNumberProgram<R>,
                                         entries: &[(u64, LineType)],
                                         project: &Path) -> Result<Vec<TracerData>>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut result: Vec<TracerData> = Vec::new();
    let ( cprog, seq) = prog.sequences()?;
    for s in seq {
        let mut temp_store : Vec<TracerData> = Vec::new();
        let mut sm = cprog.resume_from(&s);
         while let Ok(Some((header, &ln_row))) = sm.next_row() {
            if let Some(file) = ln_row.file(header) {
                let mut path = PathBuf::new();

                if let Some(dir) = file.directory(header) {
                    if let Ok(temp) = dir.to_string() {
                        path.push(temp.as_ref());
                    }
                }
                if let Ok(p) = path.canonicalize() {
                    path = p;
                }
                let is_target = path.starts_with(project.join("target"));
                // Fix relative paths and determine if in target directory
                // Source in target directory shouldn't be covered as it's either
                // autogenerated or resulting from the projects Cargo.lock
                let is_target = if path.is_relative() {
                    path.starts_with("target")
                } else {
                    path.starts_with(project.join("target"))
                };
                // Source is part of project so we cover it.
                if !is_target && path.starts_with(project) {
                    let force_test = path.starts_with(project.join("tests"));
                    if let Some(file) = ln_row.file(header) {
                        // If we can't map to line, we can't trace it.
                        let line = match ln_row.line() {
                            Some(l) => l,
                            None => continue,
                        };

                        let file = file.path_name();

                        if let Ok(file) = file.to_string() {
                            path.push(file.as_ref());
                            if !path.is_file() {
                                // Not really a source file!
                                continue;
                            }
                            let address = ln_row.address();

                            let desc = entries.iter()
                                              .filter(|&&(addr, _)| addr == address )
                                              .map(|&(_, t)| t)
                                              .nth(0)
                                              .unwrap_or(LineType::Unknown);
                            temp_store.push( TracerData {
                                path: path,
                                line: line,
                                address: Some(address),
                                trace_type: desc,
                                hits: 0u64
                            });
                        }
                    }
                }
            }
        }
        if !temp_store.is_empty() {
            temp_store.sort();
            temp_store.dedup();
            result.append(&mut temp_store);
        }
    }
    Ok(result)
}

fn get_line_addresses(endian: RunTimeEndian,
                      project: &Path,
                      obj: &OFile,
                      analysis: &HashMap<PathBuf, LineAnalysis>,
                      config: &Config) -> Result<Vec<TracerData>>  {
    let mut result: Vec<TracerData> = Vec::new();
    let debug_info = obj.section_data_by_name(".debug_info").unwrap_or(&[]);
    let debug_info = DebugInfo::new(debug_info, endian);
    let debug_abbrev = obj.section_data_by_name(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = DebugAbbrev::new(debug_abbrev, endian);
    let debug_strings = obj.section_data_by_name(".debug_str").unwrap_or(&[]);
    let debug_strings = DebugStr::new(debug_strings, endian);
    let debug_line = obj.section_data_by_name(".debug_line").unwrap_or(&[]);
    let debug_line = DebugLine::new(debug_line, endian);

    let mut iter = debug_info.units();
    while let Ok(Some(cu)) = iter.next() {
        let addr_size = cu.address_size();
        let abbr = match cu.abbreviations(&debug_abbrev) {
            Ok(a) => a,
            _ => continue,
        };
        let entries = get_entry_points(&cu, &abbr, &debug_strings)
            .iter()
            .map(|&(a, b, c)| {
                match c {
                    FunctionType::Test => (a, LineType::TestEntry(b)),
                    FunctionType::Standard => (a, LineType::FunctionEntry(b)),
                    FunctionType::Generated => (a, LineType::TestMain),
                }
            }).collect::<Vec<_>>();
        if let Ok(Some((_, root))) = cu.entries(&abbr).next_dfs() {
            let offset = match root.attr_value(DW_AT_stmt_list) {
                Ok(Some(AttributeValue::DebugLineRef(o))) => o,
                _ => continue,
            };
            let prog = debug_line.program(offset, addr_size, None, None)?;
            if let Ok(mut addresses) = get_addresses_from_program(prog, &entries, project) {
                result.append(&mut addresses);
            }
        }
    }
    // Due to rust being a higher level language multiple instructions may map
    // to the same line. This prunes these to just the first instruction address
    let mut result = result.iter()
                           .filter(|x| !(config.ignore_tests && x.path.starts_with(project.join("tests"))))
                           .filter(|x| !(config.exclude_path(&x.path)))
                           .filter(|x| !analysis.should_ignore(x.path.as_ref(), &(x.line as usize)))
                           .filter(|x| x.trace_type != LineType::TestMain)
                           .cloned()
                           .collect::<Vec<TracerData>>();

    let addresses = result.iter()
                          .map(|x| x.address.unwrap())
                          .collect::<Vec<_>>();
    // TODO Probably a more idiomatic way to do this.
    {
        let test_entries = result.iter_mut()
                                 .filter(|x| match x.trace_type {
                                     LineType::TestEntry(_) => true,
                                     _ => false,
                                 });

        for test_entry in test_entries {
            let endpoint = match test_entry.trace_type {
                LineType::TestEntry(x) => x,
                _ => continue,
            };
            let addr = test_entry.address.unwrap();
            let max_address = addresses.iter()
                                       .fold(0, |acc, x| {
                                           if x > &(addr + acc) && (x-addr) <= endpoint {
                                               *x - addr
                                           } else {
                                               acc
                                           }
                                       });
            test_entry.trace_type = LineType::TestEntry(max_address);
        }
    }
    for (file, ref line_analysis) in analysis.iter() {
        if config.exclude_path(file) {
            continue;
        }
        for line in &line_analysis.cover {
            let line64 = *line as u64;
            let contain = result.iter().any(|ref x| &x.path == file && line64 == x.line);
            if !contain && !line_analysis.should_ignore(line) {
                result.push(TracerData {
                    line: line64,
                    path: file.to_path_buf(),
                    address: None,
                    hits: 0,
                    trace_type: LineType::UnusedGeneric,
                });
            }
        }
    }
    Ok(result)
}

pub fn generate_tracemap<'a>(project: &Workspace, test: &Path, config: &'a Config) -> io::Result<TraceMap<'a>> {
    let manifest = project.root();
    let file = File::open(test)?;
    let file = unsafe {
        MmapOptions::new().map(&file)?
    };
    if let Ok(obj) = OFile::parse(&*file) {
        let h: HashMap<SourceLocation, TracerData> = HashMap::new();
        let analysis = get_line_analysis(project, config);
        let endian = if obj.is_little_endian() {
            RunTimeEndian::Little
        } else {
            RunTimeEndian::Big
        };
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}

/// Generates a list of lines we want to trace the coverage of. Used to instrument the
/// traces into the test executable
pub fn generate_tracer_data(project: &Workspace, test: &Path, config: &Config) -> io::Result<Vec<TracerData>> {
    let manifest = project.root();
    let file = File::open(test)?;
    let file = unsafe {
        MmapOptions::new().map(&file)?
    };
    if let Ok(obj) = OFile::parse(&*file) {
        let analysis = get_line_analysis(project, config);
        let endian = if obj.is_little_endian() {
            RunTimeEndian::Little
        } else {
            RunTimeEndian::Big
        };
        get_line_addresses(endian,
                           manifest,
                           &obj,
                           &analysis,
                           config)
            .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Error while parsing"))
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}

<|endoftext|>


<commit_before>use crate::{
    codegen, is_release_tag,
    not_bash::{date_iso, fs2, run},
    project_root, Mode, Result,
};

pub struct ReleaseCmd {
    pub dry_run: bool,
}

impl ReleaseCmd {
    pub fn run(self) -> Result<()> {
        if !self.dry_run {
            run!("git switch release")?;
            run!("git fetch upstream --tags --force")?;
            run!("git reset --hard tags/nightly")?;
            run!("git push")?;
        }
        codegen::generate_assists_docs(Mode::Overwrite)?;
        codegen::generate_feature_docs(Mode::Overwrite)?;

        let website_root = project_root().join("../rust-analyzer.github.io");
        let changelog_dir = website_root.join("./thisweek/_posts");

        let today = date_iso()?;
        let commit = run!("git rev-parse HEAD")?;
        let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();

        let contents = format!(
            "\
    = Changelog #{}
    :sectanchors:
    :page-layout: post

    Commit: commit:{}[] +
    Release: release:{}[]

    == New Features

    * pr:[] .

    == Fixes

    == Internal Improvements
    ",
            changelog_n, commit, today
        );

        let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
        fs2::write(&path, &contents)?;

        for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
            let src = project_root().join("./docs/user/").join(adoc);
            let dst = website_root.join(adoc);
            fs2::copy(src, dst)?;
        }

        let tags = run!("git tag --list"; echo = false)?;
        let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();

        let git_log = run!("git log {}..HEAD --merges --reverse", prev_tag; echo = false)?;
        let git_log_dst = website_root.join("git.log");
        fs2::write(git_log_dst, &git_log)?;

        Ok(())
    }
}
<commit_msg>Add sponsors section to changelog<commit_after>use crate::{
    codegen, is_release_tag,
    not_bash::{date_iso, fs2, run},
    project_root, Mode, Result,
};

pub struct ReleaseCmd {
    pub dry_run: bool,
}

impl ReleaseCmd {
    pub fn run(self) -> Result<()> {
        if !self.dry_run {
            run!("git switch release")?;
            run!("git fetch upstream --tags --force")?;
            run!("git reset --hard tags/nightly")?;
            run!("git push")?;
        }
        codegen::generate_assists_docs(Mode::Overwrite)?;
        codegen::generate_feature_docs(Mode::Overwrite)?;

        let website_root = project_root().join("../rust-analyzer.github.io");
        let changelog_dir = website_root.join("./thisweek/_posts");

        let today = date_iso()?;
        let commit = run!("git rev-parse HEAD")?;
        let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();

        let contents = format!(
            "\
= Changelog #{}
:sectanchors:
:page-layout: post

Commit: commit:{}[] +
Release: release:{}[]

== Sponsors

== New Features

* pr:[] .

== Fixes

== Internal Improvements
",
            changelog_n, commit, today
        );

        let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
        fs2::write(&path, &contents)?;

        for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
            let src = project_root().join("./docs/user/").join(adoc);
            let dst = website_root.join(adoc);
            fs2::copy(src, dst)?;
        }

        let tags = run!("git tag --list"; echo = false)?;
        let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();

        let git_log = run!("git log {}..HEAD --merges --reverse", prev_tag; echo = false)?;
        let git_log_dst = website_root.join("git.log");
        fs2::write(git_log_dst, &git_log)?;

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


<commit_before>use std::net::{UdpSocket, SocketAddr, SocketAddrV4, Ipv4Addr};
use std::sync::atomic;
use tracker::{Request, Response, Event};
use {PORT, PEER_ID};
use std::io::{Write, Cursor};
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};

pub struct Announcer {
    sock: UdpSocket,
}

impl Announcer {
    pub fn new() -> Announcer {
        let port = PORT.load(atomic::Ordering::Relaxed) as u16;
        let sock = UdpSocket::bind(("0.0.0.0", port)).unwrap();
        Announcer {
            sock
        }
    }

    pub fn announce(&mut self, req: Request) -> Response {
        let mut data = [0u8; 16];
        {
            let mut connect_req = Cursor::new(&mut data[..]);
            let tid = 420;
            connect_req.write_u64::<BigEndian>(0x41727101980).unwrap();
            connect_req.write_u32::<BigEndian>(0).unwrap();
            connect_req.write_u32::<BigEndian>(tid).unwrap();
        }
        self.sock.send_to(&data, &req.url).unwrap();

        let mut data = [0u8; 16];
        let (read, _) = self.sock.recv_from(&mut data).unwrap();
        let mut connect_resp = Cursor::new(&mut data);
        assert_eq!(read, 16);
        let action_resp = connect_resp.read_u32::<BigEndian>().unwrap();
        assert_eq!(action_resp, 0);
        let transaction_id = connect_resp.read_u32::<BigEndian>().unwrap();
        let connection_id = connect_resp.read_u64::<BigEndian>().unwrap();

        let mut data = [0u8; 98];
        {
            let mut announce_req = Cursor::new(&mut data[..]);
            announce_req.write_u64::<BigEndian>(connection_id).unwrap();
            announce_req.write_u32::<BigEndian>(1).unwrap();
            announce_req.write_u32::<BigEndian>(transaction_id).unwrap();
            announce_req.write(&req.hash).unwrap();
            announce_req.write(&PEER_ID[..]).unwrap();
            announce_req.write_u64::<BigEndian>(req.downloaded as u64).unwrap();
            announce_req.write_u64::<BigEndian>(req.left as u64).unwrap();
            announce_req.write_u64::<BigEndian>(req.uploaded as u64).unwrap();
            match req.event {
                Some(Event::Started) => {
                    announce_req.write_u32::<BigEndian>(2).unwrap();
                }
                Some(Event::Stopped) => {
                    announce_req.write_u32::<BigEndian>(3).unwrap();
                }
                Some(Event::Completed) => {
                    announce_req.write_u32::<BigEndian>(1).unwrap();
                }
                None => {
                    announce_req.write_u32::<BigEndian>(0).unwrap();
                }
            }
            // IP
            announce_req.write_u32::<BigEndian>(0).unwrap();
            // Key
            announce_req.write_u32::<BigEndian>(0).unwrap();
            // Num Want
            announce_req.write_u32::<BigEndian>(30).unwrap();
            // Port
            let port = PORT.load(atomic::Ordering::Relaxed) as u16;
            announce_req.write_u16::<BigEndian>(port).unwrap();
        };
        self.sock.send_to(&data, &req.url).unwrap();

        let mut data = [0u8; 200];
        let (read, _) = self.sock.recv_from(&mut data).unwrap();
        assert_eq!(read, 200);
        let mut announce_resp = Cursor::new(&mut data[..]);
        let action_resp = announce_resp.read_u32::<BigEndian>().unwrap();
        let mut resp = Response::empty(req.id);
        assert_eq!(action_resp, 1);
        assert_eq!(announce_resp.read_u32::<BigEndian>().unwrap(), transaction_id);
        resp.interval = announce_resp.read_u32::<BigEndian>().unwrap();
        resp.leechers = announce_resp.read_u32::<BigEndian>().unwrap();
        resp.seeders = announce_resp.read_u32::<BigEndian>().unwrap();
        for p in announce_resp.get_ref().chunks(6) {
            let ip = Ipv4Addr::new(p[0], p[1], p[2], p[3]);
            let socket = SocketAddrV4::new(ip, (&p[4..]).read_u16::<BigEndian>().unwrap());
            resp.peers.push(SocketAddr::V4(socket));
        }
        unimplemented!();
        // self.sock.
    }
}
<commit_msg>Minor fixes to udp tracker response parsing<commit_after>use std::net::{UdpSocket, SocketAddr, SocketAddrV4, Ipv4Addr};
use std::sync::atomic;
use tracker::{Request, Response, Event};
use {PORT, PEER_ID};
use std::io::{Write, Cursor};
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use url::Url;

pub struct Announcer {
    sock: UdpSocket,
}

impl Announcer {
    pub fn new() -> Announcer {
        let port = PORT.load(atomic::Ordering::Relaxed) as u16;
        let sock = UdpSocket::bind(("0.0.0.0", port)).unwrap();
        Announcer {
            sock
        }
    }

    pub fn announce(&mut self, req: Request) -> Response {
        let mut data = [0u8; 16];
        {
            let mut connect_req = Cursor::new(&mut data[..]);
            let tid = 420;
            connect_req.write_u64::<BigEndian>(0x41727101980).unwrap();
            connect_req.write_u32::<BigEndian>(0).unwrap();
            connect_req.write_u32::<BigEndian>(tid).unwrap();
        }
        let url = Url::parse(&req.url).unwrap();
        self.sock.send_to(&data, (url.host_str().unwrap(), url.port().unwrap())).unwrap();

        let mut data = [0u8; 16];
        let (read, _) = self.sock.recv_from(&mut data).unwrap();
        let mut connect_resp = Cursor::new(&mut data);
        assert_eq!(read, 16);
        let action_resp = connect_resp.read_u32::<BigEndian>().unwrap();
        assert_eq!(action_resp, 0);
        let transaction_id = connect_resp.read_u32::<BigEndian>().unwrap();
        let connection_id = connect_resp.read_u64::<BigEndian>().unwrap();

        let mut data = [0u8; 98];
        {
            let mut announce_req = Cursor::new(&mut data[..]);
            announce_req.write_u64::<BigEndian>(connection_id).unwrap();
            announce_req.write_u32::<BigEndian>(1).unwrap();
            announce_req.write_u32::<BigEndian>(transaction_id).unwrap();
            announce_req.write(&req.hash).unwrap();
            announce_req.write(&PEER_ID[..]).unwrap();
            announce_req.write_u64::<BigEndian>(req.downloaded as u64).unwrap();
            announce_req.write_u64::<BigEndian>(req.left as u64).unwrap();
            announce_req.write_u64::<BigEndian>(req.uploaded as u64).unwrap();
            match req.event {
                Some(Event::Started) => {
                    announce_req.write_u32::<BigEndian>(2).unwrap();
                }
                Some(Event::Stopped) => {
                    announce_req.write_u32::<BigEndian>(3).unwrap();
                }
                Some(Event::Completed) => {
                    announce_req.write_u32::<BigEndian>(1).unwrap();
                }
                None => {
                    announce_req.write_u32::<BigEndian>(0).unwrap();
                }
            }
            // IP
            announce_req.write_u32::<BigEndian>(0).unwrap();
            // Key
            announce_req.write_u32::<BigEndian>(0).unwrap();
            // Num Want
            announce_req.write_u32::<BigEndian>(30).unwrap();
            // Port
            let port = PORT.load(atomic::Ordering::Relaxed) as u16;
            announce_req.write_u16::<BigEndian>(port).unwrap();
        };
        self.sock.send_to(&data, (url.host_str().unwrap(), url.port().unwrap())).unwrap();

        let mut data = [0u8; 200];
        let (read, _) = self.sock.recv_from(&mut data).unwrap();
        println!("Read {:?} bytes", read);
        assert!(read >= 20);
        assert!((read - 20) % 6 == 0);
        let mut announce_resp = Cursor::new(&mut data[..read]);
        let action_resp = announce_resp.read_u32::<BigEndian>().unwrap();
        let mut resp = Response::empty(req.id);
        assert_eq!(action_resp, 1);
        assert_eq!(announce_resp.read_u32::<BigEndian>().unwrap(), transaction_id);
        resp.interval = announce_resp.read_u32::<BigEndian>().unwrap();
        resp.leechers = announce_resp.read_u32::<BigEndian>().unwrap();
        resp.seeders = announce_resp.read_u32::<BigEndian>().unwrap();
        for p in announce_resp.get_ref()[20..].chunks(6) {
            let ip = Ipv4Addr::new(p[0], p[1], p[2], p[3]);
            let socket = SocketAddrV4::new(ip, (&p[4..]).read_u16::<BigEndian>().unwrap());
            resp.peers.push(SocketAddr::V4(socket));
        }
        resp
    }
}
<|endoftext|>


<commit_before>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

/*===============================================================================================*/
//! The logging module.
//!
//! It provides basic logging functionality.
/*===============================================================================================*/

extern crate ansi_term;
extern crate log;

use self::ansi_term::Colour::{Blue, Purple, Yellow, Red};

use std::boxed::Box;
use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::Write;

/*===============================================================================================*/
/*------LOGGER STRUCT----------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The logger struct
///
/// It provides basic logging capabilities, and is designed for use within ion.
pub struct Logger {

    // Private
    log_file: BufWriter <File>,
    log_to_console: bool
}

/*===============================================================================================*/
/*------LOGGER PUBLIC STATIC METHODS-------------------------------------------------------------*/
/*===============================================================================================*/

impl Logger {

    /// Initializes the logger
    ///
    /// This is required before any logging functions are performed.
    /// Any logging done beforehand will be ignored.
    ///
    /// # Arguments
    /// * `log_file_path` - The path to where the log will be saved
    /// * `log_to_console` - Whether the log output should also be printed to the console
    ///
    /// # Return value
    /// A result, returning an error on failure.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::util::Logger;
    /// #
    /// Logger::init ("LogFile.log", false);
    pub fn init (log_file_path: &str, log_to_console: bool) -> Result<(), log::SetLoggerError> {

        log::set_logger (|max_log_level| {

            if cfg! (debug_assertions) {
                max_log_level.set (log::LogLevelFilter::Debug);
            }

            else {
                max_log_level.set (log::LogLevelFilter::Info);
            }

            Box::new (Logger {log_file: BufWriter::new (File::create (&log_file_path).unwrap ()),
                              log_to_console: log_to_console})
        })
    }
}

/*===============================================================================================*/
/*------LOGGER PRIVATE METHODS-------------------------------------------------------------------*/
/*===============================================================================================*/

impl log::Log for Logger {

    fn enabled (&self, metadata: &log::LogMetadata) -> bool {

        if cfg! (debug_assertions) {
            return metadata.level () <= log::LogLevel::Debug;
        }

        metadata.level () <= log::LogLevel::Info
    }

/*-----------------------------------------------------------------------------------------------*/

    fn log (&self, record: &log::LogRecord) {

        let output = match record.level () {

            log::LogLevel::Debug => format! ("{} ({} : {}) - {}\n", Purple.paint (record.level ().to_string ()),
                                                                    record.location ().module_path (),
                                                                    record.location ().line (),
                                                                    record.args ()),

            log::LogLevel::Info => format! ("{} ({} : {}) - {}\n", Blue.paint (record.level ().to_string ()),
                                                                   record.location ().module_path (),
                                                                   record.location ().line (),
                                                                   record.args ()),

            log::LogLevel::Warn => format! ("{} ({} : {}) - {}\n", Yellow.paint (record.level ().to_string ()),
                                                                   record.location ().module_path (),
                                                                   record.location ().line (),
                                                                   record.args ()),

            log::LogLevel::Error => format! ("{} ({} : {}) - {}\n", Red.paint (record.level ().to_string ()),
                                                                    record.location ().module_path (),
                                                                    record.location ().line (),
                                                                    record.args ()),
            _ => String::new ()
        };

        if self.log_to_console {
            print! ("{}", output);
        }

        self.log_file.get_ref ().write (format! ("{} ({} : {}) - {}\n", record.level (),
                                                                        record.location ().module_path (),
                                                                        record.location ().line (),
                                                                        record.args ()).as_bytes ()).unwrap ();
    }
}
<commit_msg>Added new line between log entries<commit_after>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

/*===============================================================================================*/
//! The logging module.
//!
//! It provides basic logging functionality.
/*===============================================================================================*/

extern crate ansi_term;
extern crate log;

use self::ansi_term::Colour::{Blue, Purple, Yellow, Red};

use std::boxed::Box;
use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::Write;

/*===============================================================================================*/
/*------LOGGER STRUCT----------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The logger struct
///
/// It provides basic logging capabilities, and is designed for use within ion.
pub struct Logger {

    // Private
    log_file: BufWriter <File>,
    log_to_console: bool
}

/*===============================================================================================*/
/*------LOGGER PUBLIC STATIC METHODS-------------------------------------------------------------*/
/*===============================================================================================*/

impl Logger {

    /// Initializes the logger
    ///
    /// This is required before any logging functions are performed.
    /// Any logging done beforehand will be ignored.
    ///
    /// # Arguments
    /// * `log_file_path` - The path to where the log will be saved
    /// * `log_to_console` - Whether the log output should also be printed to the console
    ///
    /// # Return value
    /// A result, returning an error on failure.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::util::Logger;
    /// #
    /// Logger::init ("LogFile.log", false);
    pub fn init (log_file_path: &str, log_to_console: bool) -> Result<(), log::SetLoggerError> {

        log::set_logger (|max_log_level| {

            if cfg! (debug_assertions) {
                max_log_level.set (log::LogLevelFilter::Debug);
            }

            else {
                max_log_level.set (log::LogLevelFilter::Info);
            }

            Box::new (Logger {log_file: BufWriter::new (File::create (&log_file_path).unwrap ()),
                              log_to_console: log_to_console})
        })
    }
}

/*===============================================================================================*/
/*------LOGGER PRIVATE METHODS-------------------------------------------------------------------*/
/*===============================================================================================*/

impl log::Log for Logger {

    fn enabled (&self, metadata: &log::LogMetadata) -> bool {

        if cfg! (debug_assertions) {
            return metadata.level () <= log::LogLevel::Debug;
        }

        metadata.level () <= log::LogLevel::Info
    }

/*-----------------------------------------------------------------------------------------------*/

    fn log (&self, record: &log::LogRecord) {

        let output = match record.level () {

            log::LogLevel::Debug => format! ("{} ({} : {}) - {}\n", Purple.paint (record.level ().to_string ()),
                                                                    record.location ().module_path (),
                                                                    record.location ().line (),
                                                                    record.args ()),

            log::LogLevel::Info => format! ("{} ({} : {}) - {}\n", Blue.paint (record.level ().to_string ()),
                                                                   record.location ().module_path (),
                                                                   record.location ().line (),
                                                                   record.args ()),

            log::LogLevel::Warn => format! ("{} ({} : {}) - {}\n", Yellow.paint (record.level ().to_string ()),
                                                                   record.location ().module_path (),
                                                                   record.location ().line (),
                                                                   record.args ()),

            log::LogLevel::Error => format! ("{} ({} : {}) - {}\n", Red.paint (record.level ().to_string ()),
                                                                    record.location ().module_path (),
                                                                    record.location ().line (),
                                                                    record.args ()),
            _ => String::new ()
        };

        if self.log_to_console {
            print! ("{}\n", output);
        }

        self.log_file.get_ref ().write (format! ("{} ({} : {}) - {}\n\n", record.level (),
                                                                          record.location ().module_path (),
                                                                          record.location ().line (),
                                                                          record.args ()).as_bytes ()).unwrap ();
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::RefCell,
    time::{Duration, Instant},
};

use crossbeam::{
    channel::{self, Receiver, Sender, TryRecvError},
    sync::Parker,
};
use gba::Gba;

type GbaThreadCallback = Box<dyn 'static + Send + FnMut(&mut Gba, &mut GbaThreadState)>;
type GbaThreadCallbackOnce = Box<dyn 'static + Send + FnOnce(&mut Gba, &mut GbaThreadState)>;

fn gba_thread_fn(rx: Receiver<GbaMessage>) {
    let mut ctx = Context::default();
    ctx.state.target_fps = 60.0;

    log::trace!("waiting for GBA start");
    ctx.state.paused = true;
    wait_for_gba_unpause(&mut ctx, &rx);

    let spin_sleeper = spin_sleep::SpinSleeper::default();

    log::trace!("starting GBA thread loop");
    while !ctx.state.stopped {
        let frame_start_time = Instant::now();

        ctx.gba.frame();
        ctx.on_frame
            .iter_mut()
            .for_each(|cb| (cb)(&mut ctx.gba, &mut ctx.state));
        empty_gba_message_queue(&mut ctx, &rx);

        if ctx.state.paused {
            wait_for_gba_unpause(&mut ctx, &rx);
        } else {
            let frame_duration = frame_start_time.elapsed();
            let target_frame_duration = Duration::from_secs_f64(1.0 / ctx.state.target_fps);
            if frame_duration < target_frame_duration {
                spin_sleeper.sleep(target_frame_duration - frame_duration);
            }
        }
    }
    log::trace!("exited GBA thread loop");
}

fn empty_gba_message_queue(ctx: &mut Context, rx: &Receiver<GbaMessage>) {
    loop {
        match rx.try_recv() {
            Ok(msg) => process_gba_message(ctx, msg),
            Err(TryRecvError::Disconnected) => {
                log::trace!("no more GBA handles, shutting down");
                ctx.state.stop();
                break;
            }
            Err(TryRecvError::Empty) => break,
        }
    }
}

fn wait_for_gba_unpause(ctx: &mut Context, rx: &Receiver<GbaMessage>) {
    while ctx.state.paused && !ctx.state.stopped {
        match rx.recv() {
            Ok(msg) => process_gba_message(ctx, msg),
            Err(_) => {
                log::trace!("no more GBA handles, shutting down");
                ctx.state.stop();
                break;
            }
        }
    }
}

fn process_gba_message(ctx: &mut Context, msg: GbaMessage) {
    match msg {
        GbaMessage::Shutdown => {
            log::trace!("GBA thread shutdown requested");
            ctx.state.stopped = true;
        }
        GbaMessage::CallbackAfterFrame(cb) => (cb)(&mut ctx.gba, &mut ctx.state),
        GbaMessage::CallbackOnFrame(cb) => ctx.on_frame.push(cb),
    }
}

#[derive(Default)]
struct Context {
    gba: Gba,
    state: GbaThreadState,
    on_frame: Vec<GbaThreadCallback>,
}

#[derive(Default)]
pub struct GbaThreadState {
    pub paused: bool,
    stopped: bool,
    pub target_fps: f64,
}

impl GbaThreadState {
    pub fn stop(&mut self) {
        self.stopped = true;
    }

    pub fn stopping(&self) -> bool {
        self.stopped
    }
}

/// A handle to a GBA instance running in its own thread.
pub struct GbaHandle {
    tx: Sender<GbaMessage>,
    parker: RefCell<Option<Parker>>,
}

impl GbaHandle {
    pub fn new() -> GbaHandle {
        let (tx, rx) = channel::unbounded();
        std::thread::spawn(move || gba_thread_fn(rx));
        let parker = RefCell::new(None);
        GbaHandle { tx, parker }
    }

    pub fn on_frame<F>(&self, cb: F)
    where
        F: 'static + Send + FnMut(&mut Gba, &mut GbaThreadState),
    {
        if self
            .tx
            .send(GbaMessage::CallbackOnFrame(Box::new(cb)))
            .is_err()
        {
            log::warn!("called `on_frame` on disconnected GBA handle")
        }
    }

    pub fn after_frame<F>(&self, cb: F)
    where
        F: 'static + Send + FnOnce(&mut Gba, &mut GbaThreadState),
    {
        if self
            .tx
            .send(GbaMessage::CallbackAfterFrame(Box::new(cb)))
            .is_err()
        {
            log::warn!("called `after_frame` on disconnected GBA handle")
        }
    }

    pub fn after_frame_wait<F>(&self, cb: F)
    where
        F: 'static + Send + FnOnce(&mut Gba, &mut GbaThreadState),
    {
        let mut parker = self.parker.borrow_mut();
        if parker.is_none() {
            *parker = Some(Parker::new());
        }
        let parker = parker.as_mut().unwrap();
        let unparker = parker.unparker().clone();

        self.after_frame(move |gba, state| {
            (cb)(gba, state);
            unparker.unpark();
        });

        parker.park();
    }

    pub fn set_paused(&self, paused: bool) {
        self.after_frame(move |_, state| state.paused = paused);
    }
}

impl Clone for GbaHandle {
    fn clone(&self) -> Self {
        GbaHandle {
            tx: self.tx.clone(),
            parker: RefCell::new(None),
        }
    }
}

impl Drop for GbaHandle {
    fn drop(&mut self) {
        let _ = self.tx.send(GbaMessage::Shutdown);
    }
}

impl Default for GbaHandle {
    fn default() -> Self {
        Self::new()
    }
}

enum GbaMessage {
    CallbackAfterFrame(GbaThreadCallbackOnce),
    CallbackOnFrame(GbaThreadCallback),
    Shutdown,
}
<commit_msg>Keep track of frame durations in GBA.<commit_after>use std::{
    cell::RefCell,
    time::{Duration, Instant},
};

use crossbeam::{
    channel::{self, Receiver, Sender, TryRecvError},
    sync::Parker,
};
use gba::Gba;

type GbaThreadCallback = Box<dyn 'static + Send + FnMut(&mut Gba, &mut GbaThreadState)>;
type GbaThreadCallbackOnce = Box<dyn 'static + Send + FnOnce(&mut Gba, &mut GbaThreadState)>;

fn gba_thread_fn(rx: Receiver<GbaMessage>) {
    let mut ctx = Context::default();
    ctx.state.target_fps = 60.0;

    log::trace!("waiting for GBA start");
    ctx.state.paused = true;
    wait_for_gba_unpause(&mut ctx, &rx);

    let spin_sleeper = spin_sleep::SpinSleeper::default();

    log::trace!("starting GBA thread loop");
    while !ctx.state.stopped {
        let frame_start_time = Instant::now();

        ctx.gba.frame();
        ctx.on_frame
            .iter_mut()
            .for_each(|cb| (cb)(&mut ctx.gba, &mut ctx.state));
        empty_gba_message_queue(&mut ctx, &rx);

        if ctx.state.paused {
            wait_for_gba_unpause(&mut ctx, &rx);
        } else {
            let frame_duration = frame_start_time.elapsed();
            ctx.state.frame_duration = frame_duration;
            let target_frame_duration = Duration::from_secs_f64(1.0 / ctx.state.target_fps);
            if frame_duration < target_frame_duration {
                spin_sleeper.sleep(target_frame_duration - frame_duration);
            }
        }
    }
    log::trace!("exited GBA thread loop");
}

fn empty_gba_message_queue(ctx: &mut Context, rx: &Receiver<GbaMessage>) {
    loop {
        match rx.try_recv() {
            Ok(msg) => process_gba_message(ctx, msg),
            Err(TryRecvError::Disconnected) => {
                log::trace!("no more GBA handles, shutting down");
                ctx.state.stop();
                break;
            }
            Err(TryRecvError::Empty) => break,
        }
    }
}

fn wait_for_gba_unpause(ctx: &mut Context, rx: &Receiver<GbaMessage>) {
    while ctx.state.paused && !ctx.state.stopped {
        match rx.recv() {
            Ok(msg) => process_gba_message(ctx, msg),
            Err(_) => {
                log::trace!("no more GBA handles, shutting down");
                ctx.state.stop();
                break;
            }
        }
    }
}

fn process_gba_message(ctx: &mut Context, msg: GbaMessage) {
    match msg {
        GbaMessage::Shutdown => {
            log::trace!("GBA thread shutdown requested");
            ctx.state.stopped = true;
        }
        GbaMessage::CallbackAfterFrame(cb) => (cb)(&mut ctx.gba, &mut ctx.state),
        GbaMessage::CallbackOnFrame(cb) => ctx.on_frame.push(cb),
    }
}

#[derive(Default)]
struct Context {
    gba: Gba,
    state: GbaThreadState,
    on_frame: Vec<GbaThreadCallback>,
}

#[derive(Default)]
pub struct GbaThreadState {
    pub paused: bool,
    stopped: bool,
    pub target_fps: f64,

    frame_duration: Duration,
}

impl GbaThreadState {
    pub fn stop(&mut self) {
        self.stopped = true;
    }

    pub fn stopping(&self) -> bool {
        self.stopped
    }

    /// Returns the amount of time required to render the previous frame.
    pub fn frame_duration(&self) -> Duration {
        self.frame_duration
    }
}

/// A handle to a GBA instance running in its own thread.
pub struct GbaHandle {
    tx: Sender<GbaMessage>,
    parker: RefCell<Option<Parker>>,
}

impl GbaHandle {
    pub fn new() -> GbaHandle {
        let (tx, rx) = channel::unbounded();
        std::thread::spawn(move || gba_thread_fn(rx));
        let parker = RefCell::new(None);
        GbaHandle { tx, parker }
    }

    pub fn on_frame<F>(&self, cb: F)
    where
        F: 'static + Send + FnMut(&mut Gba, &mut GbaThreadState),
    {
        if self
            .tx
            .send(GbaMessage::CallbackOnFrame(Box::new(cb)))
            .is_err()
        {
            log::warn!("called `on_frame` on disconnected GBA handle")
        }
    }

    pub fn after_frame<F>(&self, cb: F)
    where
        F: 'static + Send + FnOnce(&mut Gba, &mut GbaThreadState),
    {
        if self
            .tx
            .send(GbaMessage::CallbackAfterFrame(Box::new(cb)))
            .is_err()
        {
            log::warn!("called `after_frame` on disconnected GBA handle")
        }
    }

    pub fn after_frame_wait<F>(&self, cb: F)
    where
        F: 'static + Send + FnOnce(&mut Gba, &mut GbaThreadState),
    {
        let mut parker = self.parker.borrow_mut();
        if parker.is_none() {
            *parker = Some(Parker::new());
        }
        let parker = parker.as_mut().unwrap();
        let unparker = parker.unparker().clone();

        let msg = GbaMessage::CallbackAfterFrame(Box::new(move |gba, state| {
            (cb)(gba, state);
            unparker.unpark();
        }));

        if self.tx.send(msg).is_err() {
            log::warn!("called `after_frame_wait` on disconnected GBA handle")
        } else {
            parker.park();
        }
    }

    pub fn set_paused(&self, paused: bool) {
        self.after_frame(move |_, state| state.paused = paused);
    }
}

impl Clone for GbaHandle {
    fn clone(&self) -> Self {
        GbaHandle {
            tx: self.tx.clone(),
            parker: RefCell::new(None),
        }
    }
}

impl Drop for GbaHandle {
    fn drop(&mut self) {
        let _ = self.tx.send(GbaMessage::Shutdown);
    }
}

impl Default for GbaHandle {
    fn default() -> Self {
        Self::new()
    }
}

enum GbaMessage {
    CallbackAfterFrame(GbaThreadCallbackOnce),
    CallbackOnFrame(GbaThreadCallback),
    Shutdown,
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::fmt::{Debug, Display, Formatter, Error};
use std::path::PathBuf;
use std::result::Result as RResult;

pub use config::types::Config;
pub use config::reader::from_file;

pub mod error {
    use std::error::Error;
    use std::fmt::{Debug, Display, Formatter};
    use std::fmt::Error as FmtError;

    #[derive(Clone, Debug, PartialEq)]
    pub enum ConfigErrorKind {
        ConfigNotFound,
        ConfigParsingFailed,
        NoConfigFileFound,
    }

    #[derive(Debug)]
    pub struct ConfigError {
        kind: ConfigErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ConfigError {

        pub fn new(kind: ConfigErrorKind, cause: Option<Box<Error>>) -> ConfigError {
            ConfigError {
                kind: kind,
                cause: cause,
            }
        }

        pub fn kind(&self) -> ConfigErrorKind {
            self.kind.clone()
        }

        pub fn as_str(e: &ConfigError) -> &'static str {
            match e.kind() {
                ConfigErrorKind::ConfigNotFound      => "Config not found",
                ConfigErrorKind::ConfigParsingFailed => "Config parsing failed",
                ConfigErrorKind::NoConfigFileFound   => "No config file found",
            }
        }

    }

    impl Display for ConfigError {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "{}", ConfigError::as_str(self)));
            Ok(())
        }

    }

    impl Error for ConfigError {

        fn description(&self) -> &str {
            ConfigError::as_str(self)
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

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

pub type Result<T> = RResult<T, ConfigError>;

pub struct Configuration {
    verbosity: bool,
    editor: Option<String>,
    editor_opts: String,
}

impl Configuration {

    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = cfg.lookup_boolean("verbosity").unwrap_or(false);
            let editor      = cfg.lookup_str("editor").map(String::from);
            let editor_opts = String::from(cfg.lookup_str("editor-opts").unwrap_or(""));

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

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

}

fn fetch_config(rtp: &PathBuf) -> Result<Config> {
    use std::process::exit;
    use std::env;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;

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

    vec![
        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())
        .map(|path| {
            from_file(&path)
                    .map_err(|e| {
                        ConfigError::new(ConfigErrorKind::ConfigParsingFailed, Some(Box::new(e)))
                    })
        })
        .filter(|loaded| loaded.is_ok())
        .nth(0)
        .map(|inner| inner.unwrap())
        .ok_or(ConfigError::new(ConfigErrorKind::NoConfigFileFound, None))
}

impl Debug for Configuration {

    fn fmt(&self, f: &mut Formatter) -> RResult<(), Error> {
        try!(write!(f, "Configuration (verbose: {})", self.verbosity));
        Ok(())
    }

}

impl Default for Configuration {

    fn default() -> Configuration {
        Configuration {
            verbosity: false,
            editor: Some(String::from("nano")),
            editor_opts: String::from(""),
        }
    }

}

<commit_msg>Derive Debug instead of implementing it<commit_after>use std::default::Default;
use std::fmt::{Debug, Display, Formatter, Error};
use std::path::PathBuf;
use std::result::Result as RResult;

pub use config::types::Config;
pub use config::reader::from_file;

pub mod error {
    use std::error::Error;
    use std::fmt::{Debug, Display, Formatter};
    use std::fmt::Error as FmtError;

    #[derive(Clone, Debug, PartialEq)]
    pub enum ConfigErrorKind {
        ConfigNotFound,
        ConfigParsingFailed,
        NoConfigFileFound,
    }

    #[derive(Debug)]
    pub struct ConfigError {
        kind: ConfigErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ConfigError {

        pub fn new(kind: ConfigErrorKind, cause: Option<Box<Error>>) -> ConfigError {
            ConfigError {
                kind: kind,
                cause: cause,
            }
        }

        pub fn kind(&self) -> ConfigErrorKind {
            self.kind.clone()
        }

        pub fn as_str(e: &ConfigError) -> &'static str {
            match e.kind() {
                ConfigErrorKind::ConfigNotFound      => "Config not found",
                ConfigErrorKind::ConfigParsingFailed => "Config parsing failed",
                ConfigErrorKind::NoConfigFileFound   => "No config file found",
            }
        }

    }

    impl Display for ConfigError {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "{}", ConfigError::as_str(self)));
            Ok(())
        }

    }

    impl Error for ConfigError {

        fn description(&self) -> &str {
            ConfigError::as_str(self)
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

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

pub type Result<T> = RResult<T, ConfigError>;

#[derive(Debug)]
pub struct Configuration {
    verbosity: bool,
    editor: Option<String>,
    editor_opts: String,
}

impl Configuration {

    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = cfg.lookup_boolean("verbosity").unwrap_or(false);
            let editor      = cfg.lookup_str("editor").map(String::from);
            let editor_opts = String::from(cfg.lookup_str("editor-opts").unwrap_or(""));

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

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

}

fn fetch_config(rtp: &PathBuf) -> Result<Config> {
    use std::process::exit;
    use std::env;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;

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

    vec![
        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())
        .map(|path| {
            from_file(&path)
                    .map_err(|e| {
                        ConfigError::new(ConfigErrorKind::ConfigParsingFailed, Some(Box::new(e)))
                    })
        })
        .filter(|loaded| loaded.is_ok())
        .nth(0)
        .map(|inner| inner.unwrap())
        .ok_or(ConfigError::new(ConfigErrorKind::NoConfigFileFound, None))
}

impl Default for Configuration {

    fn default() -> Configuration {
        Configuration {
            verbosity: false,
            editor: Some(String::from("nano")),
            editor_opts: String::from(""),
        }
    }

}

<|endoftext|>


<commit_before>//! Defines the `IntoIter` owned iterator for arrays.

use crate::{
    fmt,
    iter::{ExactSizeIterator, FusedIterator, TrustedLen},
    mem::{self, MaybeUninit},
    ops::Range,
    ptr,
};

/// A by-value [array] iterator.
///
/// [array]: ../../std/primitive.array.html
#[unstable(feature = "array_value_iter", issue = "65798")]
pub struct IntoIter<T, const N: usize> {
    /// This is the array we are iterating over.
    ///
    /// Elements with index `i` where `alive.start <= i < alive.end` have not
    /// been yielded yet and are valid array entries. Elements with indices `i
    /// < alive.start` or `i >= alive.end` have been yielded already and must
    /// not be accessed anymore! Those dead elements might even be in a
    /// completely uninitialized state!
    ///
    /// So the invariants are:
    /// - `data[alive]` is alive (i.e. contains valid elements)
    /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the
    ///   elements were already read and must not be touched anymore!)
    data: [MaybeUninit<T>; N],

    /// The elements in `data` that have not been yielded yet.
    ///
    /// Invariants:
    /// - `alive.start <= alive.end`
    /// - `alive.end <= N`
    alive: Range<usize>,
}

impl<T, const N: usize> IntoIter<T, N> {
    /// Creates a new iterator over the given `array`.
    ///
    /// *Note*: this method might never get stabilized and/or removed in the
    /// future as there will likely be another, preferred way of obtaining this
    /// iterator (either via `IntoIterator` for arrays or via another way).
    #[unstable(feature = "array_value_iter", issue = "65798")]
    pub fn new(array: [T; N]) -> Self {
        // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
        // promise:
        //
        // > `MaybeUninit<T>` is guaranteed to have the same size and alignment
        // > as `T`.
        //
        // The docs even show a transmute from an array of `MaybeUninit<T>` to
        // an array of `T`.
        //
        // With that, this initialization satisfies the invariants.

        // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
        // works with const generics:
        //     `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
        //
        // Until then, we can use `mem::transmute_copy` to create a bitwise copy
        // as a different type, then forget `array` so that it is not dropped.
        unsafe {
            let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
            mem::forget(array);
            iter
        }
    }

    /// Returns an immutable slice of all elements that have not been yielded
    /// yet.
    fn as_slice(&self) -> &[T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked(self.alive.clone());
            MaybeUninit::slice_assume_init_ref(slice)
        }
    }

    /// Returns a mutable slice of all elements that have not been yielded yet.
    fn as_mut_slice(&mut self) -> &mut [T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked_mut(self.alive.clone());
            MaybeUninit::slice_assume_init_mut(slice)
        }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Iterator for IntoIter<T, N> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        // Get the next index from the front.
        //
        // Increasing `alive.start` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
        self.alive.next().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the start of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).assume_init_read() }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    fn count(self) -> usize {
        self.len()
    }

    fn last(mut self) -> Option<Self::Item> {
        self.next_back()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
    fn next_back(&mut self) -> Option<Self::Item> {
        // Get the next index from the back.
        //
        // Decreasing `alive.end` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
        self.alive.next_back().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the end of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).assume_init_read() }
        })
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Drop for IntoIter<T, N> {
    fn drop(&mut self) {
        // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
        // of elements that have not been moved out yet and that remain
        // to be dropped.
        unsafe { ptr::drop_in_place(self.as_mut_slice()) }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
    fn len(&self) -> usize {
        // Will never underflow due to the invariant `alive.start <=
        // alive.end`.
        self.alive.end - self.alive.start
    }
    fn is_empty(&self) -> bool {
        self.alive.is_empty()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}

// The iterator indeed reports the correct length. The number of "alive"
// elements (that will still be yielded) is the length of the range `alive`.
// This range is decremented in length in either `next` or `next_back`. It is
// always decremented by 1 in those methods, but only if `Some(_)` is returned.
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
    fn clone(&self) -> Self {
        // Note, we don't really need to match the exact same alive range, so
        // we can just clone into offset 0 regardless of where `self` is.
        let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };

        // Clone all alive elements.
        for (src, dst) in self.as_slice().iter().zip(&mut new.data) {
            // Write a clone into the new array, then update its alive range.
            // If cloning panics, we'll correctly drop the previous items.
            dst.write(src.clone());
            new.alive.end += 1;
        }

        new
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Only print the elements that were not yielded yet: we cannot
        // access the yielded elements anymore.
        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
    }
}
<commit_msg>Rollup merge of #79194 - est31:array_into_iter_slice, r=scottmcm<commit_after>//! Defines the `IntoIter` owned iterator for arrays.

use crate::{
    fmt,
    iter::{ExactSizeIterator, FusedIterator, TrustedLen},
    mem::{self, MaybeUninit},
    ops::Range,
    ptr,
};

/// A by-value [array] iterator.
///
/// [array]: ../../std/primitive.array.html
#[unstable(feature = "array_value_iter", issue = "65798")]
pub struct IntoIter<T, const N: usize> {
    /// This is the array we are iterating over.
    ///
    /// Elements with index `i` where `alive.start <= i < alive.end` have not
    /// been yielded yet and are valid array entries. Elements with indices `i
    /// < alive.start` or `i >= alive.end` have been yielded already and must
    /// not be accessed anymore! Those dead elements might even be in a
    /// completely uninitialized state!
    ///
    /// So the invariants are:
    /// - `data[alive]` is alive (i.e. contains valid elements)
    /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the
    ///   elements were already read and must not be touched anymore!)
    data: [MaybeUninit<T>; N],

    /// The elements in `data` that have not been yielded yet.
    ///
    /// Invariants:
    /// - `alive.start <= alive.end`
    /// - `alive.end <= N`
    alive: Range<usize>,
}

impl<T, const N: usize> IntoIter<T, N> {
    /// Creates a new iterator over the given `array`.
    ///
    /// *Note*: this method might never get stabilized and/or removed in the
    /// future as there will likely be another, preferred way of obtaining this
    /// iterator (either via `IntoIterator` for arrays or via another way).
    #[unstable(feature = "array_value_iter", issue = "65798")]
    pub fn new(array: [T; N]) -> Self {
        // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
        // promise:
        //
        // > `MaybeUninit<T>` is guaranteed to have the same size and alignment
        // > as `T`.
        //
        // The docs even show a transmute from an array of `MaybeUninit<T>` to
        // an array of `T`.
        //
        // With that, this initialization satisfies the invariants.

        // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
        // works with const generics:
        //     `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
        //
        // Until then, we can use `mem::transmute_copy` to create a bitwise copy
        // as a different type, then forget `array` so that it is not dropped.
        unsafe {
            let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
            mem::forget(array);
            iter
        }
    }

    /// Returns an immutable slice of all elements that have not been yielded
    /// yet.
    #[unstable(feature = "array_value_iter_slice", issue = "65798")]
    pub fn as_slice(&self) -> &[T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked(self.alive.clone());
            MaybeUninit::slice_assume_init_ref(slice)
        }
    }

    /// Returns a mutable slice of all elements that have not been yielded yet.
    #[unstable(feature = "array_value_iter_slice", issue = "65798")]
    pub fn as_mut_slice(&mut self) -> &mut [T] {
        // SAFETY: We know that all elements within `alive` are properly initialized.
        unsafe {
            let slice = self.data.get_unchecked_mut(self.alive.clone());
            MaybeUninit::slice_assume_init_mut(slice)
        }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Iterator for IntoIter<T, N> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        // Get the next index from the front.
        //
        // Increasing `alive.start` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
        self.alive.next().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the start of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).assume_init_read() }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    fn count(self) -> usize {
        self.len()
    }

    fn last(mut self) -> Option<Self::Item> {
        self.next_back()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
    fn next_back(&mut self) -> Option<Self::Item> {
        // Get the next index from the back.
        //
        // Decreasing `alive.end` by 1 maintains the invariant regarding
        // `alive`. However, due to this change, for a short time, the alive
        // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
        self.alive.next_back().map(|idx| {
            // Read the element from the array.
            // SAFETY: `idx` is an index into the former "alive" region of the
            // array. Reading this element means that `data[idx]` is regarded as
            // dead now (i.e. do not touch). As `idx` was the end of the
            // alive-zone, the alive zone is now `data[alive]` again, restoring
            // all invariants.
            unsafe { self.data.get_unchecked(idx).assume_init_read() }
        })
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> Drop for IntoIter<T, N> {
    fn drop(&mut self) {
        // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
        // of elements that have not been moved out yet and that remain
        // to be dropped.
        unsafe { ptr::drop_in_place(self.as_mut_slice()) }
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
    fn len(&self) -> usize {
        // Will never underflow due to the invariant `alive.start <=
        // alive.end`.
        self.alive.end - self.alive.start
    }
    fn is_empty(&self) -> bool {
        self.alive.is_empty()
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}

// The iterator indeed reports the correct length. The number of "alive"
// elements (that will still be yielded) is the length of the range `alive`.
// This range is decremented in length in either `next` or `next_back`. It is
// always decremented by 1 in those methods, but only if `Some(_)` is returned.
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
    fn clone(&self) -> Self {
        // Note, we don't really need to match the exact same alive range, so
        // we can just clone into offset 0 regardless of where `self` is.
        let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };

        // Clone all alive elements.
        for (src, dst) in self.as_slice().iter().zip(&mut new.data) {
            // Write a clone into the new array, then update its alive range.
            // If cloning panics, we'll correctly drop the previous items.
            dst.write(src.clone());
            new.alive.end += 1;
        }

        new
    }
}

#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Only print the elements that were not yielded yet: we cannot
        // access the yielded elements anymore.
        f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(unsafe_code)]

#![crate_name = "servo_url"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "servo", feature(plugin))]

#[cfg(feature = "servo")] extern crate serde;
#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
#[cfg(feature = "servo")] extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;

extern crate url;

use std::fmt;
use std::net::IpAddr;
use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Index};
use std::path::Path;
use std::sync::Arc;
use url::{Url, Origin, Position};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize))]
pub struct ServoUrl(Arc<Url>);

impl ServoUrl {
    pub fn from_url(url: Url) -> Self {
        ServoUrl(Arc::new(url))
    }

    pub fn parse_with_base(base: Option<&Self>, input: &str) -> Result<Self, url::ParseError> {
        Url::options().base_url(base.map(|b| &*b.0)).parse(input).map(Self::from_url)
    }

    pub fn into_string(self) -> String {
        Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()).into_string()
    }

    // NOTE: These methods return options that are always true temporarily until
    // we special-case some urls to avoid going through rust-url.
    pub fn into_url(self) -> Option<Url> {
        Some(Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()))
    }

    pub fn as_url(&self) -> Option<&Arc<Url>> {
        Some(&self.0)
    }

    pub fn parse(input: &str) -> Result<Self, url::ParseError> {
        Url::parse(input).map(Self::from_url)
    }

    pub fn cannot_be_a_base(&self) -> bool {
        self.0.cannot_be_a_base()
    }

    pub fn domain(&self) -> Option<&str> {
        self.0.domain()
    }

    pub fn fragment(&self) -> Option<&str> {
        self.0.fragment()
    }

    pub fn path(&self) -> &str {
        self.0.path()
    }

    pub fn origin(&self) -> Origin {
        self.0.origin()
    }

    pub fn scheme(&self) -> &str {
        self.0.scheme()
    }

    pub fn is_secure_scheme(&self) -> bool {
        let scheme = self.scheme();
        scheme == "https" || scheme == "wss"
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn as_mut_url(&mut self) -> Option<&mut Url> {
        Some(Arc::make_mut(&mut self.0))
    }

    pub fn set_username(&mut self, user: &str) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_username(user)
    }

    pub fn set_ip_host(&mut self, addr: IpAddr) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_ip_host(addr)
    }

    pub fn set_password(&mut self, pass: Option<&str>) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_password(pass)
    }

    pub fn set_fragment(&mut self, fragment: Option<&str>) {
        Arc::make_mut(&mut self.0).set_fragment(fragment)
    }

    pub fn username(&self) -> &str {
        self.0.username()
    }

    pub fn password(&self) -> Option<&str> {
        self.0.password()
    }

    pub fn to_file_path(&self) -> Result<::std::path::PathBuf, ()> {
        self.0.to_file_path()
    }

    pub fn host(&self) -> Option<url::Host<&str>> {
        self.0.host()
    }

    pub fn host_str(&self) -> Option<&str> {
        self.0.host_str()
    }

    pub fn port(&self) -> Option<u16> {
        self.0.port()
    }

    pub fn port_or_known_default(&self) -> Option<u16> {
        self.0.port_or_known_default()
    }

    pub fn join(&self, input: &str) -> Result<ServoUrl, url::ParseError> {
        self.0.join(input).map(Self::from_url)
    }

    pub fn path_segments(&self) -> Option<::std::str::Split<char>> {
        self.0.path_segments()
    }

    pub fn query(&self) -> Option<&str> {
        self.0.query()
    }

    pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Self, ()> {
        Ok(Self::from_url(try!(Url::from_file_path(path))))
    }
}

impl fmt::Display for ServoUrl {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(formatter)
    }
}

impl Index<RangeFull> for ServoUrl {
    type Output = str;
    fn index(&self, _: RangeFull) -> &str {
        &self.0[..]
    }
}

impl Index<RangeFrom<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: RangeFrom<Position>) -> &str {
        &self.0[range]
    }
}

impl Index<RangeTo<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: RangeTo<Position>) -> &str {
        &self.0[range]
    }
}

impl Index<Range<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: Range<Position>) -> &str {
        &self.0[range]
    }
}

impl From<Url> for ServoUrl {
    fn from(url: Url) -> Self {
        ServoUrl::from_url(url)
    }
}
<commit_msg>Auto merge of #15095 - servo:debug-servourl, r=nox<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(unsafe_code)]

#![crate_name = "servo_url"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "servo", feature(plugin))]

#[cfg(feature = "servo")] extern crate serde;
#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
#[cfg(feature = "servo")] extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;

extern crate url;

use std::fmt;
use std::net::IpAddr;
use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Index};
use std::path::Path;
use std::sync::Arc;
use url::{Url, Origin, Position};

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize))]
pub struct ServoUrl(Arc<Url>);

impl ServoUrl {
    pub fn from_url(url: Url) -> Self {
        ServoUrl(Arc::new(url))
    }

    pub fn parse_with_base(base: Option<&Self>, input: &str) -> Result<Self, url::ParseError> {
        Url::options().base_url(base.map(|b| &*b.0)).parse(input).map(Self::from_url)
    }

    pub fn into_string(self) -> String {
        Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()).into_string()
    }

    // NOTE: These methods return options that are always true temporarily until
    // we special-case some urls to avoid going through rust-url.
    pub fn into_url(self) -> Option<Url> {
        Some(Arc::try_unwrap(self.0).unwrap_or_else(|s| (*s).clone()))
    }

    pub fn as_url(&self) -> Option<&Arc<Url>> {
        Some(&self.0)
    }

    pub fn parse(input: &str) -> Result<Self, url::ParseError> {
        Url::parse(input).map(Self::from_url)
    }

    pub fn cannot_be_a_base(&self) -> bool {
        self.0.cannot_be_a_base()
    }

    pub fn domain(&self) -> Option<&str> {
        self.0.domain()
    }

    pub fn fragment(&self) -> Option<&str> {
        self.0.fragment()
    }

    pub fn path(&self) -> &str {
        self.0.path()
    }

    pub fn origin(&self) -> Origin {
        self.0.origin()
    }

    pub fn scheme(&self) -> &str {
        self.0.scheme()
    }

    pub fn is_secure_scheme(&self) -> bool {
        let scheme = self.scheme();
        scheme == "https" || scheme == "wss"
    }

    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }

    pub fn as_mut_url(&mut self) -> Option<&mut Url> {
        Some(Arc::make_mut(&mut self.0))
    }

    pub fn set_username(&mut self, user: &str) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_username(user)
    }

    pub fn set_ip_host(&mut self, addr: IpAddr) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_ip_host(addr)
    }

    pub fn set_password(&mut self, pass: Option<&str>) -> Result<(), ()> {
        Arc::make_mut(&mut self.0).set_password(pass)
    }

    pub fn set_fragment(&mut self, fragment: Option<&str>) {
        Arc::make_mut(&mut self.0).set_fragment(fragment)
    }

    pub fn username(&self) -> &str {
        self.0.username()
    }

    pub fn password(&self) -> Option<&str> {
        self.0.password()
    }

    pub fn to_file_path(&self) -> Result<::std::path::PathBuf, ()> {
        self.0.to_file_path()
    }

    pub fn host(&self) -> Option<url::Host<&str>> {
        self.0.host()
    }

    pub fn host_str(&self) -> Option<&str> {
        self.0.host_str()
    }

    pub fn port(&self) -> Option<u16> {
        self.0.port()
    }

    pub fn port_or_known_default(&self) -> Option<u16> {
        self.0.port_or_known_default()
    }

    pub fn join(&self, input: &str) -> Result<ServoUrl, url::ParseError> {
        self.0.join(input).map(Self::from_url)
    }

    pub fn path_segments(&self) -> Option<::std::str::Split<char>> {
        self.0.path_segments()
    }

    pub fn query(&self) -> Option<&str> {
        self.0.query()
    }

    pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Self, ()> {
        Ok(Self::from_url(try!(Url::from_file_path(path))))
    }
}

impl fmt::Display for ServoUrl {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(formatter)
    }
}

impl fmt::Debug for ServoUrl {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(formatter)
    }
}

impl Index<RangeFull> for ServoUrl {
    type Output = str;
    fn index(&self, _: RangeFull) -> &str {
        &self.0[..]
    }
}

impl Index<RangeFrom<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: RangeFrom<Position>) -> &str {
        &self.0[range]
    }
}

impl Index<RangeTo<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: RangeTo<Position>) -> &str {
        &self.0[range]
    }
}

impl Index<Range<Position>> for ServoUrl {
    type Output = str;
    fn index(&self, range: Range<Position>) -> &str {
        &self.0[range]
    }
}

impl From<Url> for ServoUrl {
    fn from(url: Url) -> Self {
        ServoUrl::from_url(url)
    }
}
<|endoftext|>