<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::collections::HashMap;
use std::io;
use std::mem;

use core::os::process::handle_from_pid;
use core::os::process::windows_child::{Child, ExitStatus, Handle};
use protocol::{self, ShutdownMethod};
use time::{Duration, SteadyTime};
use winapi::shared::minwindef::{DWORD, LPDWORD, MAX_PATH};
use winapi::shared::winerror::{ERROR_FILE_NOT_FOUND, WAIT_TIMEOUT};
use winapi::um::handleapi::{self, INVALID_HANDLE_VALUE};
use winapi::um::processthreadsapi;
use winapi::um::synchapi;
use winapi::um::tlhelp32::{self, LPPROCESSENTRY32W, PROCESSENTRY32W, TH32CS_SNAPPROCESS};
use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0};
use winapi::um::wincon;

use error::{Error, Result};
use service::Service;

const PROCESS_ACTIVE: u32 = 259;
type ProcessTable = HashMap<DWORD, Vec<DWORD>>;

pub struct Process {
    handle: Handle,
    last_status: Option<ExitStatus>,
}

impl Process {
    fn new(handle: Handle) -> Self {
        Process {
            handle: handle,
            last_status: None,
        }
    }

    pub fn id(&self) -> u32 {
        unsafe { processthreadsapi::GetProcessId(self.handle.raw()) as u32 }
    }

    /// Attempt to gracefully terminate a process and then forcefully kill it after
    /// 8 seconds if it has not terminated.
    pub fn kill(&mut self) -> ShutdownMethod {
        if self.status().is_some() {
            return ShutdownMethod::AlreadyExited;
        }
        let ret = unsafe { wincon::GenerateConsoleCtrlEvent(1, self.id()) };
        if ret == 0 {
            debug!(
                "Failed to send ctrl-break to pid {}: {}",
                self.id(),
                io::Error::last_os_error()
            );
        }

        let stop_time = SteadyTime::now() + Duration::seconds(8);
        loop {
            if ret == 0 || SteadyTime::now() > stop_time {
                let proc_table = build_proc_table();
                terminate_process_descendants(&proc_table, self.id());
                return ShutdownMethod::Killed;
            }

            if self.status().is_some() {
                return ShutdownMethod::GracefulTermination;
            }
        }
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        unsafe {
            let res = synchapi::WaitForSingleObject(self.handle.raw(), INFINITE);
            if res != WAIT_OBJECT_0 {
                return Err(io::Error::last_os_error());
            }
            let mut status = 0;
            cvt(processthreadsapi::GetExitCodeProcess(
                self.handle.raw(),
                &mut status,
            )?;
            Ok(ExitStatus::from(status))
        }
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        unsafe {
            match synchapi::WaitForSingleObject(self.handle.raw(), 0) {
                WAIT_OBJECT_0 => {}
                WAIT_TIMEOUT => return Ok(None),
                _ => return Err(io::Error::last_os_error()),
            }
            let mut status = 0;
            cvt(processthreadsapi::GetExitCodeProcess(
                self.handle.raw(),
                &mut status,
            )?;
            Ok(Some(ExitStatus::from(status)))
        }
    }

    fn status(&mut self) -> Option<ExitStatus> {
        if self.last_status.is_some() {
            return self.last_status;
        }
        match exit_code(&self.handle) {
            Some(PROCESS_ACTIVE) => None,
            Some(code) => {
                self.last_status = Some(ExitStatus::from(code));
                self.last_status
            }
            None => None,
        }
    }
}

pub fn run(msg: protocol::Spawn) -> Result<Service> {
    // Supervisors prior to version 0.53.0 pulled in beta versions of
    // powershell. The official 6.0.0 version of powershell changed
    // the name of the powershell binary to pwsh.exe. Here we will
    // first attempt the latest binary name and fall back to the
    // former name.
    match spawn_pwsh("pwsh.exe", msg.clone()) {
        Ok(service) => Ok(service),
        Err(err) => {
            if err.raw_os_error() == Some(ERROR_FILE_NOT_FOUND as i32) {
                spawn_pwsh("powershell.exe", msg).map_err(Error::Spawn)
            } else {
                Err(Error::Spawn(err))
            }
        }
    }
}

fn spawn_pwsh(ps_binary_name: &str, mut msg: protocol::Spawn) -> io::Result<Service> {
    debug!("launcher is spawning {}", msg.get_binary());
    let ps_cmd = format!("iex $(gc {} | out-string)", msg.get_binary());
    let password = if msg.get_svc_password().is_empty() {
        None
    } else {
        Some(msg.take_svc_password())
    };
    match Child::spawn(
        ps_binary_name,
        vec!["-NonInteractive", "-command", ps_cmd.as_str()],
        msg.get_env(),
        msg.get_svc_user(),
        password,
    ) {
        Ok(child) => {
            let process = Process::new(child.handle);
            Ok(Service::new(msg, process, child.stdout, child.stderr))
        }
        Err(_) => Err(io::Error::last_os_error()),
    }
}

fn build_proc_table() -> ProcessTable {
    let processes_snap_handle =
        unsafe { tlhelp32::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };

    if processes_snap_handle == INVALID_HANDLE_VALUE {
        error!(
            "Failed to call CreateToolhelp32Snapshot: {}",
            io::Error::last_os_error()
        );
        return ProcessTable::new();
    }
    let mut table = ProcessTable::new();
    let mut process_entry = PROCESSENTRY32W {
        dwSize: mem::size_of::<PROCESSENTRY32W>() as u32,
        cntUsage: 0,
        th32ProcessID: 0,
        th32DefaultHeapID: 0,
        th32ModuleID: 0,
        cntThreads: 0,
        th32ParentProcessID: 0,
        pcPriClassBase: 0,
        dwFlags: 0,
        szExeFile: [0; MAX_PATH],
    };
    // Get the first process from the snapshot.
    match unsafe {
        tlhelp32::Process32FirstW(
            processes_snap_handle,
            &mut process_entry as LPPROCESSENTRY32W,
        )
    } {
        1 => {
            // First process worked, loop to find the process with the correct name.
            let mut process_success: i32 = 1;
            // Loop through all processes until we find one where `szExeFile` == `name`.
            while process_success == 1 {
                let children = table
                    .entry(process_entry.th32ParentProcessID)
                    .or_insert(Vec::new());
                (*children).push(process_entry.th32ProcessID);
                process_success =
                    unsafe { tlhelp32::Process32NextW(processes_snap_handle, &mut process_entry) };
            }
            unsafe { handleapi::CloseHandle(processes_snap_handle) };
        }
        0 | _ => unsafe {
            handleapi::CloseHandle(processes_snap_handle);
        },
    }
    table
}

fn cvt(i: i32) -> io::Result<i32> {
    if i == 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(i)
    }
}

fn exit_code(handle: &Handle) -> Option<u32> {
    let mut exit_code: u32 = 0;
    unsafe {
        let ret = processthreadsapi::GetExitCodeProcess(handle.raw(), &mut exit_code as LPDWORD);
        if ret == 0 {
            error!(
                "Failed to retrieve Exit Code: {}",
                io::Error::last_os_error()
            );
            return None;
        }
    }
    Some(exit_code)
}

fn terminate_process_descendants(table: &ProcessTable, pid: DWORD) {
    if let Some(children) = table.get(&pid) {
        for child in children {
            terminate_process_descendants(table, child.clone());
        }
    }
    unsafe {
        match handle_from_pid(pid) {
            Some(h) => {
                if processthreadsapi::TerminateProcess(h, 1) == 0 {
                    error!(
                        "Failed to call TerminateProcess on pid {}: {}",
                        pid,
                        io::Error::last_os_error()
                    );
                }
            }
            None => {}
        }
    }
}
<commit_msg>Fix missing parenthesis<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::collections::HashMap;
use std::io;
use std::mem;

use core::os::process::handle_from_pid;
use core::os::process::windows_child::{Child, ExitStatus, Handle};
use protocol::{self, ShutdownMethod};
use time::{Duration, SteadyTime};
use winapi::shared::minwindef::{DWORD, LPDWORD, MAX_PATH};
use winapi::shared::winerror::{ERROR_FILE_NOT_FOUND, WAIT_TIMEOUT};
use winapi::um::handleapi::{self, INVALID_HANDLE_VALUE};
use winapi::um::processthreadsapi;
use winapi::um::synchapi;
use winapi::um::tlhelp32::{self, LPPROCESSENTRY32W, PROCESSENTRY32W, TH32CS_SNAPPROCESS};
use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0};
use winapi::um::wincon;

use error::{Error, Result};
use service::Service;

const PROCESS_ACTIVE: u32 = 259;
type ProcessTable = HashMap<DWORD, Vec<DWORD>>;

pub struct Process {
    handle: Handle,
    last_status: Option<ExitStatus>,
}

impl Process {
    fn new(handle: Handle) -> Self {
        Process {
            handle: handle,
            last_status: None,
        }
    }

    pub fn id(&self) -> u32 {
        unsafe { processthreadsapi::GetProcessId(self.handle.raw()) as u32 }
    }

    /// Attempt to gracefully terminate a process and then forcefully kill it after
    /// 8 seconds if it has not terminated.
    pub fn kill(&mut self) -> ShutdownMethod {
        if self.status().is_some() {
            return ShutdownMethod::AlreadyExited;
        }
        let ret = unsafe { wincon::GenerateConsoleCtrlEvent(1, self.id()) };
        if ret == 0 {
            debug!(
                "Failed to send ctrl-break to pid {}: {}",
                self.id(),
                io::Error::last_os_error()
            );
        }

        let stop_time = SteadyTime::now() + Duration::seconds(8);
        loop {
            if ret == 0 || SteadyTime::now() > stop_time {
                let proc_table = build_proc_table();
                terminate_process_descendants(&proc_table, self.id());
                return ShutdownMethod::Killed;
            }

            if self.status().is_some() {
                return ShutdownMethod::GracefulTermination;
            }
        }
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        unsafe {
            let res = synchapi::WaitForSingleObject(self.handle.raw(), INFINITE);
            if res != WAIT_OBJECT_0 {
                return Err(io::Error::last_os_error());
            }
            let mut status = 0;
            cvt(processthreadsapi::GetExitCodeProcess(
                self.handle.raw(),
                &mut status,
            ))?;
            Ok(ExitStatus::from(status))
        }
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        unsafe {
            match synchapi::WaitForSingleObject(self.handle.raw(), 0) {
                WAIT_OBJECT_0 => {}
                WAIT_TIMEOUT => return Ok(None),
                _ => return Err(io::Error::last_os_error()),
            }
            let mut status = 0;
            cvt(processthreadsapi::GetExitCodeProcess(
                self.handle.raw(),
                &mut status,
            ))?;
            Ok(Some(ExitStatus::from(status)))
        }
    }

    fn status(&mut self) -> Option<ExitStatus> {
        if self.last_status.is_some() {
            return self.last_status;
        }
        match exit_code(&self.handle) {
            Some(PROCESS_ACTIVE) => None,
            Some(code) => {
                self.last_status = Some(ExitStatus::from(code));
                self.last_status
            }
            None => None,
        }
    }
}

pub fn run(msg: protocol::Spawn) -> Result<Service> {
    // Supervisors prior to version 0.53.0 pulled in beta versions of
    // powershell. The official 6.0.0 version of powershell changed
    // the name of the powershell binary to pwsh.exe. Here we will
    // first attempt the latest binary name and fall back to the
    // former name.
    match spawn_pwsh("pwsh.exe", msg.clone()) {
        Ok(service) => Ok(service),
        Err(err) => {
            if err.raw_os_error() == Some(ERROR_FILE_NOT_FOUND as i32) {
                spawn_pwsh("powershell.exe", msg).map_err(Error::Spawn)
            } else {
                Err(Error::Spawn(err))
            }
        }
    }
}

fn spawn_pwsh(ps_binary_name: &str, mut msg: protocol::Spawn) -> io::Result<Service> {
    debug!("launcher is spawning {}", msg.get_binary());
    let ps_cmd = format!("iex $(gc {} | out-string)", msg.get_binary());
    let password = if msg.get_svc_password().is_empty() {
        None
    } else {
        Some(msg.take_svc_password())
    };
    match Child::spawn(
        ps_binary_name,
        vec!["-NonInteractive", "-command", ps_cmd.as_str()],
        msg.get_env(),
        msg.get_svc_user(),
        password,
    ) {
        Ok(child) => {
            let process = Process::new(child.handle);
            Ok(Service::new(msg, process, child.stdout, child.stderr))
        }
        Err(_) => Err(io::Error::last_os_error()),
    }
}

fn build_proc_table() -> ProcessTable {
    let processes_snap_handle =
        unsafe { tlhelp32::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };

    if processes_snap_handle == INVALID_HANDLE_VALUE {
        error!(
            "Failed to call CreateToolhelp32Snapshot: {}",
            io::Error::last_os_error()
        );
        return ProcessTable::new();
    }
    let mut table = ProcessTable::new();
    let mut process_entry = PROCESSENTRY32W {
        dwSize: mem::size_of::<PROCESSENTRY32W>() as u32,
        cntUsage: 0,
        th32ProcessID: 0,
        th32DefaultHeapID: 0,
        th32ModuleID: 0,
        cntThreads: 0,
        th32ParentProcessID: 0,
        pcPriClassBase: 0,
        dwFlags: 0,
        szExeFile: [0; MAX_PATH],
    };
    // Get the first process from the snapshot.
    match unsafe {
        tlhelp32::Process32FirstW(
            processes_snap_handle,
            &mut process_entry as LPPROCESSENTRY32W,
        )
    } {
        1 => {
            // First process worked, loop to find the process with the correct name.
            let mut process_success: i32 = 1;
            // Loop through all processes until we find one where `szExeFile` == `name`.
            while process_success == 1 {
                let children = table
                    .entry(process_entry.th32ParentProcessID)
                    .or_insert(Vec::new());
                (*children).push(process_entry.th32ProcessID);
                process_success =
                    unsafe { tlhelp32::Process32NextW(processes_snap_handle, &mut process_entry) };
            }
            unsafe { handleapi::CloseHandle(processes_snap_handle) };
        }
        0 | _ => unsafe {
            handleapi::CloseHandle(processes_snap_handle);
        },
    }
    table
}

fn cvt(i: i32) -> io::Result<i32> {
    if i == 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(i)
    }
}

fn exit_code(handle: &Handle) -> Option<u32> {
    let mut exit_code: u32 = 0;
    unsafe {
        let ret = processthreadsapi::GetExitCodeProcess(handle.raw(), &mut exit_code as LPDWORD);
        if ret == 0 {
            error!(
                "Failed to retrieve Exit Code: {}",
                io::Error::last_os_error()
            );
            return None;
        }
    }
    Some(exit_code)
}

fn terminate_process_descendants(table: &ProcessTable, pid: DWORD) {
    if let Some(children) = table.get(&pid) {
        for child in children {
            terminate_process_descendants(table, child.clone());
        }
    }
    unsafe {
        match handle_from_pid(pid) {
            Some(h) => {
                if processthreadsapi::TerminateProcess(h, 1) == 0 {
                    error!(
                        "Failed to call TerminateProcess on pid {}: {}",
                        pid,
                        io::Error::last_os_error()
                    );
                }
            }
            None => {}
        }
    }
}
<|endoftext|>


<commit_before>//! Tests for various types of file (video, image, compressed, etc).
//!
//! Currently this is dependent on the file’s name and extension, because
//! those are the only metadata that we have access to without reading the
//! file’s contents.

use ansi_term::Style;

use crate::fs::File;
use crate::output::icons::FileIcon;
use crate::theme::FileColours;

#[derive(Debug, Default, PartialEq)]
pub struct FileExtensions;

impl FileExtensions {

    /// An “immediate” file is something that can be run or activated somehow
    /// in order to kick off the build of a project. It’s usually only present
    /// in directories full of source code.
    #[allow(clippy::case_sensitive_file_extension_comparisons)]
    fn is_immediate(&self, file: &File<'_>) -> bool {
        file.name.to_lowercase().starts_with("readme") ||
        file.name.ends_with(".ninja") ||
        file.name_is_one_of( &[
            "Makefile", "Cargo.toml", "SConstruct", "CMakeLists.txt",
            "build.gradle", "pom.xml", "Rakefile", "package.json", "Gruntfile.js",
            "Gruntfile.coffee", "BUILD", "BUILD.bazel", "WORKSPACE", "build.xml",
            "webpack.config.js", "meson.build", "composer.json", "RoboFile.php", "PKGBUILD",
            "Justfile", "Procfile", "Dockerfile", "Containerfile", "Vagrantfile", "Brewfile",
            "Gemfile", "Pipfile", "build.sbt", "mix.exs", "bsconfig.json", "tsconfig.json",
        ])
    }

    fn is_image(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif",
            "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw",
            "svg", "stl", "eps", "dvi", "ps", "cbr", "jpf",
            "cbz", "xpm", "ico", "cr2", "orf", "nef", "heif",
        ])
    }

    fn is_video(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "avi", "flv", "m2v", "m4v", "mkv", "mov", "mp4", "mpeg",
            "mpg", "ogm", "ogv", "vob", "wmv", "webm", "m2ts", "heic",
        ])
    }

    fn is_music(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "aac", "m4a", "mp3", "ogg", "wma", "mka", "opus",
        ])
    }

    // Lossless music, rather than any other kind of data...
    fn is_lossless(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "alac", "ape", "flac", "wav",
        ])
    }

    fn is_crypto(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "asc", "enc", "gpg", "pgp", "sig", "signature", "pfx", "p12",
        ])
    }

    fn is_document(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "djvu", "doc", "docx", "dvi", "eml", "eps", "fotd", "key",
            "keynote", "numbers", "odp", "odt", "pages", "pdf", "ppt",
            "pptx", "rtf", "xls", "xlsx",
        ])
    }

    fn is_compressed(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "zip", "tar", "Z", "z", "gz", "bz2", "a", "ar", "7z",
            "iso", "dmg", "tc", "rar", "par", "tgz", "xz", "txz",
            "lz", "tlz", "lzma", "deb", "rpm", "zst",
        ])
    }

    fn is_temp(&self, file: &File<'_>) -> bool {
        file.name.ends_with('~')
            || (file.name.starts_with('#') && file.name.ends_with('#'))
            || file.extension_is_one_of( &[ "tmp", "swp", "swo", "swn", "bak", "bk" ])
    }

    fn is_compiled(&self, file: &File<'_>) -> bool {
        if file.extension_is_one_of( &[ "class", "elc", "hi", "o", "pyc", "zwc", "ko" ]) {
            true
        }
        else if let Some(dir) = file.parent_dir {
            file.get_source_files().iter().any(|path| dir.contains(path))
        }
        else {
            false
        }
    }
}

impl FileColours for FileExtensions {
    fn colour_file(&self, file: &File<'_>) -> Option<Style> {
        use ansi_term::Colour::*;

        Some(match file {
            f if self.is_temp(f)        => Fixed(244).normal(),
            f if self.is_immediate(f)   => Yellow.bold().underline(),
            f if self.is_image(f)       => Fixed(133).normal(),
            f if self.is_video(f)       => Fixed(135).normal(),
            f if self.is_music(f)       => Fixed(92).normal(),
            f if self.is_lossless(f)    => Fixed(93).normal(),
            f if self.is_crypto(f)      => Fixed(109).normal(),
            f if self.is_document(f)    => Fixed(105).normal(),
            f if self.is_compressed(f)  => Red.normal(),
            f if self.is_compiled(f)    => Fixed(137).normal(),
            _                           => return None,
        })
    }
}

impl FileIcon for FileExtensions {
    fn icon_file(&self, file: &File<'_>) -> Option<char> {
        use crate::output::icons::Icons;

        if self.is_music(file) || self.is_lossless(file) {
            Some(Icons::Audio.value())
        }
        else if self.is_image(file) {
            Some(Icons::Image.value())
        }
        else if self.is_video(file) {
            Some(Icons::Video.value())
        }
        else {
            None
        }
    }
}
<commit_msg>Added 'Podfile' to list of immediate files<commit_after>//! Tests for various types of file (video, image, compressed, etc).
//!
//! Currently this is dependent on the file’s name and extension, because
//! those are the only metadata that we have access to without reading the
//! file’s contents.

use ansi_term::Style;

use crate::fs::File;
use crate::output::icons::FileIcon;
use crate::theme::FileColours;

#[derive(Debug, Default, PartialEq)]
pub struct FileExtensions;

impl FileExtensions {

    /// An “immediate” file is something that can be run or activated somehow
    /// in order to kick off the build of a project. It’s usually only present
    /// in directories full of source code.
    #[allow(clippy::case_sensitive_file_extension_comparisons)]
    fn is_immediate(&self, file: &File<'_>) -> bool {
        file.name.to_lowercase().starts_with("readme") ||
        file.name.ends_with(".ninja") ||
        file.name_is_one_of( &[
            "Makefile", "Cargo.toml", "SConstruct", "CMakeLists.txt",
            "build.gradle", "pom.xml", "Rakefile", "package.json", "Gruntfile.js",
            "Gruntfile.coffee", "BUILD", "BUILD.bazel", "WORKSPACE", "build.xml", "Podfile",
            "webpack.config.js", "meson.build", "composer.json", "RoboFile.php", "PKGBUILD",
            "Justfile", "Procfile", "Dockerfile", "Containerfile", "Vagrantfile", "Brewfile",
            "Gemfile", "Pipfile", "build.sbt", "mix.exs", "bsconfig.json", "tsconfig.json",
        ])
    }

    fn is_image(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif",
            "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw",
            "svg", "stl", "eps", "dvi", "ps", "cbr", "jpf",
            "cbz", "xpm", "ico", "cr2", "orf", "nef", "heif",
        ])
    }

    fn is_video(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "avi", "flv", "m2v", "m4v", "mkv", "mov", "mp4", "mpeg",
            "mpg", "ogm", "ogv", "vob", "wmv", "webm", "m2ts", "heic",
        ])
    }

    fn is_music(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "aac", "m4a", "mp3", "ogg", "wma", "mka", "opus",
        ])
    }

    // Lossless music, rather than any other kind of data...
    fn is_lossless(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "alac", "ape", "flac", "wav",
        ])
    }

    fn is_crypto(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "asc", "enc", "gpg", "pgp", "sig", "signature", "pfx", "p12",
        ])
    }

    fn is_document(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "djvu", "doc", "docx", "dvi", "eml", "eps", "fotd", "key",
            "keynote", "numbers", "odp", "odt", "pages", "pdf", "ppt",
            "pptx", "rtf", "xls", "xlsx",
        ])
    }

    fn is_compressed(&self, file: &File<'_>) -> bool {
        file.extension_is_one_of( &[
            "zip", "tar", "Z", "z", "gz", "bz2", "a", "ar", "7z",
            "iso", "dmg", "tc", "rar", "par", "tgz", "xz", "txz",
            "lz", "tlz", "lzma", "deb", "rpm", "zst",
        ])
    }

    fn is_temp(&self, file: &File<'_>) -> bool {
        file.name.ends_with('~')
            || (file.name.starts_with('#') && file.name.ends_with('#'))
            || file.extension_is_one_of( &[ "tmp", "swp", "swo", "swn", "bak", "bk" ])
    }

    fn is_compiled(&self, file: &File<'_>) -> bool {
        if file.extension_is_one_of( &[ "class", "elc", "hi", "o", "pyc", "zwc", "ko" ]) {
            true
        }
        else if let Some(dir) = file.parent_dir {
            file.get_source_files().iter().any(|path| dir.contains(path))
        }
        else {
            false
        }
    }
}

impl FileColours for FileExtensions {
    fn colour_file(&self, file: &File<'_>) -> Option<Style> {
        use ansi_term::Colour::*;

        Some(match file {
            f if self.is_temp(f)        => Fixed(244).normal(),
            f if self.is_immediate(f)   => Yellow.bold().underline(),
            f if self.is_image(f)       => Fixed(133).normal(),
            f if self.is_video(f)       => Fixed(135).normal(),
            f if self.is_music(f)       => Fixed(92).normal(),
            f if self.is_lossless(f)    => Fixed(93).normal(),
            f if self.is_crypto(f)      => Fixed(109).normal(),
            f if self.is_document(f)    => Fixed(105).normal(),
            f if self.is_compressed(f)  => Red.normal(),
            f if self.is_compiled(f)    => Fixed(137).normal(),
            _                           => return None,
        })
    }
}

impl FileIcon for FileExtensions {
    fn icon_file(&self, file: &File<'_>) -> Option<char> {
        use crate::output::icons::Icons;

        if self.is_music(file) || self.is_lossless(file) {
            Some(Icons::Audio.value())
        }
        else if self.is_image(file) {
            Some(Icons::Image.value())
        }
        else if self.is_video(file) {
            Some(Icons::Video.value())
        }
        else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;

use smithay::{
    reexports::wayland_server::protocol::wl_surface,
    utils::Rectangle,
    wayland::{
        compositor::{roles::Role, CompositorToken, SubsurfaceRole, TraversalAction},
        shell::{
            legacy::{ShellSurface, ShellSurfaceRole},
            xdg::{ToplevelSurface, XdgSurfaceRole},
        },
    },
};

use crate::shell::SurfaceData;

pub enum Kind<R> {
    Xdg(ToplevelSurface<R>),
    Wl(ShellSurface<R>),
}

// We implement Clone manually because #[derive(..)] would require R: Clone.
impl<R> Clone for Kind<R> {
    fn clone(&self) -> Self {
        match self {
            Kind::Xdg(xdg) => Kind::Xdg(xdg.clone()),
            Kind::Wl(wl) => Kind::Wl(wl.clone()),
        }
    }
}

impl<R> Kind<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn alive(&self) -> bool {
        match *self {
            Kind::Xdg(ref t) => t.alive(),
            Kind::Wl(ref t) => t.alive(),
        }
    }
    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        match *self {
            Kind::Xdg(ref t) => t.get_surface(),
            Kind::Wl(ref t) => t.get_surface(),
        }
    }

    /// Do this handle and the other one actually refer to the same toplevel surface?
    pub fn equals(&self, other: &Self) -> bool {
        match (self, other) {
            (Kind::Xdg(a), Kind::Xdg(b)) => a.equals(b),
            (Kind::Wl(a), Kind::Wl(b)) => a.equals(b),
            _ => false,
        }
    }
}

struct Window<R> {
    location: (i32, i32),
    /// A bounding box over this window and its children.
    ///
    /// Used for the fast path of the check in `matching`, and as the fall-back for the window
    /// geometry if that's not set explicitly.
    bbox: Rectangle,
    toplevel: Kind<R>,
}

impl<R> Window<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    /// Finds the topmost surface under this point if any and returns it together with the location of this
    /// surface.
    fn matching(
        &self,
        point: (f64, f64),
        ctoken: CompositorToken<R>,
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        if !self.bbox.contains((point.0 as i32, point.1 as i32)) {
            return None;
        }
        // need to check more carefully
        let found = RefCell::new(None);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                self.location,
                |wl_surface, attributes, role, &(mut x, mut y)| {
                    let data = attributes.user_data.get::<SurfaceData>();

                    if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                        x += subdata.location.0;
                        y += subdata.location.1;
                    }

                    let surface_local_point = (point.0 - x as f64, point.1 - y as f64);
                    if data
                        .map(|data| data.contains_point(surface_local_point))
                        .unwrap_or(false)
                    {
                        *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64)));
                    }

                    TraversalAction::DoChildren((x, y))
                },
                |_, _, _, _| {},
                |_, _, _, _| {
                    // only continue if the point is not found
                    found.borrow().is_none()
                },
            );
        }
        found.into_inner()
    }

    fn self_update(&mut self, ctoken: CompositorToken<R>) {
        let (base_x, base_y) = self.location;
        let (mut min_x, mut min_y, mut max_x, mut max_y) = (base_x, base_y, base_x, base_y);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                (base_x, base_y),
                |_, attributes, role, &(mut x, mut y)| {
                    let data = attributes.user_data.get::<SurfaceData>();

                    if let Some((w, h)) = data.and_then(SurfaceData::size) {
                        if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                            x += subdata.location.0;
                            y += subdata.location.1;
                        }

                        // Update the bounding box.
                        min_x = min_x.min(x);
                        min_y = min_y.min(y);
                        max_x = max_x.max(x + w);
                        max_y = max_y.max(y + h);

                        TraversalAction::DoChildren((x, y))
                    } else {
                        // If the parent surface is unmapped, then the child surfaces are hidden as
                        // well, no need to consider them here.
                        TraversalAction::SkipChildren
                    }
                },
                |_, _, _, _| {},
                |_, _, _, _| true,
            );
        }
        self.bbox = Rectangle {
            x: min_x,
            y: min_y,
            width: max_x - min_x,
            height: max_y - min_y,
        };
    }

    /// Returns the geometry of this window.
    pub fn geometry(&self, ctoken: CompositorToken<R>) -> Rectangle {
        // It's the set geometry with the full bounding box as the fallback.
        ctoken
            .with_surface_data(self.toplevel.get_surface().unwrap(), |attributes| {
                attributes.user_data.get::<SurfaceData>().unwrap().geometry
            })
            .unwrap_or(self.bbox)
    }
}

pub struct WindowMap<R> {
    ctoken: CompositorToken<R>,
    windows: Vec<Window<R>>,
}

impl<R> WindowMap<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn new(ctoken: CompositorToken<R>) -> Self {
        WindowMap {
            ctoken,
            windows: Vec::new(),
        }
    }

    pub fn insert(&mut self, toplevel: Kind<R>, location: (i32, i32)) {
        let mut window = Window {
            location,
            bbox: Rectangle::default(),
            toplevel,
        };
        window.self_update(self.ctoken);
        self.windows.insert(0, window);
    }

    pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        for w in &self.windows {
            if let Some(surface) = w.matching(point, self.ctoken) {
                return Some(surface);
            }
        }
        None
    }

    pub fn get_surface_and_bring_to_top(
        &mut self,
        point: (f64, f64),
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        let mut found = None;
        for (i, w) in self.windows.iter().enumerate() {
            if let Some(surface) = w.matching(point, self.ctoken) {
                found = Some((i, surface));
                break;
            }
        }
        if let Some((i, surface)) = found {
            let winner = self.windows.remove(i);
            self.windows.insert(0, winner);
            Some(surface)
        } else {
            None
        }
    }

    pub fn with_windows_from_bottom_to_top<Func>(&self, mut f: Func)
    where
        Func: FnMut(&Kind<R>, (i32, i32)),
    {
        for w in self.windows.iter().rev() {
            f(&w.toplevel, w.location)
        }
    }

    pub fn refresh(&mut self) {
        self.windows.retain(|w| w.toplevel.alive());
        for w in &mut self.windows {
            w.self_update(self.ctoken);
        }
    }

    pub fn clear(&mut self) {
        self.windows.clear();
    }

    /// Returns the location of the toplevel, if it exists.
    pub fn location(&self, toplevel: &Kind<R>) -> Option<(i32, i32)> {
        self.windows
            .iter()
            .find(|w| w.toplevel.equals(toplevel))
            .map(|w| w.location)
    }

    /// Sets the location of the toplevel, if it exists.
    pub fn set_location(&mut self, toplevel: &Kind<R>, location: (i32, i32)) {
        if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) {
            w.location = location;
            w.self_update(self.ctoken);
        }
    }

    /// Returns the geometry of the toplevel, if it exists.
    pub fn geometry(&self, toplevel: &Kind<R>) -> Option<Rectangle> {
        self.windows
            .iter()
            .find(|w| w.toplevel.equals(toplevel))
            .map(|w| w.geometry(self.ctoken))
    }
}
<commit_msg>anvil.window_map: add WindowMap::find<commit_after>use std::cell::RefCell;

use smithay::{
    reexports::wayland_server::protocol::wl_surface,
    utils::Rectangle,
    wayland::{
        compositor::{roles::Role, CompositorToken, SubsurfaceRole, TraversalAction},
        shell::{
            legacy::{ShellSurface, ShellSurfaceRole},
            xdg::{ToplevelSurface, XdgSurfaceRole},
        },
    },
};

use crate::shell::SurfaceData;

pub enum Kind<R> {
    Xdg(ToplevelSurface<R>),
    Wl(ShellSurface<R>),
}

// We implement Clone manually because #[derive(..)] would require R: Clone.
impl<R> Clone for Kind<R> {
    fn clone(&self) -> Self {
        match self {
            Kind::Xdg(xdg) => Kind::Xdg(xdg.clone()),
            Kind::Wl(wl) => Kind::Wl(wl.clone()),
        }
    }
}

impl<R> Kind<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn alive(&self) -> bool {
        match *self {
            Kind::Xdg(ref t) => t.alive(),
            Kind::Wl(ref t) => t.alive(),
        }
    }
    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        match *self {
            Kind::Xdg(ref t) => t.get_surface(),
            Kind::Wl(ref t) => t.get_surface(),
        }
    }

    /// Do this handle and the other one actually refer to the same toplevel surface?
    pub fn equals(&self, other: &Self) -> bool {
        match (self, other) {
            (Kind::Xdg(a), Kind::Xdg(b)) => a.equals(b),
            (Kind::Wl(a), Kind::Wl(b)) => a.equals(b),
            _ => false,
        }
    }
}

struct Window<R> {
    location: (i32, i32),
    /// A bounding box over this window and its children.
    ///
    /// Used for the fast path of the check in `matching`, and as the fall-back for the window
    /// geometry if that's not set explicitly.
    bbox: Rectangle,
    toplevel: Kind<R>,
}

impl<R> Window<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    /// Finds the topmost surface under this point if any and returns it together with the location of this
    /// surface.
    fn matching(
        &self,
        point: (f64, f64),
        ctoken: CompositorToken<R>,
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        if !self.bbox.contains((point.0 as i32, point.1 as i32)) {
            return None;
        }
        // need to check more carefully
        let found = RefCell::new(None);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                self.location,
                |wl_surface, attributes, role, &(mut x, mut y)| {
                    let data = attributes.user_data.get::<SurfaceData>();

                    if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                        x += subdata.location.0;
                        y += subdata.location.1;
                    }

                    let surface_local_point = (point.0 - x as f64, point.1 - y as f64);
                    if data
                        .map(|data| data.contains_point(surface_local_point))
                        .unwrap_or(false)
                    {
                        *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64)));
                    }

                    TraversalAction::DoChildren((x, y))
                },
                |_, _, _, _| {},
                |_, _, _, _| {
                    // only continue if the point is not found
                    found.borrow().is_none()
                },
            );
        }
        found.into_inner()
    }

    fn self_update(&mut self, ctoken: CompositorToken<R>) {
        let (base_x, base_y) = self.location;
        let (mut min_x, mut min_y, mut max_x, mut max_y) = (base_x, base_y, base_x, base_y);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                (base_x, base_y),
                |_, attributes, role, &(mut x, mut y)| {
                    let data = attributes.user_data.get::<SurfaceData>();

                    if let Some((w, h)) = data.and_then(SurfaceData::size) {
                        if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                            x += subdata.location.0;
                            y += subdata.location.1;
                        }

                        // Update the bounding box.
                        min_x = min_x.min(x);
                        min_y = min_y.min(y);
                        max_x = max_x.max(x + w);
                        max_y = max_y.max(y + h);

                        TraversalAction::DoChildren((x, y))
                    } else {
                        // If the parent surface is unmapped, then the child surfaces are hidden as
                        // well, no need to consider them here.
                        TraversalAction::SkipChildren
                    }
                },
                |_, _, _, _| {},
                |_, _, _, _| true,
            );
        }
        self.bbox = Rectangle {
            x: min_x,
            y: min_y,
            width: max_x - min_x,
            height: max_y - min_y,
        };
    }

    /// Returns the geometry of this window.
    pub fn geometry(&self, ctoken: CompositorToken<R>) -> Rectangle {
        // It's the set geometry with the full bounding box as the fallback.
        ctoken
            .with_surface_data(self.toplevel.get_surface().unwrap(), |attributes| {
                attributes.user_data.get::<SurfaceData>().unwrap().geometry
            })
            .unwrap_or(self.bbox)
    }
}

pub struct WindowMap<R> {
    ctoken: CompositorToken<R>,
    windows: Vec<Window<R>>,
}

impl<R> WindowMap<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn new(ctoken: CompositorToken<R>) -> Self {
        WindowMap {
            ctoken,
            windows: Vec::new(),
        }
    }

    pub fn insert(&mut self, toplevel: Kind<R>, location: (i32, i32)) {
        let mut window = Window {
            location,
            bbox: Rectangle::default(),
            toplevel,
        };
        window.self_update(self.ctoken);
        self.windows.insert(0, window);
    }

    pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        for w in &self.windows {
            if let Some(surface) = w.matching(point, self.ctoken) {
                return Some(surface);
            }
        }
        None
    }

    pub fn get_surface_and_bring_to_top(
        &mut self,
        point: (f64, f64),
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        let mut found = None;
        for (i, w) in self.windows.iter().enumerate() {
            if let Some(surface) = w.matching(point, self.ctoken) {
                found = Some((i, surface));
                break;
            }
        }
        if let Some((i, surface)) = found {
            let winner = self.windows.remove(i);
            self.windows.insert(0, winner);
            Some(surface)
        } else {
            None
        }
    }

    pub fn with_windows_from_bottom_to_top<Func>(&self, mut f: Func)
    where
        Func: FnMut(&Kind<R>, (i32, i32)),
    {
        for w in self.windows.iter().rev() {
            f(&w.toplevel, w.location)
        }
    }

    pub fn refresh(&mut self) {
        self.windows.retain(|w| w.toplevel.alive());
        for w in &mut self.windows {
            w.self_update(self.ctoken);
        }
    }

    pub fn clear(&mut self) {
        self.windows.clear();
    }

    /// Finds the toplevel corresponding to the given `WlSurface`.
    pub fn find(&self, surface: &wl_surface::WlSurface) -> Option<Kind<R>> {
        self.windows.iter().find_map(|w| {
            if w.toplevel
                .get_surface()
                .map(|s| s.as_ref().equals(surface.as_ref()))
                .unwrap_or(false)
            {
                Some(w.toplevel.clone())
            } else {
                None
            }
        })
    }

    /// Returns the location of the toplevel, if it exists.
    pub fn location(&self, toplevel: &Kind<R>) -> Option<(i32, i32)> {
        self.windows
            .iter()
            .find(|w| w.toplevel.equals(toplevel))
            .map(|w| w.location)
    }

    /// Sets the location of the toplevel, if it exists.
    pub fn set_location(&mut self, toplevel: &Kind<R>, location: (i32, i32)) {
        if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) {
            w.location = location;
            w.self_update(self.ctoken);
        }
    }

    /// Returns the geometry of the toplevel, if it exists.
    pub fn geometry(&self, toplevel: &Kind<R>) -> Option<Rectangle> {
        self.windows
            .iter()
            .find(|w| w.toplevel.equals(toplevel))
            .map(|w| w.geometry(self.ctoken))
    }
}
<|endoftext|>


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

//! An owned, growable string that enforces that its contents are valid UTF-8.

use c_vec::CVec;
use char::Char;
use container::Container;
use fmt;
use io::Writer;
use iter::{Extendable, FromIterator, Iterator, range};
use mem;
use option::{None, Option, Some};
use ptr::RawPtr;
use slice::{OwnedVector, Vector, CloneableVector};
use str::{OwnedStr, Str, StrSlice, StrAllocating};
use str;
use vec::Vec;

/// A growable string stored as a UTF-8 encoded buffer.
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd)]
pub struct StrBuf {
    vec: Vec<u8>,
}

impl StrBuf {
    /// Creates a new string buffer initialized with the empty string.
    #[inline]
    pub fn new() -> StrBuf {
        StrBuf {
            vec: Vec::new(),
        }
    }

    /// Creates a new string buffer with the given capacity.
    #[inline]
    pub fn with_capacity(capacity: uint) -> StrBuf {
        StrBuf {
            vec: Vec::with_capacity(capacity),
        }
    }

    /// Creates a new string buffer from length, capacity, and a pointer.
    #[inline]
    pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> StrBuf {
        StrBuf {
            vec: Vec::from_raw_parts(length, capacity, ptr),
        }
    }

    /// Creates a new string buffer from the given string.
    #[inline]
    pub fn from_str(string: &str) -> StrBuf {
        StrBuf {
            vec: Vec::from_slice(string.as_bytes())
        }
    }

    /// Creates a new string buffer from the given owned string, taking care not to copy it.
    #[inline]
    pub fn from_owned_str(string: ~str) -> StrBuf {
        StrBuf {
            vec: string.into_bytes().move_iter().collect(),
        }
    }

    /// Tries to create a new string buffer from the given byte
    /// vector, validating that the vector is UTF-8 encoded.
    #[inline]
    pub fn from_utf8(vec: Vec<u8>) -> Option<StrBuf> {
        if str::is_utf8(vec.as_slice()) {
            Some(StrBuf { vec: vec })
        } else {
            None
        }
    }

    /// Return the underlying byte buffer, encoded as UTF-8.
    #[inline]
    pub fn into_bytes(self) -> Vec<u8> {
        self.vec
    }

    /// Pushes the given string onto this buffer; then, returns `self` so that it can be used
    /// again.
    #[inline]
    pub fn append(mut self, second: &str) -> StrBuf {
        self.push_str(second);
        self
    }

    /// Creates a string buffer by repeating a character `length` times.
    #[inline]
    pub fn from_char(length: uint, ch: char) -> StrBuf {
        if length == 0 {
            return StrBuf::new()
        }

        let mut buf = StrBuf::new();
        buf.push_char(ch);
        let size = buf.len() * length;
        buf.reserve(size);
        for _ in range(1, length) {
            buf.push_char(ch)
        }
        buf
    }

    /// Pushes the given string onto this string buffer.
    #[inline]
    pub fn push_str(&mut self, string: &str) {
        self.vec.push_all(string.as_bytes())
    }

    /// Push `ch` onto the given string `count` times.
    #[inline]
    pub fn grow(&mut self, count: uint, ch: char) {
        for _ in range(0, count) {
            self.push_char(ch)
        }
    }

    /// Returns the number of bytes that this string buffer can hold without reallocating.
    #[inline]
    pub fn byte_capacity(&self) -> uint {
        self.vec.capacity()
    }

    /// Reserves capacity for at least `extra` additional bytes in this string buffer.
    #[inline]
    pub fn reserve_additional(&mut self, extra: uint) {
        self.vec.reserve_additional(extra)
    }

    /// Reserves capacity for at least `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve(&mut self, capacity: uint) {
        self.vec.reserve(capacity)
    }

    /// Reserves capacity for exactly `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve_exact(&mut self, capacity: uint) {
        self.vec.reserve_exact(capacity)
    }

    /// Shrinks the capacity of this string buffer to match its length.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.vec.shrink_to_fit()
    }

    /// Adds the given character to the end of the string.
    #[inline]
    pub fn push_char(&mut self, ch: char) {
        let cur_len = self.len();
        unsafe {
            // This may use up to 4 bytes.
            self.vec.reserve_additional(4);

            // Attempt to not use an intermediate buffer by just pushing bytes
            // directly onto this string.
            let mut c_vector = CVec::new(self.vec.as_mut_ptr().offset(cur_len as int), 4);
            let used = ch.encode_utf8(c_vector.as_mut_slice());
            self.vec.set_len(cur_len + used);
        }
    }

    /// Pushes the given bytes onto this string buffer. This is unsafe because it does not check
    /// to ensure that the resulting string will be valid UTF-8.
    #[inline]
    pub unsafe fn push_bytes(&mut self, bytes: &[u8]) {
        self.vec.push_all(bytes)
    }

    /// Works with the underlying buffer as a byte slice.
    #[inline]
    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        self.vec.as_slice()
    }

    /// Shorten a string to the specified length (which must be <= the current length)
    #[inline]
    pub fn truncate(&mut self, len: uint) {
        assert!(self.as_slice().is_char_boundary(len));
        self.vec.truncate(len)
    }

    /// Appends a byte to this string buffer. The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn push_byte(&mut self, byte: u8) {
        self.push_bytes([byte])
    }

    /// Removes the last byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn pop_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_slice()[len - 1];
        self.vec.set_len(len - 1);
        Some(byte)
    }

    /// Removes the first byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    pub unsafe fn shift_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_slice()[0];
        *self = self.as_slice().slice(1, len).into_strbuf();
        Some(byte)
    }

    /// Views the string buffer as a mutable sequence of bytes.
    ///
    /// Callers must preserve the valid UTF-8 property.
    pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.vec
    }
}

impl Container for StrBuf {
    #[inline]
    fn len(&self) -> uint {
        self.vec.len()
    }
}

impl FromIterator<char> for StrBuf {
    fn from_iter<I:Iterator<char>>(iterator: I) -> StrBuf {
        let mut buf = StrBuf::new();
        buf.extend(iterator);
        buf
    }
}

impl Extendable<char> for StrBuf {
    fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
        for ch in iterator {
            self.push_char(ch)
        }
    }
}

impl Str for StrBuf {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            mem::transmute(self.vec.as_slice())
        }
    }
}

impl StrAllocating for StrBuf {
    #[inline]
    fn into_owned(self) -> ~str {
        unsafe {
            mem::transmute(self.vec.as_slice().to_owned())
        }
    }

    #[inline]
    fn into_strbuf(self) -> StrBuf { self }
}

impl fmt::Show for StrBuf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl<H:Writer> ::hash::Hash<H> for StrBuf {
    #[inline]
    fn hash(&self, hasher: &mut H) {
        self.as_slice().hash(hasher)
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;
    use str::{Str, StrSlice};
    use super::StrBuf;

    #[bench]
    fn bench_with_capacity(b: &mut Bencher) {
        b.iter(|| {
            StrBuf::with_capacity(100)
        });
    }

    #[bench]
    fn bench_push_str(b: &mut Bencher) {
        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
        b.iter(|| {
            let mut r = StrBuf::new();
            r.push_str(s);
        });
    }

    #[test]
    fn test_push_bytes() {
        let mut s = StrBuf::from_str("ABC");
        unsafe {
            s.push_bytes([ 'D' as u8 ]);
        }
        assert_eq!(s.as_slice(), "ABCD");
    }

    #[test]
    fn test_push_str() {
        let mut s = StrBuf::new();
        s.push_str("");
        assert_eq!(s.as_slice().slice_from(0), "");
        s.push_str("abc");
        assert_eq!(s.as_slice().slice_from(0), "abc");
        s.push_str("ประเทศไทย中华Việt Nam");
        assert_eq!(s.as_slice().slice_from(0), "abcประเทศไทย中华Việt Nam");
    }

    #[test]
    fn test_push_char() {
        let mut data = StrBuf::from_str("ประเทศไทย中");
        data.push_char('华');
        data.push_char('b'); // 1 byte
        data.push_char('¢'); // 2 byte
        data.push_char('€'); // 3 byte
        data.push_char('𤭢'); // 4 byte
        assert_eq!(data.as_slice(), "ประเทศไทย中华b¢€𤭢");
    }

    #[test]
    fn test_str_truncate() {
        let mut s = StrBuf::from_str("12345");
        s.truncate(5);
        assert_eq!(s.as_slice(), "12345");
        s.truncate(3);
        assert_eq!(s.as_slice(), "123");
        s.truncate(0);
        assert_eq!(s.as_slice(), "");

        let mut s = StrBuf::from_str("12345");
        let p = s.as_slice().as_ptr();
        s.truncate(3);
        s.push_str("6");
        let p_ = s.as_slice().as_ptr();
        assert_eq!(p_, p);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_invalid_len() {
        let mut s = StrBuf::from_str("12345");
        s.truncate(6);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_split_codepoint() {
        let mut s = StrBuf::from_str("\u00FC"); // ü
        s.truncate(1);
    }
}
<commit_msg>auto merge of #14110 : SSheldon/rust/strbuf_mutable, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An owned, growable string that enforces that its contents are valid UTF-8.

use c_vec::CVec;
use char::Char;
use container::{Container, Mutable};
use fmt;
use io::Writer;
use iter::{Extendable, FromIterator, Iterator, range};
use mem;
use option::{None, Option, Some};
use ptr::RawPtr;
use slice::{OwnedVector, Vector, CloneableVector};
use str::{OwnedStr, Str, StrSlice, StrAllocating};
use str;
use vec::Vec;

/// A growable string stored as a UTF-8 encoded buffer.
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd)]
pub struct StrBuf {
    vec: Vec<u8>,
}

impl StrBuf {
    /// Creates a new string buffer initialized with the empty string.
    #[inline]
    pub fn new() -> StrBuf {
        StrBuf {
            vec: Vec::new(),
        }
    }

    /// Creates a new string buffer with the given capacity.
    #[inline]
    pub fn with_capacity(capacity: uint) -> StrBuf {
        StrBuf {
            vec: Vec::with_capacity(capacity),
        }
    }

    /// Creates a new string buffer from length, capacity, and a pointer.
    #[inline]
    pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> StrBuf {
        StrBuf {
            vec: Vec::from_raw_parts(length, capacity, ptr),
        }
    }

    /// Creates a new string buffer from the given string.
    #[inline]
    pub fn from_str(string: &str) -> StrBuf {
        StrBuf {
            vec: Vec::from_slice(string.as_bytes())
        }
    }

    /// Creates a new string buffer from the given owned string, taking care not to copy it.
    #[inline]
    pub fn from_owned_str(string: ~str) -> StrBuf {
        StrBuf {
            vec: string.into_bytes().move_iter().collect(),
        }
    }

    /// Tries to create a new string buffer from the given byte
    /// vector, validating that the vector is UTF-8 encoded.
    #[inline]
    pub fn from_utf8(vec: Vec<u8>) -> Option<StrBuf> {
        if str::is_utf8(vec.as_slice()) {
            Some(StrBuf { vec: vec })
        } else {
            None
        }
    }

    /// Return the underlying byte buffer, encoded as UTF-8.
    #[inline]
    pub fn into_bytes(self) -> Vec<u8> {
        self.vec
    }

    /// Pushes the given string onto this buffer; then, returns `self` so that it can be used
    /// again.
    #[inline]
    pub fn append(mut self, second: &str) -> StrBuf {
        self.push_str(second);
        self
    }

    /// Creates a string buffer by repeating a character `length` times.
    #[inline]
    pub fn from_char(length: uint, ch: char) -> StrBuf {
        if length == 0 {
            return StrBuf::new()
        }

        let mut buf = StrBuf::new();
        buf.push_char(ch);
        let size = buf.len() * length;
        buf.reserve(size);
        for _ in range(1, length) {
            buf.push_char(ch)
        }
        buf
    }

    /// Pushes the given string onto this string buffer.
    #[inline]
    pub fn push_str(&mut self, string: &str) {
        self.vec.push_all(string.as_bytes())
    }

    /// Push `ch` onto the given string `count` times.
    #[inline]
    pub fn grow(&mut self, count: uint, ch: char) {
        for _ in range(0, count) {
            self.push_char(ch)
        }
    }

    /// Returns the number of bytes that this string buffer can hold without reallocating.
    #[inline]
    pub fn byte_capacity(&self) -> uint {
        self.vec.capacity()
    }

    /// Reserves capacity for at least `extra` additional bytes in this string buffer.
    #[inline]
    pub fn reserve_additional(&mut self, extra: uint) {
        self.vec.reserve_additional(extra)
    }

    /// Reserves capacity for at least `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve(&mut self, capacity: uint) {
        self.vec.reserve(capacity)
    }

    /// Reserves capacity for exactly `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve_exact(&mut self, capacity: uint) {
        self.vec.reserve_exact(capacity)
    }

    /// Shrinks the capacity of this string buffer to match its length.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.vec.shrink_to_fit()
    }

    /// Adds the given character to the end of the string.
    #[inline]
    pub fn push_char(&mut self, ch: char) {
        let cur_len = self.len();
        unsafe {
            // This may use up to 4 bytes.
            self.vec.reserve_additional(4);

            // Attempt to not use an intermediate buffer by just pushing bytes
            // directly onto this string.
            let mut c_vector = CVec::new(self.vec.as_mut_ptr().offset(cur_len as int), 4);
            let used = ch.encode_utf8(c_vector.as_mut_slice());
            self.vec.set_len(cur_len + used);
        }
    }

    /// Pushes the given bytes onto this string buffer. This is unsafe because it does not check
    /// to ensure that the resulting string will be valid UTF-8.
    #[inline]
    pub unsafe fn push_bytes(&mut self, bytes: &[u8]) {
        self.vec.push_all(bytes)
    }

    /// Works with the underlying buffer as a byte slice.
    #[inline]
    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        self.vec.as_slice()
    }

    /// Shorten a string to the specified length (which must be <= the current length)
    #[inline]
    pub fn truncate(&mut self, len: uint) {
        assert!(self.as_slice().is_char_boundary(len));
        self.vec.truncate(len)
    }

    /// Appends a byte to this string buffer. The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn push_byte(&mut self, byte: u8) {
        self.push_bytes([byte])
    }

    /// Removes the last byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn pop_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_slice()[len - 1];
        self.vec.set_len(len - 1);
        Some(byte)
    }

    /// Removes the first byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    pub unsafe fn shift_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_slice()[0];
        *self = self.as_slice().slice(1, len).into_strbuf();
        Some(byte)
    }

    /// Views the string buffer as a mutable sequence of bytes.
    ///
    /// Callers must preserve the valid UTF-8 property.
    pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.vec
    }
}

impl Container for StrBuf {
    #[inline]
    fn len(&self) -> uint {
        self.vec.len()
    }
}

impl Mutable for StrBuf {
    #[inline]
    fn clear(&mut self) {
        self.vec.clear()
    }
}

impl FromIterator<char> for StrBuf {
    fn from_iter<I:Iterator<char>>(iterator: I) -> StrBuf {
        let mut buf = StrBuf::new();
        buf.extend(iterator);
        buf
    }
}

impl Extendable<char> for StrBuf {
    fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
        for ch in iterator {
            self.push_char(ch)
        }
    }
}

impl Str for StrBuf {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            mem::transmute(self.vec.as_slice())
        }
    }
}

impl StrAllocating for StrBuf {
    #[inline]
    fn into_owned(self) -> ~str {
        unsafe {
            mem::transmute(self.vec.as_slice().to_owned())
        }
    }

    #[inline]
    fn into_strbuf(self) -> StrBuf { self }
}

impl fmt::Show for StrBuf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl<H:Writer> ::hash::Hash<H> for StrBuf {
    #[inline]
    fn hash(&self, hasher: &mut H) {
        self.as_slice().hash(hasher)
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use container::{Container, Mutable};
    use self::test::Bencher;
    use str::{Str, StrSlice};
    use super::StrBuf;

    #[bench]
    fn bench_with_capacity(b: &mut Bencher) {
        b.iter(|| {
            StrBuf::with_capacity(100)
        });
    }

    #[bench]
    fn bench_push_str(b: &mut Bencher) {
        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
        b.iter(|| {
            let mut r = StrBuf::new();
            r.push_str(s);
        });
    }

    #[test]
    fn test_push_bytes() {
        let mut s = StrBuf::from_str("ABC");
        unsafe {
            s.push_bytes([ 'D' as u8 ]);
        }
        assert_eq!(s.as_slice(), "ABCD");
    }

    #[test]
    fn test_push_str() {
        let mut s = StrBuf::new();
        s.push_str("");
        assert_eq!(s.as_slice().slice_from(0), "");
        s.push_str("abc");
        assert_eq!(s.as_slice().slice_from(0), "abc");
        s.push_str("ประเทศไทย中华Việt Nam");
        assert_eq!(s.as_slice().slice_from(0), "abcประเทศไทย中华Việt Nam");
    }

    #[test]
    fn test_push_char() {
        let mut data = StrBuf::from_str("ประเทศไทย中");
        data.push_char('华');
        data.push_char('b'); // 1 byte
        data.push_char('¢'); // 2 byte
        data.push_char('€'); // 3 byte
        data.push_char('𤭢'); // 4 byte
        assert_eq!(data.as_slice(), "ประเทศไทย中华b¢€𤭢");
    }

    #[test]
    fn test_str_truncate() {
        let mut s = StrBuf::from_str("12345");
        s.truncate(5);
        assert_eq!(s.as_slice(), "12345");
        s.truncate(3);
        assert_eq!(s.as_slice(), "123");
        s.truncate(0);
        assert_eq!(s.as_slice(), "");

        let mut s = StrBuf::from_str("12345");
        let p = s.as_slice().as_ptr();
        s.truncate(3);
        s.push_str("6");
        let p_ = s.as_slice().as_ptr();
        assert_eq!(p_, p);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_invalid_len() {
        let mut s = StrBuf::from_str("12345");
        s.truncate(6);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_split_codepoint() {
        let mut s = StrBuf::from_str("\u00FC"); // ü
        s.truncate(1);
    }

    #[test]
    fn test_str_clear() {
        let mut s = StrBuf::from_str("12345");
        s.clear();
        assert_eq!(s.len(), 0);
        assert_eq!(s.as_slice(), "");
    }
}
<|endoftext|>


<commit_before>use cocoa::appkit::{NSPasteboard, NSPasteboardTypeString};
use cocoa::base::{id, nil};
use cocoa::foundation::{NSArray, NSData, NSFastEnumeration, NSString, NSUInteger};
use std::borrow::Cow;
use std::ffi::CStr;
use {Clipboard, Item, Result};

pub trait ClipboardExt: Clipboard {
    fn clipboard_with_name(&self, name: &str) -> Self;
    fn get_items_nsarray(&self) -> id;
    fn get_raw_clipboard(&self) -> id;
}

#[derive(Debug)]
pub struct CocoaClipboard(id);

impl Clipboard for CocoaClipboard {
    fn get() -> Result<Self> where Self: Sized {
        let pboard = unsafe { NSPasteboard::generalPasteboard(nil) };
        if pboard.is_null() {
            Err(From::from("could not get pasteboard"))
        } else {
            Ok(CocoaClipboard(pboard))
        }
    }

    fn copy(&mut self, item: &Item) -> Result<()> {
        self.copy_items(&[*item])
    }

    fn copy_items(&mut self, items: &[Item]) -> Result<()> {
        let items = items.iter().map(|i| i.native_representation()).collect::<Cow<[_]>>();
        let array = unsafe { NSArray::arrayWithObjects(nil, &items) };
        unsafe {
            self.0.clearContents();
            self.0.writeObjects(array);
        }
        Ok(())
    }

    fn get_paste_text(&self)  -> Result<&str> {
        unsafe {
            let text = NSPasteboard::stringForType(self.0, NSPasteboardTypeString);
            Ok(CStr::from_ptr(text.UTF8String()).to_str().unwrap_or(""))
        }
    }

    fn get_items(&self) -> Cow<[Item]> {
        unsafe {
            self.0.pasteboardItems()
                  .iter()
                  .map(|x| Item::Text(""))
                  .collect()
        }
    }
}

impl ClipboardExt for CocoaClipboard {
    fn clipboard_with_name(&self, name: &str) -> Self {
        unimplemented!();
    }

    fn get_items_nsarray(&self) -> id {
        unimplemented!();
    }

    fn get_raw_clipboard(&self) -> id {
        unimplemented!();
    }
}

impl<'a> Item<'a> {
    fn native_representation(&self) -> id {
        match *self {
            Item::Text(text) => unsafe { NSString::alloc(nil).init_str(text) },
            Item::Image(image) => unsafe {
                let slice = image.bytes();
                let _data = NSData::dataWithBytes_length_(nil,
                                                          slice.as_ptr() as *const _,
                                                          slice.len() as NSUInteger);
                unimplemented!();
            },
            Item::Sound(sound) => {
                unimplemented!();
            }
            _ => nil
        }
    }
}
<commit_msg>Add body for ClipboardExt::get_raw_clipboard on macos<commit_after>use cocoa::appkit::{NSPasteboard, NSPasteboardTypeString};
use cocoa::base::{id, nil};
use cocoa::foundation::{NSArray, NSData, NSFastEnumeration, NSString, NSUInteger};
use std::borrow::Cow;
use std::ffi::CStr;
use {Clipboard, Item, Result};

pub trait ClipboardExt: Clipboard {
    fn clipboard_with_name(&self, name: &str) -> Self;
    fn get_items_nsarray(&self) -> id;
    fn get_raw_clipboard(&self) -> id;
}

#[derive(Debug)]
pub struct CocoaClipboard(id);

impl Clipboard for CocoaClipboard {
    fn get() -> Result<Self> where Self: Sized {
        let pboard = unsafe { NSPasteboard::generalPasteboard(nil) };
        if pboard.is_null() {
            Err(From::from("could not get pasteboard"))
        } else {
            Ok(CocoaClipboard(pboard))
        }
    }

    fn copy(&mut self, item: &Item) -> Result<()> {
        self.copy_items(&[*item])
    }

    fn copy_items(&mut self, items: &[Item]) -> Result<()> {
        let items = items.iter().map(|i| i.native_representation()).collect::<Cow<[_]>>();
        let array = unsafe { NSArray::arrayWithObjects(nil, &items) };
        unsafe {
            self.0.clearContents();
            self.0.writeObjects(array);
        }
        Ok(())
    }

    fn get_paste_text(&self)  -> Result<&str> {
        unsafe {
            let text = NSPasteboard::stringForType(self.0, NSPasteboardTypeString);
            Ok(CStr::from_ptr(text.UTF8String()).to_str().unwrap_or(""))
        }
    }

    fn get_items(&self) -> Cow<[Item]> {
        unsafe {
            self.0.pasteboardItems()
                  .iter()
                  .map(|x| Item::Text(""))
                  .collect()
        }
    }
}

impl ClipboardExt for CocoaClipboard {
    fn clipboard_with_name(&self, name: &str) -> Self {
        unimplemented!();
    }

    fn get_items_nsarray(&self) -> id {
        unimplemented!();
    }

    fn get_raw_clipboard(&self) -> id {
        self.0
    }
}

impl<'a> Item<'a> {
    fn native_representation(&self) -> id {
        match *self {
            Item::Text(text) => unsafe { NSString::alloc(nil).init_str(text) },
            Item::Image(image) => unsafe {
                let slice = image.bytes();
                let _data = NSData::dataWithBytes_length_(nil,
                                                          slice.as_ptr() as *const _,
                                                          slice.len() as NSUInteger);
                unimplemented!();
            },
            Item::Sound(sound) => {
                unimplemented!();
            }
            _ => nil
        }
    }
}
<|endoftext|>


<commit_before>macro_rules! e { ($e:expr) => { $e } }

#[macro_export]
macro_rules! make_matrix {
    ($name: ident, rows: $rows:expr, cols: $cols:expr, $($sub: ident),+) => {
        #[cfg(not(simd))]
        #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
        #[repr(C)]
        pub struct $name<N> {
            $(pub $sub: N),+
        }
        impl_matrix! { $name, $rows, $cols }
        impl_converts! { $name, $cols, $rows }
        impl_index! { $name, $cols}

    }
}

#[cfg(features = "unstable")]
macro_rules! impl_matrix {
    ($name: ident, $rows:expr, $cols:expr) => {
        impl<N> Matrix<N> for $name<N> {
            const fn nrows(&self) -> usize { $rows }
            const fn ncols(&self) -> usize { $cols }
        }
    }
}

#[cfg(not(features = "unstable"))]
macro_rules! impl_matrix {
    ($name: ident, $rows:expr, $cols:expr) => {
        impl<N> Matrix<N> for $name<N> {
            #[inline] fn nrows(&self) -> usize { $rows }
            #[inline] fn ncols(&self) -> usize { $cols }
        }
    }
}

macro_rules! impl_converts {
    ($($m: ident, $c: expr, $r: expr),+) => { $(
        impl<N> convert::AsRef<[[N; $c]; $r]> for $m<N>
        where N: Copy {

            #[inline] fn as_ref(&self) -> &[[N; $c]; $r] {
                unsafe { transmute(self) }
            }
        }
        impl<N> convert::AsMut<[[N; $c]; $c]> for $m<N>
        where N: Copy {

            #[inline] fn as_mut(&mut self) -> &mut [[N; $c]; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<'a, N> convert::From<&'a [[N; $c]; $r]> for &'a $m<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a [[N; $c]; $r]) -> &'a $m<N> {
                unsafe { transmute(a) }
            }
        }
        impl<'a, N> convert::From<&'a mut [[N; $c]; $r]> for &'a mut $m<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a mut [[N; $c]; $r]) -> &'a mut $m<N> {
                unsafe { transmute(a) }
            }
        }
    )+}
}

macro_rules! impl_index {
    ($($m: ident, $c: expr),+) => { $(
        impl<N> ops::Index<(usize, usize)> for $m<N>
        where N: Copy {

            type Output = N;
            #[inline] fn index(&self, (x, y): (usize, usize)) -> &N {
                unsafe {
                    &transmute::<&$m<N>, &[N; $c * $c]>(self)[x + y * $c]
                }
            }
        }

        impl<N> ops::IndexMut<(usize, usize)> for $m<N>
        where N: Copy {

            #[inline] fn index_mut(&mut self, (x, y): (usize, usize))
                                  -> &mut N {
                unsafe {
                    &mut transmute::<&mut $m<N>, &mut [N; $c * $c]>(self)
                        [x + y * $c]
                }
            }
        }

    )+}
}
<commit_msg>[matrix] Add docs to `make_matrix`<commit_after>macro_rules! e { ($e:expr) => { $e } }

/// Macro for constructing a new matrix type.
///
/// This can be used to construct fixed-sized matrices of whatever dimension
/// the user would like. While this crate only provides matrices of dimensons
/// 2 through 5, it's trivial to make matrices of arbitrary length using this
/// macro.
///
/// Another potential use of this macro is to create new matrices whose
/// subscripts have different names than those provided in this crate. The
/// matrices in `lin`  have subscripts where the rows are named _x_`n` and the
/// columns _y_`n` (as in Cartesian coördinates), but in some use cases, they
/// might represent different quantities. Thus, users can use this macro to
/// create new matrix types whose subscripts have names with semantic meanings
/// more appropriate to their individual use case.
///
/// # Arguments
///    - `$name`: The name of the new matrix type
///    - `$rows`: The number of rows in this matrix
///    - `$cols`: The number of columns in this matrix
///    - `$sub`: The name of each subscript or element of the matrix
///              Note that the number of `$sub`s should be equal to `$cols` *  ///              `$rows`.
///
#[macro_export]
macro_rules! make_matrix {
    ($name: ident, rows: $rows:expr, cols: $cols:expr, $($sub: ident),+) => {
        #[cfg(not(simd))]
        #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
        #[repr(C)]
        pub struct $name<N> {
            $(pub $sub: N),+
        }
        impl_matrix! { $name, $rows, $cols }
        impl_converts! { $name, $cols, $rows }
        impl_index! { $name, $cols}

    }
}

#[cfg(features = "unstable")]
macro_rules! impl_matrix {
    ($name: ident, $rows:expr, $cols:expr) => {
        impl<N> Matrix<N> for $name<N> {
            const fn nrows(&self) -> usize { $rows }
            const fn ncols(&self) -> usize { $cols }
        }
    }
}

#[cfg(not(features = "unstable"))]
macro_rules! impl_matrix {
    ($name: ident, $rows:expr, $cols:expr) => {
        impl<N> Matrix<N> for $name<N> {
            #[inline] fn nrows(&self) -> usize { $rows }
            #[inline] fn ncols(&self) -> usize { $cols }
        }
    }
}

macro_rules! impl_converts {
    ($($m: ident, $c: expr, $r: expr),+) => { $(
        impl<N> convert::AsRef<[[N; $c]; $r]> for $m<N>
        where N: Copy {

            #[inline] fn as_ref(&self) -> &[[N; $c]; $r] {
                unsafe { transmute(self) }
            }
        }
        impl<N> convert::AsMut<[[N; $c]; $c]> for $m<N>
        where N: Copy {

            #[inline] fn as_mut(&mut self) -> &mut [[N; $c]; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<'a, N> convert::From<&'a [[N; $c]; $r]> for &'a $m<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a [[N; $c]; $r]) -> &'a $m<N> {
                unsafe { transmute(a) }
            }
        }
        impl<'a, N> convert::From<&'a mut [[N; $c]; $r]> for &'a mut $m<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a mut [[N; $c]; $r]) -> &'a mut $m<N> {
                unsafe { transmute(a) }
            }
        }
    )+}
}

macro_rules! impl_index {
    ($($m: ident, $c: expr),+) => { $(
        impl<N> ops::Index<(usize, usize)> for $m<N>
        where N: Copy {

            type Output = N;
            #[inline] fn index(&self, (x, y): (usize, usize)) -> &N {
                unsafe {
                    &transmute::<&$m<N>, &[N; $c * $c]>(self)[x + y * $c]
                }
            }
        }

        impl<N> ops::IndexMut<(usize, usize)> for $m<N>
        where N: Copy {

            #[inline] fn index_mut(&mut self, (x, y): (usize, usize))
                                  -> &mut N {
                unsafe {
                    &mut transmute::<&mut $m<N>, &mut [N; $c * $c]>(self)
                        [x + y * $c]
                }
            }
        }

    )+}
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

pub use model::TwitchLinks;
pub use model::UrlString;
pub use model::DateString;
pub use model::LocaleString;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Channel {
    #[serde(rename="_links")]
    links: BTreeMap<String, String>,
    #[serde(rename="_id")]
    id: u64,
    name: String,
    display_name: String,
    game: String,
    status: String,
    mature: bool,
    delay: Option<u32>,
    language: LocaleString,
    broadcaster_language: LocaleString,
    created_at: DateString,
    updated_at: DateString,
    logo: UrlString,
    banner: Option<UrlString>,
    video_banner: Option<UrlString>,
    background: Option<UrlString>,
    profile_banner: Option<UrlString>,
    profile_banner_background_color: Option<UrlString>,
    partner: bool,
    url: UrlString,
    views: u32,
    followers: u32,
}

impl TwitchLinks for Channel {
    fn links(&self) -> &BTreeMap<String, String> {
        &self.links
    }
}

impl Channel {
    pub fn link_self(&self) -> &String {
        self.get_expected_link("self")
    }
    pub fn link_follows(&self) -> &String {
        self.get_expected_link("follows")
    }
    pub fn link_commercial(&self) -> &String {
        self.get_expected_link("commercial")
    }
    pub fn link_stream_key(&self) -> &String {
        self.get_expected_link("stream_key")
    }
    pub fn link_chat(&self) -> &String {
        self.get_expected_link("chat")
    }
    pub fn link_features(&self) -> &String {
        self.get_expected_link("features")
    }
    pub fn link_subscriptions(&self) -> &String {
        self.get_expected_link("subscriptions")
    }
    pub fn link_editors(&self) -> &String {
        self.get_expected_link("editors")
    }
    pub fn link_teams(&self) -> &String {
        self.get_expected_link("teams")
    }
    pub fn link_videos(&self) -> &String {
        self.get_expected_link("videos")
    }
    pub fn id(&self) -> u64 {
        self.id
    }
    pub fn name(&self) -> &String {
        &self.name
    }
    pub fn display_name(&self) -> &String {
        &self.display_name
    }
    pub fn game(&self) -> &String {
        &self.game
    }
    pub fn status(&self) -> &String {
        &self.status
    }
    pub fn mature(&self) -> bool {
        self.mature
    }
    pub fn delay(&self) -> Option<u32> {
        self.delay
    }
    pub fn language(&self) -> &LocaleString {
        &self.language
    }
    pub fn broadcaster_language(&self) -> &LocaleString {
        &self.broadcaster_language
    }
    pub fn created_at(&self) -> &DateString {
        &self.created_at
    }
    pub fn updated_at(&self) -> &DateString {
        &self.updated_at
    }
    pub fn logo(&self) -> &UrlString {
        &self.logo
    }
    pub fn banner(&self) -> &Option<UrlString> {
        &self.banner
    }
    pub fn video_banner(&self) -> &Option<UrlString> {
        &self.video_banner
    }
    pub fn background(&self) -> &Option<UrlString> {
        &self.background
    }
    pub fn profile_banner(&self) -> &Option<UrlString> {
        &self.profile_banner
    }
    pub fn profile_banner_background_color(&self) -> &Option<UrlString> {
        &self.profile_banner_background_color
    }
    pub fn partner(&self) -> bool {
        self.partner
    }
    pub fn url(&self) -> &UrlString {
        &self.url
    }
    pub fn views(&self) -> u32 {
        self.views
    }
    pub fn followers(&self) -> u32 {
        self.followers
    }
}
<commit_msg>Fixed channel logo possibly being null<commit_after>use std::collections::BTreeMap;

pub use model::TwitchLinks;
pub use model::UrlString;
pub use model::DateString;
pub use model::LocaleString;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Channel {
    #[serde(rename="_links")]
    links: BTreeMap<String, String>,
    #[serde(rename="_id")]
    id: u64,
    name: String,
    display_name: String,
    game: String,
    status: String,
    mature: bool,
    delay: Option<u32>,
    language: LocaleString,
    broadcaster_language: LocaleString,
    created_at: DateString,
    updated_at: DateString,
    logo: Option<UrlString>,
    banner: Option<UrlString>,
    video_banner: Option<UrlString>,
    background: Option<UrlString>,
    profile_banner: Option<UrlString>,
    profile_banner_background_color: Option<UrlString>,
    partner: bool,
    url: UrlString,
    views: u32,
    followers: u32,
}

impl TwitchLinks for Channel {
    fn links(&self) -> &BTreeMap<String, String> {
        &self.links
    }
}

impl Channel {
    pub fn link_self(&self) -> &String {
        self.get_expected_link("self")
    }
    pub fn link_follows(&self) -> &String {
        self.get_expected_link("follows")
    }
    pub fn link_commercial(&self) -> &String {
        self.get_expected_link("commercial")
    }
    pub fn link_stream_key(&self) -> &String {
        self.get_expected_link("stream_key")
    }
    pub fn link_chat(&self) -> &String {
        self.get_expected_link("chat")
    }
    pub fn link_features(&self) -> &String {
        self.get_expected_link("features")
    }
    pub fn link_subscriptions(&self) -> &String {
        self.get_expected_link("subscriptions")
    }
    pub fn link_editors(&self) -> &String {
        self.get_expected_link("editors")
    }
    pub fn link_teams(&self) -> &String {
        self.get_expected_link("teams")
    }
    pub fn link_videos(&self) -> &String {
        self.get_expected_link("videos")
    }
    pub fn id(&self) -> u64 {
        self.id
    }
    pub fn name(&self) -> &String {
        &self.name
    }
    pub fn display_name(&self) -> &String {
        &self.display_name
    }
    pub fn game(&self) -> &String {
        &self.game
    }
    pub fn status(&self) -> &String {
        &self.status
    }
    pub fn mature(&self) -> bool {
        self.mature
    }
    pub fn delay(&self) -> Option<u32> {
        self.delay
    }
    pub fn language(&self) -> &LocaleString {
        &self.language
    }
    pub fn broadcaster_language(&self) -> &LocaleString {
        &self.broadcaster_language
    }
    pub fn created_at(&self) -> &DateString {
        &self.created_at
    }
    pub fn updated_at(&self) -> &DateString {
        &self.updated_at
    }
    pub fn logo(&self) -> &Option<UrlString> {
        &self.logo
    }
    pub fn banner(&self) -> &Option<UrlString> {
        &self.banner
    }
    pub fn video_banner(&self) -> &Option<UrlString> {
        &self.video_banner
    }
    pub fn background(&self) -> &Option<UrlString> {
        &self.background
    }
    pub fn profile_banner(&self) -> &Option<UrlString> {
        &self.profile_banner
    }
    pub fn profile_banner_background_color(&self) -> &Option<UrlString> {
        &self.profile_banner_background_color
    }
    pub fn partner(&self) -> bool {
        self.partner
    }
    pub fn url(&self) -> &UrlString {
        &self.url
    }
    pub fn views(&self) -> u32 {
        self.views
    }
    pub fn followers(&self) -> u32 {
        self.followers
    }
}
<|endoftext|>


<commit_before>use core::*;

/// A player
pub struct Player {
  pos: Vec2<i64>,
  dir: Dir,
  trans: f64,
  frame: i16,
}

impl Positioned for Player {
  fn get_pos(&self) -> Vec2<i64> {
    self.pos
  }
  fn set_pos(&mut self, new_pos: Vec2<i64>) {
    self.pos = new_pos;
  }
}

impl Movable for Player {
  fn get_dir(&self) -> Dir {
    self.dir
  }
  fn set_dir(&mut self, new_dir: Dir) {
    self.dir = new_dir;
  }
}

impl Animated for Player {
  fn get_trans_state(&self) -> f64 {
    self.trans
  }
  fn get_animation_frame(&self) -> i16 {
    self.frame
  }
}

impl Sprited for Player {
  fn get_sprite(&self) -> &Texture {
    // TODO: Sprite here
  }
  fn get_width(&self) -> i16 {
    1
  }
  fn get_height(&self) -> i16 {
    1
  }
  fn get_opacity(&self) -> f64 {
    1.0
  }
}

impl Entity for Player {
  fn ID(&self) -> ID {
    ID(0) // NOTE: Player's ID is always 0
  }
  fn is_solid(&self, x: i16, y: i16) -> bool {
    false // TODO: Should it be solid?
  }
}
<commit_msg>Add unimplemented! macro<commit_after>use core::*;

/// A player
pub struct Player {
  pos: Vec2<i64>,
  dir: Dir,
  trans: f64,
  frame: i16,
}

impl Positioned for Player {
  fn get_pos(&self) -> Vec2<i64> {
    self.pos
  }
  fn set_pos(&mut self, new_pos: Vec2<i64>) {
    self.pos = new_pos;
  }
}

impl Movable for Player {
  fn get_dir(&self) -> Dir {
    self.dir
  }
  fn set_dir(&mut self, new_dir: Dir) {
    self.dir = new_dir;
  }
}

impl Animated for Player {
  fn get_trans_state(&self) -> f64 {
    self.trans
  }
  fn get_animation_frame(&self) -> i16 {
    self.frame
  }
}

impl Sprited for Player {
  fn get_sprite(&self) -> &Texture {
    unimplemented!();
    // TODO: Sprite here
  }
  fn get_width(&self) -> i16 {
    1
  }
  fn get_height(&self) -> i16 {
    1
  }
  fn get_opacity(&self) -> f64 {
    1.0
  }
}

impl Entity for Player {
  fn ID(&self) -> ID {
    ID(0) // NOTE: Player's ID is always 0
  }
  fn is_solid(&self, x: i16, y: i16) -> bool {
    false // TODO: Should it be solid?
  }
}
<|endoftext|>


<commit_before>/* io::mod.rs */

use core::mem::volatile_store;
use kernel::sgash;

mod font;

/* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/BBABEGGE.html */
pub static UART0: *mut u32 = 0x101f1000 as *mut u32;

pub static UART0_IMSC: *mut u32 = (0x101f1000 + 0x038) as *mut u32;
#[allow(dead_code)]
pub static VIC_INTENABLE: *mut u32 = (0x10140000 + 0x010) as *mut u32;

pub static mut CURSOR_X: u32 = 0;
pub static mut CURSOR_Y: u32 = 0;
pub static CURSOR_HEIGHT: u32 = 16;
pub static CURSOR_WIDTH: u32 = 8;
pub static mut CURSOR_COLOR: u32 = 0x000000FF;
pub static mut FG_COLOR: u32 = 0x00FFFFFF;
pub static mut BG_COLOR: u32 = 0xF0000000;
pub static mut CURSOR_BUFFER: [u32, ..8*16] = [0x00FF0000, ..8*16];
pub static mut SAVE_X: u32 = 0;
pub static mut SAVE_Y: u32 = 0;
pub static START_ADDR: u32 = 1024*1024;
pub static mut SCREEN_WIDTH: u32 = 0;
pub static mut SCREEN_HEIGHT: u32 = 0;

pub unsafe fn init(width: u32, height: u32)
{
    SCREEN_WIDTH = width;
    SCREEN_HEIGHT= height;
    sgash::init();

    /* For the following magic values, see
     * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/CACHEDGD.html
     */

    // 800x600
    // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/CACCCFBF.html
    if (SCREEN_WIDTH == 800 && SCREEN_HEIGHT == 600)
    {
    	ws(0x10000010, 0x2CAC);
    	ws(0x10120000, 0x1313A4C4);
    	ws(0x10120004, 0x0505F657);
    	ws(0x10120008, 0x071F1800);

	/* See http://forum.osdev.org/viewtopic.php?p=195000 */
	ws(0x10120010, START_ADDR);

	/* See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0161e/I911024.html */
	ws(0x10120018, 0x82B);
    }

    // 640x480
    // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/CACCCFBF.html
    else if (SCREEN_WIDTH == 640 && SCREEN_HEIGHT == 480)
    {
	ws(0x10000010, 0x2C77);
	ws(0x10120000, 0x3F1F3F9C);
	ws(0x10120004, 0x090B61DF);
	ws(0x10120008, 0x067F1800);

	/* See http://forum.osdev.org/viewtopic.php?p=195000 */
	ws(0x10120010, START_ADDR);

	/* See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0161e/I911024.html */
	ws(0x10120018, 0x82B);

    }
    set_bg(0x222C38);
    set_fg(0xFAFCFF);
    set_cursor_color(0xFAFCFF);
    fill_bg();
    sgash::drawstr(&"sgash> ");
    draw_cursor();
}

pub unsafe fn write_char(c: char, address: *mut u32) {
    volatile_store(address, c as u32);
}

pub unsafe fn scrollup()
{
    let mut i = CURSOR_HEIGHT*SCREEN_WIDTH;
    while i < (SCREEN_WIDTH*SCREEN_HEIGHT)
    {
	*((START_ADDR + ((i-16*SCREEN_WIDTH)*4)) as *mut u32) = *((START_ADDR+(i*4)) as *u32);
	i += 1;
    }
    i = 4*(SCREEN_WIDTH*SCREEN_HEIGHT - CURSOR_HEIGHT*SCREEN_WIDTH);
    while i < 4*SCREEN_WIDTH*SCREEN_HEIGHT
    {
	*((START_ADDR + (i as u32)) as *mut u32) = BG_COLOR;
	i += 4;
    }
    CURSOR_X = 0x0u32;
    CURSOR_Y -= CURSOR_HEIGHT;
}
pub unsafe fn draw_char(c: char)
{
    if CURSOR_X+(SCREEN_WIDTH*CURSOR_Y) >= SCREEN_WIDTH*SCREEN_HEIGHT
    {
	scrollup();
    }
    let font_offset = (c as u8) - 0x20;
    let map = font::bitmaps[font_offset];

    let mut i = -1;
    let mut j = 0;
    let mut addr = START_ADDR + 4*(CURSOR_X + CURSOR_WIDTH + 1 + SCREEN_WIDTH*CURSOR_Y);
    while j < CURSOR_HEIGHT
    {
	while i < CURSOR_WIDTH
	{
	    //let addr = START_ADDR + 4*(CURSOR_X + CURSOR_WIDTH - i + SCREEN_WIDTH*(CURSOR_Y + j));
	    //let addr = START_ADDR + 4*(CURSOR_X + CURSOR_WIDTH + SCREEN_WIDTH*CURSOR_Y) - 4*i + 4*SCREEN_WIDTH*j
	    if ((map[j] >> 4*i) & 1) == 1
	    {
		*(addr as *mut u32) = FG_COLOR;
	    }
	    else
	    {
		*(addr as *mut u32) = BG_COLOR;
	    }

	    addr-= 4;
	    i += 1;
	}
	addr += 4*(i+SCREEN_WIDTH);
	i = 0;
	j += 1;
    }
}

pub unsafe fn backup()
{
    let mut i = 0;
    let mut j = 0;
    while j < CURSOR_HEIGHT
    {
	while i < CURSOR_WIDTH
	{
	    let addr = START_ADDR + 4*(CURSOR_X + i + SCREEN_WIDTH*(CURSOR_Y + j));
	    CURSOR_BUFFER[i + j*8] = *(addr as *mut u32);
	    i += 1;
	}
	i = 0;
	j += 1;
    }
    SAVE_X = CURSOR_X;
    SAVE_Y = CURSOR_Y;
}

pub unsafe fn restore()
{
    let mut i = 0;
    let mut j = 0;
    while j < CURSOR_HEIGHT
    {
	while i < CURSOR_WIDTH
	{
	    let addr = START_ADDR + 4*(SAVE_X + i + SCREEN_WIDTH*(SAVE_Y + j));
	    *(addr as *mut u32) = CURSOR_BUFFER[i + j*8];
	    i += 1;
	}
	i = 0;
	j += 1;
    }
}

pub unsafe fn draw_cursor()
{

    let mut i = 0;
    let mut j = 0;

    while j < CURSOR_HEIGHT
    {
	while i < CURSOR_WIDTH
	{
	    let addr = START_ADDR + 4*(CURSOR_X + i + SCREEN_WIDTH*(CURSOR_Y + j));
	    *(addr as *mut u32) = CURSOR_COLOR;
	    i += 1;
	}
	i = 0;
	j += 1;
    }

}

pub unsafe fn paint(color: u32)
{
    let mut i = 0;
    while i < SCREEN_WIDTH*SCREEN_HEIGHT
    {
	*((START_ADDR as u32 + i*4) as *mut u32) = color;
	i+=1;
    }
}

pub unsafe fn fill_bg()
{
    paint(BG_COLOR);
}

#[allow(dead_code)]
pub unsafe fn read(addr: u32)	->	u32
{
    *(addr as *mut u32)
}

pub unsafe fn ws(addr: u32, value: u32)
{
    *(addr as *mut u32) = *(addr as *mut u32) | value;
}

#[allow(dead_code)]
pub unsafe fn wh(addr: u32, value: u32)
{
    *(addr as *mut u32) = value;
}

pub unsafe fn set_fg(color: u32)
{
    FG_COLOR = color;
}

pub unsafe fn set_bg(color: u32)
{
    BG_COLOR = color;
}

pub unsafe fn set_cursor_color(color: u32)
{
    CURSOR_COLOR = color;
}
<commit_msg>Retabbed<commit_after>/* io::mod.rs */

use core::mem::volatile_store;
use kernel::sgash;

mod font;

/* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/BBABEGGE.html */
pub static UART0: *mut u32 = 0x101f1000 as *mut u32;

pub static UART0_IMSC: *mut u32 = (0x101f1000 + 0x038) as *mut u32;
#[allow(dead_code)]
pub static VIC_INTENABLE: *mut u32 = (0x10140000 + 0x010) as *mut u32;

pub static mut CURSOR_X: u32 = 0;
pub static mut CURSOR_Y: u32 = 0;
pub static CURSOR_HEIGHT: u32 = 16;
pub static CURSOR_WIDTH: u32 = 8;
pub static mut CURSOR_COLOR: u32 = 0x000000FF;
pub static mut FG_COLOR: u32 = 0x00FFFFFF;
pub static mut BG_COLOR: u32 = 0xF0000000;
pub static mut CURSOR_BUFFER: [u32, ..8*16] = [0x00FF0000, ..8*16];
pub static mut SAVE_X: u32 = 0;
pub static mut SAVE_Y: u32 = 0;
pub static START_ADDR: u32 = 1024*1024;
pub static mut SCREEN_WIDTH: u32 = 0;
pub static mut SCREEN_HEIGHT: u32 = 0;

pub unsafe fn init(width: u32, height: u32)
{
	SCREEN_WIDTH = width;
	SCREEN_HEIGHT= height;
	sgash::init();

	/* For the following magic values, see
	 * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/CACHEDGD.html
	 */

	// 800x600
	// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/CACCCFBF.html
	if (SCREEN_WIDTH == 800 && SCREEN_HEIGHT == 600)
	{
		ws(0x10000010, 0x2CAC);
		ws(0x10120000, 0x1313A4C4);
		ws(0x10120004, 0x0505F657);
		ws(0x10120008, 0x071F1800);

	/* See http://forum.osdev.org/viewtopic.php?p=195000 */
	ws(0x10120010, START_ADDR);

	/* See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0161e/I911024.html */
	ws(0x10120018, 0x82B);
	}

	// 640x480
	// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/CACCCFBF.html
	else if (SCREEN_WIDTH == 640 && SCREEN_HEIGHT == 480)
	{
	ws(0x10000010, 0x2C77);
	ws(0x10120000, 0x3F1F3F9C);
	ws(0x10120004, 0x090B61DF);
	ws(0x10120008, 0x067F1800);

	/* See http://forum.osdev.org/viewtopic.php?p=195000 */
	ws(0x10120010, START_ADDR);

	/* See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0161e/I911024.html */
	ws(0x10120018, 0x82B);

	}
	set_bg(0x222C38);
	set_fg(0xFAFCFF);
	set_cursor_color(0xFAFCFF);
	fill_bg();
	sgash::drawstr(&"sgash> ");
	draw_cursor();
}

pub unsafe fn write_char(c: char, address: *mut u32) {
	volatile_store(address, c as u32);
}

pub unsafe fn scrollup()
{
	let mut i = CURSOR_HEIGHT*SCREEN_WIDTH;
	while i < (SCREEN_WIDTH*SCREEN_HEIGHT)
	{
	*((START_ADDR + ((i-16*SCREEN_WIDTH)*4)) as *mut u32) = *((START_ADDR+(i*4)) as *u32);
	i += 1;
	}
	i = 4*(SCREEN_WIDTH*SCREEN_HEIGHT - CURSOR_HEIGHT*SCREEN_WIDTH);
	while i < 4*SCREEN_WIDTH*SCREEN_HEIGHT
	{
	*((START_ADDR + (i as u32)) as *mut u32) = BG_COLOR;
	i += 4;
	}
	CURSOR_X = 0x0u32;
	CURSOR_Y -= CURSOR_HEIGHT;
}
pub unsafe fn draw_char(c: char)
{
	if CURSOR_X+(SCREEN_WIDTH*CURSOR_Y) >= SCREEN_WIDTH*SCREEN_HEIGHT
	{
	scrollup();
	}
	let font_offset = (c as u8) - 0x20;
	let map = font::bitmaps[font_offset];

	let mut i = -1;
	let mut j = 0;
	let mut addr = START_ADDR + 4*(CURSOR_X + CURSOR_WIDTH + 1 + SCREEN_WIDTH*CURSOR_Y);
	while j < CURSOR_HEIGHT
	{
	while i < CURSOR_WIDTH
	{
		//let addr = START_ADDR + 4*(CURSOR_X + CURSOR_WIDTH - i + SCREEN_WIDTH*(CURSOR_Y + j));
		//let addr = START_ADDR + 4*(CURSOR_X + CURSOR_WIDTH + SCREEN_WIDTH*CURSOR_Y) - 4*i + 4*SCREEN_WIDTH*j
		if ((map[j] >> 4*i) & 1) == 1
		{
		*(addr as *mut u32) = FG_COLOR;
		}
		else
		{
		*(addr as *mut u32) = BG_COLOR;
		}

		addr-= 4;
		i += 1;
	}
	addr += 4*(i+SCREEN_WIDTH);
	i = 0;
	j += 1;
	}
}

pub unsafe fn backup()
{
	let mut i = 0;
	let mut j = 0;
	while j < CURSOR_HEIGHT
	{
	while i < CURSOR_WIDTH
	{
		let addr = START_ADDR + 4*(CURSOR_X + i + SCREEN_WIDTH*(CURSOR_Y + j));
		CURSOR_BUFFER[i + j*8] = *(addr as *mut u32);
		i += 1;
	}
	i = 0;
	j += 1;
	}
	SAVE_X = CURSOR_X;
	SAVE_Y = CURSOR_Y;
}

pub unsafe fn restore()
{
	let mut i = 0;
	let mut j = 0;
	while j < CURSOR_HEIGHT
	{
	while i < CURSOR_WIDTH
	{
		let addr = START_ADDR + 4*(SAVE_X + i + SCREEN_WIDTH*(SAVE_Y + j));
		*(addr as *mut u32) = CURSOR_BUFFER[i + j*8];
		i += 1;
	}
	i = 0;
	j += 1;
	}
}

pub unsafe fn draw_cursor()
{

	let mut i = 0;
	let mut j = 0;

	while j < CURSOR_HEIGHT
	{
	while i < CURSOR_WIDTH
	{
		let addr = START_ADDR + 4*(CURSOR_X + i + SCREEN_WIDTH*(CURSOR_Y + j));
		*(addr as *mut u32) = CURSOR_COLOR;
		i += 1;
	}
	i = 0;
	j += 1;
	}

}

pub unsafe fn paint(color: u32)
{
	let mut i = 0;
	while i < SCREEN_WIDTH*SCREEN_HEIGHT
	{
	*((START_ADDR as u32 + i*4) as *mut u32) = color;
	i+=1;
	}
}

pub unsafe fn fill_bg()
{
	paint(BG_COLOR);
}

#[allow(dead_code)]
pub unsafe fn read(addr: u32)	->	u32
{
	*(addr as *mut u32)
}

pub unsafe fn ws(addr: u32, value: u32)
{
	*(addr as *mut u32) = *(addr as *mut u32) | value;
}

#[allow(dead_code)]
pub unsafe fn wh(addr: u32, value: u32)
{
	*(addr as *mut u32) = value;
}

pub unsafe fn set_fg(color: u32)
{
	FG_COLOR = color;
}

pub unsafe fn set_bg(color: u32)
{
	BG_COLOR = color;
}

pub unsafe fn set_cursor_color(color: u32)
{
	CURSOR_COLOR = color;
}
<|endoftext|>