<commit_before>use image::RgbaImage;
use rand::Rng;
use itertools::Itertools;

use utils::*;

pub fn encode_rgba<R: Rng>(source: &mut RgbaImage, payload: &[u8], mode: RgbaMode, mut rng: R)
{
    // number of pixels per byte
    let ppb = match mode
    {
        // 1 values per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // 4 values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    for (pixels, byte) in source.pixels_mut() // iterate pixels mutably
        .chunks(ppb).into_iter()              // split them into ppb-size chunks
        .map(|ch| ch.collect::<Vec<_>>())     // make them vectors so we can check their lengths later
        .zip(payload.iter().map(|x| *x))      // give each chunk a byte
    {
        // if the pixels don't fit exactly into their chunks,
        // the last chunk will be short. we won't use that chunk
        // (making sure the payload fits into the image is not
        // this functions job!)
        if pixels.len() != ppb
        {
            return;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                for (i, px) in pixels.into_iter().enumerate()
                {
                    // a true, or 1 bit
                    if get_bit(byte, i as u8)
                    {
                        // even = 0 bit, so it needs to be changed
                        if px.data[3] % 2 == 0
                        {
                            // special case: if it's zero, we have to go up
                            if px.data[3] == 0
                            {
                                px.data[3] = 1;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                    // a false, or 0 bit
                    else
                    {
                        // odd = 1 bit, so it needs to be changed
                        if px.data[3] % 2 == 1
                        {
                            // special case: if it's 255, we have to go down
                            if px.data[3] == 255
                            {
                                px.data[3] = 254;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                }
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            },
        }
    }
}

pub fn decode_rbga(source: &RgbaImage, mode: RgbaMode) -> Vec<u8>
{
    // pixels per byte
    let ppb = match mode
    {
        // one value per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // four values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    let mut buf = Vec::new();

    for pixels in source.pixels()         // iterate pixels
        .chunks(ppb).into_iter()          // split into ppb-sized chunks
        .map(|ch| ch.collect::<Vec<_>>()) // make them vectors so we can check their lengths
    {
        // only decode while we have enough data
        if pixels.len() != ppb
        {
            break;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                let mut byte = 0u8;

                for (i, px) in pixels.into_iter().enumerate()
                {
                    byte = set_bit(byte, i as u8, px.data[3] % 2 == 1);
                }

                buf.push(byte)
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            }
        }
    }

    buf

}

/// The encoding/decoding mode
#[derive(Copy, Clone)]
pub enum RgbaMode
{
    /// encode in alpha even/odd
    Alpha,
    /// encode in each field even/odd
    Each,
}

use std::default::Default;

impl Default for RgbaMode
{
    fn default() -> RgbaMode
    {
        RgbaMode::Alpha
    }
}
<commit_msg>Added tests for rgba alpha enconding and decoding<commit_after>use image::RgbaImage;
use rand::Rng;
use itertools::Itertools;

use utils::*;

pub fn encode_rgba<R: Rng>(source: &mut RgbaImage, payload: &[u8], mode: RgbaMode, mut rng: R)
{
    // number of pixels per byte
    let ppb = match mode
    {
        // 1 values per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // 4 values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    for (pixels, byte) in source.pixels_mut() // iterate pixels mutably
        .chunks(ppb).into_iter()              // split them into ppb-size chunks
        .map(|ch| ch.collect::<Vec<_>>())     // make them vectors so we can check their lengths later
        .zip(payload.iter().map(|x| *x))      // give each chunk a byte
    {
        // if the pixels don't fit exactly into their chunks,
        // the last chunk will be short. we won't use that chunk
        // (making sure the payload fits into the image is not
        // this functions job!)
        if pixels.len() != ppb
        {
            return;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                for (i, px) in pixels.into_iter().enumerate()
                {
                    // a true, or 1 bit
                    if get_bit(byte, i as u8)
                    {
                        // even = 0 bit, so it needs to be changed
                        if px.data[3] % 2 == 0
                        {
                            // special case: if it's zero, we have to go up
                            if px.data[3] == 0
                            {
                                px.data[3] = 1;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                    // a false, or 0 bit
                    else
                    {
                        // odd = 1 bit, so it needs to be changed
                        if px.data[3] % 2 == 1
                        {
                            // special case: if it's 255, we have to go down
                            if px.data[3] == 255
                            {
                                px.data[3] = 254;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                }
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            },
        }
    }
}

pub fn decode_rgba(source: &RgbaImage, mode: RgbaMode) -> Vec<u8>
{
    // pixels per byte
    let ppb = match mode
    {
        // one value per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // four values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    let mut buf = Vec::new();

    for pixels in source.pixels()         // iterate pixels
        .chunks(ppb).into_iter()          // split into ppb-sized chunks
        .map(|ch| ch.collect::<Vec<_>>()) // make them vectors so we can check their lengths
    {
        // only decode while we have enough data
        if pixels.len() != ppb
        {
            break;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                let mut byte = 0u8;

                for (i, px) in pixels.into_iter().enumerate()
                {
                    byte = set_bit(byte, i as u8, px.data[3] % 2 == 1);
                }

                buf.push(byte)
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            }
        }
    }

    buf

}

/// The encoding/decoding mode
#[derive(Copy, Clone)]
pub enum RgbaMode
{
    /// encode in alpha even/odd
    Alpha,
    /// encode in each field even/odd
    Each,
}

use std::default::Default;

impl Default for RgbaMode
{
    fn default() -> RgbaMode
    {
        RgbaMode::Alpha
    }
}

#[cfg(test)]
mod test
{
    use image::{ImageBuffer, Rgba};
    use rand::StdRng;

    use super::*;

    #[test]
    fn alpha()
    {
        let mut image = ImageBuffer::from_pixel(
            25,
            8,
            Rgba
            {
                data: [127u8; 4],
            });

        let payload = vec![
            1,2, 3, 4, 5, 6, 7, 8, 9, 10,
            11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
            21, 22, 23, 24, 25
        ];

        let rng = StdRng::new().unwrap();

        encode_rgba(&mut image, &payload, RgbaMode::Alpha, rng);

        let dec = decode_rgba(&image, RgbaMode::Alpha);

        assert_eq!(payload, dec);
    }
}
<|endoftext|>


<commit_before>use api::{JsRuntimeHandle, JsContextRef, JsValueRef, JsCreateRuntime, JsCreateContext, JsSetCurrentContext, JsRuntimeAttributes, JsDisposeRuntime, JsSourceContext, JsRunScript, JsErrorCode};
use std::ptr;
use libc::{c_void, wchar_t};

/// A Rust equivalent of the ChakraCore runtime.
///
/// All dependent ChakraCore runtimes and contexts are destroyed when this goes out of scope.
pub struct Runtime {
    rt: JsRuntimeHandle,
    cx: JsContextRef
}

impl Runtime {
    /// Creates a new `Runtime`.
    ///
    /// An equivalent runtime and context is created by ChakraCore when this is done.
    pub fn new(attributes: JsRuntimeAttributes) -> Result<Runtime, JsErrorCode> {
        let mut rt = JsRuntimeHandle(ptr::null_mut() as *mut c_void);
        let mut cx = JsContextRef(ptr::null_mut() as *mut c_void);
        unsafe {
            let status = JsCreateRuntime(attributes, None, &mut rt);
            match status {
                JsErrorCode::JsNoError => {
                    let status = JsCreateContext(rt, &mut cx);
                    match status {
                        JsErrorCode::JsNoError => {
                            let status = JsSetCurrentContext(cx);
                            match status {
                                JsErrorCode::JsNoError => Ok(Runtime { rt: rt, cx: cx }),
                                _ => Err(status)
                            }
                        },
                        _ => Err(status)
                    }
                },
                _ => Err(status)
            }
        }
    }

    /// Returns the `JsRuntimeHandle` from ChakraCore.
    pub fn rt(&self) -> JsRuntimeHandle {
        self.rt
    }

    /// Returns the `JsContextRef` from ChakraCore.
    pub fn cx(&self) -> JsContextRef {
        self.cx
    }

    /// Runs a script and returns the result.
    pub fn run_script(&self, script: String, context: JsSourceContext, label: String) -> Result<JsValueRef, JsErrorCode> {
        let mut result = JsValueRef(ptr::null_mut() as *mut c_void);
        let status = unsafe { JsRunScript(script.to_wchar(), context, label, &mut result) };
        match status {
            JsErrorCode::JsNoError => Ok(result),
            _ => Err(status)
        }
    }
}

impl Drop for Runtime {
    fn drop(&mut self) {
        unsafe {
            JsSetCurrentContext(JsContextRef(ptr::null_mut() as *mut c_void));
            JsDisposeRuntime(self.rt);
        }
    }
}
<commit_msg>oops wrong code<commit_after>use api::{JsRuntimeHandle, JsContextRef, JsValueRef, JsCreateRuntime, JsCreateContext, JsSetCurrentContext, JsRuntimeAttributes, JsDisposeRuntime, JsSourceContext, JsRunScript, JsErrorCode};
use std::ptr;
use libc::{c_void, wchar_t};

/// A Rust equivalent of the ChakraCore runtime.
///
/// All dependent ChakraCore runtimes and contexts are destroyed when this goes out of scope.
pub struct Runtime {
    rt: JsRuntimeHandle,
    cx: JsContextRef
}

impl Runtime {
    /// Creates a new `Runtime`.
    ///
    /// An equivalent runtime and context is created by ChakraCore when this is done.
    pub fn new(attributes: JsRuntimeAttributes) -> Result<Runtime, JsErrorCode> {
        let mut rt = JsRuntimeHandle(ptr::null_mut() as *mut c_void);
        let mut cx = JsContextRef(ptr::null_mut() as *mut c_void);
        unsafe {
            let status = JsCreateRuntime(attributes, None, &mut rt);
            match status {
                JsErrorCode::JsNoError => {
                    let status = JsCreateContext(rt, &mut cx);
                    match status {
                        JsErrorCode::JsNoError => {
                            let status = JsSetCurrentContext(cx);
                            match status {
                                JsErrorCode::JsNoError => Ok(Runtime { rt: rt, cx: cx }),
                                _ => Err(status)
                            }
                        },
                        _ => Err(status)
                    }
                },
                _ => Err(status)
            }
        }
    }

    /// Returns the `JsRuntimeHandle` from ChakraCore.
    pub fn rt(&self) -> JsRuntimeHandle {
        self.rt
    }

    /// Returns the `JsContextRef` from ChakraCore.
    pub fn cx(&self) -> JsContextRef {
        self.cx
    }

    /// Runs a script and returns the result.
    pub fn run_script(&self, script: *const wchar_t, context: JsSourceContext, label: *const wchar_t) -> Result<JsValueRef, JsErrorCode> {
        let mut result = JsValueRef(ptr::null_mut() as *mut c_void);
        let status = unsafe { JsRunScript(script, context, label, &mut result) };
        match status {
            JsErrorCode::JsNoError => Ok(result),
            _ => Err(status)
        }
    }
}

impl Drop for Runtime {
    fn drop(&mut self) {
        unsafe {
            JsSetCurrentContext(JsContextRef(ptr::null_mut() as *mut c_void));
            JsDisposeRuntime(self.rt);
        }
    }
}
<|endoftext|>


<commit_before>#![ allow (unused_parens) ]

use std::fs;
use std::fs::DirEntry;
use std::io;
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::rc::Rc;

use output::Output;

use arguments::*;
use misc::*;
use storage::*;

fn scan_directory_internal (
	arguments: & Arguments,
	output: & mut Output,
	directory: Rc <PathBuf>,
	root_path: Rc <PathBuf>,
	device_id: u64,
	in_iterator: & mut FileDatabaseIntoIterator,
	out_database: & mut FileDatabase,
	progress: & mut u64,
) -> Result <(), String> {

	let directory =
		directory.as_ref ();

	let entry_results: Vec <io::Result <DirEntry>> =
		try! (

		io_result (
			fs::read_dir (
				directory),
		).map_err (
			|error|

			format! (
				"Error reading directory: {}: {}",
				directory.to_string_lossy (),
				error)

		)

	).collect ();

	let mut entries: Vec <DirEntry> =
		Vec::new ();

	for entry_result in entry_results.into_iter () {

		entries.push (
			try! (

			io_result (
				entry_result,
			).map_err (
				|error|

				format! (
					"Error reading entry: {}",
					error)

			)

		));

	}

	entries.sort_by_key (
		|entry|

		entry.file_name ()

	);

	let mut entry_iterator =
		entries.into_iter ().peekable ();

	loop {

		{

			let entry_next =
				entry_iterator.peek ();

			if entry_next.is_none () {
				break;
			}

		}

		let entry =
			entry_iterator.next ().unwrap ();

		let entry_path =
			Rc::new (
				entry.path ());

		loop {

			let exists = {

				let in_next_option =
					in_iterator.peek ();

				if in_next_option.is_none () {
					break;
				}

				let in_next =
					in_next_option.unwrap ();

				let in_next_path =
					in_next.path.clone ();

				if in_next_path >= entry_path {
					break;
				}

				in_next_path.exists ()

			};

			if exists {

				out_database.insert_direct (
					in_iterator.next ().unwrap ());

			} else {

				in_iterator.next ();

			}

		}

		let metadata =
			try! (

			fs::symlink_metadata (
				entry.path (),
			).map_err (
				|error|

				format! (
					"Error reading metadata for: {}: {}",
					entry.path ().to_string_lossy (),
					error)

			)

		);

		let file_type =
			metadata.file_type ();

		if (

			file_type.is_symlink ()

			|| metadata.dev () != device_id

		) {

			// ignore

		} else if file_type.is_dir () {

			try! (
				scan_directory_internal (
					arguments,
					output,
					entry_path,
					root_path.clone (),
					device_id,
					in_iterator,
					out_database,
					progress));

		} else if file_type.is_file () {

			let exists = {

				let in_next_option =
					in_iterator.peek ();

				if in_next_option.is_some () {

					let in_next =
						in_next_option.unwrap ();

					let in_next_path =
						in_next.path.clone ();

					in_next_path == entry_path

				} else {

					false

				}

			};

			if exists {

				let existing_file_data =
					in_iterator.next ().unwrap ();

				let changed = (

					metadata.len () !=
						existing_file_data.size

				||

					metadata.mtime () !=
						existing_file_data.mtime

				);

				if changed {

					out_database.insert_update_metadata (
						& existing_file_data,
						root_path.clone (),
						& metadata,
					);

				} else {

					out_database.insert_direct (
						existing_file_data)

				}

			} else {

				out_database.insert_new (
					Rc::new (
						entry.path ()),
					root_path.clone (),
					& metadata,
				);

			}

		} else {

			stderrln! (
				"Ignoring unknown filetype: {:?}: {}",
				file_type,
				entry.path ().to_string_lossy ());

		};

		if * progress % 0x1000 == 0 {

			output.status (
				& format! (
					"Scanning filesystem: {}",
					entry.path ().to_string_lossy ()));

		}

		* progress += 1;

	}

	Ok (())

}

pub fn scan_directories (
	arguments: & Arguments,
	output: & mut Output,
	previous_database: FileDatabase,
) -> Result <FileDatabase, String> {

	let mut new_database: FileDatabase =
		FileDatabase::new ();

	let mut progress: u64 = 0;

	let previous_database_iterator =
		previous_database.into_iter ();

	let mut previous_database_iterator =
		previous_database_iterator.peekable ();

	for root_path in & arguments.root_paths {

		let root_path =
			new_database.get_path (
				root_path.clone ());

		let metadata =
			try! (

			fs::symlink_metadata (
				root_path.as_ref (),
			).map_err (
				|error|

				format! (
					"Error reading metadata for: {}: {}",
					root_path.to_string_lossy (),
					error)

			)

		);

		loop {

			{

				let existing_file_data_option =
					previous_database_iterator.peek ();

				if existing_file_data_option.is_none () {
					break;
				}

				let existing_file_data =
					existing_file_data_option.unwrap ();

				let existing_file_path =
					& existing_file_data.path;

				if * existing_file_path >= root_path {
					break;
				}

			}

			new_database.insert_direct (
				previous_database_iterator.next ().unwrap ());

		}

		try! (
			scan_directory_internal (
				arguments,
				output,
				root_path.clone (),
				root_path.clone (),
				metadata.dev (),
				& mut previous_database_iterator,
				& mut new_database,
				& mut progress));

	}

	for existing_file_data_ref in previous_database_iterator {

		new_database.insert_direct (
			existing_file_data_ref.clone ());

	}

	output.clear_status ();

	output.message (
		& format! (
			"Scanned {} files",
			progress));

	output.message (
		& format! (
			"Total {} files in database",
			new_database.len ()));

	Ok (new_database)

}

// ex: noet ts=4 filetype=rust
<commit_msg>don't print error on unrecognised file types<commit_after>#![ allow (unused_parens) ]

use std::fs;
use std::fs::DirEntry;
use std::io;
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::rc::Rc;

use output::Output;

use arguments::*;
use misc::*;
use storage::*;

fn scan_directory_internal (
	arguments: & Arguments,
	output: & mut Output,
	directory: Rc <PathBuf>,
	root_path: Rc <PathBuf>,
	device_id: u64,
	in_iterator: & mut FileDatabaseIntoIterator,
	out_database: & mut FileDatabase,
	progress: & mut u64,
) -> Result <(), String> {

	let directory =
		directory.as_ref ();

	let entry_results: Vec <io::Result <DirEntry>> =
		try! (

		io_result (
			fs::read_dir (
				directory),
		).map_err (
			|error|

			format! (
				"Error reading directory: {}: {}",
				directory.to_string_lossy (),
				error)

		)

	).collect ();

	let mut entries: Vec <DirEntry> =
		Vec::new ();

	for entry_result in entry_results.into_iter () {

		entries.push (
			try! (

			io_result (
				entry_result,
			).map_err (
				|error|

				format! (
					"Error reading entry: {}",
					error)

			)

		));

	}

	entries.sort_by_key (
		|entry|

		entry.file_name ()

	);

	let mut entry_iterator =
		entries.into_iter ().peekable ();

	loop {

		{

			let entry_next =
				entry_iterator.peek ();

			if entry_next.is_none () {
				break;
			}

		}

		let entry =
			entry_iterator.next ().unwrap ();

		let entry_path =
			Rc::new (
				entry.path ());

		loop {

			let exists = {

				let in_next_option =
					in_iterator.peek ();

				if in_next_option.is_none () {
					break;
				}

				let in_next =
					in_next_option.unwrap ();

				let in_next_path =
					in_next.path.clone ();

				if in_next_path >= entry_path {
					break;
				}

				in_next_path.exists ()

			};

			if exists {

				out_database.insert_direct (
					in_iterator.next ().unwrap ());

			} else {

				in_iterator.next ();

			}

		}

		let metadata =
			try! (

			fs::symlink_metadata (
				entry.path (),
			).map_err (
				|error|

				format! (
					"Error reading metadata for: {}: {}",
					entry.path ().to_string_lossy (),
					error)

			)

		);

		let file_type =
			metadata.file_type ();

		if (

			file_type.is_symlink ()

			|| metadata.dev () != device_id

		) {

			// ignore

		} else if file_type.is_dir () {

			try! (
				scan_directory_internal (
					arguments,
					output,
					entry_path,
					root_path.clone (),
					device_id,
					in_iterator,
					out_database,
					progress));

		} else if file_type.is_file () {

			let exists = {

				let in_next_option =
					in_iterator.peek ();

				if in_next_option.is_some () {

					let in_next =
						in_next_option.unwrap ();

					let in_next_path =
						in_next.path.clone ();

					in_next_path == entry_path

				} else {

					false

				}

			};

			if exists {

				let existing_file_data =
					in_iterator.next ().unwrap ();

				let changed = (

					metadata.len () !=
						existing_file_data.size

				||

					metadata.mtime () !=
						existing_file_data.mtime

				);

				if changed {

					out_database.insert_update_metadata (
						& existing_file_data,
						root_path.clone (),
						& metadata,
					);

				} else {

					out_database.insert_direct (
						existing_file_data)

				}

			} else {

				out_database.insert_new (
					Rc::new (
						entry.path ()),
					root_path.clone (),
					& metadata,
				);

			}

		};

		if * progress % 0x1000 == 0 {

			output.status (
				& format! (
					"Scanning filesystem: {}",
					entry.path ().to_string_lossy ()));

		}

		* progress += 1;

	}

	Ok (())

}

pub fn scan_directories (
	arguments: & Arguments,
	output: & mut Output,
	previous_database: FileDatabase,
) -> Result <FileDatabase, String> {

	let mut new_database: FileDatabase =
		FileDatabase::new ();

	let mut progress: u64 = 0;

	let previous_database_iterator =
		previous_database.into_iter ();

	let mut previous_database_iterator =
		previous_database_iterator.peekable ();

	for root_path in & arguments.root_paths {

		let root_path =
			new_database.get_path (
				root_path.clone ());

		let metadata =
			try! (

			fs::symlink_metadata (
				root_path.as_ref (),
			).map_err (
				|error|

				format! (
					"Error reading metadata for: {}: {}",
					root_path.to_string_lossy (),
					error)

			)

		);

		loop {

			{

				let existing_file_data_option =
					previous_database_iterator.peek ();

				if existing_file_data_option.is_none () {
					break;
				}

				let existing_file_data =
					existing_file_data_option.unwrap ();

				let existing_file_path =
					& existing_file_data.path;

				if * existing_file_path >= root_path {
					break;
				}

			}

			new_database.insert_direct (
				previous_database_iterator.next ().unwrap ());

		}

		try! (
			scan_directory_internal (
				arguments,
				output,
				root_path.clone (),
				root_path.clone (),
				metadata.dev (),
				& mut previous_database_iterator,
				& mut new_database,
				& mut progress));

	}

	for existing_file_data_ref in previous_database_iterator {

		new_database.insert_direct (
			existing_file_data_ref.clone ());

	}

	output.clear_status ();

	output.message (
		& format! (
			"Scanned {} files",
			progress));

	output.message (
		& format! (
			"Total {} files in database",
			new_database.len ()));

	Ok (new_database)

}

// ex: noet ts=4 filetype=rust
<|endoftext|>


<commit_before>//! The module defines song structs and methods.

use time::{strptime, Duration, Tm};
use rustc_serialize::{Encodable, Encoder};

use std::collections::BTreeMap;
use std::str::FromStr;
use std::fmt;

use error::{Error, ParseError};
use convert::FromIter;

/// Song ID
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Default, RustcEncodable)]
pub struct Id(pub u32);

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

/// Song place in the queue
#[derive(Debug, Copy, Clone, PartialEq, Default, RustcEncodable)]
pub struct QueuePlace {
    /// song ID
    pub id: Id,
    /// absolute zero-based song position
    pub pos: u32,
    /// song priority, if present, defaults to 0
    pub prio: u8
}

/// Song range
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Range(pub Duration, pub Option<Duration>);

impl Encodable for Range {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_tuple(2, |e|
            e.emit_tuple_arg(0, |e| e.emit_i64(self.0.num_seconds())).and_then(|_|
            e.emit_tuple_arg(1, |e| e.emit_option(|e| self.1.map(|d| e.emit_option_some(|e| d.num_seconds().encode(e))).unwrap_or_else(|| e.emit_option_none())))))
    }
}

impl Default for Range {
    fn default() -> Range {
        Range(Duration::seconds(0), None)
    }
}

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.num_seconds().fmt(f)
            .and_then(|_| f.write_str(":"))
            .and_then(|_| self.1.map(|v| v.num_seconds().fmt(f)).unwrap_or(Ok(())))
    }
}

impl FromStr for Range {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Range, ParseError> {
        let mut splits = s.split('-').flat_map(|v| v.parse().into_iter());
        match (splits.next(), splits.next()) {
            (Some(s), Some(e)) => Ok(Range(Duration::seconds(s), Some(Duration::seconds(e)))),
            (None, Some(e)) => Ok(Range(Duration::zero(), Some(Duration::seconds(e)))),
            (Some(s), None) => Ok(Range(Duration::seconds(s), None)),
            (None, None) => Ok(Range(Duration::zero(), None)),
        }
    }
}

/// Song data
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Song {
    /// filename
    pub file: String,
    /// name (for streams)
    pub name: Option<String>,
    /// last modification time
    pub last_mod: Option<Tm>,
    /// duration (in seconds resolution)
    pub duration: Option<Duration>,
    /// place in the queue (if queued for playback)
    pub place: Option<QueuePlace>,
    /// range to play (if queued for playback and range was set)
    pub range: Option<Range>,
    /// arbitrary tags, like album, artist etc
    pub tags: BTreeMap<String, String>,
}

impl Encodable for Song {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_struct("Song", 7, |e|
            e.emit_struct_field("file", 0, |e| self.file.encode(e)).and_then(|_|
            e.emit_struct_field("name", 1, |e| self.name.encode(e))).and_then(|_|
            e.emit_struct_field("last_mod", 2, |e| e.emit_option(
                    |e| self.last_mod.as_ref().map(|m| e.emit_option_some(|e| m.to_timespec().sec.encode(e))).unwrap_or_else(|| e.emit_option_none())))).and_then(|_|
            e.emit_struct_field("duration", 3, |e| e.emit_option(
                    |e| self.duration.as_ref().map(|d| e.emit_option_some(|e| d.num_seconds().encode(e))).unwrap_or_else(|| e.emit_option_none())
                    ))).and_then(|_|
            e.emit_struct_field("place", 4, |e| self.place.encode(e))).and_then(|_|
            e.emit_struct_field("range", 5, |e| self.range.encode(e))).and_then(|_|
            e.emit_struct_field("tags", 6, |e| self.tags.encode(e))))
    }
}

impl FromIter for Song {
    /// build song from map
    fn from_iter<I: Iterator<Item=Result<(String, String), Error>>>(iter: I) -> Result<Song, Error> {
        let mut result = Song::default();

        for res in iter {
            let line = try!(res);
            match &*line.0 {
                "file" => result.file = line.1.to_owned(),
                "Last-Modified" => result.last_mod = try!(strptime(&*line.1, "%Y-%m-%dT%H:%M:%S%Z").map_err(ParseError::BadTime).map(Some)),
                "Name" => result.name = Some(line.1.to_owned()),
                "Time" => result.duration = Some(Duration::seconds(try!(line.1.parse()))),
                "Range" => result.range = Some(try!(line.1.parse())),
                "Id" => match result.place {
                    None => result.place = Some(QueuePlace { id: Id(try!(line.1.parse())), pos: 0, prio: 0 }),
                    Some(ref mut place) => place.id = Id(try!(line.1.parse())),
                },
                "Pos" => match result.place {
                    None => result.place = Some(QueuePlace { pos: try!(line.1.parse()), id: Id(0), prio: 0 }),
                    Some(ref mut place) => place.pos = try!(line.1.parse()),
                },
                "Prio" => match result.place {
                    None => result.place = Some(QueuePlace { prio: try!(line.1.parse()), id: Id(0), pos: 0 }),
                    Some(ref mut place) => place.prio = try!(line.1.parse()),
                },
                _ => { result.tags.insert(line.0, line.1); }
            }
        }

        Ok(result)
    }
}

<commit_msg>encode song id to plain int<commit_after>//! The module defines song structs and methods.

use time::{strptime, Duration, Tm};
use rustc_serialize::{Encodable, Encoder};

use std::collections::BTreeMap;
use std::str::FromStr;
use std::fmt;

use error::{Error, ParseError};
use convert::FromIter;

/// Song ID
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Default)]
pub struct Id(pub u32);

impl Encodable for Id {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        self.0.encode(e)
    }
}

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

/// Song place in the queue
#[derive(Debug, Copy, Clone, PartialEq, Default, RustcEncodable)]
pub struct QueuePlace {
    /// song ID
    pub id: Id,
    /// absolute zero-based song position
    pub pos: u32,
    /// song priority, if present, defaults to 0
    pub prio: u8
}

/// Song range
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Range(pub Duration, pub Option<Duration>);

impl Encodable for Range {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_tuple(2, |e|
            e.emit_tuple_arg(0, |e| e.emit_i64(self.0.num_seconds())).and_then(|_|
            e.emit_tuple_arg(1, |e| e.emit_option(|e| self.1.map(|d| e.emit_option_some(|e| d.num_seconds().encode(e))).unwrap_or_else(|| e.emit_option_none())))))
    }
}

impl Default for Range {
    fn default() -> Range {
        Range(Duration::seconds(0), None)
    }
}

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.num_seconds().fmt(f)
            .and_then(|_| f.write_str(":"))
            .and_then(|_| self.1.map(|v| v.num_seconds().fmt(f)).unwrap_or(Ok(())))
    }
}

impl FromStr for Range {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Range, ParseError> {
        let mut splits = s.split('-').flat_map(|v| v.parse().into_iter());
        match (splits.next(), splits.next()) {
            (Some(s), Some(e)) => Ok(Range(Duration::seconds(s), Some(Duration::seconds(e)))),
            (None, Some(e)) => Ok(Range(Duration::zero(), Some(Duration::seconds(e)))),
            (Some(s), None) => Ok(Range(Duration::seconds(s), None)),
            (None, None) => Ok(Range(Duration::zero(), None)),
        }
    }
}

/// Song data
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Song {
    /// filename
    pub file: String,
    /// name (for streams)
    pub name: Option<String>,
    /// last modification time
    pub last_mod: Option<Tm>,
    /// duration (in seconds resolution)
    pub duration: Option<Duration>,
    /// place in the queue (if queued for playback)
    pub place: Option<QueuePlace>,
    /// range to play (if queued for playback and range was set)
    pub range: Option<Range>,
    /// arbitrary tags, like album, artist etc
    pub tags: BTreeMap<String, String>,
}

impl Encodable for Song {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_struct("Song", 7, |e|
            e.emit_struct_field("file", 0, |e| self.file.encode(e)).and_then(|_|
            e.emit_struct_field("name", 1, |e| self.name.encode(e))).and_then(|_|
            e.emit_struct_field("last_mod", 2, |e| e.emit_option(
                    |e| self.last_mod.as_ref().map(|m| e.emit_option_some(|e| m.to_timespec().sec.encode(e))).unwrap_or_else(|| e.emit_option_none())))).and_then(|_|
            e.emit_struct_field("duration", 3, |e| e.emit_option(
                    |e| self.duration.as_ref().map(|d| e.emit_option_some(|e| d.num_seconds().encode(e))).unwrap_or_else(|| e.emit_option_none())
                    ))).and_then(|_|
            e.emit_struct_field("place", 4, |e| self.place.encode(e))).and_then(|_|
            e.emit_struct_field("range", 5, |e| self.range.encode(e))).and_then(|_|
            e.emit_struct_field("tags", 6, |e| self.tags.encode(e))))
    }
}

impl FromIter for Song {
    /// build song from map
    fn from_iter<I: Iterator<Item=Result<(String, String), Error>>>(iter: I) -> Result<Song, Error> {
        let mut result = Song::default();

        for res in iter {
            let line = try!(res);
            match &*line.0 {
                "file" => result.file = line.1.to_owned(),
                "Last-Modified" => result.last_mod = try!(strptime(&*line.1, "%Y-%m-%dT%H:%M:%S%Z").map_err(ParseError::BadTime).map(Some)),
                "Name" => result.name = Some(line.1.to_owned()),
                "Time" => result.duration = Some(Duration::seconds(try!(line.1.parse()))),
                "Range" => result.range = Some(try!(line.1.parse())),
                "Id" => match result.place {
                    None => result.place = Some(QueuePlace { id: Id(try!(line.1.parse())), pos: 0, prio: 0 }),
                    Some(ref mut place) => place.id = Id(try!(line.1.parse())),
                },
                "Pos" => match result.place {
                    None => result.place = Some(QueuePlace { pos: try!(line.1.parse()), id: Id(0), prio: 0 }),
                    Some(ref mut place) => place.pos = try!(line.1.parse()),
                },
                "Prio" => match result.place {
                    None => result.place = Some(QueuePlace { prio: try!(line.1.parse()), id: Id(0), pos: 0 }),
                    Some(ref mut place) => place.prio = try!(line.1.parse()),
                },
                _ => { result.tags.insert(line.0, line.1); }
            }
        }

        Ok(result)
    }
}

<|endoftext|>


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

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

/// More information can be found at
/// http://lxr.free-electrons.com/source/Documentation/hwmon/sysfs-interface
pub struct Component {
    /// Temperature is in celsius.
    pub temperature: f32,
    /// Temperature max value.
    pub max: f32,
    /// The highest temperature before the computer halts.
    pub critical: Option<f32>,
    /// Component's label.
    pub label: String,
    input_file: PathBuf,
}

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

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings = HashMap::new();
    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() {
                        if let Ok(id) = entry[4..5].parse::<u32>() {
                            matchings.entry(id)
                                     .or_insert_with(|| Vec::with_capacity(1))
                                     .push(entry[6..].to_owned());
                        }
                    }
                }
            }
        }
        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() {
                    "input" => { found_input = Some(pos); }
                    "label" => { found_label = Some(pos); }
                    _ => {}
                }
                if found_label.is_some() && found_input.is_some() {
                    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{}_input", key));
                    p_max.push(&format!("temp{}_max", key));
                    p_crit.push(&format!("temp{}_crit", key));
                    if let Some(content) = get_file_line(p_label.as_path()) {
                        let label = content.replace("\n", "");
                        let max = if let Some(max) = get_file_line(p_max.as_path()) {
                            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()) {
                            Some(crit.replace("\n", "")
                                     .parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                        } else {
                            None
                        };
                        components.push(Component::new(label, p_input.as_path(), max, crit));
                        break
                    }
                }
            }
        }
    }
}

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

    /// Updates the component.
    pub fn update(&mut self) {
        if let Some(content) = get_file_line(self.input_file.as_path()) {
            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 ret = Vec::new();
    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 ret, &entry);
            }
        }
    }
    ret.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
    ret
}
<commit_msg>Fix clippy lint<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

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

/// More information can be found at
/// <http://lxr.free-electrons.com/source/Documentation/hwmon/sysfs-interface>
pub struct Component {
    /// Temperature is in celsius.
    pub temperature: f32,
    /// Temperature max value.
    pub max: f32,
    /// The highest temperature before the computer halts.
    pub critical: Option<f32>,
    /// Component's label.
    pub label: String,
    input_file: PathBuf,
}

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

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings = HashMap::new();
    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() {
                        if let Ok(id) = entry[4..5].parse::<u32>() {
                            matchings.entry(id)
                                     .or_insert_with(|| Vec::with_capacity(1))
                                     .push(entry[6..].to_owned());
                        }
                    }
                }
            }
        }
        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() {
                    "input" => { found_input = Some(pos); }
                    "label" => { found_label = Some(pos); }
                    _ => {}
                }
                if found_label.is_some() && found_input.is_some() {
                    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{}_input", key));
                    p_max.push(&format!("temp{}_max", key));
                    p_crit.push(&format!("temp{}_crit", key));
                    if let Some(content) = get_file_line(p_label.as_path()) {
                        let label = content.replace("\n", "");
                        let max = if let Some(max) = get_file_line(p_max.as_path()) {
                            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()) {
                            Some(crit.replace("\n", "")
                                     .parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                        } else {
                            None
                        };
                        components.push(Component::new(label, p_input.as_path(), max, crit));
                        break
                    }
                }
            }
        }
    }
}

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

    /// Updates the component.
    pub fn update(&mut self) {
        if let Some(content) = get_file_line(self.input_file.as_path()) {
            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 ret = Vec::new();
    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 ret, &entry);
            }
        }
    }
    ret.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
    ret
}
<|endoftext|>


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

use ComponentExt;

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

/// More information can be found at
/// <http://lxr.free-electrons.com/source/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) -> Option<String> {
    let mut reader = String::new();
    if let Ok(mut f) = File::open(file) {
        if f.read_to_string(&mut reader).is_ok() {
            Some(reader)
        } else {
            None
        }
    } else {
        None
    }
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings = HashMap::new();
    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() {
                        if let Ok(id) = entry[4..5].parse::<u32>() {
                            matchings.entry(id)
                                     .or_insert_with(|| Vec::with_capacity(1))
                                     .push(entry[6..].to_owned());
                        }
                    }
                }
            }
        }
        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() {
                    "input" => { found_input = Some(pos); }
                    "label" => { found_label = Some(pos); }
                    _ => {}
                }
                if found_label.is_some() && found_input.is_some() {
                    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{}_input", key));
                    p_max.push(&format!("temp{}_max", key));
                    p_crit.push(&format!("temp{}_crit", key));
                    if let Some(content) = get_file_line(p_label.as_path()) {
                        let label = content.replace("\n", "");
                        let max = if let Some(max) = get_file_line(p_max.as_path()) {
                            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()) {
                            Some(crit.replace("\n", "")
                                     .parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                        } else {
                            None
                        };
                        components.push(Component::new(label, p_input.as_path(), max, crit));
                        break
                    }
                }
            }
        }
    }
}

impl Component {
    /// Creates a new component with the given information.
    pub 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.update();
        c
    }

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

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
    }
}

pub fn get_components() -> Vec<Component> {
    let mut ret = Vec::new();
    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 ret, &entry);
            }
        }
    }
    ret.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
    ret
}
<commit_msg>Fix doc url<commit_after>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use ComponentExt;

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

/// More information can be found at [kernel.org][k].
///
/// 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) -> Option<String> {
    let mut reader = String::new();
    if let Ok(mut f) = File::open(file) {
        if f.read_to_string(&mut reader).is_ok() {
            Some(reader)
        } else {
            None
        }
    } else {
        None
    }
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings = HashMap::new();
    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() {
                        if let Ok(id) = entry[4..5].parse::<u32>() {
                            matchings.entry(id)
                                     .or_insert_with(|| Vec::with_capacity(1))
                                     .push(entry[6..].to_owned());
                        }
                    }
                }
            }
        }
        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() {
                    "input" => { found_input = Some(pos); }
                    "label" => { found_label = Some(pos); }
                    _ => {}
                }
                if found_label.is_some() && found_input.is_some() {
                    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{}_input", key));
                    p_max.push(&format!("temp{}_max", key));
                    p_crit.push(&format!("temp{}_crit", key));
                    if let Some(content) = get_file_line(p_label.as_path()) {
                        let label = content.replace("\n", "");
                        let max = if let Some(max) = get_file_line(p_max.as_path()) {
                            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()) {
                            Some(crit.replace("\n", "")
                                     .parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                        } else {
                            None
                        };
                        components.push(Component::new(label, p_input.as_path(), max, crit));
                        break
                    }
                }
            }
        }
    }
}

impl Component {
    /// Creates a new component with the given information.
    pub 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.update();
        c
    }

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

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
    }
}

pub fn get_components() -> Vec<Component> {
    let mut ret = Vec::new();
    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 ret, &entry);
            }
        }
    }
    ret.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
    ret
}
<|endoftext|>


<commit_before>use cgmath::{Aabb3, Point3};
use std::sync::Mutex;
use stopwatch;
use time;

use common::protocol;
use common::surroundings_loader;
use common::surroundings_loader::LoadType;
use common::voxel;

use block_position;
use client;
use lod;
use load_terrain;
use load_terrain::lod_index;
use server_update::apply_server_update;
use terrain_mesh;
use view_update::ClientToView;

const MAX_OUTSTANDING_TERRAIN_REQUESTS: u32 = 1;

pub fn update_thread<RecvServer, RecvVoxelUpdates, UpdateView0, UpdateView1, UpdateServer, EnqueueBlockUpdates>(
  quit: &Mutex<bool>,
  client: &client::T,
  recv_server: &mut RecvServer,
  recv_voxel_updates: &mut RecvVoxelUpdates,
  update_view0: &mut UpdateView0,
  update_view1: &mut UpdateView1,
  update_server: &mut UpdateServer,
  enqueue_block_updates: &mut EnqueueBlockUpdates,
) where
  RecvServer: FnMut() -> Option<protocol::ServerToClient>,
  RecvVoxelUpdates: FnMut() -> Option<(Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason)>,
  UpdateView0: FnMut(ClientToView),
  UpdateView1: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
  EnqueueBlockUpdates: FnMut(Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason),
{
  'update_loop: loop {
    if *quit.lock().unwrap() == true {
      break 'update_loop
    } else {
      stopwatch::time("update_iteration", || {
        stopwatch::time("process_server_updates", || {
          process_server_updates(client, recv_server, update_view0, update_server, enqueue_block_updates);
        });

        stopwatch::time("update_surroundings", || {
          update_surroundings(client, update_view1, update_server);
        });

        stopwatch::time("process_voxel_updates", || {
          process_voxel_updates(client, recv_voxel_updates, update_view1);
        });
      })
    }
  }
}

#[inline(never)]
fn update_surroundings<UpdateView, UpdateServer>(
  client: &client::T,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
) where
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
{
  let start = time::precise_time_ns();
  let mut i = 0;
  let player_position = *client.player_position.lock().unwrap();
  let player_position = block_position::of_world_position(&player_position);
  let mut loaded_blocks = client.loaded_blocks.lock().unwrap();
  let mut surroundings_loader = client.surroundings_loader.lock().unwrap();
  let mut updates = surroundings_loader.updates(player_position.as_pnt()) ;
  loop {
    if *client.outstanding_terrain_requests.lock().unwrap() >= MAX_OUTSTANDING_TERRAIN_REQUESTS {
      trace!("update loop breaking");
      break;
    }

    let block_position;
    let load_type;
    match updates.next() {
      None => break,
      Some((b, l)) => {
        block_position = block_position::of_pnt(&b);
        load_type = l;
      },
    }

    debug!("block surroundings");
    let distance =
      surroundings_loader::distance_between(
        player_position.as_pnt(),
        block_position.as_pnt(),
      );
    match load_type {
      LoadType::Load => {
        stopwatch::time("update_thread.load_block", || {
          let new_lod = lod_index(distance);
          let lod_change =
            loaded_blocks
            .get(&block_position)
            .map(|&(_, lod)| lod != new_lod);
          if lod_change != Some(false) {
            load_or_request_chunk(client, update_server, update_view, block_position, new_lod);
          } else {
            debug!("Not re-loading {:?} at {:?}", block_position, new_lod);
          }
        })
      },
      LoadType::Update => {
        stopwatch::time("update_thread.update_block", || {
          let new_lod = lod_index(distance);
          let lod_change =
            loaded_blocks
            .get(&block_position)
            .map(|&(_, lod)| new_lod < lod);
          if lod_change == Some(true) {
            load_or_request_chunk(client, update_server, update_view, block_position, new_lod);
          } else {
            trace!("Not updating {:?} at {:?}", block_position, new_lod);
          }
        })
      },
      LoadType::Unload => {
        stopwatch::time("update_thread.unload", || {
          // The block removal code is duplicated elsewhere.

          loaded_blocks
            .remove(&block_position)
            // If it wasn't loaded, don't unload anything.
            .map(|(block, _)| {
              for id in &block.ids {
                update_view(ClientToView::RemoveTerrain(*id));
              }
            });
        })
      },
    };

    if i >= 10 {
      i -= 10;
      if time::precise_time_ns() - start >= 1_000_000 {
        break
      }
    }
    i += 1;
  }
}

fn load_or_request_chunk<UpdateServer, UpdateView>(
  client: &client::T,
  update_server: &mut UpdateServer,
  update_view: &mut UpdateView,
  block_position: block_position::T,
  lod: lod::T,
) where
  UpdateServer: FnMut(protocol::ClientToServer),
  UpdateView: FnMut(ClientToView),
{
  let r = load_terrain::all_voxels_loaded(&client.block_voxels_loaded.lock().unwrap(), block_position, lod);
  if r && false {
    load_terrain::load_block(
      client,
      update_view,
      &block_position,
      lod,
    );
  } else {
    let voxel_size = 1 << terrain_mesh::LG_SAMPLE_SIZE[lod.0 as usize];
    update_server(
      protocol::ClientToServer::RequestVoxels(
        client.id,
        terrain_mesh::voxels_in(
          &Aabb3::new(
            Point3::new(
              (block_position.as_pnt().x << terrain_mesh::LG_WIDTH) - voxel_size,
              (block_position.as_pnt().y << terrain_mesh::LG_WIDTH) - voxel_size,
              (block_position.as_pnt().z << terrain_mesh::LG_WIDTH) - voxel_size,
            ),
            Point3::new(
              ((block_position.as_pnt().x + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
              ((block_position.as_pnt().y + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
              ((block_position.as_pnt().z + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
            ),
          ),
          terrain_mesh::LG_SAMPLE_SIZE[lod.0 as usize],
        ),
      )
    );
    *client.outstanding_terrain_requests.lock().unwrap() += 1;
  }
}

#[inline(never)]
fn process_voxel_updates<RecvVoxelUpdates, UpdateView>(
  client: &client::T,
  recv_voxel_updates: &mut RecvVoxelUpdates,
  update_view: &mut UpdateView,
) where
  RecvVoxelUpdates: FnMut() -> Option<(Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason)>,
  UpdateView: FnMut(ClientToView),
{
  let start = time::precise_time_ns();
  while let Some((voxel_updates, reason)) = recv_voxel_updates() {
    let mut update_blocks = block_position::with_lod::set::new();
    for (bounds, voxel) in voxel_updates {
      trace!("Got voxel at {:?}", bounds);
      load_terrain::load_voxel(
        client,
        voxel,
        bounds,
        |block, lod| { update_blocks.insert((block, lod)); },
      );
    }

    for (block, lod) in update_blocks.into_iter() {
      load_terrain::load_block(
        client,
        update_view,
        &block,
        lod
      )
    }

    match reason {
      protocol::VoxelReason::Updated => {},
      protocol::VoxelReason::Requested => {
        *client.outstanding_terrain_requests.lock().unwrap() -= 1;
        debug!("Outstanding terrain requests: {}", *client.outstanding_terrain_requests.lock().unwrap());
      },
    }

    if time::precise_time_ns() - start >= 1_000_000 {
      break
    }
  }
}

#[inline(never)]
fn process_server_updates<RecvServer, UpdateView, UpdateServer, EnqueueBlockUpdates>(
  client: &client::T,
  recv_server: &mut RecvServer,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
  enqueue_block_updates: &mut EnqueueBlockUpdates,
) where
  RecvServer: FnMut() -> Option<protocol::ServerToClient>,
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
  EnqueueBlockUpdates: FnMut(Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason),
{
  let start = time::precise_time_ns();
  let mut i = 0;
  while let Some(up) = recv_server() {
    apply_server_update(
      client,
      update_view,
      update_server,
      enqueue_block_updates,
      up,
    );

    if i > 10 {
      i -= 10;
      if time::precise_time_ns() - start >= 1_000_000 {
        break
      }
    }
    i += 1;
  }
}
<commit_msg>fix deadlock<commit_after>use cgmath::{Aabb3, Point3};
use std::sync::Mutex;
use stopwatch;
use time;

use common::protocol;
use common::surroundings_loader;
use common::surroundings_loader::LoadType;
use common::voxel;

use block_position;
use client;
use lod;
use load_terrain;
use load_terrain::lod_index;
use server_update::apply_server_update;
use terrain_mesh;
use view_update::ClientToView;

const MAX_OUTSTANDING_TERRAIN_REQUESTS: u32 = 1;

pub fn update_thread<RecvServer, RecvVoxelUpdates, UpdateView0, UpdateView1, UpdateServer, EnqueueBlockUpdates>(
  quit: &Mutex<bool>,
  client: &client::T,
  recv_server: &mut RecvServer,
  recv_voxel_updates: &mut RecvVoxelUpdates,
  update_view0: &mut UpdateView0,
  update_view1: &mut UpdateView1,
  update_server: &mut UpdateServer,
  enqueue_block_updates: &mut EnqueueBlockUpdates,
) where
  RecvServer: FnMut() -> Option<protocol::ServerToClient>,
  RecvVoxelUpdates: FnMut() -> Option<(Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason)>,
  UpdateView0: FnMut(ClientToView),
  UpdateView1: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
  EnqueueBlockUpdates: FnMut(Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason),
{
  'update_loop: loop {
    if *quit.lock().unwrap() == true {
      break 'update_loop
    } else {
      stopwatch::time("update_iteration", || {
        stopwatch::time("process_server_updates", || {
          process_server_updates(client, recv_server, update_view0, update_server, enqueue_block_updates);
        });

        stopwatch::time("update_surroundings", || {
          update_surroundings(client, update_view1, update_server);
        });

        stopwatch::time("process_voxel_updates", || {
          process_voxel_updates(client, recv_voxel_updates, update_view1);
        });
      })
    }
  }
}

#[inline(never)]
fn update_surroundings<UpdateView, UpdateServer>(
  client: &client::T,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
) where
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
{
  let start = time::precise_time_ns();
  let mut i = 0;
  let player_position = *client.player_position.lock().unwrap();
  let player_position = block_position::of_world_position(&player_position);
  let mut surroundings_loader = client.surroundings_loader.lock().unwrap();
  let mut updates = surroundings_loader.updates(player_position.as_pnt()) ;
  loop {
    if *client.outstanding_terrain_requests.lock().unwrap() >= MAX_OUTSTANDING_TERRAIN_REQUESTS {
      trace!("update loop breaking");
      break;
    }

    let block_position;
    let load_type;
    match updates.next() {
      None => break,
      Some((b, l)) => {
        block_position = block_position::of_pnt(&b);
        load_type = l;
      },
    }

    debug!("block surroundings");
    let distance =
      surroundings_loader::distance_between(
        player_position.as_pnt(),
        block_position.as_pnt(),
      );
    match load_type {
      LoadType::Load => {
        stopwatch::time("update_thread.load_block", || {
          let new_lod = lod_index(distance);
          let lod_change =
            client.loaded_blocks
            .lock().unwrap()
            .get(&block_position)
            .map(|&(_, lod)| lod != new_lod);
          if lod_change != Some(false) {
            load_or_request_chunk(client, update_server, update_view, block_position, new_lod);
          } else {
            debug!("Not re-loading {:?} at {:?}", block_position, new_lod);
          }
        })
      },
      LoadType::Update => {
        stopwatch::time("update_thread.update_block", || {
          let new_lod = lod_index(distance);
          let lod_change =
            client.loaded_blocks
            .lock().unwrap()
            .get(&block_position)
            .map(|&(_, lod)| new_lod < lod);
          if lod_change == Some(true) {
            load_or_request_chunk(client, update_server, update_view, block_position, new_lod);
          } else {
            trace!("Not updating {:?} at {:?}", block_position, new_lod);
          }
        })
      },
      LoadType::Unload => {
        stopwatch::time("update_thread.unload", || {
          // The block removal code is duplicated elsewhere.

          client.loaded_blocks
          .lock().unwrap()
            .remove(&block_position)
            // If it wasn't loaded, don't unload anything.
            .map(|(block, _)| {
              for id in &block.ids {
                update_view(ClientToView::RemoveTerrain(*id));
              }
            });
        })
      },
    };

    if i >= 10 {
      i -= 10;
      if time::precise_time_ns() - start >= 1_000_000 {
        break
      }
    }
    i += 1;
  }
}

fn load_or_request_chunk<UpdateServer, UpdateView>(
  client: &client::T,
  update_server: &mut UpdateServer,
  update_view: &mut UpdateView,
  block_position: block_position::T,
  lod: lod::T,
) where
  UpdateServer: FnMut(protocol::ClientToServer),
  UpdateView: FnMut(ClientToView),
{
  if load_terrain::all_voxels_loaded(&client.block_voxels_loaded.lock().unwrap(), block_position, lod) {
    load_terrain::load_block(
      client,
      update_view,
      &block_position,
      lod,
    );
  } else {
    let voxel_size = 1 << terrain_mesh::LG_SAMPLE_SIZE[lod.0 as usize];
    update_server(
      protocol::ClientToServer::RequestVoxels(
        client.id,
        terrain_mesh::voxels_in(
          &Aabb3::new(
            Point3::new(
              (block_position.as_pnt().x << terrain_mesh::LG_WIDTH) - voxel_size,
              (block_position.as_pnt().y << terrain_mesh::LG_WIDTH) - voxel_size,
              (block_position.as_pnt().z << terrain_mesh::LG_WIDTH) - voxel_size,
            ),
            Point3::new(
              ((block_position.as_pnt().x + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
              ((block_position.as_pnt().y + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
              ((block_position.as_pnt().z + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
            ),
          ),
          terrain_mesh::LG_SAMPLE_SIZE[lod.0 as usize],
        ),
      )
    );
    *client.outstanding_terrain_requests.lock().unwrap() += 1;
  }
}

#[inline(never)]
fn process_voxel_updates<RecvVoxelUpdates, UpdateView>(
  client: &client::T,
  recv_voxel_updates: &mut RecvVoxelUpdates,
  update_view: &mut UpdateView,
) where
  RecvVoxelUpdates: FnMut() -> Option<(Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason)>,
  UpdateView: FnMut(ClientToView),
{
  let start = time::precise_time_ns();
  while let Some((voxel_updates, reason)) = recv_voxel_updates() {
    let mut update_blocks = block_position::with_lod::set::new();
    for (bounds, voxel) in voxel_updates {
      trace!("Got voxel at {:?}", bounds);
      load_terrain::load_voxel(
        client,
        voxel,
        bounds,
        |block, lod| { update_blocks.insert((block, lod)); },
      );
    }

    for (block, lod) in update_blocks.into_iter() {
      load_terrain::load_block(
        client,
        update_view,
        &block,
        lod
      )
    }

    match reason {
      protocol::VoxelReason::Updated => {},
      protocol::VoxelReason::Requested => {
        *client.outstanding_terrain_requests.lock().unwrap() -= 1;
        debug!("Outstanding terrain requests: {}", *client.outstanding_terrain_requests.lock().unwrap());
      },
    }

    if time::precise_time_ns() - start >= 1_000_000 {
      break
    }
  }
}

#[inline(never)]
fn process_server_updates<RecvServer, UpdateView, UpdateServer, EnqueueBlockUpdates>(
  client: &client::T,
  recv_server: &mut RecvServer,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
  enqueue_block_updates: &mut EnqueueBlockUpdates,
) where
  RecvServer: FnMut() -> Option<protocol::ServerToClient>,
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
  EnqueueBlockUpdates: FnMut(Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason),
{
  let start = time::precise_time_ns();
  let mut i = 0;
  while let Some(up) = recv_server() {
    apply_server_update(
      client,
      update_view,
      update_server,
      enqueue_block_updates,
      up,
    );

    if i > 10 {
      i -= 10;
      if time::precise_time_ns() - start >= 1_000_000 {
        break
      }
    }
    i += 1;
  }
}
<|endoftext|>