<commit_before>// Copyright (c) 2006-2009 Graydon Hoare
// Copyright (c) 2009-2013 Mozilla Foundation

// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//
// zero.rs
//
// Minimal definitions of the core primitives in Rust. Include this file with
// your project to create a freestanding Rust program that can run on bare
// metal.
//

#[allow(ctypes)];

// Built-in traits

#[lang="copy"]
pub trait Copy {}

#[lang="owned"]
pub trait Owned {}

#[lang="freeze"]
pub trait Freeze {}

#[lang="opaque"]
pub enum Opaque {}

#[lang="ty_desc"]
pub struct TyDesc;

#[lang="ty_visitor"]
pub trait TyVisitor {}

#[lang="closure_exchange_malloc"]
pub trait ClosureExchangeMalloc {}

#[lang="send"]
pub trait Send {}

#[lang="sized"]
pub trait Sized {}

#[lang="drop"]
pub trait Drop {
    fn finalize(&self);
}

// Operator overloading

#[lang="eq"]
pub trait Eq {
    fn eq(&self, other: &Self) -> bool;
    fn ne(&self, other: &Self) -> bool;
}

#[lang="ord"]
pub trait Ord {
    fn lt(&self, other: &Self) -> bool;
    fn le(&self, other: &Self) -> bool;
    fn ge(&self, other: &Self) -> bool;
    fn gt(&self, other: &Self) -> bool;
}

#[lang="add"]
pub trait Add<Rhs,Result> {
    fn add(&self, rhs: &Rhs) -> Result;
}

#[lang="sub"]
pub trait Sub<Rhs,Result> {
    fn sub(&self, rhs: &Rhs) -> Result;
}

#[lang="mul"]
pub trait Mul<Rhs,Result> {
    fn mul(&self, rhs: &Rhs) -> Result;
}

#[lang="div"]
pub trait Div<Rhs,Result> {
    fn div(&self, rhs: &Rhs) -> Result;
}

#[lang="rem"]
pub trait Rem<Rhs,Result> {
    fn rem(&self, rhs: &Rhs) -> Result;
}

#[lang="neg"]
pub trait Neg<Rhs,Result> {
    fn neg(&self) -> Result;
}

#[lang="not"]
pub trait Not<Rhs,Result> {
    fn not(&self) -> Result;
}

#[lang="bitand"]
pub trait BitAnd<Rhs,Result> {
    fn bitand(&self, rhs: &Rhs) -> Result;
}

#[lang="bitor"]
pub trait BitOr<Rhs,Result> {
    fn bitor(&self, rhs: &Rhs) -> Result;
}

#[lang="bitxor"]
pub trait BitXor<Rhs,Result> {
    fn bitxor(&self, rhs: &Rhs) -> Result;
}

#[lang="shl"]
pub trait Shl<Rhs,Result> {
    fn shl(&self, rhs: &Rhs) -> Result;
}

#[lang="shr"]
pub trait Shr<Rhs,Result> {
    fn shr(&self, rhs: &Rhs) -> Result;
}

#[lang="index"]
pub trait Index<Index,Result> {
    fn index(&self, rhs: &Index) -> Result;
}

// String utilities

#[lang="str_eq"]
pub fn str_eq(a: &str, b: &str) -> bool {
    unsafe {
        let (aptr, alen): (*u8, uint) = transmute(a);
        let (bptr, blen): (*u8, uint) = transmute(b);
        if alen != blen {
            return false
        }
        memcmp(aptr, bptr, alen - 1) == 0
    }
}

// FIXME(pcwalton): This function is legacy junk.
#[lang="uniq_str_eq"]
pub fn uniq_str_eq(a: &~str, b: &~str) -> bool {
    str_eq(*a, *b)
}

struct StringRepr {
    fill: uint,
    alloc: uint,
}

// FIXME(pcwalton): This function should not be necessary, I don't think.
#[lang="strdup_uniq"]
pub unsafe fn strdup_uniq(ptr: *u8, len: uint) -> ~str {
    let size = size_of::<StringRepr>() + len + 1;
    let string: *mut StringRepr = transmute(exchange_malloc(transmute(0),
                                                            size));
    (*string).fill = len + 1;
    (*string).alloc = len + 1;

    let mut data_ptr: uint = transmute(string);
    data_ptr += size_of::<StringRepr>();
    let data_ptr: *mut u8 = transmute(data_ptr);
    memcpy(data_ptr, ptr, len + 1);

    transmute(string)
}

// Legacy junk

#[lang="log_type"]
pub fn log_type<T>(_: u32, _: &T) {
    // FIXME: This function should not be a lang item.
}

#[lang="annihilate"]
pub unsafe fn annihilate() {}

// Failure

#[lang="fail_"]
pub fn fail(_: *i8, _: *i8, _: uint) -> ! {
    unsafe {
        abort()
    }
}

#[lang="fail_bounds_check"]
pub fn fail_bounds_check(_: *i8, _: uint, _: uint, _: uint) {
    unsafe {
        abort()
    }
}

// Memory allocation

// FIXME: So grotesquely inefficient.
struct Header {
    minus_one: uint,    // Must be -1.
    type_desc: *i8,
    null_0: uint,       // Must be null.
    null_1: uint,       // Must be null.
}

// FIXME: This is horrendously inefficient.
#[lang="exchange_malloc"]
pub unsafe fn exchange_malloc(type_desc: *i8, size: uint) -> *i8 {
    let alloc: *mut Header = transmute(malloc(size_of::<Header>() + size));
    (*alloc).minus_one = -1;
    (*alloc).type_desc = type_desc;
    (*alloc).null_0 = 0;
    (*alloc).null_1 = 0;
    transmute(alloc)
}

#[lang="exchange_free"]
pub unsafe fn exchange_free(alloc: *i8) {
    free(transmute(alloc))
}

// Entry point

// TODO(pcwalton): Stash argc and argv somewhere. Probably needs to wait on
// global variables.
#[lang="start"]
pub fn start(main: *u8, _: int, _: **i8, _: *u8) -> int {
    unsafe {
        let main: extern "Rust" fn() = transmute(main);
        main();
        0
    }
}

// The nonexistent garbage collector

#[lang="malloc"]
pub unsafe fn gc_malloc(_: *i8, _: uint) -> *i8 {
    abort()
}

#[lang="free"]
pub unsafe fn gc_free(_: *i8) {
    abort()
}

#[lang="borrow_as_imm"]
pub unsafe fn borrow_as_imm(_: *u8, _: *i8, _: uint) -> uint {
    abort()
}

#[lang="borrow_as_mut"]
pub unsafe fn borrow_as_mut(_: *u8, _: *i8, _: uint) -> uint {
    abort()
}

#[lang="record_borrow"]
pub unsafe fn record_borrow(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="unrecord_borrow"]
pub unsafe fn unrecord_borrow(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="return_to_mut"]
pub unsafe fn return_to_mut(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="check_not_borrowed"]
pub unsafe fn check_not_borrowed(_: *u8, _: *i8, _: uint) {
    abort()
}

// libc dependencies

extern {
    #[fast_ffi]
    pub fn malloc(size: uint) -> *u8;
    #[fast_ffi]
    pub fn free(ptr: *u8);
    #[fast_ffi]
    pub fn abort() -> !;
    #[fast_ffi]
    pub fn memcpy(dest: *mut u8, src: *u8, size: uint) -> *u8;
    #[fast_ffi]
    pub fn memcmp(a: *u8, b: *u8, size: uint) -> i32;
}

// Rust intrinsic dependencies

extern "rust-intrinsic" {
    pub fn transmute<T,U>(val: T) -> U;
    pub fn size_of<T>() -> uint;
}

<commit_msg>Add fixed_stack_segment to function that use unsafe functions<commit_after>// Copyright (c) 2006-2009 Graydon Hoare
// Copyright (c) 2009-2013 Mozilla Foundation

// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//
// zero.rs
//
// Minimal definitions of the core primitives in Rust. Include this file with
// your project to create a freestanding Rust program that can run on bare
// metal.
//

#[allow(ctypes)];

// Built-in traits

#[lang="copy"]
pub trait Copy {}

#[lang="owned"]
pub trait Owned {}

#[lang="freeze"]
pub trait Freeze {}

#[lang="opaque"]
pub enum Opaque {}

#[lang="ty_desc"]
pub struct TyDesc;

#[lang="ty_visitor"]
pub trait TyVisitor {}

#[lang="closure_exchange_malloc"]
pub trait ClosureExchangeMalloc {}

#[lang="send"]
pub trait Send {}

#[lang="sized"]
pub trait Sized {}

#[lang="drop"]
pub trait Drop {
    fn finalize(&self);
}

// Operator overloading

#[lang="eq"]
pub trait Eq {
    fn eq(&self, other: &Self) -> bool;
    fn ne(&self, other: &Self) -> bool;
}

#[lang="ord"]
pub trait Ord {
    fn lt(&self, other: &Self) -> bool;
    fn le(&self, other: &Self) -> bool;
    fn ge(&self, other: &Self) -> bool;
    fn gt(&self, other: &Self) -> bool;
}

#[lang="add"]
pub trait Add<Rhs,Result> {
    fn add(&self, rhs: &Rhs) -> Result;
}

#[lang="sub"]
pub trait Sub<Rhs,Result> {
    fn sub(&self, rhs: &Rhs) -> Result;
}

#[lang="mul"]
pub trait Mul<Rhs,Result> {
    fn mul(&self, rhs: &Rhs) -> Result;
}

#[lang="div"]
pub trait Div<Rhs,Result> {
    fn div(&self, rhs: &Rhs) -> Result;
}

#[lang="rem"]
pub trait Rem<Rhs,Result> {
    fn rem(&self, rhs: &Rhs) -> Result;
}

#[lang="neg"]
pub trait Neg<Rhs,Result> {
    fn neg(&self) -> Result;
}

#[lang="not"]
pub trait Not<Rhs,Result> {
    fn not(&self) -> Result;
}

#[lang="bitand"]
pub trait BitAnd<Rhs,Result> {
    fn bitand(&self, rhs: &Rhs) -> Result;
}

#[lang="bitor"]
pub trait BitOr<Rhs,Result> {
    fn bitor(&self, rhs: &Rhs) -> Result;
}

#[lang="bitxor"]
pub trait BitXor<Rhs,Result> {
    fn bitxor(&self, rhs: &Rhs) -> Result;
}

#[lang="shl"]
pub trait Shl<Rhs,Result> {
    fn shl(&self, rhs: &Rhs) -> Result;
}

#[lang="shr"]
pub trait Shr<Rhs,Result> {
    fn shr(&self, rhs: &Rhs) -> Result;
}

#[lang="index"]
pub trait Index<Index,Result> {
    fn index(&self, rhs: &Index) -> Result;
}

// String utilities

#[lang="str_eq"]
#[fixed_stack_segment]
pub fn str_eq(a: &str, b: &str) -> bool {
    unsafe {
        let (aptr, alen): (*u8, uint) = transmute(a);
        let (bptr, blen): (*u8, uint) = transmute(b);
        if alen != blen {
            return false
        }
        memcmp(aptr, bptr, alen - 1) == 0
    }
}

// FIXME(pcwalton): This function is legacy junk.
#[lang="uniq_str_eq"]
pub fn uniq_str_eq(a: &~str, b: &~str) -> bool {
    str_eq(*a, *b)
}

struct StringRepr {
    fill: uint,
    alloc: uint,
}

// FIXME(pcwalton): This function should not be necessary, I don't think.
#[lang="strdup_uniq"]
#[fixed_stack_segment]
pub unsafe fn strdup_uniq(ptr: *u8, len: uint) -> ~str {
    let size = size_of::<StringRepr>() + len + 1;
    let string: *mut StringRepr = transmute(exchange_malloc(transmute(0),
                                                            size));
    (*string).fill = len + 1;
    (*string).alloc = len + 1;

    let mut data_ptr: uint = transmute(string);
    data_ptr += size_of::<StringRepr>();
    let data_ptr: *mut u8 = transmute(data_ptr);
    memcpy(data_ptr, ptr, len + 1);

    transmute(string)
}

// Legacy junk

#[lang="log_type"]
pub fn log_type<T>(_: u32, _: &T) {
    // FIXME: This function should not be a lang item.
}

#[lang="annihilate"]
pub unsafe fn annihilate() {}

// Failure

#[lang="fail_"]
#[fixed_stack_segment]
pub fn fail(_: *i8, _: *i8, _: uint) -> ! {
    unsafe {
        abort()
    }
}

#[lang="fail_bounds_check"]
#[fixed_stack_segment]
pub fn fail_bounds_check(_: *i8, _: uint, _: uint, _: uint) {
    unsafe {
        abort()
    }
}

// Memory allocation

// FIXME: So grotesquely inefficient.
struct Header {
    minus_one: uint,    // Must be -1.
    type_desc: *i8,
    null_0: uint,       // Must be null.
    null_1: uint,       // Must be null.
}

// FIXME: This is horrendously inefficient.
#[lang="exchange_malloc"]
#[fixed_stack_segment]
pub unsafe fn exchange_malloc(type_desc: *i8, size: uint) -> *i8 {
    let alloc: *mut Header = transmute(malloc(size_of::<Header>() + size));
    (*alloc).minus_one = -1;
    (*alloc).type_desc = type_desc;
    (*alloc).null_0 = 0;
    (*alloc).null_1 = 0;
    transmute(alloc)
}

#[lang="exchange_free"]
#[fixed_stack_segment]
pub unsafe fn exchange_free(alloc: *i8) {
    free(transmute(alloc))
}

// Entry point

// TODO(pcwalton): Stash argc and argv somewhere. Probably needs to wait on
// global variables.
#[lang="start"]
pub fn start(main: *u8, _: int, _: **i8, _: *u8) -> int {
    unsafe {
        let main: extern "Rust" fn() = transmute(main);
        main();
        0
    }
}

// The nonexistent garbage collector

#[lang="malloc"]
#[fixed_stack_segment]
pub unsafe fn gc_malloc(_: *i8, _: uint) -> *i8 {
    abort()
}

#[lang="free"]
#[fixed_stack_segment]
pub unsafe fn gc_free(_: *i8) {
    abort()
}

#[lang="borrow_as_imm"]
#[fixed_stack_segment]
pub unsafe fn borrow_as_imm(_: *u8, _: *i8, _: uint) -> uint {
    abort()
}

#[lang="borrow_as_mut"]
#[fixed_stack_segment]
pub unsafe fn borrow_as_mut(_: *u8, _: *i8, _: uint) -> uint {
    abort()
}

#[lang="record_borrow"]
#[fixed_stack_segment]
pub unsafe fn record_borrow(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="unrecord_borrow"]
#[fixed_stack_segment]
pub unsafe fn unrecord_borrow(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="return_to_mut"]
#[fixed_stack_segment]
pub unsafe fn return_to_mut(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="check_not_borrowed"]
#[fixed_stack_segment]
pub unsafe fn check_not_borrowed(_: *u8, _: *i8, _: uint) {
    abort()
}

// libc dependencies

extern {
    #[fast_ffi]
    pub fn malloc(size: uint) -> *u8;
    #[fast_ffi]
    pub fn free(ptr: *u8);
    #[fast_ffi]
    pub fn abort() -> !;
    #[fast_ffi]
    pub fn memcpy(dest: *mut u8, src: *u8, size: uint) -> *u8;
    #[fast_ffi]
    pub fn memcmp(a: *u8, b: *u8, size: uint) -> i32;
}

// Rust intrinsic dependencies

extern "rust-intrinsic" {
    pub fn transmute<T,U>(val: T) -> U;
    pub fn size_of<T>() -> uint;
}

<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use ComponentExt;

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::{metadata, read_dir, File};
use std::io::Read;
use std::path::{Path, PathBuf};

/// More information can be found at [kernel.org][k].
///
/// Note: these may not be present on virtual Linux systems, such as **Docker**
/// or **Windows Subsystem for Linux**. These hosts do not expose this information
/// and therefore `Component` elements may be missing or not as expected.
///
/// [k]: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
pub struct Component {
    temperature: f32,
    max: f32,
    critical: Option<f32>,
    label: String,
    input_file: PathBuf,
}

fn get_file_line(file: &Path, capacity: usize) -> Option<String> {
    let mut reader = String::with_capacity(capacity);
    if let Ok(mut f) = File::open(file) {
        if f.read_to_string(&mut reader).is_ok() {
            Some(reader)
        } else {
            None
        }
    } else {
        None
    }
}

fn is_file<T: AsRef<Path>>(path: T) -> bool {
    metadata(path)
        .ok()
        .map(|m| m.is_file())
        .unwrap_or_else(|| false)
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings: HashMap<u32, Vec<String>> = HashMap::with_capacity(10);

    if let Ok(dir) = read_dir(folder) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("temp")
                {
                    continue;
                }
                if let Some(entry) = entry.file_name() {
                    if let Some(entry) = entry.to_str() {
                        let mut parts = entry.split('_');
                        if let Some(Some(id)) = parts.next().map(|s| s[4..].parse::<u32>().ok()) {
                            matchings
                                .entry(id)
                                .or_insert_with(|| Vec::with_capacity(5))
                                .push(
                                    parts
                                        .next()
                                        .map(|s| format!("_{}", s))
                                        .unwrap_or_else(String::new),
                                );
                        }
                    }
                }
            }
        }
        for (key, val) in &matchings {
            let mut found_input = None;
            let mut found_label = None;
            for (pos, v) in val.iter().enumerate() {
                match v.as_str() {
                    // raspberry has empty string for temperature input
                    "_input" | "" => {
                        found_input = Some(pos);
                    }
                    "_label" => {
                        found_label = Some(pos);
                    }
                    _ => {}
                }
            }
            if let (Some(_), Some(found_input)) = (found_label, found_input) {
                let mut p_label = folder.to_path_buf();
                let mut p_input = folder.to_path_buf();
                let mut p_crit = folder.to_path_buf();
                let mut p_max = folder.to_path_buf();

                p_label.push(&format!("temp{}_label", key));
                p_input.push(&format!("temp{}{}", key, val[found_input]));
                p_max.push(&format!("temp{}_max", key));
                p_crit.push(&format!("temp{}_crit", key));
                if is_file(&p_input) {
                    let label = get_file_line(p_label.as_path(), 10)
                        .unwrap_or_else(|| format!("Component {}", key)) // needed for raspberry pi
                        .replace("\n", "");
                    let max = if let Some(max) = get_file_line(p_max.as_path(), 10) {
                        Some(max.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    let crit = if let Some(crit) = get_file_line(p_crit.as_path(), 10) {
                        Some(crit.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    components.push(Component::new(label, p_input.as_path(), max, crit));
                }
            }
        }
    }
}

impl Component {
    /// Creates a new component with the given information.
    pub(crate) fn new(
        label: String,
        input_path: &Path,
        max: Option<f32>,
        critical: Option<f32>,
    ) -> Component {
        let mut c = Component {
            temperature: 0f32,
            label,
            input_file: input_path.to_path_buf(),
            max: max.unwrap_or(0.0),
            critical,
        };
        c.refresh();
        c
    }
}

impl ComponentExt for Component {
    fn get_temperature(&self) -> f32 {
        self.temperature
    }

    fn get_max(&self) -> f32 {
        self.max
    }

    fn get_critical(&self) -> Option<f32> {
        self.critical
    }

    fn get_label(&self) -> &str {
        &self.label
    }

    fn refresh(&mut self) {
        if let Some(content) = get_file_line(self.input_file.as_path(), 10) {
            self.temperature = content
                .replace("\n", "")
                .parse::<f32>()
                .unwrap_or(100_000f32)
                / 1000f32;
            if self.temperature > self.max {
                self.max = self.temperature;
            }
        }
    }
}

pub fn get_components() -> Vec<Component> {
    if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) {
        let mut components = Vec::with_capacity(10);

        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if !entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("hwmon")
                {
                    continue;
                }
                append_files(&mut components, &entry);
            }
        }
        components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
        components
    } else if is_file("/sys/class/thermal/thermal_zone0/temp") {
        // Specfic to raspberry pi.
        vec![Component::new(
            "CPU".to_owned(),
            Path::new("/sys/class/thermal/thermal_zone0/temp"),
            None,
            None,
        )]
    } else {
        Vec::new()
    }
}
<commit_msg>Fix no temperature on Raspberry Pi<commit_after>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use ComponentExt;

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::{metadata, read_dir, File};
use std::io::Read;
use std::path::{Path, PathBuf};

/// More information can be found at [kernel.org][k].
///
/// Note: these may not be present on virtual Linux systems, such as **Docker**
/// or **Windows Subsystem for Linux**. These hosts do not expose this information
/// and therefore `Component` elements may be missing or not as expected.
///
/// [k]: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
pub struct Component {
    temperature: f32,
    max: f32,
    critical: Option<f32>,
    label: String,
    input_file: PathBuf,
}

fn get_file_line(file: &Path, capacity: usize) -> Option<String> {
    let mut reader = String::with_capacity(capacity);
    if let Ok(mut f) = File::open(file) {
        if f.read_to_string(&mut reader).is_ok() {
            Some(reader)
        } else {
            None
        }
    } else {
        None
    }
}

fn is_file<T: AsRef<Path>>(path: T) -> bool {
    metadata(path)
        .ok()
        .map(|m| m.is_file())
        .unwrap_or_else(|| false)
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings: HashMap<u32, Vec<String>> = HashMap::with_capacity(10);

    if let Ok(dir) = read_dir(folder) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("temp")
                {
                    continue;
                }
                if let Some(entry) = entry.file_name() {
                    if let Some(entry) = entry.to_str() {
                        let mut parts = entry.split('_');
                        if let Some(Some(id)) = parts.next().map(|s| s[4..].parse::<u32>().ok()) {
                            matchings
                                .entry(id)
                                .or_insert_with(|| Vec::with_capacity(5))
                                .push(
                                    parts
                                        .next()
                                        .map(|s| format!("_{}", s))
                                        .unwrap_or_else(String::new),
                                );
                        }
                    }
                }
            }
        }
        for (key, val) in &matchings {
            let mut found_input = None;
            let mut found_label = None;
            for (pos, v) in val.iter().enumerate() {
                match v.as_str() {
                    // raspberry has empty string for temperature input
                    "_input" | "" => {
                        found_input = Some(pos);
                    }
                    "_label" => {
                        found_label = Some(pos);
                    }
                    _ => {}
                }
            }
            if let (Some(_), Some(found_input)) = (found_label, found_input) {
                let mut p_label = folder.to_path_buf();
                let mut p_input = folder.to_path_buf();
                let mut p_crit = folder.to_path_buf();
                let mut p_max = folder.to_path_buf();

                p_label.push(&format!("temp{}_label", key));
                p_input.push(&format!("temp{}{}", key, val[found_input]));
                p_max.push(&format!("temp{}_max", key));
                p_crit.push(&format!("temp{}_crit", key));
                if is_file(&p_input) {
                    let label = get_file_line(p_label.as_path(), 10)
                        .unwrap_or_else(|| format!("Component {}", key)) // needed for raspberry pi
                        .replace("\n", "");
                    let max = if let Some(max) = get_file_line(p_max.as_path(), 10) {
                        Some(max.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    let crit = if let Some(crit) = get_file_line(p_crit.as_path(), 10) {
                        Some(crit.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    components.push(Component::new(label, p_input.as_path(), max, crit));
                }
            }
        }
    }
}

impl Component {
    /// Creates a new component with the given information.
    pub(crate) fn new(
        label: String,
        input_path: &Path,
        max: Option<f32>,
        critical: Option<f32>,
    ) -> Component {
        let mut c = Component {
            temperature: 0f32,
            label,
            input_file: input_path.to_path_buf(),
            max: max.unwrap_or(0.0),
            critical,
        };
        c.refresh();
        c
    }
}

impl ComponentExt for Component {
    fn get_temperature(&self) -> f32 {
        self.temperature
    }

    fn get_max(&self) -> f32 {
        self.max
    }

    fn get_critical(&self) -> Option<f32> {
        self.critical
    }

    fn get_label(&self) -> &str {
        &self.label
    }

    fn refresh(&mut self) {
        if let Some(content) = get_file_line(self.input_file.as_path(), 10) {
            self.temperature = content
                .replace("\n", "")
                .parse::<f32>()
                .unwrap_or(100_000f32)
                / 1000f32;
            if self.temperature > self.max {
                self.max = self.temperature;
            }
        }
    }
}

pub fn get_components() -> Vec<Component> {
    let mut components = Vec::with_capacity(10);
    if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if !entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("hwmon")
                {
                    continue;
                }
                append_files(&mut components, &entry);
            }
        }
        components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
    }
    if is_file("/sys/class/thermal/thermal_zone0/temp") {
        // Specfic to raspberry pi.
        components.push(Component::new(
            "CPU".to_owned(),
            Path::new("/sys/class/thermal/thermal_zone0/temp"),
            None,
            None,
        ));
    }
    if components.len() != 0 {
        components
    } else {
        Vec::new()
    }
}
<|endoftext|>


<commit_before>use std::io::stdio;
use std::io::Process;
use std::io::process;

struct Shell {
    cmd_prompt: ~str,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
        }
    }

    fn start(&mut self) {
        let mut stdin = stdio::stdin();
        loop {
            stdio::print(self.cmd_prompt);
            stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "\u274c"  =>  { return; }
                _       =>  { self.cmd(cmd_line.clone()); }
                // _ => { println!("You just ran {}", cmd_line) }
            }
        }
    }

    fn cmd(&mut self, cmd_line: ~str) {
        let mut arg_vec = ~[];
        let mut cmd = ~"";
        for (index, s) in cmd_line.split_str(" ").enumerate() {
            if index == 0 { cmd = s.to_owned(); } else { arg_vec.push(s.to_owned()); }
        }
        self.run_cmd(cmd, arg_vec);
    }

    fn run_cmd(&mut self, cmd: ~str, argv: ~[~str]) {
        if self.cmd_exists(cmd) {
            println!("Executing {}", cmd);
            let p = Process::new(cmd, argv);
            let status = p.unwrap().wait();
            match status {
                process::ExitSignal(st) => println!("Exited with signal {}", st),
                process::ExitStatus(st) => println!("Exited with status {}", st)
            }
        }
        else {
            println!("Command {} not found.", cmd)
        }
    }

    fn cmd_exists(&mut self, cmd: &str) -> bool {
        let p = Process::new("which", [cmd.to_owned()]);
        let status = p.unwrap().wait();
        match status {
            process::ExitSignal(st) => st == 0,
            process::ExitStatus(st) => st == 0
        }
    }
}

fn main() {
    Shell::new("\U0001f41a  ").start();
}
<commit_msg>Update shell commands to use the shell's stdin and out<commit_after>use std::io::stdio;
use std::io::Process;
use std::io::process;

struct Shell {
    cmd_prompt: ~str,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
        }
    }

    fn start(&mut self) {
        let mut stdin = stdio::stdin();
        loop {
            stdio::print(self.cmd_prompt);
            stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "\u274c"  =>  { return; }
                _       =>  { self.cmd(cmd_line.clone()); }
                // _ => { println!("You just ran {}", cmd_line) }
            }
        }
    }

    fn cmd(&mut self, cmd_line: ~str) {
        let mut arg_vec = ~[];
        let mut cmd = ~"";
        for (index, s) in cmd_line.split_str(" ").enumerate() {
            if index == 0 { cmd = s.to_owned(); } else { arg_vec.push(s.to_owned()); }
        }
        self.run_cmd(cmd, arg_vec);
    }

    fn run_cmd(&mut self, cmd: ~str, argv: ~[~str]) {
        if self.cmd_exists(cmd) {
            println!("Executing {}", cmd);
            let config = process::ProcessConfig {
                program: cmd,
                args: argv,
                stdin: process::InheritFd(0),
                stdout: process::InheritFd(1),
                stderr: process::InheritFd(2),
                .. process::ProcessConfig::new()
            };

            let p = Process::configure(config);
            let status = p.unwrap().wait();
            match status {
                process::ExitSignal(st) => println!("Exited with signal {}", st),
                process::ExitStatus(st) => println!("Exited with status {}", st)
            }
        }
        else {
            println!("Command {} not found.", cmd)
        }
    }

    fn cmd_exists(&mut self, cmd: &str) -> bool {
        let p = Process::new("which", [cmd.to_owned()]);
        let status = p.unwrap().wait();
        match status {
            process::ExitSignal(st) => st == 0,
            process::ExitStatus(st) => st == 0
        }
    }
}

fn main() {
    Shell::new("\U0001f41a  ").start();
}
<|endoftext|>


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

use font_template::{FontTemplate, FontTemplateDescriptor};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use mime::{TopLevel, SubLevel};
use net_traits::{AsyncResponseTarget, LoadContext, PendingAsyncLoad, ResourceTask, ResponseAction};
use platform::font_context::FontContextHandle;
use platform::font_list::for_each_available_family;
use platform::font_list::for_each_variation;
use platform::font_list::last_resort_font_families;
use platform::font_list::system_default_family;
use platform::font_template::FontTemplateData;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::mem;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use style::font_face::Source;
use style::properties::longhands::font_family::computed_value::FontFamily;
use url::Url;
use util::prefs;
use util::str::LowercaseString;
use util::task::spawn_named;

/// A list of font templates that make up a given font family.
struct FontTemplates {
    templates: Vec<FontTemplate>,
}

impl FontTemplates {
    fn new() -> FontTemplates {
        FontTemplates {
            templates: vec!(),
        }
    }

    /// Find a font in this family that matches a given descriptor.
    fn find_font_for_style(&mut self, desc: &FontTemplateDescriptor, fctx: &FontContextHandle)
                               -> Option<Arc<FontTemplateData>> {
        // TODO(Issue #189): optimize lookup for
        // regular/bold/italic/bolditalic with fixed offsets and a
        // static decision table for fallback between these values.

        // TODO(Issue #190): if not in the fast path above, do
        // expensive matching of weights, etc.
        for template in &mut self.templates {
            let maybe_template = template.data_for_descriptor(fctx, desc);
            if maybe_template.is_some() {
                return maybe_template;
            }
        }

        // If a request is made for a font family that exists,
        // pick the first valid font in the family if we failed
        // to find an exact match for the descriptor.
        for template in &mut self.templates {
            let maybe_template = template.get();
            if maybe_template.is_some() {
                return maybe_template;
            }
        }

        None
    }

    fn add_template(&mut self, identifier: Atom, maybe_data: Option<Vec<u8>>) {
        for template in &self.templates {
            if *template.identifier() == identifier {
                return;
            }
        }

        let template = FontTemplate::new(identifier, maybe_data);
        self.templates.push(template);
    }
}

/// Commands that the FontContext sends to the font cache task.
#[derive(Deserialize, Serialize, Debug)]
pub enum Command {
    GetFontTemplate(FontFamily, FontTemplateDescriptor, IpcSender<Reply>),
    GetLastResortFontTemplate(FontTemplateDescriptor, IpcSender<Reply>),
    AddWebFont(FontFamily, Source, IpcSender<()>),
    AddDownloadedWebFont(FontFamily, Url, Vec<u8>, IpcSender<()>),
    Exit(IpcSender<()>),
}

/// Reply messages sent from the font cache task to the FontContext caller.
#[derive(Deserialize, Serialize, Debug)]
pub enum Reply {
    GetFontTemplateReply(Option<Arc<FontTemplateData>>),
}

/// The font cache task itself. It maintains a list of reference counted
/// font templates that are currently in use.
struct FontCache {
    port: IpcReceiver<Command>,
    channel_to_self: IpcSender<Command>,
    generic_fonts: HashMap<FontFamily, LowercaseString>,
    local_families: HashMap<LowercaseString, FontTemplates>,
    web_families: HashMap<LowercaseString, FontTemplates>,
    font_context: FontContextHandle,
    resource_task: ResourceTask,
}

fn populate_generic_fonts() -> HashMap<FontFamily, LowercaseString> {
    let mut generic_fonts = HashMap::with_capacity(5);

    append_map(&mut generic_fonts, FontFamily::Serif, "Times New Roman");
    append_map(&mut generic_fonts, FontFamily::SansSerif, "Arial");
    append_map(&mut generic_fonts, FontFamily::Cursive, "Apple Chancery");
    append_map(&mut generic_fonts, FontFamily::Fantasy, "Papyrus");
    append_map(&mut generic_fonts, FontFamily::Monospace, "Menlo");

    fn append_map(generic_fonts: &mut HashMap<FontFamily, LowercaseString>,
                  font_family: FontFamily,
                  mapped_name: &str) {
        let family_name = {
            let opt_system_default = system_default_family(font_family.name());
            match opt_system_default {
                Some(system_default) => LowercaseString::new(&system_default),
                None => LowercaseString::new(mapped_name)
            }
        };

        generic_fonts.insert(font_family, family_name);
    }

    generic_fonts
}

impl FontCache {
    fn run(&mut self) {
        loop {
            let msg = self.port.recv().unwrap();

            match msg {
                Command::GetFontTemplate(family, descriptor, result) => {
                    let maybe_font_template = self.find_font_template(&family, &descriptor);
                    result.send(Reply::GetFontTemplateReply(maybe_font_template)).unwrap();
                }
                Command::GetLastResortFontTemplate(descriptor, result) => {
                    let font_template = self.last_resort_font_template(&descriptor);
                    result.send(Reply::GetFontTemplateReply(Some(font_template))).unwrap();
                }
                Command::AddWebFont(family, src, result) => {
                    let family_name = LowercaseString::new(family.name());
                    if !self.web_families.contains_key(&family_name) {
                        let templates = FontTemplates::new();
                        self.web_families.insert(family_name, templates);
                    }

                    match src {
                        Source::Url(ref url_source) => {
                            let url = &url_source.url;
                            let load = PendingAsyncLoad::new(LoadContext::Font,
                                                             self.resource_task.clone(),
                                                             url.clone(),
                                                             None);
                            let (data_sender, data_receiver) = ipc::channel().unwrap();
                            let data_target = AsyncResponseTarget {
                                sender: data_sender,
                            };
                            load.load_async(data_target);
                            let channel_to_self = self.channel_to_self.clone();
                            let url = (*url).clone();
                            let bytes = Mutex::new(Vec::new());
                            let response_valid = Mutex::new(false);
                            ROUTER.add_route(data_receiver.to_opaque(), box move |message| {
                                let response: ResponseAction = message.to().unwrap();
                                match response {
                                    ResponseAction::HeadersAvailable(metadata) => {
                                        let is_response_valid =
                                            metadata.content_type.as_ref().map_or(false, |content_type| {
                                                let mime = &content_type.0;
                                                is_supported_font_type(&mime.0, &mime.1)
                                            });
                                        info!("{} font with MIME type {:?}",
                                              if is_response_valid { "Loading" } else { "Ignoring" },
                                              metadata.content_type);
                                        *response_valid.lock().unwrap() = is_response_valid;
                                    }
                                    ResponseAction::ResponseComplete(Err(_)) => {}
                                    ResponseAction::DataAvailable(new_bytes) => {
                                        if *response_valid.lock().unwrap() {
                                            bytes.lock().unwrap().extend(new_bytes.into_iter())
                                        }
                                    }
                                    ResponseAction::ResponseComplete(Ok(_)) => {
                                        if !*response_valid.lock().unwrap() {
                                            drop(result.send(()));
                                            return;
                                        }
                                        let mut bytes = bytes.lock().unwrap();
                                        let bytes = mem::replace(&mut *bytes, Vec::new());
                                        let command =
                                            Command::AddDownloadedWebFont(family.clone(),
                                                                          url.clone(),
                                                                          bytes,
                                                                          result.clone());
                                        channel_to_self.send(command).unwrap();
                                    }
                                }
                            });
                        }
                        Source::Local(ref family) => {
                            let family_name = LowercaseString::new(family.name());
                            let templates = &mut self.web_families.get_mut(&family_name).unwrap();
                            for_each_variation(&family_name, |path| {
                                templates.add_template(Atom::from(&*path), None);
                            });
                            result.send(()).unwrap();
                        }
                    }
                }
                Command::AddDownloadedWebFont(family, url, bytes, result) => {
                    let family_name = LowercaseString::new(family.name());

                    let templates = &mut self.web_families.get_mut(&family_name).unwrap();
                    templates.add_template(Atom::from(&*url.to_string()), Some(bytes));
                    drop(result.send(()));
                }
                Command::Exit(result) => {
                    result.send(()).unwrap();
                    break;
                }
            }
        }
    }

    fn refresh_local_families(&mut self) {
        self.local_families.clear();
        for_each_available_family(|family_name| {
            let family_name = LowercaseString::new(&family_name);
            if !self.local_families.contains_key(&family_name) {
                let templates = FontTemplates::new();
                self.local_families.insert(family_name, templates);
            }
        });
    }

    fn transform_family(&self, family: &FontFamily) -> LowercaseString {
        match self.generic_fonts.get(family) {
            None => LowercaseString::new(family.name()),
            Some(mapped_family) => (*mapped_family).clone()
        }
    }

    fn find_font_in_local_family(&mut self, family_name: &LowercaseString, desc: &FontTemplateDescriptor)
                                -> Option<Arc<FontTemplateData>> {
        // TODO(Issue #188): look up localized font family names if canonical name not found
        // look up canonical name
        if self.local_families.contains_key(family_name) {
            debug!("FontList: Found font family with name={}", &**family_name);
            let s = self.local_families.get_mut(family_name).unwrap();

            if s.templates.is_empty() {
                for_each_variation(family_name, |path| {
                    s.add_template(Atom::from(&*path), None);
                });
            }

            // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
            // if such family exists, try to match style to a font

            s.find_font_for_style(desc, &self.font_context)
        } else {
            debug!("FontList: Couldn't find font family with name={}", &**family_name);
            None
        }
    }

    fn find_font_in_web_family(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
                                -> Option<Arc<FontTemplateData>> {
        let family_name = LowercaseString::new(family.name());

        if self.web_families.contains_key(&family_name) {
            let templates = self.web_families.get_mut(&family_name).unwrap();
            templates.find_font_for_style(desc, &self.font_context)
        } else {
            None
        }
    }

    fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
                            -> Option<Arc<FontTemplateData>> {
        self.find_font_in_web_family(family, desc)
            .or_else(|| {
                let transformed_family = self.transform_family(family);
                self.find_font_in_local_family(&transformed_family, desc)
            })
    }

    fn last_resort_font_template(&mut self, desc: &FontTemplateDescriptor)
                                        -> Arc<FontTemplateData> {
        let last_resort = last_resort_font_families();

        for family in &last_resort {
            let family = LowercaseString::new(family);
            let maybe_font_in_family = self.find_font_in_local_family(&family, desc);
            if let Some(family) = maybe_font_in_family {
                return family;
            }
        }

        panic!("Unable to find any fonts that match (do you have fallback fonts installed?)");
    }
}

/// The public interface to the font cache task, used exclusively by
/// the per-thread/task FontContext structures.
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct FontCacheTask {
    chan: IpcSender<Command>,
}

impl FontCacheTask {
    pub fn new(resource_task: ResourceTask) -> FontCacheTask {
        let (chan, port) = ipc::channel().unwrap();

        let channel_to_self = chan.clone();
        spawn_named("FontCacheTask".to_owned(), move || {
            // TODO: Allow users to specify these.
            let generic_fonts = populate_generic_fonts();

            let mut cache = FontCache {
                port: port,
                channel_to_self: channel_to_self,
                generic_fonts: generic_fonts,
                local_families: HashMap::new(),
                web_families: HashMap::new(),
                font_context: FontContextHandle::new(),
                resource_task: resource_task,
            };

            cache.refresh_local_families();
            cache.run();
        });

        FontCacheTask {
            chan: chan,
        }
    }

    pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor)
                                                -> Option<Arc<FontTemplateData>> {

        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::GetFontTemplate(family, desc, response_chan)).unwrap();

        let reply = response_port.recv().unwrap();

        match reply {
            Reply::GetFontTemplateReply(data) => {
                data
            }
        }
    }

    pub fn last_resort_font_template(&self, desc: FontTemplateDescriptor)
                                                -> Arc<FontTemplateData> {

        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::GetLastResortFontTemplate(desc, response_chan)).unwrap();

        let reply = response_port.recv().unwrap();

        match reply {
            Reply::GetFontTemplateReply(data) => {
                data.unwrap()
            }
        }
    }

    pub fn add_web_font(&self, family: FontFamily, src: Source, sender: IpcSender<()>) {
        self.chan.send(Command::AddWebFont(family, src, sender)).unwrap();
    }

    pub fn exit(&self) {
        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::Exit(response_chan)).unwrap();
        response_port.recv().unwrap();
    }
}

// derived from http://stackoverflow.com/a/10864297/3830
fn is_supported_font_type(toplevel: &TopLevel, sublevel: &SubLevel) -> bool {
    if !prefs::get_pref("net.mime.sniff").as_boolean().unwrap_or(false) {
        return true;
    }

    match (toplevel, sublevel) {
        (&TopLevel::Application, &SubLevel::Ext(ref ext)) => {
            match &ext[..] {
                //FIXME: once sniffing is enabled by default, we shouldn't need nonstandard
                //       MIME types here.
                "font-sfnt" | "x-font-ttf" | "x-font-truetype" | "x-font-opentype" => true,
                _ => false,
            }
        }
        _ => false,
    }
}
<commit_msg>gfx: handle the ResponseAction::ResponseComplete error case in font_cache_task<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use font_template::{FontTemplate, FontTemplateDescriptor};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use mime::{TopLevel, SubLevel};
use net_traits::{AsyncResponseTarget, LoadContext, PendingAsyncLoad, ResourceTask, ResponseAction};
use platform::font_context::FontContextHandle;
use platform::font_list::for_each_available_family;
use platform::font_list::for_each_variation;
use platform::font_list::last_resort_font_families;
use platform::font_list::system_default_family;
use platform::font_template::FontTemplateData;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::mem;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use style::font_face::Source;
use style::properties::longhands::font_family::computed_value::FontFamily;
use url::Url;
use util::prefs;
use util::str::LowercaseString;
use util::task::spawn_named;

/// A list of font templates that make up a given font family.
struct FontTemplates {
    templates: Vec<FontTemplate>,
}

impl FontTemplates {
    fn new() -> FontTemplates {
        FontTemplates {
            templates: vec!(),
        }
    }

    /// Find a font in this family that matches a given descriptor.
    fn find_font_for_style(&mut self, desc: &FontTemplateDescriptor, fctx: &FontContextHandle)
                               -> Option<Arc<FontTemplateData>> {
        // TODO(Issue #189): optimize lookup for
        // regular/bold/italic/bolditalic with fixed offsets and a
        // static decision table for fallback between these values.

        // TODO(Issue #190): if not in the fast path above, do
        // expensive matching of weights, etc.
        for template in &mut self.templates {
            let maybe_template = template.data_for_descriptor(fctx, desc);
            if maybe_template.is_some() {
                return maybe_template;
            }
        }

        // If a request is made for a font family that exists,
        // pick the first valid font in the family if we failed
        // to find an exact match for the descriptor.
        for template in &mut self.templates {
            let maybe_template = template.get();
            if maybe_template.is_some() {
                return maybe_template;
            }
        }

        None
    }

    fn add_template(&mut self, identifier: Atom, maybe_data: Option<Vec<u8>>) {
        for template in &self.templates {
            if *template.identifier() == identifier {
                return;
            }
        }

        let template = FontTemplate::new(identifier, maybe_data);
        self.templates.push(template);
    }
}

/// Commands that the FontContext sends to the font cache task.
#[derive(Deserialize, Serialize, Debug)]
pub enum Command {
    GetFontTemplate(FontFamily, FontTemplateDescriptor, IpcSender<Reply>),
    GetLastResortFontTemplate(FontTemplateDescriptor, IpcSender<Reply>),
    AddWebFont(FontFamily, Source, IpcSender<()>),
    AddDownloadedWebFont(FontFamily, Url, Vec<u8>, IpcSender<()>),
    Exit(IpcSender<()>),
}

/// Reply messages sent from the font cache task to the FontContext caller.
#[derive(Deserialize, Serialize, Debug)]
pub enum Reply {
    GetFontTemplateReply(Option<Arc<FontTemplateData>>),
}

/// The font cache task itself. It maintains a list of reference counted
/// font templates that are currently in use.
struct FontCache {
    port: IpcReceiver<Command>,
    channel_to_self: IpcSender<Command>,
    generic_fonts: HashMap<FontFamily, LowercaseString>,
    local_families: HashMap<LowercaseString, FontTemplates>,
    web_families: HashMap<LowercaseString, FontTemplates>,
    font_context: FontContextHandle,
    resource_task: ResourceTask,
}

fn populate_generic_fonts() -> HashMap<FontFamily, LowercaseString> {
    let mut generic_fonts = HashMap::with_capacity(5);

    append_map(&mut generic_fonts, FontFamily::Serif, "Times New Roman");
    append_map(&mut generic_fonts, FontFamily::SansSerif, "Arial");
    append_map(&mut generic_fonts, FontFamily::Cursive, "Apple Chancery");
    append_map(&mut generic_fonts, FontFamily::Fantasy, "Papyrus");
    append_map(&mut generic_fonts, FontFamily::Monospace, "Menlo");

    fn append_map(generic_fonts: &mut HashMap<FontFamily, LowercaseString>,
                  font_family: FontFamily,
                  mapped_name: &str) {
        let family_name = {
            let opt_system_default = system_default_family(font_family.name());
            match opt_system_default {
                Some(system_default) => LowercaseString::new(&system_default),
                None => LowercaseString::new(mapped_name)
            }
        };

        generic_fonts.insert(font_family, family_name);
    }

    generic_fonts
}

impl FontCache {
    fn run(&mut self) {
        loop {
            let msg = self.port.recv().unwrap();

            match msg {
                Command::GetFontTemplate(family, descriptor, result) => {
                    let maybe_font_template = self.find_font_template(&family, &descriptor);
                    result.send(Reply::GetFontTemplateReply(maybe_font_template)).unwrap();
                }
                Command::GetLastResortFontTemplate(descriptor, result) => {
                    let font_template = self.last_resort_font_template(&descriptor);
                    result.send(Reply::GetFontTemplateReply(Some(font_template))).unwrap();
                }
                Command::AddWebFont(family, src, result) => {
                    let family_name = LowercaseString::new(family.name());
                    if !self.web_families.contains_key(&family_name) {
                        let templates = FontTemplates::new();
                        self.web_families.insert(family_name, templates);
                    }

                    match src {
                        Source::Url(ref url_source) => {
                            let url = &url_source.url;
                            let load = PendingAsyncLoad::new(LoadContext::Font,
                                                             self.resource_task.clone(),
                                                             url.clone(),
                                                             None);
                            let (data_sender, data_receiver) = ipc::channel().unwrap();
                            let data_target = AsyncResponseTarget {
                                sender: data_sender,
                            };
                            load.load_async(data_target);
                            let channel_to_self = self.channel_to_self.clone();
                            let url = (*url).clone();
                            let bytes = Mutex::new(Vec::new());
                            let response_valid = Mutex::new(false);
                            ROUTER.add_route(data_receiver.to_opaque(), box move |message| {
                                let response: ResponseAction = message.to().unwrap();
                                match response {
                                    ResponseAction::HeadersAvailable(metadata) => {
                                        let is_response_valid =
                                            metadata.content_type.as_ref().map_or(false, |content_type| {
                                                let mime = &content_type.0;
                                                is_supported_font_type(&mime.0, &mime.1)
                                            });
                                        info!("{} font with MIME type {:?}",
                                              if is_response_valid { "Loading" } else { "Ignoring" },
                                              metadata.content_type);
                                        *response_valid.lock().unwrap() = is_response_valid;
                                    }
                                    ResponseAction::DataAvailable(new_bytes) => {
                                        if *response_valid.lock().unwrap() {
                                            bytes.lock().unwrap().extend(new_bytes.into_iter())
                                        }
                                    }
                                    ResponseAction::ResponseComplete(response) => {
                                        if response.is_err() || !*response_valid.lock().unwrap() {
                                            drop(result.send(()));
                                            return;
                                        }
                                        let mut bytes = bytes.lock().unwrap();
                                        let bytes = mem::replace(&mut *bytes, Vec::new());
                                        let command =
                                            Command::AddDownloadedWebFont(family.clone(),
                                                                          url.clone(),
                                                                          bytes,
                                                                          result.clone());
                                        channel_to_self.send(command).unwrap();
                                    }
                                }
                            });
                        }
                        Source::Local(ref family) => {
                            let family_name = LowercaseString::new(family.name());
                            let templates = &mut self.web_families.get_mut(&family_name).unwrap();
                            for_each_variation(&family_name, |path| {
                                templates.add_template(Atom::from(&*path), None);
                            });
                            result.send(()).unwrap();
                        }
                    }
                }
                Command::AddDownloadedWebFont(family, url, bytes, result) => {
                    let family_name = LowercaseString::new(family.name());

                    let templates = &mut self.web_families.get_mut(&family_name).unwrap();
                    templates.add_template(Atom::from(&*url.to_string()), Some(bytes));
                    drop(result.send(()));
                }
                Command::Exit(result) => {
                    result.send(()).unwrap();
                    break;
                }
            }
        }
    }

    fn refresh_local_families(&mut self) {
        self.local_families.clear();
        for_each_available_family(|family_name| {
            let family_name = LowercaseString::new(&family_name);
            if !self.local_families.contains_key(&family_name) {
                let templates = FontTemplates::new();
                self.local_families.insert(family_name, templates);
            }
        });
    }

    fn transform_family(&self, family: &FontFamily) -> LowercaseString {
        match self.generic_fonts.get(family) {
            None => LowercaseString::new(family.name()),
            Some(mapped_family) => (*mapped_family).clone()
        }
    }

    fn find_font_in_local_family(&mut self, family_name: &LowercaseString, desc: &FontTemplateDescriptor)
                                -> Option<Arc<FontTemplateData>> {
        // TODO(Issue #188): look up localized font family names if canonical name not found
        // look up canonical name
        if self.local_families.contains_key(family_name) {
            debug!("FontList: Found font family with name={}", &**family_name);
            let s = self.local_families.get_mut(family_name).unwrap();

            if s.templates.is_empty() {
                for_each_variation(family_name, |path| {
                    s.add_template(Atom::from(&*path), None);
                });
            }

            // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
            // if such family exists, try to match style to a font

            s.find_font_for_style(desc, &self.font_context)
        } else {
            debug!("FontList: Couldn't find font family with name={}", &**family_name);
            None
        }
    }

    fn find_font_in_web_family(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
                                -> Option<Arc<FontTemplateData>> {
        let family_name = LowercaseString::new(family.name());

        if self.web_families.contains_key(&family_name) {
            let templates = self.web_families.get_mut(&family_name).unwrap();
            templates.find_font_for_style(desc, &self.font_context)
        } else {
            None
        }
    }

    fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
                            -> Option<Arc<FontTemplateData>> {
        self.find_font_in_web_family(family, desc)
            .or_else(|| {
                let transformed_family = self.transform_family(family);
                self.find_font_in_local_family(&transformed_family, desc)
            })
    }

    fn last_resort_font_template(&mut self, desc: &FontTemplateDescriptor)
                                        -> Arc<FontTemplateData> {
        let last_resort = last_resort_font_families();

        for family in &last_resort {
            let family = LowercaseString::new(family);
            let maybe_font_in_family = self.find_font_in_local_family(&family, desc);
            if let Some(family) = maybe_font_in_family {
                return family;
            }
        }

        panic!("Unable to find any fonts that match (do you have fallback fonts installed?)");
    }
}

/// The public interface to the font cache task, used exclusively by
/// the per-thread/task FontContext structures.
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct FontCacheTask {
    chan: IpcSender<Command>,
}

impl FontCacheTask {
    pub fn new(resource_task: ResourceTask) -> FontCacheTask {
        let (chan, port) = ipc::channel().unwrap();

        let channel_to_self = chan.clone();
        spawn_named("FontCacheTask".to_owned(), move || {
            // TODO: Allow users to specify these.
            let generic_fonts = populate_generic_fonts();

            let mut cache = FontCache {
                port: port,
                channel_to_self: channel_to_self,
                generic_fonts: generic_fonts,
                local_families: HashMap::new(),
                web_families: HashMap::new(),
                font_context: FontContextHandle::new(),
                resource_task: resource_task,
            };

            cache.refresh_local_families();
            cache.run();
        });

        FontCacheTask {
            chan: chan,
        }
    }

    pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor)
                                                -> Option<Arc<FontTemplateData>> {

        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::GetFontTemplate(family, desc, response_chan)).unwrap();

        let reply = response_port.recv().unwrap();

        match reply {
            Reply::GetFontTemplateReply(data) => {
                data
            }
        }
    }

    pub fn last_resort_font_template(&self, desc: FontTemplateDescriptor)
                                                -> Arc<FontTemplateData> {

        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::GetLastResortFontTemplate(desc, response_chan)).unwrap();

        let reply = response_port.recv().unwrap();

        match reply {
            Reply::GetFontTemplateReply(data) => {
                data.unwrap()
            }
        }
    }

    pub fn add_web_font(&self, family: FontFamily, src: Source, sender: IpcSender<()>) {
        self.chan.send(Command::AddWebFont(family, src, sender)).unwrap();
    }

    pub fn exit(&self) {
        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::Exit(response_chan)).unwrap();
        response_port.recv().unwrap();
    }
}

// derived from http://stackoverflow.com/a/10864297/3830
fn is_supported_font_type(toplevel: &TopLevel, sublevel: &SubLevel) -> bool {
    if !prefs::get_pref("net.mime.sniff").as_boolean().unwrap_or(false) {
        return true;
    }

    match (toplevel, sublevel) {
        (&TopLevel::Application, &SubLevel::Ext(ref ext)) => {
            match &ext[..] {
                //FIXME: once sniffing is enabled by default, we shouldn't need nonstandard
                //       MIME types here.
                "font-sfnt" | "x-font-ttf" | "x-font-truetype" | "x-font-opentype" => true,
                _ => false,
            }
        }
        _ => false,
    }
}
<|endoftext|>


<commit_before>#[cfg_attr(doc, aquamarine::aquamarine)]
/// Representations of JavaScript's core builtin types.
///
/// ## Modeling JavaScript Types
///
/// All JavaScript values in Neon implement the abstract [`Value`](Value) trait, which
/// is the most generic way to work with JavaScript values. Neon provides a
/// number of types that implement this trait, each representing a particular
/// type of JavaScript value.
///
/// By convention, JavaScript types in Neon have the prefix `Js` in their name,
/// such as [`JsNumber`](crate::types::JsNumber) (for the JavaScript `number`
/// type) or [`JsFunction`](crate::types::JsFunction) (for the JavaScript
/// `function` type).
///
/// ### Handles and Casts
///
/// Access to JavaScript values in Neon works through [handles](crate::handle),
/// which ensure the safe interoperation between Rust and the JavaScript garbage
/// collector. This means, for example, a Rust variable that stores a JavaScript string
/// will have the type `Handle<JsString>` rather than [`JsString`](crate::types::JsString).
///
/// Neon types model the JavaScript type hierarchy through the use of *casts*.
/// The [`Handle::upcast()`](crate::handle::Handle::upcast) method safely converts
/// a handle to a JavaScript value of one type into a handle to a value of its
/// supertype. For example, it's safe to treat a [`JsArray`](crate::types::JsArray)
/// as a [`JsObject`](crate::types::JsObject), so you can do an "upcast" and it will
/// never fail:
///
/// ```
/// # use neon::prelude::*;
/// fn as_object(array: Handle<JsArray>) -> Handle<JsObject> {
///     let object: Handle<JsObject> = array.upcast();
///     object
/// }
/// ```
///
/// Unlike upcasts, the [`Handle::downcast()`](crate::handle::Handle::downcast) method
/// requires a runtime check to test a value's type at runtime, so it can fail with
/// a [`DowncastError`](crate::handle::DowncastError):
///
/// ```
/// # use neon::prelude::*;
/// fn as_array<'a>(
///     cx: &mut impl Context<'a>,
///     object: Handle<'a, JsObject>
/// ) -> JsResult<'a, JsArray> {
///     object.downcast(cx).or_throw(cx)
/// }
/// ```
///
/// ### The JavaScript Type Hierarchy
///
/// The top of the JavaScript type hierarchy is modeled with the Neon type
/// [`JsValue`](JsValue). A [handle](crate::handle) to a `JsValue` can refer
/// to any JavaScript value. (For TypeScript programmers, this can be thought
/// of as similar to TypeScript's [`unknown`][unknown] type.)
///
/// From there, the type hierarchy divides into _object types_ and _primitive
/// types_:
///
/// ```mermaid
/// flowchart LR
/// JsValue(JsValue)
/// JsValue-->JsObject(JsObject)
/// click JsValue "./struct.JsValue.html" "JsValue"
/// click JsObject "./struct.JsObject.html" "JsObject"
/// subgraph primitives [Primitive Types]
///     JsBoolean(JsBoolean)
///     JsNumber(JsNumber)
///     JsString(JsString)
///     JsNull(JsNull)
///     JsUndefined(JsUndefined)
///     click JsBoolean "./struct.JsBoolean.html" "JsBoolean"
///     click JsNumber "./struct.JsNumber.html" "JsNumber"
///     click JsString "./struct.JsString.html" "JsString"
///     click JsNull "./struct.JsNull.html" "JsNull"
///     click JsUndefined "./struct.JsUndefined.html" "JsUndefined"
/// end
/// JsValue-->primitives
/// ```
///
/// The top of the object type hierarchy is [`JsObject`](JsObject). A handle to a
/// `JsObject` can refer to any JavaScript object.
///
/// The primitive types are the built-in JavaScript datatypes that are not object
/// types: [`JsBoolean`](JsBoolean), [`JsNumber`](JsNumber), [`JsString`](JsString),
/// [`JsNull`](JsNull), and [`JsUndefined`](JsUndefined).
///
/// #### Object Types
///
/// The object type hierarchy further divides into a number of different subtypes:
///
/// ```mermaid
/// flowchart LR
/// JsObject(JsObject)
/// click JsObject "./struct.JsObject.html" "JsObject"
/// subgraph objects [Standard Object Types]
///     JsFunction(JsFunction)
///     JsArray(JsArray)
///     JsDate(JsDate)
///     JsError(JsError)
///     click JsFunction "./struct.JsFunction.html" "JsFunction"
///     click JsArray "./struct.JsArray.html" "JsArray"
///     click JsDate "./struct.JsDate.html" "JsDate"
///     click JsError "./struct.JsError.html" "JsError"
/// end
/// subgraph typedarrays [Typed Arrays]
///     JsBuffer(JsBuffer)
///     JsArrayBuffer(JsArrayBuffer)
///     JsTypedArray("JsTypedArray<T>")
///     click JsBuffer "./struct.JsBuffer.html" "JsBuffer"
///     click JsArrayBuffer "./struct.JsArrayBuffer.html" "JsArrayBuffer"
///     click JsTypedArray "./struct.JsTypedArray.html" "JsTypedArray"
/// end
/// subgraph custom [Custom Types]
///     JsBox(JsBox)
///     click JsBox "./struct.JsBox.html" "JsBox"
/// end
/// JsObject-->objects
/// JsObject-->typedarrays
/// JsObject-->custom
/// ```
///
/// These include several categories of object types:
/// - **Standard object types:** [`JsFunction`](JsFunction), [`JsArray`](JsArray),
///   [`JsDate`](JsDate), and [`JsError`](JsError).
/// - **Typed arrays:** [`JsBuffer`](JsBuffer), [`JsArrayBuffer`](JsArrayBuffer),
///   and [`JsTypedArray<T>`](JsTypedArray).
/// - **Custom types:** [`JsBox`](JsBox), a special Neon type that allows the creation
///   of custom objects that own Rust data structures.
///
/// All object types implement the [`Object`](crate::object::Object) trait, which
/// allows getting and setting properties of an object.
///
/// [unknown]: https://mariusschulz.com/blog/the-unknown-type-in-typescript#the-unknown-type
pub mod exports {
    pub use crate::types_impl::*;
}
<commit_msg>Copy nit: avoid the word "number" when describing object types<commit_after>#[cfg_attr(doc, aquamarine::aquamarine)]
/// Representations of JavaScript's core builtin types.
///
/// ## Modeling JavaScript Types
///
/// All JavaScript values in Neon implement the abstract [`Value`](Value) trait, which
/// is the most generic way to work with JavaScript values. Neon provides a
/// number of types that implement this trait, each representing a particular
/// type of JavaScript value.
///
/// By convention, JavaScript types in Neon have the prefix `Js` in their name,
/// such as [`JsNumber`](crate::types::JsNumber) (for the JavaScript `number`
/// type) or [`JsFunction`](crate::types::JsFunction) (for the JavaScript
/// `function` type).
///
/// ### Handles and Casts
///
/// Access to JavaScript values in Neon works through [handles](crate::handle),
/// which ensure the safe interoperation between Rust and the JavaScript garbage
/// collector. This means, for example, a Rust variable that stores a JavaScript string
/// will have the type `Handle<JsString>` rather than [`JsString`](crate::types::JsString).
///
/// Neon types model the JavaScript type hierarchy through the use of *casts*.
/// The [`Handle::upcast()`](crate::handle::Handle::upcast) method safely converts
/// a handle to a JavaScript value of one type into a handle to a value of its
/// supertype. For example, it's safe to treat a [`JsArray`](crate::types::JsArray)
/// as a [`JsObject`](crate::types::JsObject), so you can do an "upcast" and it will
/// never fail:
///
/// ```
/// # use neon::prelude::*;
/// fn as_object(array: Handle<JsArray>) -> Handle<JsObject> {
///     let object: Handle<JsObject> = array.upcast();
///     object
/// }
/// ```
///
/// Unlike upcasts, the [`Handle::downcast()`](crate::handle::Handle::downcast) method
/// requires a runtime check to test a value's type at runtime, so it can fail with
/// a [`DowncastError`](crate::handle::DowncastError):
///
/// ```
/// # use neon::prelude::*;
/// fn as_array<'a>(
///     cx: &mut impl Context<'a>,
///     object: Handle<'a, JsObject>
/// ) -> JsResult<'a, JsArray> {
///     object.downcast(cx).or_throw(cx)
/// }
/// ```
///
/// ### The JavaScript Type Hierarchy
///
/// The top of the JavaScript type hierarchy is modeled with the Neon type
/// [`JsValue`](JsValue). A [handle](crate::handle) to a `JsValue` can refer
/// to any JavaScript value. (For TypeScript programmers, this can be thought
/// of as similar to TypeScript's [`unknown`][unknown] type.)
///
/// From there, the type hierarchy divides into _object types_ and _primitive
/// types_:
///
/// ```mermaid
/// flowchart LR
/// JsValue(JsValue)
/// JsValue-->JsObject(JsObject)
/// click JsValue "./struct.JsValue.html" "JsValue"
/// click JsObject "./struct.JsObject.html" "JsObject"
/// subgraph primitives [Primitive Types]
///     JsBoolean(JsBoolean)
///     JsNumber(JsNumber)
///     JsString(JsString)
///     JsNull(JsNull)
///     JsUndefined(JsUndefined)
///     click JsBoolean "./struct.JsBoolean.html" "JsBoolean"
///     click JsNumber "./struct.JsNumber.html" "JsNumber"
///     click JsString "./struct.JsString.html" "JsString"
///     click JsNull "./struct.JsNull.html" "JsNull"
///     click JsUndefined "./struct.JsUndefined.html" "JsUndefined"
/// end
/// JsValue-->primitives
/// ```
///
/// The top of the object type hierarchy is [`JsObject`](JsObject). A handle to a
/// `JsObject` can refer to any JavaScript object.
///
/// The primitive types are the built-in JavaScript datatypes that are not object
/// types: [`JsBoolean`](JsBoolean), [`JsNumber`](JsNumber), [`JsString`](JsString),
/// [`JsNull`](JsNull), and [`JsUndefined`](JsUndefined).
///
/// #### Object Types
///
/// The object type hierarchy further divides into a variety of different subtypes:
///
/// ```mermaid
/// flowchart LR
/// JsObject(JsObject)
/// click JsObject "./struct.JsObject.html" "JsObject"
/// subgraph objects [Standard Object Types]
///     JsFunction(JsFunction)
///     JsArray(JsArray)
///     JsDate(JsDate)
///     JsError(JsError)
///     click JsFunction "./struct.JsFunction.html" "JsFunction"
///     click JsArray "./struct.JsArray.html" "JsArray"
///     click JsDate "./struct.JsDate.html" "JsDate"
///     click JsError "./struct.JsError.html" "JsError"
/// end
/// subgraph typedarrays [Typed Arrays]
///     JsBuffer(JsBuffer)
///     JsArrayBuffer(JsArrayBuffer)
///     JsTypedArray("JsTypedArray<T>")
///     click JsBuffer "./struct.JsBuffer.html" "JsBuffer"
///     click JsArrayBuffer "./struct.JsArrayBuffer.html" "JsArrayBuffer"
///     click JsTypedArray "./struct.JsTypedArray.html" "JsTypedArray"
/// end
/// subgraph custom [Custom Types]
///     JsBox(JsBox)
///     click JsBox "./struct.JsBox.html" "JsBox"
/// end
/// JsObject-->objects
/// JsObject-->typedarrays
/// JsObject-->custom
/// ```
///
/// These include several categories of object types:
/// - **Standard object types:** [`JsFunction`](JsFunction), [`JsArray`](JsArray),
///   [`JsDate`](JsDate), and [`JsError`](JsError).
/// - **Typed arrays:** [`JsBuffer`](JsBuffer), [`JsArrayBuffer`](JsArrayBuffer),
///   and [`JsTypedArray<T>`](JsTypedArray).
/// - **Custom types:** [`JsBox`](JsBox), a special Neon type that allows the creation
///   of custom objects that own Rust data structures.
///
/// All object types implement the [`Object`](crate::object::Object) trait, which
/// allows getting and setting properties of an object.
///
/// [unknown]: https://mariusschulz.com/blog/the-unknown-type-in-typescript#the-unknown-type
pub mod exports {
    pub use crate::types_impl::*;
}
<|endoftext|>


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

// Code to handle a single block device.

use std::{fs::OpenOptions, path::PathBuf};

use chrono::{DateTime, TimeZone, Utc};

use devicemapper::{Device, Sectors};

use crate::{
    engine::{
        event::get_engine_listener_list,
        strat_engine::{
            backstore::{
                metadata::{BDAExtendedSize, MDADataSize, BDA},
                range_alloc::RangeAllocator,
            },
            serde_structs::{BaseBlockDevSave, Recordable},
        },
        BlockDev, BlockDevState, DevUuid, EngineEvent, MaybeDbusPath,
    },
    stratis::StratisResult,
};

#[derive(Debug)]
pub struct StratBlockDev {
    dev: Device,
    pub(super) devnode: PathBuf,
    bda: BDA,
    used: RangeAllocator,
    user_info: Option<String>,
    hardware_info: Option<String>,
    dbus_path: MaybeDbusPath,
}

impl StratBlockDev {
    /// Make a new BlockDev from the parameters.
    /// Allocate space for the Stratis metadata on the device.
    /// - dev: the device, identified by number
    /// - devnode: the device node
    /// - bda: the device's BDA
    /// - other_segments: segments claimed for non-Stratis metadata use
    /// - user_info: user settable identifying information
    /// - hardware_info: identifying information in the hardware
    /// Returns an error if it is impossible to allocate all segments on the
    /// device.
    /// NOTE: It is possible that the actual device size is greater than
    /// the recorded device size. In that case, the additional space available
    /// on the device is simply invisible to the blockdev. Consequently, it
    /// is invisible to the engine, and is not part of the total size value
    /// reported on the D-Bus.
    #[allow(clippy::new_ret_no_self)]
    pub fn new(
        dev: Device,
        devnode: PathBuf,
        bda: BDA,
        upper_segments: &[(Sectors, Sectors)],
        user_info: Option<String>,
        hardware_info: Option<String>,
    ) -> StratisResult<StratBlockDev> {
        let mut segments = vec![(Sectors(0), bda.size().sectors())];
        segments.extend(upper_segments);
        let allocator = RangeAllocator::new(bda.dev_size(), &segments)?;

        Ok(StratBlockDev {
            dev,
            devnode,
            bda,
            used: allocator,
            user_info,
            hardware_info,
            dbus_path: MaybeDbusPath(None),
        })
    }

    /// Returns the blockdev's Device
    pub fn device(&self) -> &Device {
        &self.dev
    }

    pub fn wipe_metadata(&self) -> StratisResult<()> {
        let mut f = OpenOptions::new().write(true).open(&self.devnode)?;
        BDA::wipe(&mut f)
    }

    pub fn save_state(&mut self, time: &DateTime<Utc>, metadata: &[u8]) -> StratisResult<()> {
        let mut f = OpenOptions::new().write(true).open(&self.devnode)?;
        self.bda.save_state(time, metadata, &mut f)
    }

    /// The device's UUID.
    pub fn uuid(&self) -> DevUuid {
        self.bda.dev_uuid()
    }

    /// Find some sector ranges that could be allocated. If more
    /// sectors are needed than are available, return partial results.
    /// If all sectors are desired, use available() method to get all.
    pub fn request_space(&mut self, size: Sectors) -> (Sectors, Vec<(Sectors, Sectors)>) {
        let prev_state = self.state();
        let result = self.used.request(size);
        if result.0 > Sectors(0) && prev_state != BlockDevState::InUse {
            get_engine_listener_list().notify(&EngineEvent::BlockdevStateChanged {
                dbus_path: self.get_dbus_path(),
                state: BlockDevState::InUse,
            });
        }
        result
    }

    // ALL SIZE METHODS (except size(), which is in BlockDev impl.)
    /// The number of Sectors on this device used by Stratis for metadata
    pub fn metadata_size(&self) -> BDAExtendedSize {
        self.bda.size()
    }

    /// The number of Sectors on this device not allocated for any purpose.
    /// self.size() - self.metadata_size() >= self.available()
    pub fn available(&self) -> Sectors {
        self.used.available()
    }

    /// The maximum size of variable length metadata that can be accommodated.
    /// self.max_metadata_size() < self.metadata_size()
    pub fn max_metadata_size(&self) -> MDADataSize {
        self.bda.max_data_size()
    }

    /// Set the user info on this blockdev.
    /// The user_info may be None, which unsets user info.
    /// Returns true if the user info was changed, otherwise false.
    pub fn set_user_info(&mut self, user_info: Option<&str>) -> bool {
        set_blockdev_user_info!(self; user_info)
    }
}

impl BlockDev for StratBlockDev {
    fn devnode(&self) -> PathBuf {
        self.devnode.clone()
    }

    fn user_info(&self) -> Option<&str> {
        self.user_info.as_ref().map(|x| &**x)
    }

    fn hardware_info(&self) -> Option<&str> {
        self.hardware_info.as_ref().map(|x| &**x)
    }

    fn initialization_time(&self) -> DateTime<Utc> {
        // This cast will result in an incorrect, negative value starting in
        // the year 292,277,026,596. :-)
        Utc.timestamp(self.bda.initialization_time() as i64, 0)
    }

    fn size(&self) -> Sectors {
        let size = self.used.size();
        assert_eq!(self.bda.dev_size(), size);
        size
    }

    fn state(&self) -> BlockDevState {
        // TODO: Implement support for other BlockDevStates
        if self.used.used() > self.bda.size().sectors() {
            BlockDevState::InUse
        } else {
            BlockDevState::NotInUse
        }
    }

    fn set_dbus_path(&mut self, path: MaybeDbusPath) {
        self.dbus_path = path
    }

    fn get_dbus_path(&self) -> &MaybeDbusPath {
        &self.dbus_path
    }
}

impl Recordable<BaseBlockDevSave> for StratBlockDev {
    fn record(&self) -> BaseBlockDevSave {
        BaseBlockDevSave {
            uuid: self.uuid(),
            user_info: self.user_info.clone(),
            hardware_info: self.hardware_info.clone(),
        }
    }
}
<commit_msg>Use StratBlockDev::metadata_size in one place<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle a single block device.

use std::{fs::OpenOptions, path::PathBuf};

use chrono::{DateTime, TimeZone, Utc};

use devicemapper::{Device, Sectors};

use crate::{
    engine::{
        event::get_engine_listener_list,
        strat_engine::{
            backstore::{
                metadata::{BDAExtendedSize, MDADataSize, BDA},
                range_alloc::RangeAllocator,
            },
            serde_structs::{BaseBlockDevSave, Recordable},
        },
        BlockDev, BlockDevState, DevUuid, EngineEvent, MaybeDbusPath,
    },
    stratis::StratisResult,
};

#[derive(Debug)]
pub struct StratBlockDev {
    dev: Device,
    pub(super) devnode: PathBuf,
    bda: BDA,
    used: RangeAllocator,
    user_info: Option<String>,
    hardware_info: Option<String>,
    dbus_path: MaybeDbusPath,
}

impl StratBlockDev {
    /// Make a new BlockDev from the parameters.
    /// Allocate space for the Stratis metadata on the device.
    /// - dev: the device, identified by number
    /// - devnode: the device node
    /// - bda: the device's BDA
    /// - other_segments: segments claimed for non-Stratis metadata use
    /// - user_info: user settable identifying information
    /// - hardware_info: identifying information in the hardware
    /// Returns an error if it is impossible to allocate all segments on the
    /// device.
    /// NOTE: It is possible that the actual device size is greater than
    /// the recorded device size. In that case, the additional space available
    /// on the device is simply invisible to the blockdev. Consequently, it
    /// is invisible to the engine, and is not part of the total size value
    /// reported on the D-Bus.
    #[allow(clippy::new_ret_no_self)]
    pub fn new(
        dev: Device,
        devnode: PathBuf,
        bda: BDA,
        upper_segments: &[(Sectors, Sectors)],
        user_info: Option<String>,
        hardware_info: Option<String>,
    ) -> StratisResult<StratBlockDev> {
        let mut segments = vec![(Sectors(0), bda.size().sectors())];
        segments.extend(upper_segments);
        let allocator = RangeAllocator::new(bda.dev_size(), &segments)?;

        Ok(StratBlockDev {
            dev,
            devnode,
            bda,
            used: allocator,
            user_info,
            hardware_info,
            dbus_path: MaybeDbusPath(None),
        })
    }

    /// Returns the blockdev's Device
    pub fn device(&self) -> &Device {
        &self.dev
    }

    pub fn wipe_metadata(&self) -> StratisResult<()> {
        let mut f = OpenOptions::new().write(true).open(&self.devnode)?;
        BDA::wipe(&mut f)
    }

    pub fn save_state(&mut self, time: &DateTime<Utc>, metadata: &[u8]) -> StratisResult<()> {
        let mut f = OpenOptions::new().write(true).open(&self.devnode)?;
        self.bda.save_state(time, metadata, &mut f)
    }

    /// The device's UUID.
    pub fn uuid(&self) -> DevUuid {
        self.bda.dev_uuid()
    }

    /// Find some sector ranges that could be allocated. If more
    /// sectors are needed than are available, return partial results.
    /// If all sectors are desired, use available() method to get all.
    pub fn request_space(&mut self, size: Sectors) -> (Sectors, Vec<(Sectors, Sectors)>) {
        let prev_state = self.state();
        let result = self.used.request(size);
        if result.0 > Sectors(0) && prev_state != BlockDevState::InUse {
            get_engine_listener_list().notify(&EngineEvent::BlockdevStateChanged {
                dbus_path: self.get_dbus_path(),
                state: BlockDevState::InUse,
            });
        }
        result
    }

    // ALL SIZE METHODS (except size(), which is in BlockDev impl.)
    /// The number of Sectors on this device used by Stratis for metadata
    pub fn metadata_size(&self) -> BDAExtendedSize {
        self.bda.size()
    }

    /// The number of Sectors on this device not allocated for any purpose.
    /// self.size() - self.metadata_size() >= self.available()
    pub fn available(&self) -> Sectors {
        self.used.available()
    }

    /// The maximum size of variable length metadata that can be accommodated.
    /// self.max_metadata_size() < self.metadata_size()
    pub fn max_metadata_size(&self) -> MDADataSize {
        self.bda.max_data_size()
    }

    /// Set the user info on this blockdev.
    /// The user_info may be None, which unsets user info.
    /// Returns true if the user info was changed, otherwise false.
    pub fn set_user_info(&mut self, user_info: Option<&str>) -> bool {
        set_blockdev_user_info!(self; user_info)
    }
}

impl BlockDev for StratBlockDev {
    fn devnode(&self) -> PathBuf {
        self.devnode.clone()
    }

    fn user_info(&self) -> Option<&str> {
        self.user_info.as_ref().map(|x| &**x)
    }

    fn hardware_info(&self) -> Option<&str> {
        self.hardware_info.as_ref().map(|x| &**x)
    }

    fn initialization_time(&self) -> DateTime<Utc> {
        // This cast will result in an incorrect, negative value starting in
        // the year 292,277,026,596. :-)
        Utc.timestamp(self.bda.initialization_time() as i64, 0)
    }

    fn size(&self) -> Sectors {
        let size = self.used.size();
        assert_eq!(self.bda.dev_size(), size);
        size
    }

    fn state(&self) -> BlockDevState {
        // TODO: Implement support for other BlockDevStates
        if self.used.used() > self.metadata_size().sectors() {
            BlockDevState::InUse
        } else {
            BlockDevState::NotInUse
        }
    }

    fn set_dbus_path(&mut self, path: MaybeDbusPath) {
        self.dbus_path = path
    }

    fn get_dbus_path(&self) -> &MaybeDbusPath {
        &self.dbus_path
    }
}

impl Recordable<BaseBlockDevSave> for StratBlockDev {
    fn record(&self) -> BaseBlockDevSave {
        BaseBlockDevSave {
            uuid: self.uuid(),
            user_info: self.user_info.clone(),
            hardware_info: self.hardware_info.clone(),
        }
    }
}
<|endoftext|>


<commit_before>//! Hello World client

extern mod zmq;

fn main() {
    println("Conneting to hello world server...\n");

    let mut context = zmq::Context::new();
    let mut requester = context.socket(zmq::REQ).unwrap();

    assert!(requester.connect("tcp://localhost:5555").is_ok());

    let mut msg = zmq::Message::new();

    for x in range(0, 10) {
        println!("Sending Hello {}", x);
        requester.send(bytes!("Hello"), 0);

        requester.recv(&mut msg, 0).unwrap();
        msg.with_str(|s| {
            println!("Received World {}: {}", s, x);
        })
    }
}
<commit_msg>fix typo<commit_after>//! Hello World client

extern mod zmq;

fn main() {
    println("Connecting to hello world server...\n");

    let mut context = zmq::Context::new();
    let mut requester = context.socket(zmq::REQ).unwrap();

    assert!(requester.connect("tcp://localhost:5555").is_ok());

    let mut msg = zmq::Message::new();

    for x in range(0, 10) {
        println!("Sending Hello {}", x);
        requester.send(bytes!("Hello"), 0);

        requester.recv(&mut msg, 0).unwrap();
        msg.with_str(|s| {
            println!("Received World {}: {}", s, x);
        })
    }
}
<|endoftext|>