<commit_before>use std;
use libc;

use baseline;
use baseline::fct::BailoutInfo;
use cpu;
use ctxt::{Context, CTXT, FctId, get_ctxt};
use execstate::ExecState;
use os_cpu::*;
use stacktrace::{handle_exception, get_stacktrace};

#[cfg(target_family = "windows")]
use winapi::winnt::EXCEPTION_POINTERS;

#[cfg(target_family = "unix")]
pub fn register_signals(ctxt: &Context) {
    unsafe {
        let ptr = ctxt as *const Context as *const u8;
        CTXT = Some(ptr);

        let mut sa: libc::sigaction = std::mem::uninitialized();

        sa.sa_sigaction = handler as usize;
        libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
        sa.sa_flags = libc::SA_SIGINFO;

        if libc::sigaction(libc::SIGSEGV,
                           &sa as *const libc::sigaction,
                           0 as *mut libc::sigaction) == -1 {
            libc::perror("sigaction for SIGSEGV failed".as_ptr() as *const libc::c_char);
        }

        if libc::sigaction(libc::SIGILL,
                           &sa as *const libc::sigaction,
                           0 as *mut libc::sigaction) == -1 {
            libc::perror("sigaction for SIGILL failed".as_ptr() as *const libc::c_char);
        }
    }
}

#[cfg(target_family = "windows")]
pub fn register_signals(ctxt: &Context) {
    use kernel32::AddVectoredExceptionHandler;

    unsafe {
        AddVectoredExceptionHandler(1, Some(handler));
    }
}

#[cfg(target_family = "windows")]
extern "system" fn handler(exception: *mut EXCEPTION_POINTERS) -> i32 {
    use winapi::excpt;

    if fault_handler(exception) {
        return excpt::ExceptionContinueExecution.0 as i32;
    }

    excpt::ExceptionContinueSearch.0 as i32
}

#[cfg(target_family = "windows")]
fn fault_handler(exception: *mut EXCEPTION_POINTERS) -> bool {
    unsafe {
        let record = (*exception).ExceptionRecord;
        let context = (*exception).ContextRecord;
    }

    false
}

#[cfg(target_family = "unix")]
fn handler(signo: libc::c_int, _: *const u8, ucontext: *const u8) {
    let mut es = read_execstate(ucontext);
    let ctxt = get_ctxt();

    if let Some(trap) = detect_trap(signo as i32, &es) {
        match trap {
            Trap::COMPILER => compile_request(ctxt, &mut es, ucontext),

            Trap::DIV0 => {
                println!("division by 0");
                let stacktrace = get_stacktrace(ctxt, &es);
                stacktrace.dump(ctxt);
                unsafe {
                    libc::_exit(101);
                }
            }

            Trap::ASSERT => {
                println!("assert failed");
                let stacktrace = get_stacktrace(ctxt, &es);
                stacktrace.dump(ctxt);
                unsafe {
                    libc::_exit(101);
                }
            }

            Trap::INDEX_OUT_OF_BOUNDS => {
                println!("array index out of bounds");
                let stacktrace = get_stacktrace(ctxt, &es);
                stacktrace.dump(ctxt);
                unsafe {
                    libc::_exit(102);
                }
            }

            Trap::NIL => {
                println!("nil check failed");
                let stacktrace = get_stacktrace(ctxt, &es);
                stacktrace.dump(ctxt);
                unsafe {
                    libc::_exit(103);
                }
            }

            Trap::THROW => {
                let handler_found = handle_exception(&mut es);

                if handler_found {
                    write_execstate(&es, ucontext as *mut u8);
                } else {
                    println!("uncaught exception");
                    unsafe {
                        libc::_exit(104);
                    }
                }
            }

            Trap::CAST => {
                println!("cast failed");
                let stacktrace = get_stacktrace(ctxt, &es);
                stacktrace.dump(ctxt);
                unsafe {
                    libc::_exit(105);
                }
            }

            Trap::UNEXPECTED => {
                println!("unexpected exception");
                let stacktrace = get_stacktrace(ctxt, &es);
                stacktrace.dump(ctxt);
                unsafe {
                    libc::_exit(106);
                }
            }
        }

        // could not recognize trap -> crash vm
    } else {
        println!("error: trap not detected (signal {}).", signo);
        println!();
        println!("{:?}", &es);
        println!();

        {
            let code_map = ctxt.code_map.lock().unwrap();
            code_map.dump(ctxt);
        }

        unsafe {
            libc::_exit(1);
        }
    }
}

fn compile_request(ctxt: &Context, es: &mut ExecState, ucontext: *const u8) {
    let fct_id = {
        let code_map = ctxt.code_map.lock().unwrap();
        code_map.get(es.pc as *const u8)
    };

    if let Some(fct_id) = fct_id {
        let mut sfi = cpu::sfi_from_execution_state(es);

        ctxt.use_sfi(&mut sfi, || {
            let jit_fct = baseline::generate(ctxt, fct_id);
            let fct = ctxt.fct_by_id(fct_id);

            if fct.is_virtual() {
                patch_vtable_call(ctxt, es, fct_id, jit_fct);
            } else {
                patch_fct_call(ctxt, es, jit_fct);
            }

            write_execstate(es, ucontext as *mut u8);
        });
    } else {
        println!("error: code not found for address {:x}", es.pc);
        unsafe {
            libc::_exit(200);
        }
    }
}

fn patch_vtable_call(ctxt: &Context, es: &mut ExecState, fid: FctId, fct_ptr: *const u8) {
    let fct = ctxt.fct_by_id(fid);
    let vtable_index = fct.vtable_index.unwrap();
    let cls_id = fct.owner_class.unwrap();

    let cls = ctxt.cls_by_id(cls_id);
    let vtable = cls.vtable.as_ref().unwrap();

    let methodtable = vtable.table_mut();
    methodtable[vtable_index as usize] = fct_ptr as usize;

    // execute fct call again
    es.pc = fct_ptr as usize;
}

pub fn patch_fct_call(ctxt: &Context, es: &mut ExecState, fct_ptr: *const u8) {
    // get return address from top of stack
    let ra = cpu::ra_from_execstate(es);

    let fct_id = {
        let code_map = ctxt.code_map.lock().unwrap();
        code_map.get(ra as *const u8).expect("return address not found")
    };

    let fct = ctxt.fct_by_id(fct_id);
    let src = fct.src();
    let src = src.lock().unwrap();
    let jit_fct = src.jit_fct.as_ref().expect("jitted fct not found");

    let offset = ra - jit_fct.fct_ptr() as usize;
    let bailout = jit_fct.bailouts.get(offset as i32).expect("bailout info not found");

    // get address of function pointer
    let disp = match bailout {
        &BailoutInfo::Compile(disp) => disp as isize,
    };

    let fct_addr: *mut usize = (ra as isize - disp) as *mut _;

    // write function pointer
    unsafe {
        *fct_addr = fct_ptr as usize;
    }

    // execute fct call again
    es.pc = fct_ptr as usize;
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Trap {
    COMPILER,
    DIV0,
    ASSERT,
    INDEX_OUT_OF_BOUNDS,
    NIL,
    THROW,
    CAST,
    UNEXPECTED,
}

impl Trap {
    pub fn int(self) -> u32 {
        match self {
            Trap::COMPILER => 0,
            Trap::DIV0 => 1,
            Trap::ASSERT => 2,
            Trap::INDEX_OUT_OF_BOUNDS => 3,
            Trap::NIL => 4,
            Trap::THROW => 5,
            Trap::CAST => 6,
            Trap::UNEXPECTED => 7,
        }
    }

    pub fn from(value: u32) -> Option<Trap> {
        match value {
            0 => Some(Trap::COMPILER),
            1 => Some(Trap::DIV0),
            2 => Some(Trap::ASSERT),
            3 => Some(Trap::INDEX_OUT_OF_BOUNDS),
            4 => Some(Trap::NIL),
            5 => Some(Trap::THROW),
            6 => Some(Trap::CAST),
            7 => Some(Trap::UNEXPECTED),
            _ => None,
        }
    }
}
<commit_msg>use get_ctxt invocation after detect_trap succeeds<commit_after>use std;
use libc;

use baseline;
use baseline::fct::BailoutInfo;
use cpu;
use ctxt::{Context, CTXT, FctId, get_ctxt};
use execstate::ExecState;
use os_cpu::*;
use stacktrace::{handle_exception, get_stacktrace};

#[cfg(target_family = "windows")]
use winapi::winnt::EXCEPTION_POINTERS;

#[cfg(target_family = "unix")]
pub fn register_signals(ctxt: &Context) {
    unsafe {
        let ptr = ctxt as *const Context as *const u8;
        CTXT = Some(ptr);

        let mut sa: libc::sigaction = std::mem::uninitialized();

        sa.sa_sigaction = handler as usize;
        libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
        sa.sa_flags = libc::SA_SIGINFO;

        if libc::sigaction(libc::SIGSEGV,
                           &sa as *const libc::sigaction,
                           0 as *mut libc::sigaction) == -1 {
            libc::perror("sigaction for SIGSEGV failed".as_ptr() as *const libc::c_char);
        }

        if libc::sigaction(libc::SIGILL,
                           &sa as *const libc::sigaction,
                           0 as *mut libc::sigaction) == -1 {
            libc::perror("sigaction for SIGILL failed".as_ptr() as *const libc::c_char);
        }
    }
}

#[cfg(target_family = "windows")]
pub fn register_signals(ctxt: &Context) {
    use kernel32::AddVectoredExceptionHandler;

    unsafe {
        AddVectoredExceptionHandler(1, Some(handler));
    }
}

#[cfg(target_family = "windows")]
extern "system" fn handler(exception: *mut EXCEPTION_POINTERS) -> i32 {
    use winapi::excpt;

    if fault_handler(exception) {
        return excpt::ExceptionContinueExecution.0 as i32;
    }

    excpt::ExceptionContinueSearch.0 as i32
}

#[cfg(target_family = "windows")]
fn fault_handler(exception: *mut EXCEPTION_POINTERS) -> bool {
    unsafe {
        let record = (*exception).ExceptionRecord;
        let context = (*exception).ContextRecord;
    }

    false
}

#[cfg(target_family = "unix")]
fn handler(signo: libc::c_int, _: *const u8, ucontext: *const u8) {
    let mut es = read_execstate(ucontext);

    if let Some(trap) = detect_trap(signo as i32, &es) {
        handle_trap(trap, &mut es);

    // could not recognize trap -> crash vm
    } else {
        println!("error: trap not detected (signal {}).", signo);
        println!();
        println!("{:?}", &es);
        println!();

        {
            let code_map = ctxt.code_map.lock().unwrap();
            code_map.dump(ctxt);
        }

        unsafe {
            libc::_exit(1);
        }
    }
}

fn handle_trap(trap: Trap, es: &mut ExecState) {
    let ctxt = get_ctxt();

    match trap {
        Trap::COMPILER => compile_request(ctxt, &mut es, ucontext),

        Trap::DIV0 => {
            println!("division by 0");
            let stacktrace = get_stacktrace(ctxt, &es);
            stacktrace.dump(ctxt);
            unsafe {
                libc::_exit(101);
            }
        }

        Trap::ASSERT => {
            println!("assert failed");
            let stacktrace = get_stacktrace(ctxt, &es);
            stacktrace.dump(ctxt);
            unsafe {
                libc::_exit(101);
            }
        }

        Trap::INDEX_OUT_OF_BOUNDS => {
            println!("array index out of bounds");
            let stacktrace = get_stacktrace(ctxt, &es);
            stacktrace.dump(ctxt);
            unsafe {
                libc::_exit(102);
            }
        }

        Trap::NIL => {
            println!("nil check failed");
            let stacktrace = get_stacktrace(ctxt, &es);
            stacktrace.dump(ctxt);
            unsafe {
                libc::_exit(103);
            }
        }

        Trap::THROW => {
            let handler_found = handle_exception(&mut es);

            if handler_found {
                write_execstate(&es, ucontext as *mut u8);
            } else {
                println!("uncaught exception");
                unsafe {
                    libc::_exit(104);
                }
            }
        }

        Trap::CAST => {
            println!("cast failed");
            let stacktrace = get_stacktrace(ctxt, &es);
            stacktrace.dump(ctxt);
            unsafe {
                libc::_exit(105);
            }
        }

        Trap::UNEXPECTED => {
            println!("unexpected exception");
            let stacktrace = get_stacktrace(ctxt, &es);
            stacktrace.dump(ctxt);
            unsafe {
                libc::_exit(106);
            }
        }
    }
}

fn compile_request(ctxt: &Context, es: &mut ExecState, ucontext: *const u8) {
    let fct_id = {
        let code_map = ctxt.code_map.lock().unwrap();
        code_map.get(es.pc as *const u8)
    };

    if let Some(fct_id) = fct_id {
        let mut sfi = cpu::sfi_from_execution_state(es);

        ctxt.use_sfi(&mut sfi, || {
            let jit_fct = baseline::generate(ctxt, fct_id);
            let fct = ctxt.fct_by_id(fct_id);

            if fct.is_virtual() {
                patch_vtable_call(ctxt, es, fct_id, jit_fct);
            } else {
                patch_fct_call(ctxt, es, jit_fct);
            }

            write_execstate(es, ucontext as *mut u8);
        });
    } else {
        println!("error: code not found for address {:x}", es.pc);
        unsafe {
            libc::_exit(200);
        }
    }
}

fn patch_vtable_call(ctxt: &Context, es: &mut ExecState, fid: FctId, fct_ptr: *const u8) {
    let fct = ctxt.fct_by_id(fid);
    let vtable_index = fct.vtable_index.unwrap();
    let cls_id = fct.owner_class.unwrap();

    let cls = ctxt.cls_by_id(cls_id);
    let vtable = cls.vtable.as_ref().unwrap();

    let methodtable = vtable.table_mut();
    methodtable[vtable_index as usize] = fct_ptr as usize;

    // execute fct call again
    es.pc = fct_ptr as usize;
}

pub fn patch_fct_call(ctxt: &Context, es: &mut ExecState, fct_ptr: *const u8) {
    // get return address from top of stack
    let ra = cpu::ra_from_execstate(es);

    let fct_id = {
        let code_map = ctxt.code_map.lock().unwrap();
        code_map.get(ra as *const u8).expect("return address not found")
    };

    let fct = ctxt.fct_by_id(fct_id);
    let src = fct.src();
    let src = src.lock().unwrap();
    let jit_fct = src.jit_fct.as_ref().expect("jitted fct not found");

    let offset = ra - jit_fct.fct_ptr() as usize;
    let bailout = jit_fct.bailouts.get(offset as i32).expect("bailout info not found");

    // get address of function pointer
    let disp = match bailout {
        &BailoutInfo::Compile(disp) => disp as isize,
    };

    let fct_addr: *mut usize = (ra as isize - disp) as *mut _;

    // write function pointer
    unsafe {
        *fct_addr = fct_ptr as usize;
    }

    // execute fct call again
    es.pc = fct_ptr as usize;
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Trap {
    COMPILER,
    DIV0,
    ASSERT,
    INDEX_OUT_OF_BOUNDS,
    NIL,
    THROW,
    CAST,
    UNEXPECTED,
}

impl Trap {
    pub fn int(self) -> u32 {
        match self {
            Trap::COMPILER => 0,
            Trap::DIV0 => 1,
            Trap::ASSERT => 2,
            Trap::INDEX_OUT_OF_BOUNDS => 3,
            Trap::NIL => 4,
            Trap::THROW => 5,
            Trap::CAST => 6,
            Trap::UNEXPECTED => 7,
        }
    }

    pub fn from(value: u32) -> Option<Trap> {
        match value {
            0 => Some(Trap::COMPILER),
            1 => Some(Trap::DIV0),
            2 => Some(Trap::ASSERT),
            3 => Some(Trap::INDEX_OUT_OF_BOUNDS),
            4 => Some(Trap::NIL),
            5 => Some(Trap::THROW),
            6 => Some(Trap::CAST),
            7 => Some(Trap::UNEXPECTED),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>#[allow(unused)]
pub mod entity;
pub mod http;
pub mod response;
pub mod postparams;

extern crate hyper;
extern crate serde_json;
extern crate urlencoded;

use hyper::client;
use hyper::mime::Mime;
use std;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::Read;
use std::option::Option;
use std::process::exit;
use std::result::Result;

#[derive(Debug)]
pub struct Api {
    base_uri: &'static str,
    api_key: String,
    login_token: String,
    client: hyper::client::Client,
    user_agent: String,
}

#[allow(unused)]
impl Api {

    /// Create a new api client
    pub fn new(api_key: String) -> Api {
        let crates_version = &std::env::var("CARGO_PKG_VERSION")
            .unwrap_or("unknown".to_string());
        let crates_name = std::env::var("CARGO_PKG_NAME").
            unwrap_or("unknown".to_string());

        let ua = format!("libproxer-rust({}/v{})", crates_name, crates_version);

        Api {
            base_uri:    "http://proxer.me/api/v1/",
            api_key:     api_key,
            login_token: "None".to_string(),
            client:      hyper::client::Client::new(),
            user_agent:  ua,
        }
    }

    pub fn info_get_full_info(self, id: u32) -> Result<client::response::Response, hyper::Error> {
        use api::entity::response::*;
        let url = "info/fullentry";

        let mut post = postparams::Postparams::new();

        post.add("id", id);

        response::Response::new::<info::fullinfo::FullInfo>(self.http_req(url, post))
    }

    fn http_req<T: ToString>(self, url: &str, data: T) -> Result<client::response::Response, hyper::Error> {
        let uri = self.base_uri.to_string()+url;
        let hyper_url = hyper::Url::parse(&uri).unwrap();

        let mut headers = hyper::header::Headers::new();
        header! {(ProxerApiKeyHeader, "proxer-api-key") => [String]}
        header! {(UserAgent, "User-Agent") => [String]}
        headers.set(ProxerApiKeyHeader(self.api_key));
        headers.set(UserAgent(self.user_agent));
        headers.set(hyper::header::ContentType::form_url_encoded());

        self.client
            .post(hyper_url)
            .headers(headers)
            .body(&data.to_string())
            .send()
    }

    pub fn read_json(json: String) -> std::result::Result<serde_json::Value, serde_json::Error> {
        serde_json::from_str(&json)
    }
}

fn hashmap_to_encoded_url(params: HashMap<String, String>) -> String{
    "foobar".to_string()
}
<commit_msg>remove unused function<commit_after>#[allow(unused)]
pub mod entity;
pub mod http;
pub mod response;
pub mod postparams;

extern crate hyper;
extern crate serde_json;
extern crate urlencoded;

use hyper::client;
use hyper::mime::Mime;
use std;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::Read;
use std::option::Option;
use std::process::exit;
use std::result::Result;

#[derive(Debug)]
pub struct Api {
    base_uri: &'static str,
    api_key: String,
    login_token: String,
    client: hyper::client::Client,
    user_agent: String,
}

#[allow(unused)]
impl Api {

    /// Create a new api client
    pub fn new(api_key: String) -> Api {
        let crates_version = &std::env::var("CARGO_PKG_VERSION")
            .unwrap_or("unknown".to_string());
        let crates_name = std::env::var("CARGO_PKG_NAME").
            unwrap_or("unknown".to_string());

        let ua = format!("libproxer-rust({}/v{})", crates_name, crates_version);

        Api {
            base_uri:    "http://proxer.me/api/v1/",
            api_key:     api_key,
            login_token: "None".to_string(),
            client:      hyper::client::Client::new(),
            user_agent:  ua,
        }
    }

    pub fn info_get_full_info(self, id: u32) -> Result<client::response::Response, hyper::Error> {
        use api::entity::response::*;
        let url = "info/fullentry";

        let mut post = postparams::Postparams::new();

        post.add("id", id);

        response::Response::new::<info::fullinfo::FullInfo>(self.http_req(url, post))
    }

    fn http_req<T: ToString>(self, url: &str, data: T) -> Result<client::response::Response, hyper::Error> {
        let uri = self.base_uri.to_string()+url;
        let hyper_url = hyper::Url::parse(&uri).unwrap();

        let mut headers = hyper::header::Headers::new();
        header! {(ProxerApiKeyHeader, "proxer-api-key") => [String]}
        header! {(UserAgent, "User-Agent") => [String]}
        headers.set(ProxerApiKeyHeader(self.api_key));
        headers.set(UserAgent(self.user_agent));
        headers.set(hyper::header::ContentType::form_url_encoded());

        self.client
            .post(hyper_url)
            .headers(headers)
            .body(&data.to_string())
            .send()
    }

    pub fn read_json(json: String) -> std::result::Result<serde_json::Value, serde_json::Error> {
        serde_json::from_str(&json)
    }
}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="columns" sub_properties="column-count column-width" experimental="True"
                    extra_prefixes="moz" spec="https://drafts.csswg.org/css-multicol/#propdef-columns">
    use properties::longhands::{column_count, column_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {

        let mut column_count = None;
        let mut column_width = None;
        let mut autos = 0;

        loop {
            if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
                // Leave the options to None, 'auto' is the initial value.
                autos += 1;
                continue
            }

            if column_count.is_none() {
                if let Ok(value) = input.try(|input| column_count::parse(context, input)) {
                    column_count = Some(value);
                    continue
                }
            }

            if column_width.is_none() {
                if let Ok(value) = input.try(|input| column_width::parse(context, input)) {
                    column_width = Some(value);
                    continue
                }
            }

            break
        }

        let values = autos + column_count.iter().len() + column_width.iter().len();
        if values == 0 || values > 2 {
            Err(())
        } else {
            Ok(Longhands {
                column_count: column_count,
                column_width: column_width,
            })
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.column_width.to_css(dest));
            try!(write!(dest, " "));

            self.column_count.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="column-rule" products="gecko" extra_prefixes="moz"
    sub_properties="column-rule-width column-rule-style column-rule-color"
    spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule">
    use properties::longhands::{column_rule_width, column_rule_style};
    use properties::longhands::column_rule_color;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "width style color".split():
        let mut column_rule_${name} = None;
        % endfor
        let mut any = false;

        loop {
            % for name in "width style color".split():
            if column_rule_${name}.is_none() {
                if let Ok(value) = input.try(|input|
                        column_rule_${name}::parse(context, input)) {
                    column_rule_${name} = Some(value);
                    any = true;
                    continue
                }
            }
            % endfor

            break
        }
        if any {
            Ok(Longhands {
                % for name in "width style".split():
                    column_rule_${name}: column_rule_${name}
                        .or(Some(column_rule_${name}::get_initial_specified_value())),
                % endfor
                column_rule_color: column_rule_color,
            })
        } else {
            Err(())
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut need_space = false;
            try!(self.column_rule_width.to_css(dest));

            if let DeclaredValue::Value(ref width) = *self.column_rule_width {
                try!(width.to_css(dest));
                need_space = true;
            }

            if let DeclaredValue::Value(ref style) = *self.column_rule_style {
                if need_space {
                    try!(write!(dest, " "));
                }
                try!(style.to_css(dest));
                need_space = true;
            }

            if let DeclaredValue::Value(ref color) = *self.column_rule_color {
                if need_space {
                    try!(write!(dest, " "));
                }
                try!(color.to_css(dest));
            }
            Ok(())
        }
    }
</%helpers:shorthand>
<commit_msg>Auto merge of #15170 - upsuper:column-rule, r=Wafflespeanut<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="columns" sub_properties="column-count column-width" experimental="True"
                    extra_prefixes="moz" spec="https://drafts.csswg.org/css-multicol/#propdef-columns">
    use properties::longhands::{column_count, column_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {

        let mut column_count = None;
        let mut column_width = None;
        let mut autos = 0;

        loop {
            if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
                // Leave the options to None, 'auto' is the initial value.
                autos += 1;
                continue
            }

            if column_count.is_none() {
                if let Ok(value) = input.try(|input| column_count::parse(context, input)) {
                    column_count = Some(value);
                    continue
                }
            }

            if column_width.is_none() {
                if let Ok(value) = input.try(|input| column_width::parse(context, input)) {
                    column_width = Some(value);
                    continue
                }
            }

            break
        }

        let values = autos + column_count.iter().len() + column_width.iter().len();
        if values == 0 || values > 2 {
            Err(())
        } else {
            Ok(Longhands {
                column_count: column_count,
                column_width: column_width,
            })
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.column_width.to_css(dest));
            try!(write!(dest, " "));

            self.column_count.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="column-rule" products="gecko" extra_prefixes="moz"
    sub_properties="column-rule-width column-rule-style column-rule-color"
    spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule">
    use properties::longhands::{column_rule_width, column_rule_style};
    use properties::longhands::column_rule_color;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "width style color".split():
        let mut column_rule_${name} = None;
        % endfor
        let mut any = false;

        loop {
            % for name in "width style color".split():
            if column_rule_${name}.is_none() {
                if let Ok(value) = input.try(|input|
                        column_rule_${name}::parse(context, input)) {
                    column_rule_${name} = Some(value);
                    any = true;
                    continue
                }
            }
            % endfor

            break
        }
        if any {
            Ok(Longhands {
                % for name in "width style".split():
                    column_rule_${name}: column_rule_${name}
                        .or(Some(column_rule_${name}::get_initial_specified_value())),
                % endfor
                column_rule_color: column_rule_color,
            })
        } else {
            Err(())
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut need_space = false;

            if let DeclaredValue::Value(ref width) = *self.column_rule_width {
                try!(width.to_css(dest));
                need_space = true;
            }

            if let DeclaredValue::Value(ref style) = *self.column_rule_style {
                if need_space {
                    try!(write!(dest, " "));
                }
                try!(style.to_css(dest));
                need_space = true;
            }

            if let DeclaredValue::Value(ref color) = *self.column_rule_color {
                if need_space {
                    try!(write!(dest, " "));
                }
                try!(color.to_css(dest));
            }
            Ok(())
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>use tokio::reactor::Handle;
use futures::{Future, Poll, Async};
use std::net::SocketAddr;
use replica::client::ReplicaClient;
use tail::client::TailClient;
use tail::{TailRequest, TailResponse};
use replica::{LogPos, ReplicaRequest, ReplicaResponse};
use tokio_service::Service;
use std::sync::{Arc, Mutex};
use {Error, ErrorKind};

#[derive(Debug)]
pub struct FatClient {
    head: Arc<ReplicaClient>,
    tail: Arc<TailClient>,
    last_known_head: Arc<Mutex<LogPos>>,
}

// States:
// ```dot
// new -> request_sent;
// request_sent -> done_okay;
// request_sent -> failed_badver;
// failed_badver -> request_sent;
// ```
//
type ReplicaFut = <ReplicaClient as Service>::Future;
type TailFut = <TailClient as Service>::Future;

pub struct LogItemFut(ReplicaFut);
pub struct FetchNextFut(TailFut);

//

impl FatClient {
    pub fn new(handle: Handle, head: &SocketAddr, tail: &SocketAddr) -> Self {
        let repl = ReplicaClient::new(handle.clone(), head);
        let tail = TailClient::new(handle, tail);

        FatClient {
            head: Arc::new(repl),
            tail: Arc::new(tail),
            last_known_head: Arc::new(Mutex::new(LogPos::zero())),
        }
    }

    pub fn log_item(&self, body: Vec<u8>) -> LogItemFut {
        let current = *self.last_known_head.lock().expect("lock current");
        let req = ReplicaRequest::AppendLogEntry {
            assumed_offset: current,
            entry_offset: current.next(),
            datum: body.clone(),
        };
        LogItemFut(self.head.call(req))
    }

    pub fn fetch_next(&self, after: LogPos) -> FetchNextFut {
        let req = TailRequest::FetchNextAfter(after);
        let f = self.tail.call(req);
        FetchNextFut(f)
    }
}

impl Future for LogItemFut {
    type Item = LogPos;
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match try_ready!(self.0.poll()) {
            ReplicaResponse::Done(offset) => {
                debug!("Done =>{:?}", offset);
                return Ok(Async::Ready(offset));
            }
            ReplicaResponse::BadSequence(head) => {
                debug!("BadSequence =>{:?}", head);
                return Err(ErrorKind::BadSequence(head).into());
            }
        }
    }
}
impl Future for FetchNextFut {
    type Item = (LogPos, Vec<u8>);
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match try_ready!(self.0.poll()) {
            TailResponse::NextItem(offset, value) => {
                debug!("Done =>{:?}", offset);
                return Ok(Async::Ready((offset, value)));
            }
        }

    }
}
<commit_msg>Abstract over clients in FatClient for testability.<commit_after>use tokio::reactor::Handle;
use futures::{Future, Poll, Async};
use std::net::SocketAddr;
use replica::client::ReplicaClient;
use tail::client::TailClient;
use tail::{TailRequest, TailResponse};
use replica::{LogPos, ReplicaRequest, ReplicaResponse};
use tokio_service::Service;
use std::sync::{Arc, Mutex};
use {Error, ErrorKind};

#[derive(Debug)]
pub struct FatClient<H, T> {
    head: H,
    tail: T,
    last_known_head: Arc<Mutex<LogPos>>,
}

// States:
// ```dot
// new -> request_sent;
// request_sent -> done_okay;
// request_sent -> failed_badver;
// failed_badver -> request_sent;
// ```
//
pub struct LogItemFut<F>(F);
pub struct FetchNextFut<F>(F);

//

impl FatClient<ReplicaClient, TailClient> {
    pub fn new(handle: Handle, head: &SocketAddr, tail: &SocketAddr) -> Self {
        let repl = ReplicaClient::new(handle.clone(), head);
        let tail = TailClient::new(handle, tail);

        FatClient {
            head: repl,
            tail: tail,
            last_known_head: Arc::new(Mutex::new(LogPos::zero())),
        }
    }
}

impl<H, T> FatClient<H, T>
    where H: Service<Request = ReplicaRequest, Response = ReplicaResponse>,
          T: Service<Request = TailRequest, Response = TailResponse>
{
    pub fn log_item(&self, body: Vec<u8>) -> LogItemFut<H::Future> {
        let current = *self.last_known_head.lock().expect("lock current");
        let req = ReplicaRequest::AppendLogEntry {
            assumed_offset: current,
            entry_offset: current.next(),
            datum: body.clone(),
        };
        LogItemFut(self.head.call(req))
    }

    pub fn fetch_next(&self, after: LogPos) -> FetchNextFut<T::Future> {
        let req = TailRequest::FetchNextAfter(after);
        let f = self.tail.call(req);
        FetchNextFut(f)
    }
}

impl<F: Future<Item = ReplicaResponse, Error = Error>> Future for LogItemFut<F> {
    type Item = LogPos;
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match try_ready!(self.0.poll()) {
            ReplicaResponse::Done(offset) => {
                debug!("Done =>{:?}", offset);
                return Ok(Async::Ready(offset));
            }
            ReplicaResponse::BadSequence(head) => {
                debug!("BadSequence =>{:?}", head);
                return Err(ErrorKind::BadSequence(head).into());
            }
        }
    }
}

impl<F: Future<Item = TailResponse, Error = Error>> Future for FetchNextFut<F> {
    type Item = (LogPos, Vec<u8>);
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match try_ready!(self.0.poll()) {
            TailResponse::NextItem(offset, value) => {
                debug!("Done =>{:?}", offset);
                return Ok(Async::Ready((offset, value)));
            }
        }

    }
}
<|endoftext|>


<commit_before>use ffi;
use libc::{c_uint, c_int, c_void};
use num::complex::Complex64;

use plan::RawPlan;

/// How much effort FFTW should put into computing the best strategy
/// to use.
///
/// The `FFTW_WISDOM_ONLY` rigor level is replaced by the
pub enum Rigor {
    Estimate,
    Measure,
    Patient,
    Exhaustive,
}
impl Rigor {
    fn flags(self) -> c_uint {
        match self {
            Estimate => ffi::FFTW_ESTIMATE,
            Measure => ffi::FFTW_MEASURE,
            Patient => ffi::FFTW_PATIENT,
            Exhaustive => ffi::FFTW_EXHAUSTIVE,
        }
    }
}

/// The direction of the transform to perform..
pub enum Direction {
    Forward, Backward
}

/// Control the basic properties of a set of transforms.
pub struct Planner {
    rigor: Rigor,
    wisdom_restriction: bool,
    direction: Direction,
}

impl Planner {
    /// Construct a new planner with default values.
    ///
    /// This defaults to a forward transform with estimate rigor.
    pub fn new() -> Planner {
        Planner {
            rigor: Estimate,
            wisdom_restriction: false,
            direction: Forward,
        }
    }

    /// Set the rigor to use for this plan.
    pub fn rigor(&mut self, r: Rigor) -> &mut Planner {
        self.rigor = r;
        self
    }
    /// Set whether the planner should only be successfully created if
    /// there exists wisdom created with at least the rigor level set.
    pub fn wisdom_restriction(&mut self, wisdom_only: bool) -> &mut Planner {
        self.wisdom_restriction = wisdom_only;
        self
    }

    /// Set the direction of the transform to perform.
    pub fn direction(&mut self, direction: Direction) -> &mut Planner {
        self.direction = direction;
        self
    }

    fn flags(&self) -> c_uint {
        self.rigor.flags() | if self.wisdom_restriction {
            ffi::FFTW_WISDOM_ONLY
        } else {
            0
        }
    }
    fn dir(&self) -> c_int {
        match self.direction {
            Forward => ffi::FFTW_FORWARD,
            Backward => ffi::FFTW_BACKWARD,
        }
    }

    pub fn inplace(&self) -> InPlacePlanner {
        InPlacePlanner { plan: *self }
    }

    pub fn c2c<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[Complex64]>, O: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: c2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    pub fn c2r<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[Complex64]>, O: DerefMut<[f64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len() / 2 + 1);
        let dims = Detailed(vec![Dim { n: 2 * (in_.len() - 1),
                                       in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: c2r,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    pub fn r2c<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[f64]>, O: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() / 2 + 1 <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: r2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    #[cfg(r2r_is_hard)]
    pub fn r2r<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[f64]>, O: DerefMut<[f64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: r2r,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
}

pub struct InPlacePlanner {
    plan: Planner
}

impl InPlacePlanner {
    pub fn c2c<I>(&self, in_: I) -> PlanMem<I, I>
        where I: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: self.plan,
            in_: in_,
            out: None,
            planner: c2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
}

type GuruPlanner =
    unsafe fn(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan;

unsafe fn c2c(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft(rank, dims,
                            howmany_rank, howmany_dims,
                            in_ as *mut _, out as *mut _,
                            sign, flags)
}

unsafe fn r2c(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              _sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft_r2c(rank, dims,
                                howmany_rank, howmany_dims,
                                in_ as *mut _, out as *mut _,
                                flags)
}
unsafe fn c2r(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              _sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft_c2r(rank, dims,
                                howmany_rank, howmany_dims,
                                in_ as *mut _, out as *mut _,
                                flags)
}
#[cfg(r2r_is_hard)]
unsafe fn r2r(n: c_int, in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_r2r_1d(n,
                          in_ as *mut f64, out as *mut f64,
                          sign, flags)
}

#[repr(C)]
pub struct Dim {
    pub n: uint,
    pub in_stride: uint,
    pub out_stride: uint,
}

enum Dims {
    Contiguous(Vec<uint>),
    Detailed(Vec<Dim>),
}

pub struct PlanMem<I, O> {
    plan: Planner,
    dims: Dims,
    how_many: Dims,
    in_: I,
    out: Option<O>,
    planner: GuruPlanner
}

impl<X, Y, I: DerefMut<[X]>, O: DerefMut<[Y]>> PlanMem<I, O> {
    pub fn dimensions(mut self, dims: Vec<uint>) -> PlanMem<I, O> {
        unimplemented!()
        self.dims = Contiguous(dims);
        self
    }
    pub fn multiples(mut self, number: uint) -> PlanMem<I, O> {
        unimplemented!()
        self.how_many = Contiguous(vec![number]);
        self
    }
    pub fn plan(mut self) -> Result<Planned<I, O>, PlanMem<I, O>> {
        let plan;
        {
            let in_ptr = self.in_.as_mut_ptr() as *mut c_void;
            let out_ptr = match self.out {
                None => in_ptr,
                Some(ref mut o) => o.as_mut_ptr() as *mut c_void,
            };
            let dims = match self.dims {
                Contiguous(_) => unimplemented!(),
                Detailed(ref v) => v.as_slice()
            };
            assert!(dims.len() == 1);

            plan = RawPlan::new(|| unsafe {
                (self.planner)(
                    dims.len() as c_int, dims.as_ptr() as *const ffi::fftw_iodim64,
                    0, [].as_ptr(),
                    in_ptr,
                    out_ptr,
                    self.plan.dir(),
                    self.plan.flags())
            });
        }
        match plan {
            None => Err(self),
            Some(p) => Ok(Planned { mem: self, plan: p })
        }
    }
}

pub struct Planned<I, O> {
    mem: PlanMem<I, O>,
    plan: RawPlan,
}

impl<X, Y, I: DerefMut<[X]>, O: DerefMut<[Y]>> Planned<I, O> {
    pub fn input(&mut self) -> &mut [X] {
        &mut *self.mem.in_
    }
    pub fn output(&mut self) -> Option<&mut [Y]> {
        self.mem.out.as_mut().map(|o| &mut **o)
    }

    pub fn execute(&mut self) {
        unsafe {
            self.plan.execute()
        }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use libc::ptrdiff_t;
    use ffi::Struct_fftw_iodim64_do_not_use_me;
    use super::Dim;

    #[test]
    fn iodims_are_compatible() {
        // handle 32-bit and 64-bit platforms properly
        let n = 0x0102_0304_0506_0708u64 as uint;
        let is = 0x090A_0B0C_0D0E_0F00u64 as uint;
        let os = 0x1122_3344_5566_7788u64 as uint;

        let d = Dim { n: n, in_stride: is, out_stride: os };
        let f = Struct_fftw_iodim64_do_not_use_me {
            n: n as ptrdiff_t, is: is as ptrdiff_t, os: os as ptrdiff_t
        };
        type T = (uint, uint, uint);
        unsafe {
            assert_eq!(mem::transmute::<_, T>(d), mem::transmute::<_, T>(f));
        }
    }
}
<commit_msg>Switch to by-value builder, move dimension/multiples handling to Planner.<commit_after>use ffi;
use libc::{c_uint, c_int, c_void};
use num::complex::Complex64;

use plan::RawPlan;

/// How much effort FFTW should put into computing the best strategy
/// to use.
///
/// The `FFTW_WISDOM_ONLY` rigor level is replaced by the
pub enum Rigor {
    Estimate,
    Measure,
    Patient,
    Exhaustive,
}
impl Rigor {
    fn flags(self) -> c_uint {
        match self {
            Estimate => ffi::FFTW_ESTIMATE,
            Measure => ffi::FFTW_MEASURE,
            Patient => ffi::FFTW_PATIENT,
            Exhaustive => ffi::FFTW_EXHAUSTIVE,
        }
    }
}

/// The direction of the transform to perform..
pub enum Direction {
    Forward, Backward
}

/// Control the basic properties of a set of transforms.
pub struct Planner {
    rigor: Rigor,
    wisdom_restriction: bool,
    direction: Direction,

    #[allow(dead_code)]
    dims: Vec<Dim>,
    #[allow(dead_code)]
    howmany: Vec<Dim>,
}

impl Planner {
    /// Construct a new planner with default values.
    ///
    /// This defaults to a forward transform with estimate rigor.
    pub fn new() -> Planner {
        Planner {
            rigor: Estimate,
            wisdom_restriction: false,
            direction: Forward,
            dims: vec![],
            howmany: vec![],
        }
    }

    /// Set the rigor to use for this plan.
    pub fn rigor(mut self, r: Rigor) -> Planner {
        self.rigor = r;
        self
    }
    /// Set whether the planner should only be successfully created if
    /// there exists wisdom created with at least the rigor level set.
    pub fn wisdom_restriction(mut self, wisdom_only: bool) -> Planner {
        self.wisdom_restriction = wisdom_only;
        self
    }

    /// Set the direction of the transform to perform.
    pub fn direction(mut self, direction: Direction) -> Planner {
        self.direction = direction;
        self
    }

    #[cfg(higher_dim_is_hard)]
    pub fn dims_row_major(mut self, dims: Vec<uint>) -> Planner {
        assert!(dims.len() >= 1);

        self.dims = dims.iter().map(|n| Dim { n: *n, in_stride: 1, out_stride: 1 });
        for i in range(0, self.dims.len() - 1).rev() {
            let stride = self.dims[i + 1].n * self.dims[i + 1].in_stride;
            self.dims[i].in_stride = stride;
            self.dims[i].out_stride = stride;
        }

        self
    }
    #[cfg(higher_dim_is_hard)]
    pub fn multiples(mut self, number: uint) -> PlanMem<I, O> {
        unimplemented!()
        self.how_many = Contiguous(vec![number]);
        self
    }

    fn flags(&self) -> c_uint {
        self.rigor.flags() | if self.wisdom_restriction {
            ffi::FFTW_WISDOM_ONLY
        } else {
            0
        }
    }
    fn dir(&self) -> c_int {
        match self.direction {
            Forward => ffi::FFTW_FORWARD,
            Backward => ffi::FFTW_BACKWARD,
        }
    }

    pub fn inplace(self) -> InPlacePlanner {
        InPlacePlanner { plan: self }
    }

    pub fn c2c<I, O>(self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[Complex64]>, O: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len());
        let dims = vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }];
        PlanMem {
            plan: self,
            in_: in_,
            out: Some(out),
            planner: c2c,

            dims: dims,
            how_many: vec![],
        }
    }
    pub fn c2r<I, O>(self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[Complex64]>, O: DerefMut<[f64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len() / 2 + 1);
        let dims = vec![Dim { n: 2 * (in_.len() - 1), in_stride: 1, out_stride: 1 }];
        PlanMem {
            plan: self,
            in_: in_,
            out: Some(out),
            planner: c2r,

            dims: dims,
            how_many: vec![],
        }
    }
    pub fn r2c<I, O>(self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[f64]>, O: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() / 2 + 1 <= out.len());
        let dims = vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }];
        PlanMem {
            plan: self,
            in_: in_,
            out: Some(out),
            planner: r2c,

            dims: dims,
            how_many: vec![],
        }
    }
    #[cfg(r2r_is_hard)]
    pub fn r2r<I, O>(self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[f64]>, O: DerefMut<[f64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len());
        let dims = vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }];
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: r2r,

            dims: dims,
            how_many: vec![],
        }
    }
}

pub struct InPlacePlanner {
    plan: Planner
}

impl InPlacePlanner {
    pub fn c2c<I>(self, in_: I) -> PlanMem<I, I>
        where I: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        let dims = vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }];
        PlanMem {
            plan: self.plan,
            in_: in_,
            out: None,
            planner: c2c,

            dims: dims,
            how_many: vec![],
        }
    }
}

type GuruPlanner =
    unsafe fn(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan;

unsafe fn c2c(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft(rank, dims,
                            howmany_rank, howmany_dims,
                            in_ as *mut _, out as *mut _,
                            sign, flags)
}

unsafe fn r2c(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              _sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft_r2c(rank, dims,
                                howmany_rank, howmany_dims,
                                in_ as *mut _, out as *mut _,
                                flags)
}
unsafe fn c2r(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              _sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft_c2r(rank, dims,
                                howmany_rank, howmany_dims,
                                in_ as *mut _, out as *mut _,
                                flags)
}
#[cfg(r2r_is_hard)]
unsafe fn r2r(n: c_int, in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_r2r_1d(n,
                          in_ as *mut f64, out as *mut f64,
                          sign, flags)
}

#[repr(C)]
pub struct Dim {
    pub n: uint,
    pub in_stride: uint,
    pub out_stride: uint,
}

pub struct PlanMem<I, O> {
    plan: Planner,
    dims: Vec<Dim>,
    #[allow(dead_code)]
    how_many: Vec<Dim>,
    in_: I,
    out: Option<O>,
    planner: GuruPlanner
}

impl<X, Y, I: DerefMut<[X]>, O: DerefMut<[Y]>> PlanMem<I, O> {
    pub fn plan(mut self) -> Result<Planned<I, O>, PlanMem<I, O>> {
        let plan;
        {
            let in_ptr = self.in_.as_mut_ptr() as *mut c_void;
            let out_ptr = match self.out {
                None => in_ptr,
                Some(ref mut o) => o.as_mut_ptr() as *mut c_void,
            };
            assert!(self.dims.len() == 1);

            plan = RawPlan::new(|| unsafe {
                (self.planner)(
                    self.dims.len() as c_int,
                    self.dims.as_ptr() as *const ffi::fftw_iodim64,
                    0, [].as_ptr(),
                    in_ptr,
                    out_ptr,
                    self.plan.dir(),
                    self.plan.flags())
            });
        }
        match plan {
            None => Err(self),
            Some(p) => Ok(Planned { mem: self, plan: p })
        }
    }
}

pub struct Planned<I, O> {
    mem: PlanMem<I, O>,
    plan: RawPlan,
}

impl<X, Y, I: DerefMut<[X]>, O: DerefMut<[Y]>> Planned<I, O> {
    pub fn input(&mut self) -> &mut [X] {
        &mut *self.mem.in_
    }
    pub fn output(&mut self) -> Option<&mut [Y]> {
        self.mem.out.as_mut().map(|o| &mut **o)
    }

    pub fn execute(&mut self) {
        unsafe {
            self.plan.execute()
        }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use libc::ptrdiff_t;
    use ffi::Struct_fftw_iodim64_do_not_use_me;
    use super::Dim;

    #[test]
    fn iodims_are_compatible() {
        // handle 32-bit and 64-bit platforms properly
        let n = 0x0102_0304_0506_0708u64 as uint;
        let is = 0x090A_0B0C_0D0E_0F00u64 as uint;
        let os = 0x1122_3344_5566_7788u64 as uint;

        let d = Dim { n: n, in_stride: is, out_stride: os };
        let f = Struct_fftw_iodim64_do_not_use_me {
            n: n as ptrdiff_t, is: is as ptrdiff_t, os: os as ptrdiff_t
        };
        type T = (uint, uint, uint);
        unsafe {
            assert_eq!(mem::transmute::<_, T>(d), mem::transmute::<_, T>(f));
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_cat"]

// This file is part of the uutils coreutils package.
//
// (c) Jordi Boggiano <j.boggiano@seld.be>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

// last synced with: cat (GNU coreutils) 8.13

#[macro_use]
extern crate uucore;

use std::fs::File;
use std::intrinsics::{copy_nonoverlapping};
use std::io::{stdout, stdin, stderr, Write, Read, Result};
use uucore::fs::is_stdin_interactive;

static SYNTAX: &'static str = "[OPTION]... [FILE]...";
static SUMMARY: &'static str = "Concatenate FILE(s), or standard input, to standard output
 With no FILE, or when FILE is -, read standard input.";
static LONG_HELP: &'static str = "";

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
        .optflag("A", "show-all", "equivalent to -vET")
        .optflag("b",
                 "number-nonblank",
                 "number nonempty output lines, overrides -n")
        .optflag("e", "", "equivalent to -vE")
        .optflag("E", "show-ends", "display $ at end of each line")
        .optflag("n", "number", "number all output lines")
        .optflag("s", "squeeze-blank", "suppress repeated empty output lines")
        .optflag("t", "", "equivalent to -vT")
        .optflag("T", "show-tabs", "display TAB characters as ^I")
        .optflag("v",
                 "show-nonprinting",
                 "use ^ and M- notation, except for LF (\\n) and TAB (\\t)")
        .parse(args);

    let number_mode = if matches.opt_present("b") {
        NumberingMode::NumberNonEmpty
    } else if matches.opt_present("n") {
        NumberingMode::NumberAll
    } else {
        NumberingMode::NumberNone
    };
    let show_nonprint =
        matches.opts_present(&["A".to_owned(), "e".to_owned(), "t".to_owned(), "v".to_owned()]);
    let show_ends = matches.opts_present(&["E".to_owned(), "A".to_owned(), "e".to_owned()]);
    let show_tabs = matches.opts_present(&["A".to_owned(), "T".to_owned(), "t".to_owned()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_owned());
    }

    exec(files,
         number_mode,
         show_nonprint,
         show_ends,
         show_tabs,
         squeeze_blank);

    0
}

#[derive(Eq, PartialEq)]
enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool, show_ends: bool) {
    // initialize end of line
    let end_of_line = if show_ends {
        "$\n".as_bytes()
    } else {
        "\n".as_bytes()
    };

    let mut line_counter: usize = 1;

    for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[..])) {

        let mut in_buf = [0; 1024 * 31];
        let mut out_buf = [0; 1024 * 64];
        let mut writer = UnsafeWriter::new(&mut out_buf[..], stdout());
        let mut at_line_start = true;
        let mut one_blank_kept = false;
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }

            let in_buf = &in_buf[..n];
            let mut pos = 0;
            while pos < n {
                writer.possibly_flush();
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank || !one_blank_kept {
                        one_blank_kept = true;
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        writer.write_all(end_of_line).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    pos += 1;
                    continue;
                } else if one_blank_kept {
                    one_blank_kept = false;
                }
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                }
                match in_buf[pos..].iter().position(|c| *c == '\n' as u8) {
                    Some(p) => {
                        writer.write_all(&in_buf[pos..pos + p]).unwrap();
                        writer.write_all(end_of_line).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                        pos += p + 1;
                        at_line_start = true;
                    }
                    None => {
                        writer.write_all(&in_buf[pos..]).unwrap();
                        at_line_start = false;
                        break;
                    }
                };
            }
        }
    }
}

fn write_bytes(files: Vec<String>,
               number: NumberingMode,
               squeeze_blank: bool,
               show_ends: bool,
               show_tabs: bool,
               show_nonprint: bool) {
    // initialize end of line
    let end_of_line = if show_ends {
        "$\n".as_bytes()
    } else {
        "\n".as_bytes()
    };
    // initialize tab simbol
    let tab = if show_tabs {
        "^I".as_bytes()
    } else {
        "\t".as_bytes()
    };

    let mut line_counter: usize = 1;

    for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[..])) {

        // Flush all 1024 iterations.
        let mut flush_counter = 0usize..1024;

        let mut in_buf = [0; 1024 * 32];
        let mut out_buf = [0; 1024 * 64];
        let mut writer = UnsafeWriter::new(&mut out_buf[..], stdout());
        let mut at_line_start = true;
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }

            for &byte in in_buf[..n].iter() {
                if flush_counter.next().is_none() {
                    writer.possibly_flush();
                    flush_counter = 0usize..1024;
                }
                if byte == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        writer.write_all(end_of_line).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                    at_line_start = false;
                }

                // This code is slow because of the many branches. cat in glibc avoids
                // this by having the whole loop inside show_nonprint.
                if byte == '\t' as u8 {
                        writer.write_all(tab)
                    } else if show_nonprint {
                        let byte = match byte {
                            128...255 => {
                                writer.write_all("M-".as_bytes()).unwrap();
                                byte - 128
                            }
                            _ => byte,
                        };
                        match byte {
                            0...31 => writer.write_all(&['^' as u8, byte + 64]),
                            127 => writer.write_all(&['^' as u8, byte - 64]),
                            _ => writer.write_all(&[byte]),
                        }
                    } else {
                        writer.write_all(&[byte])
                    }
                    .unwrap();
            }
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout();
    let mut in_buf = [0; 1024 * 64];

    for (mut reader, _) in files.iter().filter_map(|p| open(&p[..])) {
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }
            // This interface is completely broken.
            writer.write_all(&in_buf[..n]).unwrap();
        }
    }
}

fn exec(files: Vec<String>,
        number: NumberingMode,
        show_nonprint: bool,
        show_ends: bool,
        show_tabs: bool,
        squeeze_blank: bool) {

    if show_nonprint || show_tabs {
        write_bytes(files,
                    number,
                    squeeze_blank,
                    show_ends,
                    show_tabs,
                    show_nonprint);
    } else if number != NumberingMode::NumberNone || squeeze_blank || show_ends {
        write_lines(files, number, squeeze_blank, show_ends);
    } else {
        write_fast(files);
    }
    pipe_flush!();
}

fn open(path: &str) -> Option<(Box<Read>, bool)> {
    if path == "-" {
        let stdin = stdin();
        return Some((Box::new(stdin) as Box<Read>, is_stdin_interactive()));
    }

    match File::open(path) {
        Ok(f) => Some((Box::new(f) as Box<Read>, false)),
        Err(e) => {
            (writeln!(&mut stderr(), "cat: {0}: {1}", path, e.to_string())).unwrap();
            None
        }
    }
}

struct UnsafeWriter<'a, W: Write> {
    inner: W,
    buf: &'a mut [u8],
    pos: usize,
    threshold: usize,
}

impl<'a, W: Write> UnsafeWriter<'a, W> {
    fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
        let threshold = buf.len() / 2;
        UnsafeWriter {
            inner: inner,
            buf: buf,
            pos: 0,
            threshold: threshold,
        }
    }

    fn flush_buf(&mut self) -> Result<()> {
        if self.pos != 0 {
            let ret = self.inner.write(&self.buf[..self.pos]);
            self.pos = 0;
            match ret {
                Ok(_) => Ok(()),
                Err(e) => Err(e),
            }
        } else {
            Ok(())
        }
    }

    fn possibly_flush(&mut self) {
        if self.pos > self.threshold {
            self.inner.write_all(&self.buf[..self.pos]).unwrap();
            self.pos = 0;
        }
    }
}

//#[inline(never)]
//fn fail() -> ! {
//    panic!("assertion failed");
//}

impl<'a, W: Write> Write for UnsafeWriter<'a, W> {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        //let dst = &mut self.buf[self.pos..];
        let len = buf.len();
        // assertion is  true for current code
        // and it is a bottlneck place
        // if len > dst.len() {
        //     fail();
        // }
        unsafe { copy_nonoverlapping(buf.as_ptr(), self.buf[self.pos..].as_mut_ptr(), len) }
        self.pos += len;
        Ok(len)
    }

    fn flush(&mut self) -> Result<()> {
        self.flush_buf().and_then(|()| self.inner.flush())
    }
}

impl<'a, W: Write> Drop for UnsafeWriter<'a, W> {
    fn drop(&mut self) {
        let _ = self.flush_buf();
    }
}
<commit_msg>Fixed and made the comments clearer<commit_after>#![crate_name = "uu_cat"]

// This file is part of the uutils coreutils package.
//
// (c) Jordi Boggiano <j.boggiano@seld.be>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

// last synced with: cat (GNU coreutils) 8.13

#[macro_use]
extern crate uucore;

use std::fs::File;
use std::intrinsics::{copy_nonoverlapping};
use std::io::{stdout, stdin, stderr, Write, Read, Result};
use uucore::fs::is_stdin_interactive;

static SYNTAX: &'static str = "[OPTION]... [FILE]...";
static SUMMARY: &'static str = "Concatenate FILE(s), or standard input, to standard output
 With no FILE, or when FILE is -, read standard input.";
static LONG_HELP: &'static str = "";

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
        .optflag("A", "show-all", "equivalent to -vET")
        .optflag("b",
                 "number-nonblank",
                 "number nonempty output lines, overrides -n")
        .optflag("e", "", "equivalent to -vE")
        .optflag("E", "show-ends", "display $ at end of each line")
        .optflag("n", "number", "number all output lines")
        .optflag("s", "squeeze-blank", "suppress repeated empty output lines")
        .optflag("t", "", "equivalent to -vT")
        .optflag("T", "show-tabs", "display TAB characters as ^I")
        .optflag("v",
                 "show-nonprinting",
                 "use ^ and M- notation, except for LF (\\n) and TAB (\\t)")
        .parse(args);

    let number_mode = if matches.opt_present("b") {
        NumberingMode::NumberNonEmpty
    } else if matches.opt_present("n") {
        NumberingMode::NumberAll
    } else {
        NumberingMode::NumberNone
    };
    let show_nonprint =
        matches.opts_present(&["A".to_owned(), "e".to_owned(), "t".to_owned(), "v".to_owned()]);
    let show_ends = matches.opts_present(&["E".to_owned(), "A".to_owned(), "e".to_owned()]);
    let show_tabs = matches.opts_present(&["A".to_owned(), "T".to_owned(), "t".to_owned()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_owned());
    }

    exec(files,
         number_mode,
         show_nonprint,
         show_ends,
         show_tabs,
         squeeze_blank);

    0
}

#[derive(Eq, PartialEq)]
enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool, show_ends: bool) {
    // initialize end of line
    let end_of_line = if show_ends {
        "$\n".as_bytes()
    } else {
        "\n".as_bytes()
    };

    let mut line_counter: usize = 1;

    for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[..])) {

        let mut in_buf = [0; 1024 * 31];
        let mut out_buf = [0; 1024 * 64];
        let mut writer = UnsafeWriter::new(&mut out_buf[..], stdout());
        let mut at_line_start = true;
        let mut one_blank_kept = false;
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }

            let in_buf = &in_buf[..n];
            let mut pos = 0;
            while pos < n {
                writer.possibly_flush();
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank || !one_blank_kept {
                        one_blank_kept = true;
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        writer.write_all(end_of_line).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    pos += 1;
                    continue;
                } else if one_blank_kept {
                    one_blank_kept = false;
                }
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                }
                match in_buf[pos..].iter().position(|c| *c == '\n' as u8) {
                    Some(p) => {
                        writer.write_all(&in_buf[pos..pos + p]).unwrap();
                        writer.write_all(end_of_line).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                        pos += p + 1;
                        at_line_start = true;
                    }
                    None => {
                        writer.write_all(&in_buf[pos..]).unwrap();
                        at_line_start = false;
                        break;
                    }
                };
            }
        }
    }
}

fn write_bytes(files: Vec<String>,
               number: NumberingMode,
               squeeze_blank: bool,
               show_ends: bool,
               show_tabs: bool,
               show_nonprint: bool) {
    // initialize end of line
    let end_of_line = if show_ends {
        "$\n".as_bytes()
    } else {
        "\n".as_bytes()
    };
    // initialize tab simbol
    let tab = if show_tabs {
        "^I".as_bytes()
    } else {
        "\t".as_bytes()
    };

    let mut line_counter: usize = 1;

    for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[..])) {

        // Flush all 1024 iterations.
        let mut flush_counter = 0usize..1024;

        let mut in_buf = [0; 1024 * 32];
        let mut out_buf = [0; 1024 * 64];
        let mut writer = UnsafeWriter::new(&mut out_buf[..], stdout());
        let mut at_line_start = true;
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }

            for &byte in in_buf[..n].iter() {
                if flush_counter.next().is_none() {
                    writer.possibly_flush();
                    flush_counter = 0usize..1024;
                }
                if byte == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        writer.write_all(end_of_line).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                    at_line_start = false;
                }

                // This code is slow because of the many branches. cat in glibc avoids
                // this by having the whole loop inside show_nonprint.
                if byte == '\t' as u8 {
                        writer.write_all(tab)
                    } else if show_nonprint {
                        let byte = match byte {
                            128...255 => {
                                writer.write_all("M-".as_bytes()).unwrap();
                                byte - 128
                            }
                            _ => byte,
                        };
                        match byte {
                            0...31 => writer.write_all(&['^' as u8, byte + 64]),
                            127 => writer.write_all(&['^' as u8, byte - 64]),
                            _ => writer.write_all(&[byte]),
                        }
                    } else {
                        writer.write_all(&[byte])
                    }
                    .unwrap();
            }
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout();
    let mut in_buf = [0; 1024 * 64];

    for (mut reader, _) in files.iter().filter_map(|p| open(&p[..])) {
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }
            // This interface is completely broken.
            writer.write_all(&in_buf[..n]).unwrap();
        }
    }
}

fn exec(files: Vec<String>,
        number: NumberingMode,
        show_nonprint: bool,
        show_ends: bool,
        show_tabs: bool,
        squeeze_blank: bool) {

    if show_nonprint || show_tabs {
        write_bytes(files,
                    number,
                    squeeze_blank,
                    show_ends,
                    show_tabs,
                    show_nonprint);
    } else if number != NumberingMode::NumberNone || squeeze_blank || show_ends {
        write_lines(files, number, squeeze_blank, show_ends);
    } else {
        write_fast(files);
    }
    pipe_flush!();
}

fn open(path: &str) -> Option<(Box<Read>, bool)> {
    if path == "-" {
        let stdin = stdin();
        return Some((Box::new(stdin) as Box<Read>, is_stdin_interactive()));
    }

    match File::open(path) {
        Ok(f) => Some((Box::new(f) as Box<Read>, false)),
        Err(e) => {
            (writeln!(&mut stderr(), "cat: {0}: {1}", path, e.to_string())).unwrap();
            None
        }
    }
}

struct UnsafeWriter<'a, W: Write> {
    inner: W,
    buf: &'a mut [u8],
    pos: usize,
    threshold: usize,
}

impl<'a, W: Write> UnsafeWriter<'a, W> {
    fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
        let threshold = buf.len() / 2;
        UnsafeWriter {
            inner: inner,
            buf: buf,
            pos: 0,
            threshold: threshold,
        }
    }

    fn flush_buf(&mut self) -> Result<()> {
        if self.pos != 0 {
            let ret = self.inner.write(&self.buf[..self.pos]);
            self.pos = 0;
            match ret {
                Ok(_) => Ok(()),
                Err(e) => Err(e),
            }
        } else {
            Ok(())
        }
    }

    fn possibly_flush(&mut self) {
        if self.pos > self.threshold {
            self.inner.write_all(&self.buf[..self.pos]).unwrap();
            self.pos = 0;
        }
    }
}

// This method was used in Write::write only. It must not be called in the correct cat code
// and is placed in the bottleneck place, so it is not used anymore.
// Uncomment this and code in Write::write for more convenient testing of a new cat version.
//#[inline(never)]
//fn fail() -> ! {
//    panic!("assertion failed");
//}

impl<'a, W: Write> Write for UnsafeWriter<'a, W> {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        //let dst = &mut self.buf[self.pos..];
        let len = buf.len();
        // the condition is false for current code and every correct code
        // see fail method comment for more information
        // if len > dst.len() {
        //     fail();
        // }
        unsafe { copy_nonoverlapping(buf.as_ptr(), self.buf[self.pos..].as_mut_ptr(), len) }
        self.pos += len;
        Ok(len)
    }

    fn flush(&mut self) -> Result<()> {
        self.flush_buf().and_then(|()| self.inner.flush())
    }
}

impl<'a, W: Write> Drop for UnsafeWriter<'a, W> {
    fn drop(&mut self) {
        let _ = self.flush_buf();
    }
}
<|endoftext|>


<commit_before>mod score;
pub mod consts;

use std::ascii::AsciiExt;
pub use self::score::*;

/// Compares two characters case-insensitively
///
/// # Examples
///
/// ```
/// assert!(rff::fuzzy::eq('a', 'A'));
/// ```
pub fn eq(a: char, b: char) -> bool {
    match a {
        a if a == b => true,
        a if a.is_ascii() && !b.is_ascii() => false,
        a if !a.is_ascii() && b.is_ascii() => false,
        a if a.is_ascii() && b.is_ascii() => {
            a.to_ascii_lowercase().eq(&b.to_ascii_lowercase())
        },
        a => a.to_lowercase().eq(b.to_lowercase())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[test]
    fn test_eq() {
        assert!(eq('a', 'A'));
        assert!(eq('山', '山'));
        assert!(!eq('a', 'b'));
    }

    #[bench]
    fn bench_eq_same(b: &mut Bencher) {
        b.iter(|| eq('a', 'a'));
    }

    #[bench]
    fn bench_eq_ascii(b: &mut Bencher) {
        b.iter(|| eq('a', 'A'));
    }

    #[bench]
    fn bench_eq_utf8(b: &mut Bencher) {
        b.iter(|| eq('ø', 'Ø'));
    }

    #[bench]
    fn bench_eq_mixed(b: &mut Bencher) {
        b.iter(|| eq('a', 'Ø'));
    }
}
<commit_msg>Add fuzzy::matches(needle, haystack)<commit_after>mod score;
pub mod consts;

use std::ascii::AsciiExt;
pub use self::score::*;

/// Compares two characters case-insensitively
///
/// # Examples
///
/// ```
/// assert!(rff::fuzzy::eq('a', 'A'));
/// ```
pub fn eq(a: char, b: char) -> bool {
    match a {
        a if a == b => true,
        a if a.is_ascii() && !b.is_ascii() => false,
        a if !a.is_ascii() && b.is_ascii() => false,
        a if a.is_ascii() && b.is_ascii() => {
            a.to_ascii_lowercase().eq(&b.to_ascii_lowercase())
        },
        a => a.to_lowercase().eq(b.to_lowercase())
    }
}

/// Searches for needle's chars in the haystack
///
/// # Examples
///
/// ```
/// assert!(rff::fuzzy::matches("amo", "app/models/order"));
/// ```
pub fn matches(needle: &str, haystack: &str) -> bool {
    let mut hchars = haystack.chars();

    'outer: for n in needle.chars() {
        loop {
            match hchars.next() {
                Some(h) if eq(h, n) => continue 'outer,
                Some(_) => continue,
                None => return false
            }
        }
    }

    true
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[test]
    fn test_eq() {
        assert!(eq('a', 'A'));
        assert!(eq('山', '山'));
        assert!(!eq('a', 'b'));
    }

    #[test]
    fn test_matches() {
        assert!(matches("a", "a"));
        assert!(matches("a", "abc"));
        assert!(matches("abc", "abc"));
        assert!(matches("ABC", "abc"));
        assert!(matches("abc", "a1b2c3"));
        assert!(matches("abc", "a1b2c3"));
        assert!(matches("test", "t/e/s/t"));
        assert!(matches("test", "t💣e💣s💣t"));
        assert!(matches("💣💣💣", "t💣e💣s💣t"));

        assert!(!matches("abc", "ab"));
        assert!(!matches("abc", "cab"));
        assert!(!matches("abc", ""));

        assert!(matches("", ""));
        assert!(matches("", "ab"));

        // UTF-8 case testing
        assert!(matches("a", "A"));
        assert!(matches("A", "a"));
        assert!(matches("山", "山"));
        assert!(matches("café", "CAFÉ"))
    }

    #[bench]
    fn bench_eq_same(b: &mut Bencher) {
        b.iter(|| eq('a', 'a'));
    }

    #[bench]
    fn bench_eq_ascii(b: &mut Bencher) {
        b.iter(|| eq('a', 'A'));
    }

    #[bench]
    fn bench_eq_utf8(b: &mut Bencher) {
        b.iter(|| eq('ø', 'Ø'));
    }

    #[bench]
    fn bench_eq_mixed(b: &mut Bencher) {
        b.iter(|| eq('a', 'Ø'));
    }

    #[bench]
    fn bench_matches(b: &mut Bencher) {
        b.iter(|| matches("amor", "app/models/order.rb"))
    }

    #[bench]
    fn bench_matches_mixed_case(b: &mut Bencher) {
        b.iter(|| matches("AMOr", "App/Models/Order.rb"))
    }

    #[bench]
    fn bench_matches_multiple(b: &mut Bencher) {
        b.iter(|| {
            matches("amor", "app/models/order.rb");
            matches("amor", "spec/models/order_spec.rb");
            matches("amor", "other_garbage.rb");
            matches("amor", "Gemfile");
            matches("amor", "node_modules/test/a/thing.js");
            matches("amor", "vendor/bundle/ruby/gem.rb")
        })
    }
}
<|endoftext|>


<commit_before>use Addr;
use system::memory::{ptr, read};

#[derive(Copy, Clone)]
pub struct Flag(pub Addr, pub u8);

pub const HAS_SEEN_HELMAROC_ARRIVING_AT_OUTSET: Flag = Flag(0x803B872C, 1 << 0);
pub const FOREST_OF_FAIRIES_BOKOBLINS_SPAWNED: Flag = Flag(0x803B872C, 1 << 2);
pub const TALKED_TO_FARM_GUY_ON_OUTSET: Flag = Flag(0x803B872C, 1 << 4);
pub const RESCUED_TETRA: Flag = Flag(0x803B872D, 1 << 0);
pub const GOT_A_RUPEE_ON_THE_OUTSET_ROCKS: Flag = Flag(0x803B872D, 1 << 2);
pub const TALKED_TO_ORCA_AFTER_HELMAROC_ARRIVED: Flag = Flag(0x803B872D, 1 << 3);
pub const SAW_A_LIGHT_OPERATOR_BOKOBLIN: Flag = Flag(0x803B872E, 1 << 0);
pub const TALKED_TO_SNOT_KID: Flag = Flag(0x803B872E, 1 << 5);
pub const SAW_TETRA_IN_FOREST_OF_FAIRIES: Flag = Flag(0x803B872E, 1 << 7);
pub const KILLED_ONE_FOREST_OF_FAIRIES_BOKOBLIN: Flag = Flag(0x803B872F, 1 << 0);
pub const PIRATE_SHIP_ARRIVING_ON_OUTSET: Flag = Flag(0x803B872F, 1 << 4);
pub const PICKED_UP_FIRST_BARREL_IN_FF1: Flag = Flag(0x803B8730, 1 << 0);
pub const GRABBED_FIRST_ROPE_IN_FF1: Flag = Flag(0x803B8730, 1 << 1);
pub const GOT_THROWN_INTO_JAIL_IN_FF1: Flag = Flag(0x803B8730, 1 << 2);
pub const KILLED_BOTH_FOREST_OF_FAIRIES_BOKOBLINS: Flag = Flag(0x803B8730, 1 << 7);
pub const GOSSIP_STONE_AT_FF1: Flag = Flag(0x803B8731, 1 << 5);
pub const COMPLETED_PIRATE_SHIP_MINIGAME: Flag = Flag(0x803B8733, 1 << 4);
pub const SAW_PIRATE_SHIP_MINIGAME_INTRO: Flag = Flag(0x803B8733, 1 << 5);
pub const GOT_CATAPULTED_TO_FF1_AND_SPAWN_THERE: Flag = Flag(0x803B8734, 1 << 0);
pub const LONG_TETRA_TEXT_ON_OUTSET: Flag = Flag(0x803B8734, 1 << 1);
pub const TETRA_TOLD_YOU_TO_CLIMB_UP_THE_LADDER: Flag = Flag(0x803B8734, 1 << 2);
pub const COMPLETED_PIRATE_SHIP_MINIGAME_AND_SPAWN_ON_PIRATE_SHIP: Flag = Flag(0x803B8734, 1 << 3);
pub const SAIL_INTRODUCTION_TEXT_AND_MAP_UNLOCKED: Flag = Flag(0x803B8735, 1 << 3);
pub const ENDLESS_NIGHT: Flag = Flag(0x803B8736, 1 << 1);
pub const KORL_DINS_PEARL_TEXT_ALLOWING_YOU_TO_ENTER_HIM: Flag = Flag(0x803B8736, 1 << 7);
pub const HURRICANE_SPIN_UNLOCKED: Flag = Flag(0x803B8737, 1 << 5);
pub const PIRATES_ON_OUTSET: Flag = Flag(0x803B873A, 1 << 5);
pub const KORL_UNLOCKED_AND_SPAWN_ON_WINDFALL: Flag = Flag(0x803B873B, 1 << 7);
pub const WATCHED_FIRE_AND_ICE_ARROWS_CUTSCENE: Flag = Flag(0x803B873C, 1 << 0);
pub const MEDLI_ON_DRI_INTRODUCTION_CUTSCENE_WATCHED: Flag = Flag(0x803B8740, 1 << 1);
pub const SHOWED_MEDLI_THE_WIND_WAKER_ON_DRI: Flag = Flag(0x803B8741, 1 << 2);
pub const HAS_MAKAR_ON_BOAT_1: Flag = Flag(0x803B8742, 1 << 2);
pub const HAS_MEDLI_ON_BOAT_1: Flag = Flag(0x803B8742, 1 << 3);
pub const HAS_MAKAR_ON_BOAT_2_AND_IS_GRABABLE: Flag = Flag(0x803B8742, 1 << 4);
pub const HAS_MEDLI_ON_BOAT_2_AND_CAN_CARRY_YOU: Flag = Flag(0x803B8742, 1 << 5);
pub const TALKED_TO_KORL_AFTER_HYRULE_2_AND_FF3_ACTIVE: Flag = Flag(0x803B8744, 1 << 5);
pub const IS_ALLOWED_TO_ENTER_KORL: Flag = Flag(0x803B8745, 1 << 7);
pub const TOWER_OF_THE_GODS_RAISED: Flag = Flag(0x803B874A, 1 << 6);
pub const WATCHED_DEPARTURE_CUTSCENE_AND_SPAWN_ON_PIRATE_SHIP: Flag = Flag(0x803B8750, 1 << 0);
pub const TALKED_TO_SAIL_SHOP_NPC: Flag = Flag(0x803B8750, 1 << 5);
pub const WATCHED_FIND_SISTER_IN_FF1_CUTSCENE: Flag = Flag(0x803B8751, 1 << 7);
pub const SOME_WEIRD_FIRE_AND_ICE_ARROWS_CUTSCENE_FLAG: Flag = Flag(0x803B8753, 1 << 6);
pub const MAKAR_IN_WIND_TEMPLE: Flag = Flag(0x803B8755, 1 << 4);
pub const MEDLI_IN_EARTH_TEMPLE: Flag = Flag(0x803B8755, 1 << 5);
pub const ENTER_KORL_FOR_THE_FIRST_TIME_AND_SPAWN_ANYWHERE: Flag = Flag(0x803B8756, 1 << 3);
pub const HAS_HEROS_CLOTHES: Flag = Flag(0x803B8756, 1 << 7);
pub const MIGHTY_DARKNUTS_DEFEATED: Flag = Flag(0x803B8758, 1 << 0);
pub const BARRIER_DOWN: Flag = Flag(0x803B8758, 1 << 1);
pub const ANIMATION_SET_2: Flag = Flag(0x803B8759, 1 << 0);
pub const TETRA_TO_ZELDA_CUTSCENE: Flag = Flag(0x803B8759, 1 << 1);
pub const MASTER_SWORD_CUTSCENE: Flag = Flag(0x803B8759, 1 << 2);
pub const HYRULE_3_WARP_CUTSCENE: Flag = Flag(0x803B8759, 1 << 3);
pub const RINGING_BELL_AND_HYRULE_1_CUTSCENE: Flag = Flag(0x803B8759, 1 << 4);
pub const WIND_GODS_ARIA_CUTSCENE: Flag = Flag(0x803B8759, 1 << 5);
pub const EARTH_GODS_LYRIC_CUTSCENE: Flag = Flag(0x803B8759, 1 << 6);
pub const WATCHED_MEETING_KORL_CUTSCENE: Flag = Flag(0x803B875A, 1 << 0);
pub const MAKAR_IN_WIND_TEMPLE_ENTRANCE: Flag = Flag(0x803B875A, 1 << 1);
pub const MEDLI_IN_EARTH_TEMPLE_ENTRANCE: Flag = Flag(0x803B875A, 1 << 2);
pub const PEARL_TOWER_CUTSCENE: Flag = Flag(0x803B875A, 1 << 7);
pub const DID_SWORD_FIGHTING_TUTORIAL: Flag = Flag(0x803B875B, 1 << 4);
pub const GOT_SHIELD_FROM_GRANDMA: Flag = Flag(0x803B875E, 1 << 1);
pub const WATCHED_DESCENDING_DOWN_TO_HYRULE_2_CUTSCENE: Flag = Flag(0x803B875E, 1 << 7);
pub const WATCHED_TEXT_AFTER_FIRE_AND_ICE_ARROWS_CUTSCENE: Flag = Flag(0x803B875F, 1 << 7);
pub const HAS_SEEN_INTRO: Flag = Flag(0x803B8761, 1 << 4);
pub const MIGHTY_DARKNUTS_SPAWNED: Flag = Flag(0x803B8761, 1 << 5);
pub const COLORS_IN_HYRULE: Flag = Flag(0x803B8764, 1 << 1);
pub const WATCHED_COURTYARD_CUTSCENE: Flag = Flag(0x803B8764, 1 << 2);
pub const MOVED_STATUE_IN_HYRULE: Flag = Flag(0x803B8764, 1 << 5);
pub const WATCHED_FF2_GANONDORF_CUTSCENE: Flag = Flag(0x803B8765, 1 << 4);
pub const HYRULE_3_ELECTRICAL_BARRIER_CUTSCENE_1: Flag = Flag(0x803B8765, 1 << 7);
pub const TRIALS_JALHALLA: Flag = Flag(0x803B8765, 1 << 0);
pub const TRIALS_KALLE_DEMOS: Flag = Flag(0x803B8765, 1 << 1);
pub const TRIALS_GOHMA: Flag = Flag(0x803B8765, 1 << 2);
pub const TRIALS_MOLGERA: Flag = Flag(0x803B8766, 1 << 7);
pub const PULLED_MASTER_SWORD_IN_HYRULE_1_SWINGING_CUTSCENE: Flag = Flag(0x803B8766, 1 << 2);
pub const MEDLI_DRAGON_ROOST_CUTSCENE_WATCHED: Flag = Flag(0x803B8767, 1 << 4);
pub const HYRULE_1_ELECTRICAL_BARRIER_DEACTIVATED: Flag = Flag(0x803B8767, 1 << 6);
pub const FF3_TO_HYRULE_WARP_ACTIVE: Flag = Flag(0x803B8769, 1 << 1);
pub const DONT_SHOW_WEAPONS: Flag = Flag(0x803B876B, 1 << 6);

impl Flag {
    pub fn activate(self) {
        let Flag(addr, value) = self;
        let ptr = ptr::<u8>(addr);
        unsafe {
            *ptr |= value;
        }
    }

    pub fn deactivate(self) {
        let Flag(addr, value) = self;
        let ptr = ptr::<u8>(addr);
        unsafe {
            *ptr &= 0xFF ^ value;
        }
    }

    pub fn is_active(self) -> bool {
        let Flag(addr, mask) = self;
        let value = read::<u8>(addr);
        value & mask != 0
    }

    pub fn toggle(self) {
        if self.is_active() {
            self.deactivate()
        } else {
            self.activate()
        }
    }
}
<commit_msg>Fix Outset character names<commit_after>use Addr;
use system::memory::{ptr, read};

#[derive(Copy, Clone)]
pub struct Flag(pub Addr, pub u8);

pub const HAS_SEEN_HELMAROC_ARRIVING_AT_OUTSET: Flag = Flag(0x803B872C, 1 << 0);
pub const FOREST_OF_FAIRIES_BOKOBLINS_SPAWNED: Flag = Flag(0x803B872C, 1 << 2);
pub const TALKED_TO_MESA_ON_OUTSET: Flag = Flag(0x803B872C, 1 << 4);
pub const RESCUED_TETRA: Flag = Flag(0x803B872D, 1 << 0);
pub const GOT_A_RUPEE_ON_THE_OUTSET_ROCKS: Flag = Flag(0x803B872D, 1 << 2);
pub const TALKED_TO_ORCA_AFTER_HELMAROC_ARRIVED: Flag = Flag(0x803B872D, 1 << 3);
pub const SAW_A_LIGHT_OPERATOR_BOKOBLIN: Flag = Flag(0x803B872E, 1 << 0);
pub const TALKED_TO_ZILL_ON_OUTSET: Flag = Flag(0x803B872E, 1 << 5);
pub const SAW_TETRA_IN_FOREST_OF_FAIRIES: Flag = Flag(0x803B872E, 1 << 7);
pub const KILLED_ONE_FOREST_OF_FAIRIES_BOKOBLIN: Flag = Flag(0x803B872F, 1 << 0);
pub const PIRATE_SHIP_ARRIVING_ON_OUTSET: Flag = Flag(0x803B872F, 1 << 4);
pub const PICKED_UP_FIRST_BARREL_IN_FF1: Flag = Flag(0x803B8730, 1 << 0);
pub const GRABBED_FIRST_ROPE_IN_FF1: Flag = Flag(0x803B8730, 1 << 1);
pub const GOT_THROWN_INTO_JAIL_IN_FF1: Flag = Flag(0x803B8730, 1 << 2);
pub const KILLED_BOTH_FOREST_OF_FAIRIES_BOKOBLINS: Flag = Flag(0x803B8730, 1 << 7);
pub const GOSSIP_STONE_AT_FF1: Flag = Flag(0x803B8731, 1 << 5);
pub const COMPLETED_PIRATE_SHIP_MINIGAME: Flag = Flag(0x803B8733, 1 << 4);
pub const SAW_PIRATE_SHIP_MINIGAME_INTRO: Flag = Flag(0x803B8733, 1 << 5);
pub const GOT_CATAPULTED_TO_FF1_AND_SPAWN_THERE: Flag = Flag(0x803B8734, 1 << 0);
pub const LONG_TETRA_TEXT_ON_OUTSET: Flag = Flag(0x803B8734, 1 << 1);
pub const TETRA_TOLD_YOU_TO_CLIMB_UP_THE_LADDER: Flag = Flag(0x803B8734, 1 << 2);
pub const COMPLETED_PIRATE_SHIP_MINIGAME_AND_SPAWN_ON_PIRATE_SHIP: Flag = Flag(0x803B8734, 1 << 3);
pub const SAIL_INTRODUCTION_TEXT_AND_MAP_UNLOCKED: Flag = Flag(0x803B8735, 1 << 3);
pub const ENDLESS_NIGHT: Flag = Flag(0x803B8736, 1 << 1);
pub const KORL_DINS_PEARL_TEXT_ALLOWING_YOU_TO_ENTER_HIM: Flag = Flag(0x803B8736, 1 << 7);
pub const HURRICANE_SPIN_UNLOCKED: Flag = Flag(0x803B8737, 1 << 5);
pub const PIRATES_ON_OUTSET: Flag = Flag(0x803B873A, 1 << 5);
pub const KORL_UNLOCKED_AND_SPAWN_ON_WINDFALL: Flag = Flag(0x803B873B, 1 << 7);
pub const WATCHED_FIRE_AND_ICE_ARROWS_CUTSCENE: Flag = Flag(0x803B873C, 1 << 0);
pub const MEDLI_ON_DRI_INTRODUCTION_CUTSCENE_WATCHED: Flag = Flag(0x803B8740, 1 << 1);
pub const SHOWED_MEDLI_THE_WIND_WAKER_ON_DRI: Flag = Flag(0x803B8741, 1 << 2);
pub const HAS_MAKAR_ON_BOAT_1: Flag = Flag(0x803B8742, 1 << 2);
pub const HAS_MEDLI_ON_BOAT_1: Flag = Flag(0x803B8742, 1 << 3);
pub const HAS_MAKAR_ON_BOAT_2_AND_IS_GRABABLE: Flag = Flag(0x803B8742, 1 << 4);
pub const HAS_MEDLI_ON_BOAT_2_AND_CAN_CARRY_YOU: Flag = Flag(0x803B8742, 1 << 5);
pub const TALKED_TO_KORL_AFTER_HYRULE_2_AND_FF3_ACTIVE: Flag = Flag(0x803B8744, 1 << 5);
pub const IS_ALLOWED_TO_ENTER_KORL: Flag = Flag(0x803B8745, 1 << 7);
pub const TOWER_OF_THE_GODS_RAISED: Flag = Flag(0x803B874A, 1 << 6);
pub const WATCHED_DEPARTURE_CUTSCENE_AND_SPAWN_ON_PIRATE_SHIP: Flag = Flag(0x803B8750, 1 << 0);
pub const TALKED_TO_SAIL_SHOP_NPC: Flag = Flag(0x803B8750, 1 << 5);
pub const WATCHED_FIND_SISTER_IN_FF1_CUTSCENE: Flag = Flag(0x803B8751, 1 << 7);
pub const SOME_WEIRD_FIRE_AND_ICE_ARROWS_CUTSCENE_FLAG: Flag = Flag(0x803B8753, 1 << 6);
pub const MAKAR_IN_WIND_TEMPLE: Flag = Flag(0x803B8755, 1 << 4);
pub const MEDLI_IN_EARTH_TEMPLE: Flag = Flag(0x803B8755, 1 << 5);
pub const ENTER_KORL_FOR_THE_FIRST_TIME_AND_SPAWN_ANYWHERE: Flag = Flag(0x803B8756, 1 << 3);
pub const HAS_HEROS_CLOTHES: Flag = Flag(0x803B8756, 1 << 7);
pub const MIGHTY_DARKNUTS_DEFEATED: Flag = Flag(0x803B8758, 1 << 0);
pub const BARRIER_DOWN: Flag = Flag(0x803B8758, 1 << 1);
pub const ANIMATION_SET_2: Flag = Flag(0x803B8759, 1 << 0);
pub const TETRA_TO_ZELDA_CUTSCENE: Flag = Flag(0x803B8759, 1 << 1);
pub const MASTER_SWORD_CUTSCENE: Flag = Flag(0x803B8759, 1 << 2);
pub const HYRULE_3_WARP_CUTSCENE: Flag = Flag(0x803B8759, 1 << 3);
pub const RINGING_BELL_AND_HYRULE_1_CUTSCENE: Flag = Flag(0x803B8759, 1 << 4);
pub const WIND_GODS_ARIA_CUTSCENE: Flag = Flag(0x803B8759, 1 << 5);
pub const EARTH_GODS_LYRIC_CUTSCENE: Flag = Flag(0x803B8759, 1 << 6);
pub const WATCHED_MEETING_KORL_CUTSCENE: Flag = Flag(0x803B875A, 1 << 0);
pub const MAKAR_IN_WIND_TEMPLE_ENTRANCE: Flag = Flag(0x803B875A, 1 << 1);
pub const MEDLI_IN_EARTH_TEMPLE_ENTRANCE: Flag = Flag(0x803B875A, 1 << 2);
pub const PEARL_TOWER_CUTSCENE: Flag = Flag(0x803B875A, 1 << 7);
pub const DID_SWORD_FIGHTING_TUTORIAL: Flag = Flag(0x803B875B, 1 << 4);
pub const GOT_SHIELD_FROM_GRANDMA: Flag = Flag(0x803B875E, 1 << 1);
pub const WATCHED_DESCENDING_DOWN_TO_HYRULE_2_CUTSCENE: Flag = Flag(0x803B875E, 1 << 7);
pub const WATCHED_TEXT_AFTER_FIRE_AND_ICE_ARROWS_CUTSCENE: Flag = Flag(0x803B875F, 1 << 7);
pub const HAS_SEEN_INTRO: Flag = Flag(0x803B8761, 1 << 4);
pub const MIGHTY_DARKNUTS_SPAWNED: Flag = Flag(0x803B8761, 1 << 5);
pub const COLORS_IN_HYRULE: Flag = Flag(0x803B8764, 1 << 1);
pub const WATCHED_COURTYARD_CUTSCENE: Flag = Flag(0x803B8764, 1 << 2);
pub const MOVED_STATUE_IN_HYRULE: Flag = Flag(0x803B8764, 1 << 5);
pub const WATCHED_FF2_GANONDORF_CUTSCENE: Flag = Flag(0x803B8765, 1 << 4);
pub const HYRULE_3_ELECTRICAL_BARRIER_CUTSCENE_1: Flag = Flag(0x803B8765, 1 << 7);
pub const TRIALS_JALHALLA: Flag = Flag(0x803B8765, 1 << 0);
pub const TRIALS_KALLE_DEMOS: Flag = Flag(0x803B8765, 1 << 1);
pub const TRIALS_GOHMA: Flag = Flag(0x803B8765, 1 << 2);
pub const TRIALS_MOLGERA: Flag = Flag(0x803B8766, 1 << 7);
pub const PULLED_MASTER_SWORD_IN_HYRULE_1_SWINGING_CUTSCENE: Flag = Flag(0x803B8766, 1 << 2);
pub const MEDLI_DRAGON_ROOST_CUTSCENE_WATCHED: Flag = Flag(0x803B8767, 1 << 4);
pub const HYRULE_1_ELECTRICAL_BARRIER_DEACTIVATED: Flag = Flag(0x803B8767, 1 << 6);
pub const FF3_TO_HYRULE_WARP_ACTIVE: Flag = Flag(0x803B8769, 1 << 1);
pub const DONT_SHOW_WEAPONS: Flag = Flag(0x803B876B, 1 << 6);

impl Flag {
    pub fn activate(self) {
        let Flag(addr, value) = self;
        let ptr = ptr::<u8>(addr);
        unsafe {
            *ptr |= value;
        }
    }

    pub fn deactivate(self) {
        let Flag(addr, value) = self;
        let ptr = ptr::<u8>(addr);
        unsafe {
            *ptr &= 0xFF ^ value;
        }
    }

    pub fn is_active(self) -> bool {
        let Flag(addr, mask) = self;
        let value = read::<u8>(addr);
        value & mask != 0
    }

    pub fn toggle(self) {
        if self.is_active() {
            self.deactivate()
        } else {
            self.activate()
        }
    }
}
<|endoftext|>