<commit_before>//! Standard Rust log crate adapter to slog-rs
//!
//! This crate allows using `slog` features with code
//! using legacy `log` statements.
//!
//! `log` crate expects a global logger to be registered
//! (popular one is `env_logger`) as a handler for all
//! `info!(...)` and similar.
//!
//! `slog-stdlog` will register itself as `log` global handler and forward all
//! legacy logging statements to `slog`'s `Logger`. That means existing logging
//! `debug!` (even in dependencies crates) work and utilize `slog` composable
//! drains.
//!
//! See `init()` documentation for minimal working example.
//!
//! Note: Whilte `slog-scope` provides a similiar functionality, the `slog-scope` and `slog-stdlog`
//! keep track of distinct logging scopes.
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate crossbeam;

use slog::{DrainExt, ser};

use log::LogMetadata;
use std::sync::Arc;
use std::cell::RefCell;
use std::{io, fmt};
use std::io::Write;

use slog::Level;
use crossbeam::sync::ArcCell;

thread_local! {
    static TL_SCOPES: RefCell<Vec<slog::Logger>> = RefCell::new(Vec::with_capacity(8))
}

lazy_static! {
    static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
        Arc::new(
            slog::Logger::root(slog::Discard, o!())
        )
    );
}

fn set_global_logger(l: slog::Logger) {
    let _ = GLOBAL_LOGGER.set(Arc::new(l));
}

struct Logger;

fn log_to_slog_level(level: log::LogLevel) -> Level {
    match level {
        log::LogLevel::Trace => Level::Trace,
        log::LogLevel::Debug => Level::Debug,
        log::LogLevel::Info => Level::Info,
        log::LogLevel::Warn => Level::Warning,
        log::LogLevel::Error => Level::Error,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, r: &log::LogRecord) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let module = r.location().__module_path;
        let file = r.location().__file;
        let line = r.location().line();
        with_current_logger(|l| {
            let s = slog::RecordStatic {
                level: level,
                file: file,
                line: line,
                column: 0,
                function: "",
                module: module,
                target: target,
            };
            l.log(&slog::Record::new(&s, *args, &[]))
        })
    }
}

/// Set a `slog::Logger` as a global `log` create handler
///
/// This will forward all `log` records to `slog` logger.
///
/// ```
/// // only use `o` macro from `slog` crate
/// #[macro_use(o)]
/// extern crate slog;
/// #[macro_use]
/// extern crate log;
/// extern crate slog_stdlog;
///
/// fn main() {
///     let root = slog::Logger::root(
///         slog::Discard,
///         o!("build-id" => "8dfljdf"),
///     );
///     slog_stdlog::set_logger(root).unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn set_logger(logger: slog::Logger) -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::max());
        set_global_logger(logger);
        Box::new(Logger)
    })
}

/// Set a `slog::Logger` as a global `log` create handler
///
/// This will forward `log` records that satisfy `log_level_filter` to `slog` logger.
pub fn set_logger_level(logger: slog::Logger,
                        log_level_filter: log::LogLevelFilter)
                        -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level_filter);
        set_global_logger(logger);
        Box::new(Logger)
    })
}

/// Minimal initialization with default drain
///
/// The exact default drain is unspecified and will
/// change in future versions! Use `set_logger` instead
/// to build customized drain.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// extern crate slog_stdlog;
///
/// fn main() {
///     slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    let drain = slog::level_filter(Level::Info, slog_term::streamer().compact().build());
    set_logger(slog::Logger::root(drain.fuse(), o!()))
}

struct ScopeGuard;

impl ScopeGuard {
    fn new(logger: slog::Logger) -> Self {
        TL_SCOPES.with(|s| {
            s.borrow_mut().push(logger);
        });

        ScopeGuard
    }
}

impl Drop for ScopeGuard {
    fn drop(&mut self) {
        TL_SCOPES.with(|s| {
            s.borrow_mut().pop().expect("TL_SCOPES should contain a logger");
        })
    }
}

/// Access the currently active logger
///
/// The reference logger will be either:
/// * global logger, or
/// * currently active scope logger
///
/// **Warning**: Calling `scope` inside `f`
/// will result in a panic.
pub fn with_current_logger<F, R>(f: F) -> R
    where F: FnOnce(&slog::Logger) -> R
{
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        if s.is_empty() {
            f(&GLOBAL_LOGGER.get())
        } else {
            f(&s[s.len() - 1])
        }
    })
}

/// Access the `Logger` for the current logging scope
pub fn logger() -> slog::Logger {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        if s.is_empty() {
            (*GLOBAL_LOGGER.get()).clone()
        } else {
            s[s.len() - 1].clone()
        }
    })
}

/// Execute code in a logging scope
///
/// Logging scopes allow using different logger for legacy logging
/// statements in part of the code.
///
/// Logging scopes can be nested and are panic safe.
///
/// `logger` is the `Logger` to use during the duration of `f`.
/// `with_current_logger` can be used to build it as a child of currently active
/// logger.
///
/// `f` is a code to be executed in the logging scope.
///
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
/// with a global logger, as a current logger.
pub fn scope<SF, R>(logger: slog::Logger, f: SF) -> R
    where SF: FnOnce() -> R
{
    let _guard = ScopeGuard::new(logger);
    f()
}

/// Drain logging `Record`s into `log` crate
///
/// Using `StdLog` is effectively the same as using `log::info!(...)` and
/// other standard logging statements.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values : &'a slog::OwnedKeyValueList
}

impl<'a> LazyLogString<'a> {

    fn new(info : &'a slog::Record, logger_values : &'a slog::OwnedKeyValueList) -> Self {

        LazyLogString {
            info: info,
            logger_values: logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        try!(write!(f, "{}", self.info.msg()));

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io, ": ".into());

        let res = {
            || -> io::Result<()> {

            for (ref k, ref v) in self.logger_values.iter() {
                try!(ser.io().write_all(", ".as_bytes()));
                try!(v.serialize(self.info, k, &mut ser));
            }

            for &(ref k, ref v) in self.info.values().iter() {
                try!(ser.io().write_all(", ".as_bytes()));
                try!(v.serialize(self.info, k, &mut ser));
            }
            Ok(())
        }
        }().map_err(|_| fmt::Error);

        try!(res);

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))

    }
}

impl slog::Drain for StdLog {
    type Error = io::Error;
    fn log(&self, info: &slog::Record, logger_values : &slog::OwnedKeyValueList) -> io::Result<()> {

        let level = match info.level() {
            slog::Level::Critical => log::LogLevel::Error,
            slog::Level::Error => log::LogLevel::Error,
            slog::Level::Warning => log::LogLevel::Warn,
            slog::Level::Info => log::LogLevel::Info,
            slog::Level::Debug => log::LogLevel::Debug,
            slog::Level::Trace => log::LogLevel::Trace,
        };

        let target = info.target();

        let location = log::LogLocation {
            __module_path: info.module(),
            __file: info.file(),
            __line: info.line(),
        };

        let lazy = LazyLogString::new(info, logger_values);
        // Please don't yell at me for this! :D
        // https://github.com/rust-lang-nursery/log/issues/95
        log::__log(level, target, &location, format_args!("{}", lazy));

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    separator: String,
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W, separator: String) -> Self {
        KSV {
            io: io,
            separator: separator,
        }
    }

    fn io(&mut self) -> &mut W {
        &mut self.io
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> ser::Serializer for KSV<W> {
    fn emit_none(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, "None"));
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}", key));
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
}
<commit_msg>Document how to do compile-time log level filtering<commit_after>//! Standard Rust log crate adapter to slog-rs
//!
//! This crate allows using `slog` features with code
//! using legacy `log` statements.
//!
//! `log` crate expects a global logger to be registered
//! (popular one is `env_logger`) as a handler for all
//! `info!(...)` and similar.
//!
//! `slog-stdlog` will register itself as `log` global handler and forward all
//! legacy logging statements to `slog`'s `Logger`. That means existing logging
//! `debug!` (even in dependencies crates) work and utilize `slog` composable
//! drains.
//!
//! See `init()` documentation for minimal working example.
//!
//! Note: While `slog-scope` provides a similiar functionality, the `slog-scope` and `slog-stdlog`
//! keep track of distinct logging scopes.
//!
//! ## Compile-time log level filtering
//!
//! For filtering `debug!` and other `log` statements at compile-time, configure the features on
//! the `log` crate in your `Cargo.toml`:
//!
//! ```norust
//! log = { version = "*", features = ["max_level_trace", "release_max_level_warn"] }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate crossbeam;

use slog::{DrainExt, ser};

use log::LogMetadata;
use std::sync::Arc;
use std::cell::RefCell;
use std::{io, fmt};
use std::io::Write;

use slog::Level;
use crossbeam::sync::ArcCell;

thread_local! {
    static TL_SCOPES: RefCell<Vec<slog::Logger>> = RefCell::new(Vec::with_capacity(8))
}

lazy_static! {
    static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
        Arc::new(
            slog::Logger::root(slog::Discard, o!())
        )
    );
}

fn set_global_logger(l: slog::Logger) {
    let _ = GLOBAL_LOGGER.set(Arc::new(l));
}

struct Logger;

fn log_to_slog_level(level: log::LogLevel) -> Level {
    match level {
        log::LogLevel::Trace => Level::Trace,
        log::LogLevel::Debug => Level::Debug,
        log::LogLevel::Info => Level::Info,
        log::LogLevel::Warn => Level::Warning,
        log::LogLevel::Error => Level::Error,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, r: &log::LogRecord) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let module = r.location().__module_path;
        let file = r.location().__file;
        let line = r.location().line();
        with_current_logger(|l| {
            let s = slog::RecordStatic {
                level: level,
                file: file,
                line: line,
                column: 0,
                function: "",
                module: module,
                target: target,
            };
            l.log(&slog::Record::new(&s, *args, &[]))
        })
    }
}

/// Set a `slog::Logger` as a global `log` create handler
///
/// This will forward all `log` records to `slog` logger.
///
/// ```
/// // only use `o` macro from `slog` crate
/// #[macro_use(o)]
/// extern crate slog;
/// #[macro_use]
/// extern crate log;
/// extern crate slog_stdlog;
///
/// fn main() {
///     let root = slog::Logger::root(
///         slog::Discard,
///         o!("build-id" => "8dfljdf"),
///     );
///     slog_stdlog::set_logger(root).unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn set_logger(logger: slog::Logger) -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::max());
        set_global_logger(logger);
        Box::new(Logger)
    })
}

/// Set a `slog::Logger` as a global `log` create handler
///
/// This will forward `log` records that satisfy `log_level_filter` to `slog` logger.
pub fn set_logger_level(logger: slog::Logger,
                        log_level_filter: log::LogLevelFilter)
                        -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level_filter);
        set_global_logger(logger);
        Box::new(Logger)
    })
}

/// Minimal initialization with default drain
///
/// The exact default drain is unspecified and will
/// change in future versions! Use `set_logger` instead
/// to build customized drain.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// extern crate slog_stdlog;
///
/// fn main() {
///     slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    let drain = slog::level_filter(Level::Info, slog_term::streamer().compact().build());
    set_logger(slog::Logger::root(drain.fuse(), o!()))
}

struct ScopeGuard;

impl ScopeGuard {
    fn new(logger: slog::Logger) -> Self {
        TL_SCOPES.with(|s| {
            s.borrow_mut().push(logger);
        });

        ScopeGuard
    }
}

impl Drop for ScopeGuard {
    fn drop(&mut self) {
        TL_SCOPES.with(|s| {
            s.borrow_mut().pop().expect("TL_SCOPES should contain a logger");
        })
    }
}

/// Access the currently active logger
///
/// The reference logger will be either:
/// * global logger, or
/// * currently active scope logger
///
/// **Warning**: Calling `scope` inside `f`
/// will result in a panic.
pub fn with_current_logger<F, R>(f: F) -> R
    where F: FnOnce(&slog::Logger) -> R
{
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        if s.is_empty() {
            f(&GLOBAL_LOGGER.get())
        } else {
            f(&s[s.len() - 1])
        }
    })
}

/// Access the `Logger` for the current logging scope
pub fn logger() -> slog::Logger {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        if s.is_empty() {
            (*GLOBAL_LOGGER.get()).clone()
        } else {
            s[s.len() - 1].clone()
        }
    })
}

/// Execute code in a logging scope
///
/// Logging scopes allow using different logger for legacy logging
/// statements in part of the code.
///
/// Logging scopes can be nested and are panic safe.
///
/// `logger` is the `Logger` to use during the duration of `f`.
/// `with_current_logger` can be used to build it as a child of currently active
/// logger.
///
/// `f` is a code to be executed in the logging scope.
///
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
/// with a global logger, as a current logger.
pub fn scope<SF, R>(logger: slog::Logger, f: SF) -> R
    where SF: FnOnce() -> R
{
    let _guard = ScopeGuard::new(logger);
    f()
}

/// Drain logging `Record`s into `log` crate
///
/// Using `StdLog` is effectively the same as using `log::info!(...)` and
/// other standard logging statements.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values : &'a slog::OwnedKeyValueList
}

impl<'a> LazyLogString<'a> {

    fn new(info : &'a slog::Record, logger_values : &'a slog::OwnedKeyValueList) -> Self {

        LazyLogString {
            info: info,
            logger_values: logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        try!(write!(f, "{}", self.info.msg()));

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io, ": ".into());

        let res = {
            || -> io::Result<()> {

            for (ref k, ref v) in self.logger_values.iter() {
                try!(ser.io().write_all(", ".as_bytes()));
                try!(v.serialize(self.info, k, &mut ser));
            }

            for &(ref k, ref v) in self.info.values().iter() {
                try!(ser.io().write_all(", ".as_bytes()));
                try!(v.serialize(self.info, k, &mut ser));
            }
            Ok(())
        }
        }().map_err(|_| fmt::Error);

        try!(res);

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))

    }
}

impl slog::Drain for StdLog {
    type Error = io::Error;
    fn log(&self, info: &slog::Record, logger_values : &slog::OwnedKeyValueList) -> io::Result<()> {

        let level = match info.level() {
            slog::Level::Critical => log::LogLevel::Error,
            slog::Level::Error => log::LogLevel::Error,
            slog::Level::Warning => log::LogLevel::Warn,
            slog::Level::Info => log::LogLevel::Info,
            slog::Level::Debug => log::LogLevel::Debug,
            slog::Level::Trace => log::LogLevel::Trace,
        };

        let target = info.target();

        let location = log::LogLocation {
            __module_path: info.module(),
            __file: info.file(),
            __line: info.line(),
        };

        let lazy = LazyLogString::new(info, logger_values);
        // Please don't yell at me for this! :D
        // https://github.com/rust-lang-nursery/log/issues/95
        log::__log(level, target, &location, format_args!("{}", lazy));

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    separator: String,
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W, separator: String) -> Self {
        KSV {
            io: io,
            separator: separator,
        }
    }

    fn io(&mut self) -> &mut W {
        &mut self.io
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> ser::Serializer for KSV<W> {
    fn emit_none(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, "None"));
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}", key));
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Maciej Piechotka
 *
 * 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.
 */

#[comment = "Wrapper for libxml2's DOM parser."];
#[crate_id = "github.com/uzytkownik/xml-rs#xml:0.1"];
#[crate_type = "lib"];

extern mod extra;

mod ffi;

/**
 * An XML document.
 */
pub struct Document {
    priv doc: *ffi::xmlDoc
}

/**
 * An XML element
 */
pub struct Element<'r> {
    priv node: &'r ffi::xmlNode
}

/**
 * Text inside an XML.
 */
pub struct Text<'r> {
    priv node: &'r ffi::xmlNode
}

/**
 * Possible children of an element.
 */
pub enum ElementChildren<'r> {
    ElementElementChild(Element<'r>),
    TextElementChild(Text<'r>)
}

#[unsafe_destructor]
impl Drop for Document {
    fn drop(&mut self) {
        unsafe {
            ffi::xmlFreeDoc(self.doc);
        }
    }
}

impl Document {
    /**
     * Find the root element, if it exists.
     */
    pub fn get_root_element<'r>(&'r self) -> Option<Element<'r>> {
        use std::ptr::is_not_null;
        unsafe {
            let elem = ffi::xmlDocGetRootElement(self.doc);
            if (is_not_null(elem)) {
                Some(Element {node: &*elem})
            } else {
                None
            }
        }
    }
}

impl<'r> Element<'r> {
    /**
     * Gets the name of the element.
     */
    pub fn name(&self) -> ~str {
        unsafe {std::str::raw::from_c_str(self.node.name as *i8)}
    }
    /**
     * Finds all children of the element.
     */
    pub fn children(&self) -> ~[ElementChildren<'r>] {
        std::vec::build(None, |push| {
            unsafe {
                let mut cur = self.node.children;
                while (std::ptr::is_not_null(cur)) {
                    match (*cur)._type {
                        ffi::ElementNode => push(ElementElementChild(Element {node: &*cur})),
                        ffi::TextNode => push(TextElementChild(Text {node: &*cur})),
                        t => error!("Unsupported type {}", t.to_str())
                    }
                    cur = (*cur).next;
                }
            }
        })
    }
}

impl<'r> Text<'r> {
    pub fn content(&self) -> ~str {
        unsafe {
            std::str::raw::from_c_str(self.node.content as *i8)
        }
    }
}

/**
 * Reads the buffer treating it as if it came from url.
 *
 * It returns the document if buffer contained valid XML.
 */
pub fn read_memory_with_url(buffer: &[u8], url: Option<&str>) -> Option<Document> {
    unsafe {
        use std::libc::c_int;
        use std::ptr::{null,is_not_null};
        ffi::xmlCheckVersion(ffi::xmlVersion);
        let doc = ffi::xmlReadMemory(buffer.as_ptr(), buffer.len() as c_int,
                                     url.map(|x| x.as_ptr()).unwrap_or(null()) as *i8,
                                     null(), 64 | 32 /* No errors or warnings for now */);
        if (is_not_null(doc)) {
            Some(Document {doc: doc})
        } else {
            None
        }
    }
}

/**
 * Reads the buffer and return the document if it contains valid XML.
 */
pub fn read_memory(buffer: &[u8]) -> Option<Document> {
    read_memory_with_url(buffer, None)
}
<commit_msg>Add license attribute<commit_after>/*
 * Copyright (C) 2014 Maciej Piechotka
 *
 * 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.
 */

#[comment = "Wrapper for libxml2's DOM parser."];
#[crate_id = "github.com/uzytkownik/xml-rs#xml:0.1"];
#[crate_type = "lib"];
#[license = "MIT"];

extern mod extra;

mod ffi;

/**
 * An XML document.
 */
pub struct Document {
    priv doc: *ffi::xmlDoc
}

/**
 * An XML element
 */
pub struct Element<'r> {
    priv node: &'r ffi::xmlNode
}

/**
 * Text inside an XML.
 */
pub struct Text<'r> {
    priv node: &'r ffi::xmlNode
}

/**
 * Possible children of an element.
 */
pub enum ElementChildren<'r> {
    ElementElementChild(Element<'r>),
    TextElementChild(Text<'r>)
}

#[unsafe_destructor]
impl Drop for Document {
    fn drop(&mut self) {
        unsafe {
            ffi::xmlFreeDoc(self.doc);
        }
    }
}

impl Document {
    /**
     * Find the root element, if it exists.
     */
    pub fn get_root_element<'r>(&'r self) -> Option<Element<'r>> {
        use std::ptr::is_not_null;
        unsafe {
            let elem = ffi::xmlDocGetRootElement(self.doc);
            if (is_not_null(elem)) {
                Some(Element {node: &*elem})
            } else {
                None
            }
        }
    }
}

impl<'r> Element<'r> {
    /**
     * Gets the name of the element.
     */
    pub fn name(&self) -> ~str {
        unsafe {std::str::raw::from_c_str(self.node.name as *i8)}
    }
    /**
     * Finds all children of the element.
     */
    pub fn children(&self) -> ~[ElementChildren<'r>] {
        std::vec::build(None, |push| {
            unsafe {
                let mut cur = self.node.children;
                while (std::ptr::is_not_null(cur)) {
                    match (*cur)._type {
                        ffi::ElementNode => push(ElementElementChild(Element {node: &*cur})),
                        ffi::TextNode => push(TextElementChild(Text {node: &*cur})),
                        t => error!("Unsupported type {}", t.to_str())
                    }
                    cur = (*cur).next;
                }
            }
        })
    }
}

impl<'r> Text<'r> {
    pub fn content(&self) -> ~str {
        unsafe {
            std::str::raw::from_c_str(self.node.content as *i8)
        }
    }
}

/**
 * Reads the buffer treating it as if it came from url.
 *
 * It returns the document if buffer contained valid XML.
 */
pub fn read_memory_with_url(buffer: &[u8], url: Option<&str>) -> Option<Document> {
    unsafe {
        use std::libc::c_int;
        use std::ptr::{null,is_not_null};
        ffi::xmlCheckVersion(ffi::xmlVersion);
        let doc = ffi::xmlReadMemory(buffer.as_ptr(), buffer.len() as c_int,
                                     url.map(|x| x.as_ptr()).unwrap_or(null()) as *i8,
                                     null(), 64 | 32 /* No errors or warnings for now */);
        if (is_not_null(doc)) {
            Some(Document {doc: doc})
        } else {
            None
        }
    }
}

/**
 * Reads the buffer and return the document if it contains valid XML.
 */
pub fn read_memory(buffer: &[u8]) -> Option<Document> {
    read_memory_with_url(buffer, None)
}
<|endoftext|>


<commit_before>//
// sprocketnes/mem.rs
//
// Author: Patrick Walton
//

use apu::Apu;
use input::Input;
use mapper::Mapper;
use ppu::Ppu;
use util::Save;

use std::cell::RefCell;
use std::io::File;
use std::rc::Rc;

//
// The memory interface
//

/// The basic memory interface
pub trait Mem {
    fn loadb(&mut self, addr: u16) -> u8;
    fn storeb(&mut self, addr: u16, val: u8);
}

pub trait MemUtil {
    fn loadw(&mut self, addr: u16) -> u16;
    fn storew(&mut self, addr: u16, val: u16);
    fn loadw_zp(&mut self, addr: u8) -> u16;
}

impl<M:Mem> MemUtil for M {
    fn loadw(&mut self, addr: u16) -> u16 {
        self.loadb(addr) as u16 | (self.loadb(addr + 1) as u16 << 8)
    }
    fn storew(&mut self, addr: u16, val: u16) {
        self.storeb(addr, (val & 0xff) as u8);
        self.storeb(addr + 1, ((val >> 8) & 0xff) as u8);
    }
    // Like loadw, but has wraparound behavior on the zero page for address 0xff.
    fn loadw_zp(&mut self, addr: u8) -> u16 {
        self.loadb(addr as u16) as u16 | (self.loadb((addr + 1) as u16) as u16 << 8)
    }
}

//
// The NES' paltry 2KB of RAM
//

pub struct Ram([u8, ..0x800]);

impl Mem for Ram {
    fn loadb(&mut self, addr: u16) -> u8     { self[addr & 0x7ff] }
    fn storeb(&mut self, addr: u16, val: u8) { self[addr & 0x7ff] = val }
}

impl Save for Ram {
    fn save(&mut self, fd: &mut File) {
        let mut array: &mut [u8] = **self;
        array.save(fd)
    }
    fn load(&mut self, fd: &mut File) {
        let mut array: &mut [u8] = **self;
        array.load(fd)
    }
}

//
// The main CPU memory map
//

pub struct MemMap {
    ram: Ram,
    ppu: Ppu,
    input: Input,
    mapper: Rc<RefCell<~Mapper:Freeze+Send>>,
    apu: Apu,
}

impl MemMap {
    pub fn new(ppu: Ppu,
               input: Input,
               mapper: Rc<RefCell<~Mapper:Freeze+Send>>,
               apu: Apu)
               -> MemMap {
        MemMap {
            ram: Ram([ 0, ..0x800 ]),
            ppu: ppu,
            input: input,
            mapper: mapper,
            apu: apu,
        }
    }
}

impl Mem for MemMap {
    fn loadb(&mut self, addr: u16) -> u8 {
        if addr < 0x2000 {
            self.ram.loadb(addr)
        } else if addr < 0x4000 {
            self.ppu.loadb(addr)
        } else if addr == 0x4016 {
            self.input.loadb(addr)
        } else if addr <= 0x4018 {
            self.apu.loadb(addr)
        } else if addr < 0x6000 {
            0   // FIXME: I think some mappers use regs in this area?
        } else {
            let mut mapper = self.mapper.borrow().borrow_mut();
            mapper.get().prg_loadb(addr)
        }
    }
    fn storeb(&mut self, addr: u16, val: u8) {
        if addr < 0x2000 {
            self.ram.storeb(addr, val)
        } else if addr < 0x4000 {
            self.ppu.storeb(addr, val)
        } else if addr == 0x4016 {
            self.input.storeb(addr, val)
        } else if addr <= 0x4018 {
            self.apu.storeb(addr, val)
        } else if addr < 0x6000 {
            // Nothing. FIXME: I think some mappers use regs in this area?
        } else {
            let mut mapper = self.mapper.borrow().borrow_mut();
            mapper.get().prg_storeb(addr, val)
        }
    }
}

save_struct!(MemMap { ram, ppu, apu })

<commit_msg>Update from single tuple struct for mem.rs<commit_after>//
// sprocketnes/mem.rs
//
// Author: Patrick Walton
//

use apu::Apu;
use input::Input;
use mapper::Mapper;
use ppu::Ppu;
use util::Save;

use std::cell::RefCell;
use std::io::File;
use std::rc::Rc;

//
// The memory interface
//

/// The basic memory interface
pub trait Mem {
    fn loadb(&mut self, addr: u16) -> u8;
    fn storeb(&mut self, addr: u16, val: u8);
}

pub trait MemUtil {
    fn loadw(&mut self, addr: u16) -> u16;
    fn storew(&mut self, addr: u16, val: u16);
    fn loadw_zp(&mut self, addr: u8) -> u16;
}

impl<M:Mem> MemUtil for M {
    fn loadw(&mut self, addr: u16) -> u16 {
        self.loadb(addr) as u16 | (self.loadb(addr + 1) as u16 << 8)
    }
    fn storew(&mut self, addr: u16, val: u16) {
        self.storeb(addr, (val & 0xff) as u8);
        self.storeb(addr + 1, ((val >> 8) & 0xff) as u8);
    }
    // Like loadw, but has wraparound behavior on the zero page for address 0xff.
    fn loadw_zp(&mut self, addr: u8) -> u16 {
        self.loadb(addr as u16) as u16 | (self.loadb((addr + 1) as u16) as u16 << 8)
    }
}

//
// The NES' paltry 2KB of RAM
//

pub struct Ram { val: [u8, ..0x800] }

impl Deref<[u8, ..0x800]> for Ram {
    fn deref<'a>(&'a self) -> &'a [u8, ..0x800] {
        &self.val
    }
}

impl Mem for Ram {
    fn loadb(&mut self, addr: u16) -> u8     { self[addr & 0x7ff] }
    fn storeb(&mut self, addr: u16, val: u8) { self[addr & 0x7ff] = val }
}

impl Save for Ram {
    fn save(&mut self, fd: &mut File) {
        let mut array: &mut [u8] = **self;
        array.save(fd)
    }
    fn load(&mut self, fd: &mut File) {
        let mut array: &mut [u8] = **self;
        array.load(fd)
    }
}

//
// The main CPU memory map
//

pub struct MemMap {
    ram: Ram,
    ppu: Ppu,
    input: Input,
    mapper: Rc<RefCell<~Mapper:Freeze+Send>>,
    apu: Apu,
}

impl MemMap {
    pub fn new(ppu: Ppu,
               input: Input,
               mapper: Rc<RefCell<~Mapper:Freeze+Send>>,
               apu: Apu)
               -> MemMap {
        MemMap {
            ram: Ram{val: [ 0, ..0x800 ]},
            ppu: ppu,
            input: input,
            mapper: mapper,
            apu: apu,
        }
    }
}

impl Mem for MemMap {
    fn loadb(&mut self, addr: u16) -> u8 {
        if addr < 0x2000 {
            self.ram.loadb(addr)
        } else if addr < 0x4000 {
            self.ppu.loadb(addr)
        } else if addr == 0x4016 {
            self.input.loadb(addr)
        } else if addr <= 0x4018 {
            self.apu.loadb(addr)
        } else if addr < 0x6000 {
            0   // FIXME: I think some mappers use regs in this area?
        } else {
            let mut mapper = self.mapper.borrow_mut();
            mapper.get().prg_loadb(addr)
        }
    }
    fn storeb(&mut self, addr: u16, val: u8) {
        if addr < 0x2000 {
            self.ram.storeb(addr, val)
        } else if addr < 0x4000 {
            self.ppu.storeb(addr, val)
        } else if addr == 0x4016 {
            self.input.storeb(addr, val)
        } else if addr <= 0x4018 {
            self.apu.storeb(addr, val)
        } else if addr < 0x6000 {
            // Nothing. FIXME: I think some mappers use regs in this area?
        } else {
            let mut mapper = self.mapper.borrow_mut();
            mapper.get().prg_storeb(addr, val)
        }
    }
}

save_struct!(MemMap { ram, ppu, apu })

<|endoftext|>


<commit_before>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num, hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost > other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            (a.r-b.r)*(a.r-b.r) + (a.g-b.g)*(a.g-b.g) + (a.b-b.b)*(a.b-b.b) ) as float)
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    let mut retval: ~[~[Pixel]] = ~[];

    let file: &str = filename.to_owned();
//    let file2: ~str = file.to_owned();
    let split_filename: ~[&str] = file.split_iter('.').collect();
    let file_data: &str = split_filename[0] + ".txt";

    println(fmt!("The image name is [%?]", file));
    println(fmt!("The image data will be stored at [%?]", file_data));

    //read in the .txt associated with the file title
    let path = &PosixPath(file_data);

    match std::io::file_reader(path) {
	Ok(reader) => {
	    //run the java program to process the image
/*	    let program: &str = "java ImageReader";
	    let argv: ~[~str] = ~[file2];
	    let mut prog = std::run::Process::new(program, argv,
		std::run::ProcessOptions {
			env: None,
			dir: None,
			in_fd: None,
			out_fd: None,
			err_fd: None
		}
	    );
	    prog.finish();
*/
	    //parse out the array dimensions
    	    let dimensions_str: &str = reader.read_line();
    	    println(fmt!("dimensons: %s",dimensions_str));
	    let mut h: int = 0;
	    let mut w: int = 0;
	    match dimensions_str[0] as char {
		'H' => {
		    let split_dim: ~[&str] = dimensions_str.split_iter('W').collect();
		    h = from_str(split_dim[0].slice(1,split_dim[0].len())).unwrap();
		    w = from_str(split_dim[1]).unwrap();
		    println(fmt!("Dimensions passed: H %? W %?",h,w));
		    //let retval: ~[ ~[Pixel, ..w], ..h];
		}
		_ => {println("Dimensions corrupted! Abort");}
	    }

	    //fill in the retVal array with pixel data
            //let mut rowfirst = false;
	    for row in range(0,h){
//                if(!rowfirst) {
                retval.push(~[]);
                //rowfirst = true; }
		for col in range(0,w){
	    	    if !reader.eof() {
			let line: &str = reader.read_line();
			//println(line);
			let rpos:uint = match line.find('R') { Some(n)=>n,None=>line.len() };
			let gpos:uint = match line.find('G') { Some(n)=>n,None=>line.len() };
			let bpos:uint = match line.find('B') { Some(n)=>n,None=>line.len() };

			if rpos == line.len() || gpos == line.len() || bpos == line.len() {
			    println("Pixel data corrupted! Abort");
			}

			let R:int = from_str(line.slice(rpos+1,gpos)).unwrap();
			let G:int = from_str(line.slice(gpos+1,bpos)).unwrap();
			let B:int = from_str(line.slice(bpos+1,line.len())).unwrap();

			//println(fmt!("R %? G %? B %?",R,G,B));

			//fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
			retval[row].push(Pixel::new(R,G,B,col,row));

		    }
		    else {
			println("Data file corrupted! Abort");
		    }
		}
	    }
	},
	Err(err)   => { fail!(err) }
    }

    retval
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);
    let height = pixels.len() as int;
    let width = pixels[0].len() as int;

    println(fmt!("Dimensions received: H %? W %?",height,width));

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[];
    for h in range(0,height){
	find_arcs.push(~[]);
        for w in range(0,width){
 //           println(fmt!("pix %?",pixels[h][w]));
	    find_arcs[h].push(arc::RWArc::new(pixels[h][w]));
	}
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let corners = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];

    let mut color_index = 0;
    for &corner in corners.iter(){
        let (a,b) = corner;
        do arcs[b][a].write |pix| {
            pix.color = color_index;
        }
        color_index+=1;
    }

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        do spawn { // split into threads here
            let c = a;
            let d = b;
            let mut x=a;
            let mut y=b;

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();
            let mut newvisit: bool = true;
            let mut boundaries: ~[Edge] = ~[];
            let mut color: int = -1;
            do shared_arcs[b][a].read |pix| {
                color = pix.color;
            }

            println(fmt!("start at (%i,%i): color = %i",c,d,color));

            loop { // iterate through items in the queue, which contains all of the edges/vertices
                if(newvisit){
//                   println(fmt!("(%i,%i) : (%i,%i)",c,d,x,y));
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x-1,y)];
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking
                            // if neighbor at coord has not been colored
                            let mut newvertex = false;
                            let mut colored = false;
                            do shared_arcs[z][w].read |dest| {
                                if dest.color >= 0 {
                                    colored = true;
                                }
                            }
                            if !colored {
                                do shared_arcs[z][w].write |dest| {
                                    if dest.color < 0 {
                                        dest.color = color;
                                        newvertex = true;
                                    } else {
                                        // edge has crossed a cut during a race since we last checked if it was uncolored
                                        colored = true;
                                    }
                                }
                            }
                            if colored { // this is an else to the above if
                                // we have found an edge that crosses a cut!
                                // here, somehow collect the edges that cross our cut
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        if dest.color != color {
                                            boundaries.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                            println(fmt!("%?\n-->%?",src,dest));

                                        }
                                    }
                                }
                            }
                            if newvertex { // then we have a new vertex
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop();
                match edge {
                    Some(e) => {
                        println(fmt!("(%i,%i) pop (%i,%i)-%f-(%i,%i)",c,d,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
                        // not in any tree
                        let coord = (e.dest.x,e.dest.y);
//                        println(fmt!("before runtime error? %?",coord));
                        if !visited.contains_key(&coord){
 // use visited hashmap to figure out if we're at a new vertex.
                            visited.insert(coord,true);
                            x = e.dest.x;
                            y = e.dest.y;
                            newvisit = true;
//                            println(fmt!("%? %f",coord,e.cost));
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }

            for e in boundaries.iter() {
                println(fmt!("(%i,%i:%i) boundary (%i,%i)-%f-(%i,%i)",c,d,color,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
            }
        }
    }

    for h in range(0,height){
        for w in range(0,width){
            do arcs[h][w].read |pix| {
                println(fmt!("color(%i,%i) %i",w,h,pix.color));
	    }
        }
    }
}
<commit_msg>better commenting<commit_after>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num, hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost > other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            (a.r-b.r)*(a.r-b.r) + (a.g-b.g)*(a.g-b.g) + (a.b-b.b)*(a.b-b.b) ) as float)
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    let mut retval: ~[~[Pixel]] = ~[];

    let file: &str = filename.to_owned();
//    let file2: ~str = file.to_owned();
    let split_filename: ~[&str] = file.split_iter('.').collect();
    let file_data: &str = split_filename[0] + ".txt";

    println(fmt!("The image name is [%?]", file));
    println(fmt!("The image data will be stored at [%?]", file_data));

    //read in the .txt associated with the file title
    let path = &PosixPath(file_data);

    match std::io::file_reader(path) {
	Ok(reader) => {
	    //run the java program to process the image
/*	    let program: &str = "java ImageReader";
	    let argv: ~[~str] = ~[file2];
	    let mut prog = std::run::Process::new(program, argv,
		std::run::ProcessOptions {
			env: None,
			dir: None,
			in_fd: None,
			out_fd: None,
			err_fd: None
		}
	    );
	    prog.finish();
*/
	    //parse out the array dimensions
    	    let dimensions_str: &str = reader.read_line();
    	    println(fmt!("dimensons: %s",dimensions_str));
	    let mut h: int = 0;
	    let mut w: int = 0;
	    match dimensions_str[0] as char {
		'H' => {
		    let split_dim: ~[&str] = dimensions_str.split_iter('W').collect();
		    h = from_str(split_dim[0].slice(1,split_dim[0].len())).unwrap();
		    w = from_str(split_dim[1]).unwrap();
		    println(fmt!("Dimensions passed: H %? W %?",h,w));
		    //let retval: ~[ ~[Pixel, ..w], ..h];
		}
		_ => {println("Dimensions corrupted! Abort");}
	    }

	    //fill in the retVal array with pixel data
            //let mut rowfirst = false;
	    for row in range(0,h){
//                if(!rowfirst) {
                retval.push(~[]);
                //rowfirst = true; }
		for col in range(0,w){
	    	    if !reader.eof() {
			let line: &str = reader.read_line();
			//println(line);
			let rpos:uint = match line.find('R') { Some(n)=>n,None=>line.len() };
			let gpos:uint = match line.find('G') { Some(n)=>n,None=>line.len() };
			let bpos:uint = match line.find('B') { Some(n)=>n,None=>line.len() };

			if rpos == line.len() || gpos == line.len() || bpos == line.len() {
			    println("Pixel data corrupted! Abort");
			}

			let R:int = from_str(line.slice(rpos+1,gpos)).unwrap();
			let G:int = from_str(line.slice(gpos+1,bpos)).unwrap();
			let B:int = from_str(line.slice(bpos+1,line.len())).unwrap();

			//println(fmt!("R %? G %? B %?",R,G,B));

			//fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
			retval[row].push(Pixel::new(R,G,B,col,row));

		    }
		    else {
			println("Data file corrupted! Abort");
		    }
		}
	    }
	},
	Err(err)   => { fail!(err) }
    }

    retval
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);
    let height = pixels.len() as int;
    let width = pixels[0].len() as int;

    println(fmt!("Dimensions received: H %? W %?",height,width));

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[];
    for h in range(0,height){
	find_arcs.push(~[]);
        for w in range(0,width){
 //           println(fmt!("pix %?",pixels[h][w]));
	    find_arcs[h].push(arc::RWArc::new(pixels[h][w]));
	}
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let corners = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];

    let mut color_index = 0;
    for &corner in corners.iter(){
        let (a,b) = corner;
        do arcs[b][a].write |pix| {
            pix.color = color_index;
        }
        color_index+=1;
    }

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        do spawn { // split into threads here
            let c = a;
            let d = b;
            let mut x=a;
            let mut y=b;

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();
            let mut newvisit: bool = true;
            let mut boundaries: ~[Edge] = ~[];
            let mut color: int = -1;
            do shared_arcs[b][a].read |pix| {
                color = pix.color;
            }

            println(fmt!("start at (%i,%i): color = %i",c,d,color));

            loop {
                //  at most once each:
                //   visit the next vertex (determined by the last edge we chose or the starting vertex) to claim its neighbors and add its edges to our queue
                //   pop the next edge off the queue, which contains all of the edges between vertices claimed by the local thread

                if(newvisit){ // if the next vertex has not previously been visited to claim neighbors and add edges
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x-1,y)]; // potential neighbors
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking on neighbors to only select valid edges
                            let mut newvertex = false;
                            let mut colored = false;
                            do shared_arcs[z][w].read |dest| {
                                if dest.color >= 0 {
                                    colored = true; //vertex has been previously claimed
                                }
                            }
                            if !colored { // this thread will claim the unclaimed vertex
                                do shared_arcs[z][w].write |dest| {
                                    if dest.color < 0 {
                                        dest.color = color;
                                        newvertex = true;
                                    } else {
                                        // edge has been claimed during a race since we last checked. add to supervertex boundary
                                        colored = true;
                                    }
                                }
                            }
                            if colored {
                                // we have found an edge that crosses a cut!
                                // here, somehow collect these edges for contraction later
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        if dest.color != color {
                                            boundaries.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                            println(fmt!("%?\n-->%?",src,dest));
                                        }
                                    }
                                }
                            }
                            if newvertex { // we have an unvisited but previously claimed vertex
                                // add the edge to our local edges queue
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop(); // should fail only when we've exhausted all the edges in our queue, i.e. this thread is done running Prim
                match edge {
                    Some(e) => {
                        println(fmt!("(%i,%i) pop (%i,%i)-%f-(%i,%i)",c,d,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
                        let coord = (e.dest.x,e.dest.y);
                        if !visited.contains_key(&coord){
                            // use visited hashmap to figure out if we're at a new vertex or a previously seen one
                            visited.insert(coord,true); //add to growing spanning forest
                            x = e.dest.x; // update search coordinates for next iteration
                            y = e.dest.y;
                            newvisit = true; // update flag to claim new vertex's neighbors
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }

            for e in boundaries.iter() {
                println(fmt!("(%i,%i:%i) boundary (%i,%i)-%f-(%i,%i)",c,d,color,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
            }
        }
    }

    for h in range(0,height){
        for w in range(0,width){
            do arcs[h][w].read |pix| {
                println(fmt!("color(%i,%i) %i",w,h,pix.color));
	    }
        }
    }
}
<|endoftext|>


<commit_before>use vec3::Vec3;
use scene::Scene;
use intersection::Intersection;
use std::f64::INFINITY;

pub struct Ray {
    pub origin: Vec3,
    pub direction: Vec3
}

impl Ray {
    pub fn get_nearest_hit<'a>(&self, scene: &'a Scene) -> Option<Intersection<'a>> {
        let t_min = 0.000001;
        let mut nearest_hit = None;
        let mut nearest_t = INFINITY;

        for prim in scene.prims.iter() {
            let intersection = prim.intersects(self, t_min, nearest_t);

            nearest_hit = match intersection {
                Some(intersection) => {
                    if intersection.t > t_min && intersection.t < nearest_t {
                        Some(intersection)
                    } else {
                        nearest_hit
                    }
                }

                None => {nearest_hit}
            };

            nearest_t = match nearest_hit {
                Some(nearest_hit) => {nearest_hit.t}
                None => {nearest_t}
            };
        }

        nearest_hit
    }
}
<commit_msg>Slightly clean up ray.<commit_after>use vec3::Vec3;
use scene::Scene;
use intersection::Intersection;
use std::f64::INFINITY;

pub struct Ray {
    pub origin: Vec3,
    pub direction: Vec3
}

impl Ray {
    pub fn get_nearest_hit<'a>(&self, scene: &'a Scene) -> Option<Intersection<'a>> {
        let t_min = 0.000001;
        let mut nearest_hit = None;
        let mut nearest_t = INFINITY;

        for prim in scene.prims.iter() {
            let intersection = prim.intersects(self, t_min, nearest_t);

            nearest_hit = match intersection {
                Some(intersection) => {
                    if intersection.t > t_min && intersection.t < nearest_t {
                        nearest_t = intersection.t;
                        Some(intersection)
                    } else {
                        nearest_hit
                    }
                }

                None => {nearest_hit}
            };
        }

        nearest_hit
    }
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/vfs/handle.rs
//! Opened file interface
use prelude::*;
use super::node::{CacheHandle,NodeType};
use lib::byte_str::ByteString;
use super::Path;

#[derive(Debug)]
/// Open without caring what the file type is (e.g. enumeration)
pub struct Any {
	node: CacheHandle,
}
#[derive(Debug)]
/// Normal file
pub struct File {
	node: CacheHandle,
	mode: FileOpenMode,
}
#[derive(Debug)]
/// Directory (for enumeration)
pub struct Dir {
	node: CacheHandle,
}
#[derive(Debug)]
/// Symbolic link (allows reading the link contents)
pub struct Symlink {
	node: CacheHandle,
}
#[derive(Debug)]
/// Special file (?API exposed)
pub struct Special {
	node: CacheHandle,
}

#[derive(Debug)]
pub enum FileOpenMode
{
	/// Shared read-only, multiple readers but no writers visible
	///
	/// When opened in this manner, the file contents cannot change, but it might extend
	SharedRO,
	/// Open for execution (multiple readers)
	///
	/// No file changes visible to handles, must be an executable file
	Execute,
	/// Eclusive read-write, denies any other opens while held (except Append)
	///
	/// No changes to the file will be visible to the user (as the file is locked)
	ExclRW,
	/// Unique read-write, does Copy-on-write to create a new file
	///
	/// No changes to the file will be visible to the user (as it has its own copy)
	UniqueRW,
	/// Append only (allows multiple readers/writers)
	///
	/// Cannot read, all writes go to the end of the file (a write call is atomic)
	Append,
	/// Unsynchronised read-write
	///
	/// No synchronisation at all, fails if any other open type is active.
	Unsynch,
}

#[derive(Debug)]
pub enum MemoryMapMode
{
	/// Read-only mapping of a file
	ReadOnly,
	/// Executable mapping of a file
	Execute,
	/// Copy-on-write (used for executable files)
	COW,
	/// Allows writing to the backing file
	WriteBack,
}

impl Any
{
	/// Open the specified path (not caring what the actual type is)
	pub fn open(path: &Path) -> super::Result<Any> {
		let node = try!(CacheHandle::from_path(path));
		Ok(Any { node: node })
	}

	/// Upgrade the handle to a directory handle
	pub fn to_dir(self) -> super::Result<Dir> {
		if self.node.is_dir() {
			Ok(Dir { node: self.node })
		}
		else {
			Err(super::Error::TypeMismatch)
		}
	}
}

pub struct MemoryMapHandle<'a>
{
	handle: &'a File,
	base: *mut (),
	len: usize,
}

impl File
{
	/// Open the specified path as a file
	pub fn open(path: &Path, mode: FileOpenMode) -> super::Result<File> {
		let node = try!(CacheHandle::from_path(path));
		if !node.is_file() {
			return Err(super::Error::TypeMismatch);
		}
		match mode
		{
		// TODO: Mark file as shared
		// TODO: Check permissions (must be readable in current context)
		FileOpenMode::SharedRO => {},
		// TODO: Mark file as shared
		// TODO: Check permissions (must be executable in current context)
		FileOpenMode::Execute => {},
		_ => todo!("Acquire lock depending on mode({:?})", mode),
		}
		Ok(File { node: node, mode: mode })
	}

	pub fn size(&self) -> u64 {
		self.node.get_valid_size()
	}

	/// Read data from the file at the specified offset
	///
	/// Returns the number of read bytes (which might be less than the size of the input
	/// slice).
	pub fn read(&self, ofs: u64, dst: &mut [u8]) -> super::Result<usize> {
		assert!(self.node.is_file());
		self.node.read(ofs, dst)
	}
	pub fn write(&self, ofs: u64, src: &[u8]) -> super::Result<usize> {
		todo!("Handle::write({:#x}, {:p}+{}", ofs, src.as_ptr(), src.len());
	}

	/// Map a file into the address space
	pub fn memory_map(&self, address: usize, ofs: u64, size: usize, mode: MemoryMapMode) -> super::Result<MemoryMapHandle> {
		// - Check that this file is opened in a sufficent mode to allow this form of mapping
		match mode
		{
		// Read only - Pretty much anything
		MemoryMapMode::ReadOnly => match self.mode
			{
			FileOpenMode::Execute => {},
			FileOpenMode::SharedRO => {},
			//FileOpenMode::ExclRW => /* NOTE: Needs extra checks to ensure that aliasing does not occur */
			//FileOpenMode::UniqueRW => /* NOTE: Needs extra checks to ensure that aliasing does not occur */
			_ => return Err(super::Error::PermissionDenied),
			},
		// Executable - Execute mode only
		MemoryMapMode::Execute => match self.mode
			{
			FileOpenMode::Execute => {},
			_ => return Err(super::Error::PermissionDenied),
			},
		// COW - Execute mode only
		// - TODO: Could allow COW of readonly files? (as soon as it's written, the page is detached from the file)
		MemoryMapMode::COW => match self.mode
			{
			FileOpenMode::Execute => {},
			//FileOpenMode::SharedRO => {},
			_ => return Err(super::Error::PermissionDenied),
			},
		// Writeback - Requires exclusive access to the file (or a copy)
		MemoryMapMode::WriteBack => match self.mode
			{
			//FileOpenMode::ExclRW => /* NOTE: Needs extra checks to ensure that aliasing does not occur */
			//FileOpenMode::UniqueRW => /* NOTE: Needs extra checks to ensure that aliasing does not occur */
			_ => return Err(super::Error::PermissionDenied),
			},
		}

		// TODO: Handle unaligned mappings somehow
		// - Depends on several qirks:
		//  > Unaligned address could write to an existing page (converting it to a private) - But how would that interact with existing mappings?
		//  > Unaligned sizes would usually cause a new anon mapping, but if its unaligned becuase of EOF, it should just be COW as usual
		assert!(address % ::PAGE_SIZE == 0, "TODO: Unaligned memory_map (address={})", address);
		assert!(size % ::PAGE_SIZE == 0, "TODO: Unaligned memory_map (size={})", size);
		if address % ::PAGE_SIZE != (ofs % ::PAGE_SIZE as u64) as usize {
			return Err( super::Error::Unknown("memory_map alignment mismatch") );
		}
		// - Limit checking (ofs + size must be within size of the file)
		// TODO: Limit checking
		// - Reserve the region to be mapped (reserve sticks a zero page in)
		let page_count = size / ::PAGE_SIZE;
		let mut resv = match ::memory::virt::reserve(address as *mut (), page_count)
			{
			Ok(v) => v,
			Err(e) => {
				log_notice!("mmap reserve error {:?}", e);
				return Err( super::Error::Locked );
				},
			};
		// - Obtain handles to each cached page, and map into the reservation
		for i in 0 .. page_count {
			let page = ofs / ::PAGE_SIZE as u64 + i as u64;
			// 1. Search the node for this particular page
			//let lh = self.page_cache.read();
			//  - If found, map over region
			// 2. Drop lock, read data from file, and try again
			//drop(lh)
			try!( self.node.read(page * ::PAGE_SIZE as u64, resv.get_mut_page(i)) );
			// 3. Acquire write on lock, and attempt to insert a handle to this page
			//let lh = self.page_cache.write();
			//match lh.try_insert(pag, self.get_page_handle(i))
			//{
			//Ok(_) => {},	// Inserted correctly
			//Err(h) => {	// Another handle made a page for this first
			//	resv.map_at(i, h);	// - Map over our original attempt
			//	},
			//}
		}
		resv.finalise( match mode
			{
			MemoryMapMode::ReadOnly  => ::memory::virt::ProtectionMode::UserRO,
			MemoryMapMode::Execute   => ::memory::virt::ProtectionMode::UserRX,
			MemoryMapMode::COW       => ::memory::virt::ProtectionMode::UserCOW,
			MemoryMapMode::WriteBack => ::memory::virt::ProtectionMode::UserRW,
			})
			.unwrap();
		Ok(MemoryMapHandle {
			handle: self,
			base: address as *mut (),
			len: page_count * ::PAGE_SIZE,
			})
	}
}
impl ::core::ops::Drop for File
{
	fn drop(&mut self) {
		match self.mode
		{
		FileOpenMode::SharedRO => {},
		_ => todo!("File::drop() - mode={:?}", self.mode),
		}
		// TODO: For files, we need to release the lock
	}
}

impl<'a> Drop for MemoryMapHandle<'a>
{
	fn drop(&mut self)
	{
		todo!("MemoryMapHandle::drop {{ handle={:?}, base={:p}+{}}}", self.handle, self.base, self.len);
	}
}

impl Dir
{
	/// Open a provided path as a directory
	pub fn open(path: &Path) -> super::Result<Dir> {
		try!(Any::open(path)).to_dir()
	}

	pub fn iter(&self) -> DirIter {
		DirIter {
			handle: self,
			ents: [
				Default::default(), Default::default(),
				Default::default(), Default::default(),
				],
			pos: 0,
			ofs: 0,
			count: 0,
		}
	}

	/// Create a new directory
	pub fn mkdir(&self, name: &str) -> super::Result<Dir> {
		let node = try!(self.node.create(name.as_ref(), NodeType::Dir));
		assert!(node.is_dir());
		Ok( Dir { node: node } )
	}
	/// Create a new symbolic link
	pub fn symlink(&self, name: &str, target: &Path) -> super::Result<()> {
		try!(self.node.create(name.as_ref(), NodeType::Symlink(target)));
		Ok( () )
	}
}

pub struct DirIter<'a> {
	handle: &'a Dir,
	count: usize,
	ofs: usize,
	pos: usize,
	ents: [(super::node::InodeId,ByteString); 4],
}
impl<'a> ::core::iter::Iterator for DirIter<'a> {
	type Item = ByteString;
	fn next(&mut self) -> Option<ByteString> {
		if self.ofs == self.count {
			match self.handle.node.read_dir(self.pos, &mut self.ents)
			{
			Err(e) => {
				log_warning!("Error while iterating dir: {:?}", e);
				return None;
				},
			Ok((next,count)) => {
				self.pos = next;
				self.count = count;
				},
			}
			if self.count == 0 {
				return None;
			}
			self.ofs = 1;
		}
		else {
			self.ofs += 1;
		}
		Some( ::core::mem::replace(&mut self.ents[self.ofs-1].1, ByteString::new()) )
	}
}

<commit_msg>(minor) Add assert to todo!'d Handle::write<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/vfs/handle.rs
//! Opened file interface
use prelude::*;
use super::node::{CacheHandle,NodeType};
use lib::byte_str::ByteString;
use super::Path;

#[derive(Debug)]
/// Open without caring what the file type is (e.g. enumeration)
pub struct Any {
	node: CacheHandle,
}
#[derive(Debug)]
/// Normal file
pub struct File {
	node: CacheHandle,
	mode: FileOpenMode,
}
#[derive(Debug)]
/// Directory (for enumeration)
pub struct Dir {
	node: CacheHandle,
}
#[derive(Debug)]
/// Symbolic link (allows reading the link contents)
pub struct Symlink {
	node: CacheHandle,
}
#[derive(Debug)]
/// Special file (?API exposed)
pub struct Special {
	node: CacheHandle,
}

#[derive(Debug)]
pub enum FileOpenMode
{
	/// Shared read-only, multiple readers but no writers visible
	///
	/// When opened in this manner, the file contents cannot change, but it might extend
	SharedRO,
	/// Open for execution (multiple readers)
	///
	/// No file changes visible to handles, must be an executable file
	Execute,
	/// Eclusive read-write, denies any other opens while held (except Append)
	///
	/// No changes to the file will be visible to the user (as the file is locked)
	ExclRW,
	/// Unique read-write, does Copy-on-write to create a new file
	///
	/// No changes to the file will be visible to the user (as it has its own copy)
	UniqueRW,
	/// Append only (allows multiple readers/writers)
	///
	/// Cannot read, all writes go to the end of the file (a write call is atomic)
	Append,
	/// Unsynchronised read-write
	///
	/// No synchronisation at all, fails if any other open type is active.
	Unsynch,
}

#[derive(Debug)]
pub enum MemoryMapMode
{
	/// Read-only mapping of a file
	ReadOnly,
	/// Executable mapping of a file
	Execute,
	/// Copy-on-write (used for executable files)
	COW,
	/// Allows writing to the backing file
	WriteBack,
}

impl Any
{
	/// Open the specified path (not caring what the actual type is)
	pub fn open(path: &Path) -> super::Result<Any> {
		let node = try!(CacheHandle::from_path(path));
		Ok(Any { node: node })
	}

	/// Upgrade the handle to a directory handle
	pub fn to_dir(self) -> super::Result<Dir> {
		if self.node.is_dir() {
			Ok(Dir { node: self.node })
		}
		else {
			Err(super::Error::TypeMismatch)
		}
	}
}

pub struct MemoryMapHandle<'a>
{
	handle: &'a File,
	base: *mut (),
	len: usize,
}

impl File
{
	/// Open the specified path as a file
	pub fn open(path: &Path, mode: FileOpenMode) -> super::Result<File> {
		let node = try!(CacheHandle::from_path(path));
		if !node.is_file() {
			return Err(super::Error::TypeMismatch);
		}
		match mode
		{
		// TODO: Mark file as shared
		// TODO: Check permissions (must be readable in current context)
		FileOpenMode::SharedRO => {},
		// TODO: Mark file as shared
		// TODO: Check permissions (must be executable in current context)
		FileOpenMode::Execute => {},
		_ => todo!("Acquire lock depending on mode({:?})", mode),
		}
		Ok(File { node: node, mode: mode })
	}

	pub fn size(&self) -> u64 {
		self.node.get_valid_size()
	}

	/// Read data from the file at the specified offset
	///
	/// Returns the number of read bytes (which might be less than the size of the input
	/// slice).
	pub fn read(&self, ofs: u64, dst: &mut [u8]) -> super::Result<usize> {
		assert!(self.node.is_file());
		self.node.read(ofs, dst)
	}
	pub fn write(&self, ofs: u64, src: &[u8]) -> super::Result<usize> {
		assert!(self.node.is_file());
		todo!("Handle::write({:#x}, {:p}+{}", ofs, src.as_ptr(), src.len());
	}

	/// Map a file into the address space
	pub fn memory_map(&self, address: usize, ofs: u64, size: usize, mode: MemoryMapMode) -> super::Result<MemoryMapHandle> {
		// - Check that this file is opened in a sufficent mode to allow this form of mapping
		match mode
		{
		// Read only - Pretty much anything
		MemoryMapMode::ReadOnly => match self.mode
			{
			FileOpenMode::Execute => {},
			FileOpenMode::SharedRO => {},
			//FileOpenMode::ExclRW => /* NOTE: Needs extra checks to ensure that aliasing does not occur */
			//FileOpenMode::UniqueRW => /* NOTE: Needs extra checks to ensure that aliasing does not occur */
			_ => return Err(super::Error::PermissionDenied),
			},
		// Executable - Execute mode only
		MemoryMapMode::Execute => match self.mode
			{
			FileOpenMode::Execute => {},
			_ => return Err(super::Error::PermissionDenied),
			},
		// COW - Execute mode only
		// - TODO: Could allow COW of readonly files? (as soon as it's written, the page is detached from the file)
		MemoryMapMode::COW => match self.mode
			{
			FileOpenMode::Execute => {},
			//FileOpenMode::SharedRO => {},
			_ => return Err(super::Error::PermissionDenied),
			},
		// Writeback - Requires exclusive access to the file (or a copy)
		MemoryMapMode::WriteBack => match self.mode
			{
			//FileOpenMode::ExclRW => /* NOTE: Needs extra checks to ensure that aliasing does not occur */
			//FileOpenMode::UniqueRW => /* NOTE: Needs extra checks to ensure that aliasing does not occur */
			_ => return Err(super::Error::PermissionDenied),
			},
		}

		// TODO: Handle unaligned mappings somehow
		// - Depends on several qirks:
		//  > Unaligned address could write to an existing page (converting it to a private) - But how would that interact with existing mappings?
		//  > Unaligned sizes would usually cause a new anon mapping, but if its unaligned becuase of EOF, it should just be COW as usual
		assert!(address % ::PAGE_SIZE == 0, "TODO: Unaligned memory_map (address={})", address);
		assert!(size % ::PAGE_SIZE == 0, "TODO: Unaligned memory_map (size={})", size);
		if address % ::PAGE_SIZE != (ofs % ::PAGE_SIZE as u64) as usize {
			return Err( super::Error::Unknown("memory_map alignment mismatch") );
		}
		// - Limit checking (ofs + size must be within size of the file)
		// TODO: Limit checking
		// - Reserve the region to be mapped (reserve sticks a zero page in)
		let page_count = size / ::PAGE_SIZE;
		let mut resv = match ::memory::virt::reserve(address as *mut (), page_count)
			{
			Ok(v) => v,
			Err(e) => {
				log_notice!("mmap reserve error {:?}", e);
				return Err( super::Error::Locked );
				},
			};
		// - Obtain handles to each cached page, and map into the reservation
		for i in 0 .. page_count {
			let page = ofs / ::PAGE_SIZE as u64 + i as u64;
			// 1. Search the node for this particular page
			//let lh = self.page_cache.read();
			//  - If found, map over region
			// 2. Drop lock, read data from file, and try again
			//drop(lh)
			try!( self.node.read(page * ::PAGE_SIZE as u64, resv.get_mut_page(i)) );
			// 3. Acquire write on lock, and attempt to insert a handle to this page
			//let lh = self.page_cache.write();
			//match lh.try_insert(pag, self.get_page_handle(i))
			//{
			//Ok(_) => {},	// Inserted correctly
			//Err(h) => {	// Another handle made a page for this first
			//	resv.map_at(i, h);	// - Map over our original attempt
			//	},
			//}
		}
		resv.finalise( match mode
			{
			MemoryMapMode::ReadOnly  => ::memory::virt::ProtectionMode::UserRO,
			MemoryMapMode::Execute   => ::memory::virt::ProtectionMode::UserRX,
			MemoryMapMode::COW       => ::memory::virt::ProtectionMode::UserCOW,
			MemoryMapMode::WriteBack => ::memory::virt::ProtectionMode::UserRW,
			})
			.unwrap();
		Ok(MemoryMapHandle {
			handle: self,
			base: address as *mut (),
			len: page_count * ::PAGE_SIZE,
			})
	}
}
impl ::core::ops::Drop for File
{
	fn drop(&mut self) {
		match self.mode
		{
		FileOpenMode::SharedRO => {},
		_ => todo!("File::drop() - mode={:?}", self.mode),
		}
		// TODO: For files, we need to release the lock
	}
}

impl<'a> Drop for MemoryMapHandle<'a>
{
	fn drop(&mut self)
	{
		todo!("MemoryMapHandle::drop {{ handle={:?}, base={:p}+{}}}", self.handle, self.base, self.len);
	}
}

impl Dir
{
	/// Open a provided path as a directory
	pub fn open(path: &Path) -> super::Result<Dir> {
		try!(Any::open(path)).to_dir()
	}

	pub fn iter(&self) -> DirIter {
		DirIter {
			handle: self,
			ents: [
				Default::default(), Default::default(),
				Default::default(), Default::default(),
				],
			pos: 0,
			ofs: 0,
			count: 0,
		}
	}

	/// Create a new directory
	pub fn mkdir(&self, name: &str) -> super::Result<Dir> {
		let node = try!(self.node.create(name.as_ref(), NodeType::Dir));
		assert!(node.is_dir());
		Ok( Dir { node: node } )
	}
	/// Create a new symbolic link
	pub fn symlink(&self, name: &str, target: &Path) -> super::Result<()> {
		try!(self.node.create(name.as_ref(), NodeType::Symlink(target)));
		Ok( () )
	}
}

pub struct DirIter<'a> {
	handle: &'a Dir,
	count: usize,
	ofs: usize,
	pos: usize,
	ents: [(super::node::InodeId,ByteString); 4],
}
impl<'a> ::core::iter::Iterator for DirIter<'a> {
	type Item = ByteString;
	fn next(&mut self) -> Option<ByteString> {
		if self.ofs == self.count {
			match self.handle.node.read_dir(self.pos, &mut self.ents)
			{
			Err(e) => {
				log_warning!("Error while iterating dir: {:?}", e);
				return None;
				},
			Ok((next,count)) => {
				self.pos = next;
				self.count = count;
				},
			}
			if self.count == 0 {
				return None;
			}
			self.ofs = 1;
		}
		else {
			self.ofs += 1;
		}
		Some( ::core::mem::replace(&mut self.ents[self.ofs-1].1, ByteString::new()) )
	}
}

<|endoftext|>


<commit_before>use hardware::cartridge::Cartridge;
use hardware::handler_holder::GBHandlerHolder;
use hardware::apu::NoisePattern;
use hardware::cpu::Cpu;

const VOLUME_MAX: i16 = 32000;
pub const AUDIO_BUFFER_SIZE: usize = 1470;

pub struct Emulator {
    pub cpu: Cpu,
    noise_7_bit: [u8; 127],
    noise_15_bit: [u8; 32767],
    phase: Phase,
    frequency: f64,
}

impl Emulator {
    pub fn from_data(data: &[u8], frequency: f64) -> Result<Emulator, String> {
        let handler = GBHandlerHolder::new(Cartridge::from_data(data));

        Ok(Emulator {
            cpu: Cpu::new(Box::new(handler)),
            frequency: frequency,
            noise_7_bit: generate_noise_7_bit(),
            noise_15_bit: generate_noise_15_bit(),
            phase: Phase {
                channel_1: 0.0,
                channel_2: 0.0,
                channel_3: 0.0,
                channel_4: 0.0,
            },
        })
    }

    pub fn reset(&mut self) {
        self.cpu.reset();
    }

    pub fn generate_sound(&mut self) -> [i16; AUDIO_BUFFER_SIZE] {
        let audio = self.cpu.handler_holder.get_audio_buffer();

        let mut i = 0;

        let mut channel_1_phase = self.phase.channel_1;
        let channel_1_frequency = 131072 / (2048 - audio.sound_1().frequency());
        let channel_1_phase_inc = channel_1_frequency as f64 / self.frequency;
        let channel_1_volume = (VOLUME_MAX as f64 * audio.sound_1().volume() as f64
                                / 16.0 / 4.0) as i16;

        let mut channel_2_phase = self.phase.channel_2;
        let channel_2_frequency = 131072 / (2048 - audio.sound_2().frequency());
        let channel_2_phase_inc = channel_2_frequency as f64 / self.frequency;
        let channel_2_volume = (VOLUME_MAX as f64 * audio.sound_2().volume() as f64
                                / 16.0 / 4.0) as i16;

        let mut channel_3_phase = self.phase.channel_3;
        let mut channel_3_pattern = [0; 32];
        for i in 0..16 {
            channel_3_pattern[i * 2]     = (audio.sound_3().wave_pattern()[i] & 0xF0) >> 4;
            channel_3_pattern[i * 2 + 1] =  audio.sound_3().wave_pattern()[i] & 0x0F;
        }

        let channel_3_frequency = 65536 / (2048 - audio.sound_3().frequency());
        let channel_3_volume = (VOLUME_MAX as f64 * audio.sound_3().volume().to_volume() as f64
                                / 4.0) as i16;
        let channel_3_phase_inc = channel_3_frequency as f64 / self.frequency;

        let channel_4_pattern = match audio.sound_4().pattern() {
            NoisePattern::C15 => &self.noise_15_bit[..],
            NoisePattern::C7  => &self.noise_7_bit[..],
        };
        let mut channel_4_phase = self.phase.channel_4 % channel_4_pattern.len() as f64;
        let channel_4_phase_inc = audio.sound_4().frequency() as f64 / self.frequency;
        let channel_4_volume = (VOLUME_MAX as f64 * audio.sound_4().volume() as f64
                                / 16.0 / 4.0) as i16;

        let mut out = [0; AUDIO_BUFFER_SIZE];

        while i < out.len() {
            let channel_1 = if channel_1_phase < audio.sound_1().wave_duty() as f64 {
                channel_1_volume
            } else {
                -channel_1_volume
            };

            let channel_2 = if channel_2_phase < audio.sound_2().wave_duty() as f64 {
                channel_2_volume
            } else {
                -channel_2_volume
            };

            let channel_3_index = (channel_3_phase * 32.0) as usize;
            let channel_3 = ((channel_3_pattern[channel_3_index] as f32 - 7.0)
                            / 8.0 * channel_3_volume as f32) as i16;

            let channel_4_index = channel_4_phase as usize;
            let channel_4_bit = channel_4_pattern[channel_4_index];
            let channel_4 = if channel_4_bit == 1 {
                channel_4_volume
            } else {
                -channel_4_volume
            };

            out[i] =
                  ((if audio.sound_1().playing_left() { channel_1 } else { 0 }) +
                   (if audio.sound_2().playing_left() { channel_2 } else { 0 }) +
                   (if audio.sound_3().playing_left() { channel_3 } else { 0 }) +
                   (if audio.sound_4().playing_left() { channel_4 } else { 0 })) / 4;

            out[i + 1] =
               ((if audio.sound_1().playing_right() { channel_1 } else { 0 }) +
                (if audio.sound_2().playing_right() { channel_2 } else { 0 }) +
                (if audio.sound_3().playing_right() { channel_3 } else { 0 }) +
                (if audio.sound_4().playing_right() { channel_3 } else { 0 })) / 4;

            channel_1_phase = (channel_1_phase + channel_1_phase_inc) % 1.0;
            channel_2_phase = (channel_2_phase + channel_2_phase_inc) % 1.0;
            channel_3_phase = (channel_3_phase + channel_3_phase_inc) % 1.0;
            channel_4_phase = (channel_4_phase + channel_4_phase_inc)
                            % channel_4_pattern.len() as f64;

            i += 2;
        }

        self.phase = Phase {
            channel_1: channel_1_phase,
            channel_2: channel_2_phase,
            channel_3: channel_3_phase,
            channel_4: channel_4_phase,
        };

        out
    }
}

#[derive(Clone, Copy)]
pub struct Phase {
    channel_1: f64,
    channel_2: f64,
    channel_3: f64,
    channel_4: f64,
}

fn sound_rng(v: u16, generator: u16) -> u16 {
    let bit = v & 1;
    let next = v >> 1;
    if bit != 0 {
        next ^ generator
    } else {
        next
    }
}

fn generate_noise_array(out: &mut [u8], generator: u16, bits: u32) {
    assert!(bits < 16);

    let mut v = 2u16.pow(bits) - 1;

    for i in 0..out.len() {
        out[i] = (v & 1) as u8;
        v = sound_rng(v, generator);
    }

    // Let's verify that we have reached the end of the cycle
    assert_eq!(2u16.pow(bits) - 1, v);
}

fn generate_noise_7_bit() -> [u8; 127] {
    let mut pattern = [0; 127];
    generate_noise_array(&mut pattern, 0b1000001, 7);
    pattern
}

fn generate_noise_15_bit() -> [u8; 32767] {
    let mut pattern = [0; 32767];
    generate_noise_array(&mut pattern, 0b100000000000001, 15);
    pattern
}
<commit_msg>Fix sound_4 right channel.<commit_after>use hardware::cartridge::Cartridge;
use hardware::handler_holder::GBHandlerHolder;
use hardware::apu::NoisePattern;
use hardware::cpu::Cpu;

const VOLUME_MAX: i16 = 32000;
pub const AUDIO_BUFFER_SIZE: usize = 1470;

pub struct Emulator {
    pub cpu: Cpu,
    noise_7_bit: [u8; 127],
    noise_15_bit: [u8; 32767],
    phase: Phase,
    frequency: f64,
}

impl Emulator {
    pub fn from_data(data: &[u8], frequency: f64) -> Result<Emulator, String> {
        let handler = GBHandlerHolder::new(Cartridge::from_data(data));

        Ok(Emulator {
            cpu: Cpu::new(Box::new(handler)),
            frequency: frequency,
            noise_7_bit: generate_noise_7_bit(),
            noise_15_bit: generate_noise_15_bit(),
            phase: Phase {
                channel_1: 0.0,
                channel_2: 0.0,
                channel_3: 0.0,
                channel_4: 0.0,
            },
        })
    }

    pub fn reset(&mut self) {
        self.cpu.reset();
    }

    pub fn generate_sound(&mut self) -> [i16; AUDIO_BUFFER_SIZE] {
        let audio = self.cpu.handler_holder.get_audio_buffer();

        let mut i = 0;

        let mut channel_1_phase = self.phase.channel_1;
        let channel_1_frequency = 131072 / (2048 - audio.sound_1().frequency());
        let channel_1_phase_inc = channel_1_frequency as f64 / self.frequency;
        let channel_1_volume = (VOLUME_MAX as f64 * audio.sound_1().volume() as f64
                                / 16.0 / 4.0) as i16;

        let mut channel_2_phase = self.phase.channel_2;
        let channel_2_frequency = 131072 / (2048 - audio.sound_2().frequency());
        let channel_2_phase_inc = channel_2_frequency as f64 / self.frequency;
        let channel_2_volume = (VOLUME_MAX as f64 * audio.sound_2().volume() as f64
                                / 16.0 / 4.0) as i16;

        let mut channel_3_phase = self.phase.channel_3;
        let mut channel_3_pattern = [0; 32];
        for i in 0..16 {
            channel_3_pattern[i * 2]     = (audio.sound_3().wave_pattern()[i] & 0xF0) >> 4;
            channel_3_pattern[i * 2 + 1] =  audio.sound_3().wave_pattern()[i] & 0x0F;
        }

        let channel_3_frequency = 65536 / (2048 - audio.sound_3().frequency());
        let channel_3_volume = (VOLUME_MAX as f64 * audio.sound_3().volume().to_volume() as f64
                                / 4.0) as i16;
        let channel_3_phase_inc = channel_3_frequency as f64 / self.frequency;

        let channel_4_pattern = match audio.sound_4().pattern() {
            NoisePattern::C15 => &self.noise_15_bit[..],
            NoisePattern::C7  => &self.noise_7_bit[..],
        };
        let mut channel_4_phase = self.phase.channel_4 % channel_4_pattern.len() as f64;
        let channel_4_phase_inc = audio.sound_4().frequency() as f64 / self.frequency;
        let channel_4_volume = (VOLUME_MAX as f64 * audio.sound_4().volume() as f64
                                / 16.0 / 4.0) as i16;

        let mut out = [0; AUDIO_BUFFER_SIZE];

        while i < out.len() {
            let channel_1 = if channel_1_phase < audio.sound_1().wave_duty() as f64 {
                channel_1_volume
            } else {
                -channel_1_volume
            };

            let channel_2 = if channel_2_phase < audio.sound_2().wave_duty() as f64 {
                channel_2_volume
            } else {
                -channel_2_volume
            };

            let channel_3_index = (channel_3_phase * 32.0) as usize;
            let channel_3 = ((channel_3_pattern[channel_3_index] as f32 - 7.0)
                            / 8.0 * channel_3_volume as f32) as i16;

            let channel_4_index = channel_4_phase as usize;
            let channel_4_bit = channel_4_pattern[channel_4_index];
            let channel_4 = if channel_4_bit == 1 {
                channel_4_volume
            } else {
                -channel_4_volume
            };

            out[i] =
                  ((if audio.sound_1().playing_left() { channel_1 } else { 0 }) +
                   (if audio.sound_2().playing_left() { channel_2 } else { 0 }) +
                   (if audio.sound_3().playing_left() { channel_3 } else { 0 }) +
                   (if audio.sound_4().playing_left() { channel_4 } else { 0 })) / 4;

            out[i + 1] =
               ((if audio.sound_1().playing_right() { channel_1 } else { 0 }) +
                (if audio.sound_2().playing_right() { channel_2 } else { 0 }) +
                (if audio.sound_3().playing_right() { channel_3 } else { 0 }) +
                (if audio.sound_4().playing_right() { channel_4 } else { 0 })) / 4;

            channel_1_phase = (channel_1_phase + channel_1_phase_inc) % 1.0;
            channel_2_phase = (channel_2_phase + channel_2_phase_inc) % 1.0;
            channel_3_phase = (channel_3_phase + channel_3_phase_inc) % 1.0;
            channel_4_phase = (channel_4_phase + channel_4_phase_inc)
                            % channel_4_pattern.len() as f64;

            i += 2;
        }

        self.phase = Phase {
            channel_1: channel_1_phase,
            channel_2: channel_2_phase,
            channel_3: channel_3_phase,
            channel_4: channel_4_phase,
        };

        out
    }
}

#[derive(Clone, Copy)]
pub struct Phase {
    channel_1: f64,
    channel_2: f64,
    channel_3: f64,
    channel_4: f64,
}

fn sound_rng(v: u16, generator: u16) -> u16 {
    let bit = v & 1;
    let next = v >> 1;
    if bit != 0 {
        next ^ generator
    } else {
        next
    }
}

fn generate_noise_array(out: &mut [u8], generator: u16, bits: u32) {
    assert!(bits < 16);

    let mut v = 2u16.pow(bits) - 1;

    for i in 0..out.len() {
        out[i] = (v & 1) as u8;
        v = sound_rng(v, generator);
    }

    // Let's verify that we have reached the end of the cycle
    assert_eq!(2u16.pow(bits) - 1, v);
}

fn generate_noise_7_bit() -> [u8; 127] {
    let mut pattern = [0; 127];
    generate_noise_array(&mut pattern, 0b1000001, 7);
    pattern
}

fn generate_noise_15_bit() -> [u8; 32767] {
    let mut pattern = [0; 32767];
    generate_noise_array(&mut pattern, 0b100000000000001, 15);
    pattern
}
<|endoftext|>