<commit_before>use std::ptr;
use libc::{c_int};
use glib::{Error};
use glib::object::{Ref};
use glib::translate::{FromGlib, FromGlibPtr, FromGlibPtrContainer};
use glib_sys::{GObject};
use secret_collection::SecretCollection;
use ffi;

bitflags! {
    flags SecretServiceFlags: c_int {
        const SECRET_SERVICE_NONE               = 0,
        const SECRET_SERVICE_OPEN_SESSION       = 1 << 1,
        const SECRET_SERVICE_LOAD_COLLECTIONS   = 1 << 2,
    }
}

pub type SecretResult<T> = Result<T, Error>;

pub struct SecretService(Ref);

impl SecretService {

    /// Constructs a new SecretService which has established a session and whose collections are loaded.
    pub fn get() -> Option<Self>{
        SecretService::with_flags(SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS)
    }

    /// Constructs a new SecretService.
    /// The underlying FFI object might be identical for multiple instances of this struct.
    /// `flags` specifies which features will be enabled after construction.
    pub fn with_flags(flags: SecretServiceFlags) -> Option<Self> {
        let ptr = unsafe {ffi::secret_service_get_sync(flags.bits(), ptr::null_mut(), ptr::null_mut())};
        if ptr.is_null(){
            None
        } else {
            Some(SecretService(Ref::from_glib_full(ptr as *mut GObject)))
        }
    }

    #[inline]
    fn raw(&self) -> *mut ffi::SecretServiceFFI {
        self.0.to_glib_none() as *mut ffi::SecretServiceFFI
    }

    /// Get the flags representing what features of the SecretService have been initialized.
    pub fn get_flags(&self) -> SecretServiceFlags {
        let flags = unsafe {ffi::secret_service_get_flags(self.raw())};
        SecretServiceFlags::from_bits(flags).unwrap()
    }

    /// Get the set of algorithms being used to transfer secrets between this secret service proxy and the Secret Service itself.
    /// Returns `None` if no session has been established yet.
    /// The contained String has the format "algorithm-algorithm-algorithm-..."
    pub fn get_session_algorithms(&self) -> Option<String> {
        unsafe{
            let res_c = ffi::secret_service_get_session_algorithms(self.raw());
            if res_c.is_null(){
                None
            } else {
                Some(FromGlibPtr::from_glib_none(res_c))
            }
        }
    }

    pub fn get_collections(&self) -> Option<Vec<SecretCollection>> {
        unsafe {
            let glist = ffi::secret_service_get_collections(self.raw());
            if glist.is_null(){
                None
            } else {
                Some(FromGlibPtrContainer::from_glib_none(glist))
            }
        }
    }

    /// Ensures that a session is established.
    /// This function should rarely be needed. Construct a SecretService with the `SECRET_SERVICE_OPEN_SESSION` flag instead.
    /// Returns true if a session has been established, false otherwise.
    pub fn ensure_session(&self) -> bool {
        unsafe {
            let established = ffi::secret_service_ensure_session_sync(self.raw(), ptr::null_mut(), ptr::null_mut());
            FromGlib::from_glib(established)
        }
    }

    /// Ensures that the collections are loaded.
    /// This function should rarely be needed. Construct a SecretService with the `SECRET_SERVICE_LOAD_COLLECTIONS` flag instead.
    /// Returns true if a session has been established, false otherwise.
    pub fn load_collections(&self) -> bool {
        unsafe {
            let loaded = ffi::secret_service_load_collections_sync(self.raw(), ptr::null_mut(), ptr::null_mut());
            FromGlib::from_glib(loaded)
        }
    }

}
<commit_msg>method stubs<commit_after>use std::ptr;
use libc::{c_int};
use glib::{Error};
use glib::object::{Ref};
use glib::translate::{FromGlib, FromGlibPtr, FromGlibPtrContainer};
use glib_sys::{GObject};
use secret_collection::SecretCollection;
use ffi;

bitflags! {
    flags SecretServiceFlags: c_int {
        const SECRET_SERVICE_NONE              = 0,
        const SECRET_SERVICE_OPEN_SESSION      = 1 << 1,
        const SECRET_SERVICE_LOAD_COLLECTIONS  = 1 << 2,
    }
}

bitflags! {
    flags SecretSearchFlags: c_int {
        const SECRET_SEARCH_NONE               = 0,
	    const SECRET_SEARCH_ALL                = 1 << 1,
	    const SECRET_SEARCH_UNLOCK             = 1 << 2,
	    const SECRET_SEARCH_LOAD_SECRETS       = 1 << 3,
    }
}

pub type SecretResult<T> = Result<T, Error>;

pub struct SecretService(Ref);

impl SecretService {

    /// Constructs a new SecretService which has established a session and whose collections are loaded.
    pub fn get() -> Option<Self>{
        SecretService::with_flags(SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS)
    }

    /// Constructs a new SecretService.
    /// The underlying FFI object might be identical for multiple instances of this struct.
    /// `flags` specifies which features will be enabled after construction.
    pub fn with_flags(flags: SecretServiceFlags) -> Option<Self> {
        let ptr = unsafe {ffi::secret_service_get_sync(flags.bits(), ptr::null_mut(), ptr::null_mut())};
        if ptr.is_null(){
            None
        } else {
            Some(SecretService(Ref::from_glib_full(ptr as *mut GObject)))
        }
    }

    #[inline]
    fn raw(&self) -> *mut ffi::SecretServiceFFI {
        self.0.to_glib_none() as *mut ffi::SecretServiceFFI
    }

    /// Get the flags representing what features of the SecretService have been initialized.
    pub fn get_flags(&self) -> SecretServiceFlags {
        let flags = unsafe {ffi::secret_service_get_flags(self.raw())};
        SecretServiceFlags::from_bits(flags).unwrap()
    }

    /// Get the set of algorithms being used to transfer secrets between this secret service proxy and the Secret Service itself.
    /// Returns `None` if no session has been established yet.
    /// The contained String has the format "algorithm-algorithm-algorithm-..."
    pub fn get_session_algorithms(&self) -> Option<String> {
        unsafe{
            let res_c = ffi::secret_service_get_session_algorithms(self.raw());
            if res_c.is_null(){
                None
            } else {
                Some(FromGlibPtr::from_glib_none(res_c))
            }
        }
    }

    pub fn get_collections(&self) -> Option<Vec<SecretCollection>> {
        unsafe {
            let glist = ffi::secret_service_get_collections(self.raw());
            if glist.is_null(){
                None
            } else {
                Some(FromGlibPtrContainer::from_glib_none(glist))
            }
        }
    }

    /*
    pub fn search() -> Vec<SecretItem> {
        unimplemented!()
    }
    */

    /*
    pub fn lock () -> Vec<SecretItem> {

    }
    */

    /*
    pub fn unlock () -> Vec<SecretItem> {

    }
    */

    /*
    pub fn store () -> bool {

    }
    */

    /*
    pub fn lookup () -> SecretValue {

    }
    */

    /*
    pub fn clear () -> bool {

    }
    */

    /*
    pub fn set_alias(&str alias, ) -> bool {
        //FIXME: actually we should put this into SecretCollection
    }
    */

    /// Ensures that a session is established.
    /// This function should rarely be needed. Construct a SecretService with the `SECRET_SERVICE_OPEN_SESSION` flag instead.
    /// Returns true if a session has been established, false otherwise.
    pub fn ensure_session(&self) -> bool {
        unsafe {
            let established = ffi::secret_service_ensure_session_sync(self.raw(), ptr::null_mut(), ptr::null_mut());
            FromGlib::from_glib(established)
        }
    }

    /// Ensures that the collections are loaded.
    /// This function should rarely be needed. Construct a SecretService with the `SECRET_SERVICE_LOAD_COLLECTIONS` flag instead.
    /// Returns true if a session has been established, false otherwise.
    pub fn load_collections(&self) -> bool {
        unsafe {
            let loaded = ffi::secret_service_load_collections_sync(self.raw(), ptr::null_mut(), ptr::null_mut());
            FromGlib::from_glib(loaded)
        }
    }

}
<|endoftext|>


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

use context::{ ContextTrait, Shared };
use iron::{Request, Response, IronResult};
use iron::headers::ContentType;
use iron::status::Status;
use router::Router;
use core::marker::Reflect;

pub fn create<Ctx: Send + Reflect + ContextTrait + 'static> (context: Shared<Ctx>) -> Router {

    let mut router = Router::new();
    let context1 = context.clone();
    router.get("list.json", move |_: &mut Request| -> IronResult<Response> {
        // Build a json representation of the services.
        let ctx = context1.lock().unwrap();
        let serialized = itry!(ctx.services_as_json());

        let mut response = Response::with(serialized);
        response.status = Some(Status::Ok);
        response.headers.set(ContentType::json());

        Ok(response)
    });

    let context2 = context.clone();
    router.get(":service/:command", move |req: &mut Request| -> IronResult<Response> {
        // Call a function on a service.
        let ctx = context2.lock().unwrap();

        let id = req.extensions.get::<Router>().unwrap().find("service").unwrap_or("");
        match ctx.get_service(id) {
            None => {
                let mut response = Response::with(format!("No Such Service: {}", id));
                response.status = Some(Status::BadRequest);
                response.headers.set(ContentType::plaintext());
                Ok(response)
            }
            Some(service) => {
                service.process_request(req)
            }
        }
    });
    router
}

// FIXME: Declare this crate in the test module, and avoid the use of pub
// When this comment was written, putting these 2 lines in before_each returns a compile error:
// ``` error: unresolved import `self::iron_test::request`. Could not find `iron_test` in
// service_router::service_router` [E0432] ```
extern crate iron_test;
pub use self::iron_test::{request, response};

describe! service_router {
    before_each {
        use stubs::context::ContextStub;
        use iron::Headers;

        let context = ContextStub::blank_shared();
        let service_router = create(context);
    }

    it "should create list.json" {
        let response = request::get("http://localhost:3000/list.json",
                        Headers::new(),
                        &service_router).unwrap();

        let result = response::extract_body_to_string(response);
        assert_eq!(result, "{}");
    }

    it "should make service available" {
        let response = request::get("http://localhost:3000/1/a-command",
                        Headers::new(),
                        &service_router).unwrap();

        let result = response::extract_body_to_string(response);
        assert_eq!(result, "request processed");
    }

    it "should return an error if no service was found" {
        let response = request::get("http://localhost:3000/unknown-id/a-command",
                        Headers::new(),
                        &service_router).unwrap();

        let result = response::extract_body_to_string(response);
        assert_eq!(result, "No Such Service: unknown-id");
    }
}
<commit_msg>Fix compilation error<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use context::{ ContextTrait, Shared };
use iron::{Request, Response, IronResult};
use iron::headers::ContentType;
use iron::status::Status;
use router::Router;
use core::marker::Reflect;

pub fn create<Ctx: Send + Reflect + ContextTrait + 'static> (context: Shared<Ctx>) -> Router {

    let mut router = Router::new();
    let context1 = context.clone();
    router.get("list.json", move |_: &mut Request| -> IronResult<Response> {
        // Build a json representation of the services.
        let ctx = context1.lock().unwrap();
        let serialized = itry!(ctx.services_as_json());

        let mut response = Response::with(serialized);
        response.status = Some(Status::Ok);
        response.headers.set(ContentType::json());

        Ok(response)
    });

    let context2 = context.clone();
    router.get(":service/:command", move |req: &mut Request| -> IronResult<Response> {
        // Call a function on a service.
        let ctx = context2.lock().unwrap();

        let id = req.extensions.get::<Router>().unwrap().find("service").unwrap_or("");
        match ctx.get_service(id) {
            None => {
                let mut response = Response::with(format!("No Such Service: {}", id));
                response.status = Some(Status::BadRequest);
                response.headers.set(ContentType::plaintext());
                Ok(response)
            }
            Some(service) => {
                service.process_request(req)
            }
        }
    });
    router
}

// FIXME: Declare this crate in the test module, and avoid the use of pub
// When this comment was written, putting these 2 lines in before_each returns a compile error:
// ``` error: unresolved import `self::iron_test::request`. Could not find `iron_test` in
// service_router::service_router` [E0432] ```
extern crate iron_test;
pub use self::iron_test::{request, response};

#[cfg(test)]
describe! service_router {
    before_each {
        use stubs::context::ContextStub;
        use iron::Headers;

        let context = ContextStub::blank_shared();
        let service_router = create(context);
    }

    it "should create list.json" {
        let response = request::get("http://localhost:3000/list.json",
                        Headers::new(),
                        &service_router).unwrap();

        let result = response::extract_body_to_string(response);
        assert_eq!(result, "{}");
    }

    it "should make service available" {
        let response = request::get("http://localhost:3000/1/a-command",
                        Headers::new(),
                        &service_router).unwrap();

        let result = response::extract_body_to_string(response);
        assert_eq!(result, "request processed");
    }

    it "should return an error if no service was found" {
        let response = request::get("http://localhost:3000/unknown-id/a-command",
                        Headers::new(),
                        &service_router).unwrap();

        let result = response::extract_body_to_string(response);
        assert_eq!(result, "No Such Service: unknown-id");
    }
}
<|endoftext|>


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

pub struct Translator
{
  rules: HashMap<(char, char), char>,
}

impl Translator
{
  pub fn new() -> Translator
  {
    Translator
    {
      rules: HashMap::new(),
    }
  }

  pub fn default() -> Translator
  {
    Translator
    {
      rules: HashMap::new(),
    }
  }

  fn translate_char(&self, current : char, previous : char) -> char
  {
    match self.rules.get(&(current, previous))
    {
      Some(result) => return *result,
      None => return 'a'
    }
  }

  pub fn translate(&self, text : &str) -> String
  {
    let mut result = String::with_capacity(text.len() * std::mem::size_of::<char>());

    let mut previous = ' ';
    for c in text.chars()
    {
      previous = self.translate_char(c, previous);
      result.push(previous);
    }

    result
  }
}
<commit_msg>'translate' match refactoring<commit_after>use std::collections::HashMap;

pub struct Translator
{
  rules: HashMap<(char, char), char>,
}

impl Translator
{
  pub fn new() -> Translator
  {
    Translator
    {
      rules: HashMap::new(),
    }
  }

  pub fn default() -> Translator
  {
    Translator
    {
      rules: HashMap::new(),
    }
  }

  fn translate_char(&self, current : char, previous : char) -> char
  {
    match self.rules.get(&(current, previous))
    {
      Some(result) => *result,
      None => 'a'
    }
  }

  pub fn translate(&self, text : &str) -> String
  {
    let mut result = String::with_capacity(text.len() * std::mem::size_of::<char>());

    let mut previous = ' ';
    for c in text.chars()
    {
      previous = self.translate_char(c, previous);
      result.push(previous);
    }

    result
  }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::io::{Io, Pio, ReadOnly, WriteOnly};

use graphics::display::VBEMODEINFO;

use fs::KScheme;

use drivers::kb_layouts::layouts;

pub struct Ps2Keyboard<'a> {
    bus: &'a mut Ps2
}

impl<'a> Ps2Keyboard<'a> {
    //TODO: Use result
    fn cmd(&mut self, command: u8) -> u8 {
        self.bus.wait_write();
        self.bus.data.write(command);
        self.bus.wait_read();
        self.bus.data.read()
    }
}

pub struct Ps2Mouse<'a> {
    bus: &'a mut Ps2
}

impl<'a> Ps2Mouse<'a> {
    //TODO: Use result
    fn cmd(&mut self, command: u8) -> u8 {
        self.bus.write(0xD4, command);
        self.bus.wait_read();
        self.bus.data.read()
    }
}

/// PS2
pub struct Ps2 {
    /// The data register
    data: Pio<u8>,
    /// The status register
    sts: ReadOnly<u8, Pio<u8>>,
    /// The command register
    cmd: WriteOnly<u8, Pio<u8>>,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// AltGr?
    altgr: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: i32,
    /// Mouse point y
    mouse_y: i32,
    /// Layout for keyboard
    /// Default: English
    layout: layouts::Layout,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio::new(0x60),
            sts: ReadOnly::new(Pio::new(0x64)),
            cmd: WriteOnly::new(Pio::new(0x64)),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            altgr: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: layouts::Layout::English,
        };

        module.init();

        module
    }

    fn wait_read(&self) {
        while ! self.sts.readf(1) {}
    }

    fn wait_write(&self) {
        while self.sts.readf(2) {}
    }

    fn cmd(&mut self, command: u8) {
        self.wait_write();
        self.cmd.write(command);
    }

    fn read(&mut self, command: u8) -> u8 {
        self.cmd(command);
        self.wait_read();
        self.data.read()
    }

    fn write(&mut self, command: u8, data: u8) {
        self.cmd(command);
        self.wait_write();
        self.data.write(data);
    }

    fn keyboard<'a>(&'a mut self) -> Ps2Keyboard<'a> {
        Ps2Keyboard {
            bus: self
        }
    }

    fn mouse<'a>(&'a mut self) -> Ps2Mouse<'a> {
        Ps2Mouse {
            bus: self
        }
    }

    fn init(&mut self) {
        while self.sts.readf(1) {
            self.data.read();
        }

        debugln!(" + PS/2");

        // No interrupts, system flag set, clocks enabled, translation enabled
        self.write(0x60, 0b01000100);

        while self.sts.readf(1) {
            debugln!("Extra {}: {:X}", line!(), self.data.read());
        }

        // Enable First Port
        debugln!("   + Keyboard");
        self.cmd(0xAE);

        while self.sts.readf(1) {
            debugln!("Extra {}: {:X}", line!(), self.data.read());
        }

        {
            // Reset
            debug!("     - Reset {:X}", self.keyboard().cmd(0xFF));
            self.wait_read();
            debugln!(", {:X}", self.data.read());

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }

            // Set defaults
            debugln!("     - Set defaults {:X}", self.keyboard().cmd(0xF6));

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }

            // Enable Streaming
            debugln!("     - Enable streaming {:X}", self.keyboard().cmd(0xF4));

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }
        }

        // Enable Second Port
        debugln!("   + PS/2 Mouse");
        self.cmd(0xA8);

        while self.sts.readf(1) {
            debugln!("Extra {}: {:X}", line!(), self.data.read());
        }

        {
            // Reset
            debug!("     - Reset {:X}", self.keyboard().cmd(0xFF));
            self.wait_read();
            debugln!(", {:X}", self.data.read());

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }

            // Set defaults
            debugln!("     - Set defaults {:X}", self.mouse().cmd(0xF6));

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }

            // Enable Streaming
            debugln!("     - Enable streaming {:X}", self.mouse().cmd(0xF4));

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }
        }

        // Key and mouse interrupts, system flag set, clocks enabled, translation enabled
        self.write(0x60, 0b01000111);

        while self.sts.readf(1) {
            debugln!("Extra {}: {:X}", line!(), self.data.read());
        }
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self, mut scancode: u8) -> Option<KeyEvent> {
        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        } else if scancode == 0xE0 {
            let scancode_byte_2 = self.data.read();
            if scancode_byte_2 == 0x38 {
                self.altgr = true;
            } else if scancode_byte_2 == 0xB8 {
                self.altgr = false;
            } else {
                scancode = scancode_byte_2;
            }
        }

        let shift = self.caps_lock != (self.lshift || self.rshift);

        return Some(KeyEvent {
            character: layouts::char_for_scancode(scancode & 0x7F, shift, self.altgr, &self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self, byte: u8) -> Option<MouseEvent> {
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = (self.mouse_packet[1] as isize -
                     (((self.mouse_packet[0] as isize) << 4) & 0x100)) as i32;
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = ((((self.mouse_packet[0] as isize) << 3) & 0x100) -
                     self.mouse_packet[2] as isize) as i32;
            } else {
                y = 0;
            }

            if let Some(mode_info) = unsafe { VBEMODEINFO } {
                self.mouse_x = cmp::max(0, cmp::min(mode_info.xresolution as i32, self.mouse_x + x));
                self.mouse_y = cmp::max(0, cmp::min(mode_info.yresolution as i32, self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = match layout {
            0 => layouts::Layout::English,
            1 => layouts::Layout::French,
            2 => layouts::Layout::German,
            _ => layouts::Layout::English,
        }
    }
}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0xC {
            let data = self.data.read();
            if let Some(mouse_event) = self.mouse_interrupt(data) {
                if ::env().console.lock().draw {
                    //Ignore mouse event
                } else {
                    ::env().events.send(mouse_event.to_event());
                }
            }
        } else if irq == 1 {
            let data = self.data.read();
            if let Some(key_event) = self.keyboard_interrupt(data) {
                if ::env().console.lock().draw {
                    ::env().console.lock().event(key_event.to_event());
                } else {
                    ::env().events.send(key_event.to_event());
                }
            }
        }
    }
}
<commit_msg>Fix swapping of mouse/keyboard<commit_after>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::io::{Io, Pio, ReadOnly, WriteOnly};

use graphics::display::VBEMODEINFO;

use fs::KScheme;

use drivers::kb_layouts::layouts;

pub struct Ps2Keyboard<'a> {
    bus: &'a mut Ps2
}

impl<'a> Ps2Keyboard<'a> {
    //TODO: Use result
    fn cmd(&mut self, command: u8) -> u8 {
        self.bus.wait_write();
        self.bus.data.write(command);
        self.bus.wait_read();
        self.bus.data.read()
    }
}

pub struct Ps2Mouse<'a> {
    bus: &'a mut Ps2
}

impl<'a> Ps2Mouse<'a> {
    //TODO: Use result
    fn cmd(&mut self, command: u8) -> u8 {
        self.bus.write(0xD4, command);
        self.bus.wait_read();
        self.bus.data.read()
    }
}

/// PS2
pub struct Ps2 {
    /// The data register
    data: Pio<u8>,
    /// The status register
    sts: ReadOnly<u8, Pio<u8>>,
    /// The command register
    cmd: WriteOnly<u8, Pio<u8>>,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// AltGr?
    altgr: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: i32,
    /// Mouse point y
    mouse_y: i32,
    /// Layout for keyboard
    /// Default: English
    layout: layouts::Layout,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio::new(0x60),
            sts: ReadOnly::new(Pio::new(0x64)),
            cmd: WriteOnly::new(Pio::new(0x64)),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            altgr: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: layouts::Layout::English,
        };

        module.init();

        module
    }

    fn wait_read(&self) {
        while ! self.sts.readf(1) {}
    }

    fn wait_write(&self) {
        while self.sts.readf(2) {}
    }

    fn cmd(&mut self, command: u8) {
        self.wait_write();
        self.cmd.write(command);
    }

    fn read(&mut self, command: u8) -> u8 {
        self.cmd(command);
        self.wait_read();
        self.data.read()
    }

    fn write(&mut self, command: u8, data: u8) {
        self.cmd(command);
        self.wait_write();
        self.data.write(data);
    }

    fn keyboard<'a>(&'a mut self) -> Ps2Keyboard<'a> {
        Ps2Keyboard {
            bus: self
        }
    }

    fn mouse<'a>(&'a mut self) -> Ps2Mouse<'a> {
        Ps2Mouse {
            bus: self
        }
    }

    fn init(&mut self) {
        while self.sts.readf(1) {
            self.data.read();
        }

        debugln!(" + PS/2");

        // No interrupts, system flag set, clocks enabled, translation enabled
        self.write(0x60, 0b01000100);

        while self.sts.readf(1) {
            debugln!("Extra {}: {:X}", line!(), self.data.read());
        }

        // Enable First Port
        debugln!("   + Keyboard");
        self.cmd(0xAE);

        while self.sts.readf(1) {
            debugln!("Extra {}: {:X}", line!(), self.data.read());
        }

        {
            // Reset
            debug!("     - Reset {:X}", self.keyboard().cmd(0xFF));
            self.wait_read();
            debugln!(", {:X}", self.data.read());

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }

            // Set defaults
            debugln!("     - Set defaults {:X}", self.keyboard().cmd(0xF6));

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }

            // Enable Streaming
            debugln!("     - Enable streaming {:X}", self.keyboard().cmd(0xF4));

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }
        }

        // Enable Second Port
        debugln!("   + PS/2 Mouse");
        self.cmd(0xA8);

        while self.sts.readf(1) {
            debugln!("Extra {}: {:X}", line!(), self.data.read());
        }

        {
            // Reset
            debug!("     - Reset {:X}", self.keyboard().cmd(0xFF));
            self.wait_read();
            debugln!(", {:X}", self.data.read());

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }

            // Set defaults
            debugln!("     - Set defaults {:X}", self.mouse().cmd(0xF6));

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }

            // Enable Streaming
            debugln!("     - Enable streaming {:X}", self.mouse().cmd(0xF4));

            while self.sts.readf(1) {
                debugln!("Extra {}: {:X}", line!(), self.data.read());
            }
        }

        // Key and mouse interrupts, system flag set, clocks enabled, translation enabled
        self.write(0x60, 0b01000111);

        while self.sts.readf(1) {
            debugln!("Extra {}: {:X}", line!(), self.data.read());
        }
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self, mut scancode: u8) -> Option<KeyEvent> {
        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        } else if scancode == 0xE0 {
            let scancode_byte_2 = self.data.read();
            if scancode_byte_2 == 0x38 {
                self.altgr = true;
            } else if scancode_byte_2 == 0xB8 {
                self.altgr = false;
            } else {
                scancode = scancode_byte_2;
            }
        }

        let shift = self.caps_lock != (self.lshift || self.rshift);

        return Some(KeyEvent {
            character: layouts::char_for_scancode(scancode & 0x7F, shift, self.altgr, &self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self, byte: u8) -> Option<MouseEvent> {
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = (self.mouse_packet[1] as isize -
                     (((self.mouse_packet[0] as isize) << 4) & 0x100)) as i32;
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = ((((self.mouse_packet[0] as isize) << 3) & 0x100) -
                     self.mouse_packet[2] as isize) as i32;
            } else {
                y = 0;
            }

            if let Some(mode_info) = unsafe { VBEMODEINFO } {
                self.mouse_x = cmp::max(0, cmp::min(mode_info.xresolution as i32, self.mouse_x + x));
                self.mouse_y = cmp::max(0, cmp::min(mode_info.yresolution as i32, self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = match layout {
            0 => layouts::Layout::English,
            1 => layouts::Layout::French,
            2 => layouts::Layout::German,
            _ => layouts::Layout::English,
        }
    }
}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0xC || irq == 0x1 {
            loop {
                let status = self.sts.read();
                if status & 0x21 == 0x21 {
                    let data = self.data.read();
                    if let Some(mouse_event) = self.mouse_interrupt(data) {
                        if ::env().console.lock().draw {
                            //Ignore mouse event
                        } else {
                            ::env().events.send(mouse_event.to_event());
                        }
                    }
                } else if status & 0x21 == 0x01 {
                    let data = self.data.read();
                    if let Some(key_event) = self.keyboard_interrupt(data) {
                        if ::env().console.lock().draw {
                            ::env().console.lock().event(key_event.to_event());
                        } else {
                            ::env().events.send(key_event.to_event());
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>import alder::*;

mod alder {
  export burnside;
  export everett::{flanders};
  export irving::{johnson, kearney};
  export marshall::{};

  enum burnside { couch, davis }
  enum everett { flanders, glisan, hoyt }
  enum irving { johnson, kearney, lovejoy }
  enum marshall { northrup, overton }

}

fn main() {
  let _pettygrove: burnside = couch;
  let _quimby: everett = flanders;
  let _raleigh: irving = johnson;
  let _savier: marshall;
}
<commit_msg>test: Make tag-exports not use the obsolete tag export syntax<commit_after>import alder::*;

mod alder {
  export burnside;
  export everett;
  export flanders;
  export irving;
  export johnson;
  export kearney;
  export marshall;

  enum burnside { couch, davis }
  enum everett { flanders, glisan, hoyt }
  enum irving { johnson, kearney, lovejoy }
  enum marshall { northrup, overton }

}

fn main() {
  let _pettygrove: burnside = couch;
  let _quimby: everett = flanders;
  let _raleigh: irving = johnson;
  let _savier: marshall;
}
<|endoftext|>


<commit_before>// use std::io::File;
use std::os;

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        println!("open \"{}\" ...", args[1]);
    }
}
<commit_msg>This is temporary code to show how to use a Foreign Function Interface (FFI) to C libraries.<commit_after>// use std::io::File;
use std::os;
use std::fmt;

#[repr(C)]
struct Complex {
    re: f32,
    im: f32,
}

#[link(name = "m")]
extern {
    fn csqrtf(z: Complex) -> Complex;
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        println!("open \"{}\" ...", args[1]);
        let z = Complex { re: -1.0, im: 0.0 };
        let z_sqrt = unsafe {
            csqrtf(z)
        };
        println!("the square root of {} is {}", z, z_sqrt);
    }
}

impl fmt::Show for Complex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.im < 0. {
            write!(f, "{}-{}i", self.re, -self.im)
        } else {
            write!(f, "{}+{}i", self.re, self.im)
        }
    }
}
<|endoftext|>


<commit_before>use std::path::{PathBuf, Path};
use std::fs;
use std::error::Error;
use std::fmt;

#[cfg(feature = "cache")]
use time::{self, Timespec};
#[cfg(feature = "cache")]
use std::time::Duration;

use iron::prelude::*;
use iron::{Handler, Url, status};
#[cfg(feature = "cache")]
use iron::modifier::Modifier;
use iron::modifiers::Redirect;
use mount::OriginalUrl;
use requested_path::RequestedPath;

/// The static file-serving `Handler`.
///
/// This handler serves files from a single filesystem path, which may be absolute or relative.
/// Incoming requests are mapped onto the filesystem by appending their URL path to the handler's
/// root path. If the filesystem path corresponds to a regular file, the handler will attempt to
/// serve it. Otherwise, if the path corresponds to a directory containing an `index.html`,
/// the handler will attempt to serve that instead.
///
/// ## Errors
///
/// If the path doesn't match any real object in the filesystem, the handler will return
/// a Response with `status::NotFound`. If an IO error occurs whilst attempting to serve
/// a file, `FileError(IoError)` will be returned.
#[derive(Clone)]
pub struct Static {
    /// The path this handler is serving files from.
    pub root: PathBuf,
    #[cfg(feature = "cache")]
    cache: Option<Cache>,
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    #[cfg(feature = "cache")]
    pub fn new<P: Into<PathBuf>>(root: P) -> Static {
        Static {
            root: root.into(),
            cache: None
        }
    }

    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    #[cfg(not(feature = "cache"))]
    pub fn new<P: Into<PathBuf>>(root: P) -> Static {
        Static {
            root: root.into(),
        }
    }

    /// Specify the response's `cache-control` header with a given duration. Internally, this is
    /// a helper function to set a `Cache` on an instance of `Static`.
    ///
    /// ## Example
    ///
    /// ```ignore
    /// let cached_static_handler = Static::new(path).cache(Duration::from_secs(30*24*60*60));
    /// ```
    #[cfg(feature = "cache")]
    pub fn cache(self, duration: Duration) -> Static {
        self.set(Cache::new(duration))
    }

    #[cfg(feature = "cache")]
    fn try_cache<P: AsRef<Path>>(&self, req: &mut Request, path: P) -> IronResult<Response> {
        match self.cache {
            None => Ok(Response::with((status::Ok, path.as_ref()))),
            Some(ref cache) => cache.handle(req, path.as_ref()),
        }
    }
}

impl Handler for Static {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        use std::io;

        let requested_path = RequestedPath::new(&self.root, req);

        let metadata = match fs::metadata(&requested_path.path) {
            Ok(meta) => meta,
            Err(e) => {
                let status = match e.kind() {
                    io::ErrorKind::NotFound => status::NotFound,
                    io::ErrorKind::PermissionDenied => status::Forbidden,
                    _ => status::InternalServerError,
                };

                return Err(IronError::new(e, status))
            },
        };

        // If the URL ends in a slash, serve the file directly.
        // Otherwise, redirect to the directory equivalent of the URL.
        if requested_path.should_redirect(&metadata, req) {
            // Perform an HTTP 301 Redirect.
            let mut original_url = match req.extensions.get::<OriginalUrl>() {
                None => &req.url,
                Some(original_url) => original_url,
            }.clone().into_generic_url();

            // Append the trailing slash
            //
            // rust-url automatically turns an empty string in the last
            // slot in the path into a trailing slash.
            original_url.path_segments_mut().unwrap().push("");
            let redirect_path = Url::from_generic_url(original_url).unwrap();

            return Ok(Response::with((status::MovedPermanently,
                                      format!("Redirecting to {}", redirect_path),
                                      Redirect(redirect_path))));
        }

        match requested_path.get_file(&metadata) {
            // If no file is found, return a 404 response.
            None => Err(IronError::new(NoFile, status::NotFound)),
            // Won't panic because we know the file exists from get_file.
            #[cfg(feature = "cache")]
            Some(path) => self.try_cache(req, path),
            #[cfg(not(feature = "cache"))]
            Some(path) => {
                let path: &Path = &path;
                Ok(Response::with((status::Ok, path)))
            },
        }
    }
}

impl Set for Static {}

/// A modifier for `Static` to specify a response's `cache-control`.
#[cfg(feature = "cache")]
#[derive(Clone)]
pub struct Cache {
    /// The length of time the file should be cached for.
    pub duration: Duration,
}

#[cfg(feature = "cache")]
impl Cache {
    /// Create a new instance of `Cache` with a given duration.
    pub fn new(duration: Duration) -> Cache {
        Cache { duration: duration }
    }

    fn handle<P: AsRef<Path>>(&self, req: &mut Request, path: P) -> IronResult<Response> {
        use iron::headers::{IfModifiedSince, HttpDate};

        let path = path.as_ref();

        let last_modified_time = match fs::metadata(path) {
            Err(error) => return Err(IronError::new(error, status::InternalServerError)),
            Ok(metadata) => {
                use filetime::FileTime;

                let time = FileTime::from_last_modification_time(&metadata);
                Timespec::new(time.seconds() as i64, time.nanoseconds() as i32)
            },
        };

        let if_modified_since = match req.headers.get::<IfModifiedSince>().cloned() {
            None => return Ok(self.response_with_cache(req, path, last_modified_time)),
            Some(IfModifiedSince(HttpDate(time))) => time.to_timespec(),
        };

        if last_modified_time <= if_modified_since {
            Ok(Response::with(status::NotModified))
        } else {
            Ok(self.response_with_cache(req, path, last_modified_time))
        }
    }

    fn response_with_cache<P: AsRef<Path>>(&self,
                                           req: &mut Request,
                                           path: P,
                                           modified: Timespec) -> IronResult<Response> {
        use iron::headers::{CacheControl, LastModified, CacheDirective, HttpDate};
        use iron::headers::{ContentLength, ContentType};
        use iron::method::Method;
        use iron::mime::{Mime, TopLevel, SubLevel};
        use iron::modifiers::Header;

        let seconds = self.duration.as_secs() as u32;
        let cache = vec![CacheDirective::Public, CacheDirective::MaxAge(seconds)];
        let metadata = fs::metadata(path.as_ref());

        if metadata.is_err() {
            return Err(IronError::new(metadata.unwrap_err(), status::InternalServerError))
        }

        let mut response = if req.method == Method::Head {
            let has_ct = req.headers.get::<ContentType>();
            let cont_type = match has_ct {
                None => ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])),
                Some(t) => t.clone()
            };
            Response::with((status::Ok, Header(cont_type), Header(ContentLength(metadata.len()))))
        } else {
            Response::with((status::Ok, path.as_ref()));
        };

        response.headers.set(CacheControl(cache));
        response.headers.set(LastModified(HttpDate(time::at(modified))));

        Ok(response)
    }
}

#[cfg(feature = "cache")]
impl Modifier<Static> for Cache {
    fn modify(self, static_handler: &mut Static) {
        static_handler.cache = Some(self);
    }
}

/// Thrown if no file is found. It is always accompanied by a NotFound response.
#[derive(Debug)]
pub struct NoFile;

impl Error for NoFile {
    fn description(&self) -> &str { "File not found" }
}

impl fmt::Display for NoFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}
<commit_msg>(fix) Allow building with the cache feature again<commit_after>use std::path::{PathBuf, Path};
use std::fs;
use std::error::Error;
use std::fmt;

#[cfg(feature = "cache")]
use time::{self, Timespec};
#[cfg(feature = "cache")]
use std::time::Duration;

use iron::prelude::*;
use iron::{Handler, Url, status};
#[cfg(feature = "cache")]
use iron::modifier::Modifier;
use iron::modifiers::Redirect;
use mount::OriginalUrl;
use requested_path::RequestedPath;

/// The static file-serving `Handler`.
///
/// This handler serves files from a single filesystem path, which may be absolute or relative.
/// Incoming requests are mapped onto the filesystem by appending their URL path to the handler's
/// root path. If the filesystem path corresponds to a regular file, the handler will attempt to
/// serve it. Otherwise, if the path corresponds to a directory containing an `index.html`,
/// the handler will attempt to serve that instead.
///
/// ## Errors
///
/// If the path doesn't match any real object in the filesystem, the handler will return
/// a Response with `status::NotFound`. If an IO error occurs whilst attempting to serve
/// a file, `FileError(IoError)` will be returned.
#[derive(Clone)]
pub struct Static {
    /// The path this handler is serving files from.
    pub root: PathBuf,
    #[cfg(feature = "cache")]
    cache: Option<Cache>,
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    #[cfg(feature = "cache")]
    pub fn new<P: Into<PathBuf>>(root: P) -> Static {
        Static {
            root: root.into(),
            cache: None
        }
    }

    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    #[cfg(not(feature = "cache"))]
    pub fn new<P: Into<PathBuf>>(root: P) -> Static {
        Static {
            root: root.into(),
        }
    }

    /// Specify the response's `cache-control` header with a given duration. Internally, this is
    /// a helper function to set a `Cache` on an instance of `Static`.
    ///
    /// ## Example
    ///
    /// ```ignore
    /// let cached_static_handler = Static::new(path).cache(Duration::from_secs(30*24*60*60));
    /// ```
    #[cfg(feature = "cache")]
    pub fn cache(self, duration: Duration) -> Static {
        self.set(Cache::new(duration))
    }

    #[cfg(feature = "cache")]
    fn try_cache<P: AsRef<Path>>(&self, req: &mut Request, path: P) -> IronResult<Response> {
        match self.cache {
            None => Ok(Response::with((status::Ok, path.as_ref()))),
            Some(ref cache) => cache.handle(req, path.as_ref()),
        }
    }
}

impl Handler for Static {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        use std::io;

        let requested_path = RequestedPath::new(&self.root, req);

        let metadata = match fs::metadata(&requested_path.path) {
            Ok(meta) => meta,
            Err(e) => {
                let status = match e.kind() {
                    io::ErrorKind::NotFound => status::NotFound,
                    io::ErrorKind::PermissionDenied => status::Forbidden,
                    _ => status::InternalServerError,
                };

                return Err(IronError::new(e, status))
            },
        };

        // If the URL ends in a slash, serve the file directly.
        // Otherwise, redirect to the directory equivalent of the URL.
        if requested_path.should_redirect(&metadata, req) {
            // Perform an HTTP 301 Redirect.
            let mut original_url = match req.extensions.get::<OriginalUrl>() {
                None => &req.url,
                Some(original_url) => original_url,
            }.clone().into_generic_url();

            // Append the trailing slash
            //
            // rust-url automatically turns an empty string in the last
            // slot in the path into a trailing slash.
            original_url.path_segments_mut().unwrap().push("");
            let redirect_path = Url::from_generic_url(original_url).unwrap();

            return Ok(Response::with((status::MovedPermanently,
                                      format!("Redirecting to {}", redirect_path),
                                      Redirect(redirect_path))));
        }

        match requested_path.get_file(&metadata) {
            // If no file is found, return a 404 response.
            None => Err(IronError::new(NoFile, status::NotFound)),
            // Won't panic because we know the file exists from get_file.
            #[cfg(feature = "cache")]
            Some(path) => self.try_cache(req, path),
            #[cfg(not(feature = "cache"))]
            Some(path) => {
                let path: &Path = &path;
                Ok(Response::with((status::Ok, path)))
            },
        }
    }
}

impl Set for Static {}

/// A modifier for `Static` to specify a response's `cache-control`.
#[cfg(feature = "cache")]
#[derive(Clone)]
pub struct Cache {
    /// The length of time the file should be cached for.
    pub duration: Duration,
}

#[cfg(feature = "cache")]
impl Cache {
    /// Create a new instance of `Cache` with a given duration.
    pub fn new(duration: Duration) -> Cache {
        Cache { duration: duration }
    }

    fn handle<P: AsRef<Path>>(&self, req: &mut Request, path: P) -> IronResult<Response> {
        use iron::headers::{IfModifiedSince, HttpDate};

        let path = path.as_ref();

        let last_modified_time = match fs::metadata(path) {
            Err(error) => return Err(IronError::new(error, status::InternalServerError)),
            Ok(metadata) => {
                use filetime::FileTime;

                let time = FileTime::from_last_modification_time(&metadata);
                Timespec::new(time.seconds() as i64, time.nanoseconds() as i32)
            },
        };

        let if_modified_since = match req.headers.get::<IfModifiedSince>().cloned() {
            None => return self.response_with_cache(req, path, last_modified_time),
            Some(IfModifiedSince(HttpDate(time))) => time.to_timespec(),
        };

        if last_modified_time <= if_modified_since {
            Ok(Response::with(status::NotModified))
        } else {
            self.response_with_cache(req, path, last_modified_time)
        }
    }

    fn response_with_cache<P: AsRef<Path>>(&self,
                                           req: &mut Request,
                                           path: P,
                                           modified: Timespec) -> IronResult<Response> {
        use iron::headers::{CacheControl, LastModified, CacheDirective, HttpDate};
        use iron::headers::{ContentLength, ContentType};
        use iron::method::Method;
        use iron::mime::{Mime, TopLevel, SubLevel};
        use iron::modifiers::Header;

        let seconds = self.duration.as_secs() as u32;
        let cache = vec![CacheDirective::Public, CacheDirective::MaxAge(seconds)];
        let metadata = fs::metadata(path.as_ref());

        let metadata = try!(metadata.map_err(|e| IronError::new(e, status::InternalServerError)));

        let mut response = if req.method == Method::Head {
            let has_ct = req.headers.get::<ContentType>();
            let cont_type = match has_ct {
                None => ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])),
                Some(t) => t.clone()
            };
            Response::with((status::Ok, Header(cont_type), Header(ContentLength(metadata.len()))))
        } else {
            Response::with((status::Ok, path.as_ref()))
        };

        response.headers.set(CacheControl(cache));
        response.headers.set(LastModified(HttpDate(time::at(modified))));

        Ok(response)
    }
}

#[cfg(feature = "cache")]
impl Modifier<Static> for Cache {
    fn modify(self, static_handler: &mut Static) {
        static_handler.cache = Some(self);
    }
}

/// Thrown if no file is found. It is always accompanied by a NotFound response.
#[derive(Debug)]
pub struct NoFile;

impl Error for NoFile {
    fn description(&self) -> &str { "File not found" }
}

impl fmt::Display for NoFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}
<|endoftext|>


<commit_before>//! A basic `Variable` implementation.
//!
//! `FunctionBuilderContext`, `FunctionBuilder`, and related types have a `Variable`
//! type parameter, to allow frontends that identify variables with
//! their own index types to use them directly. Frontends which don't
//! can use the `Variable` defined here.

use core::u32;
use cranelift_codegen::entity::EntityRef;

///! An opaque reference to a variable.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Variable(u32);

impl Variable {
    /// Create a new Variable with the given index.
    pub fn with_u32(index: u32) -> Self {
        debug_assert!(index < u32::MAX);
        Self(index)
    }
}

impl EntityRef for Variable {
    fn new(index: usize) -> Self {
        debug_assert!(index < (u32::MAX as usize));
        Self(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}
<commit_msg>Update outdated documentation<commit_after>//! A basic `Variable` implementation.
//!
//! Frontends can use any indexing scheme they see fit and
//! generate the appropriate `Variable` instances.

use core::u32;
use cranelift_codegen::entity::EntityRef;

///! An opaque reference to a variable.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Variable(u32);

impl Variable {
    /// Create a new Variable with the given index.
    pub fn with_u32(index: u32) -> Self {
        debug_assert!(index < u32::MAX);
        Self(index)
    }
}

impl EntityRef for Variable {
    fn new(index: usize) -> Self {
        debug_assert!(index < (u32::MAX as usize));
        Self(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}
<|endoftext|>


<commit_before>// # References
//
// - Section 7.4 "Hints" of ACLE
// - Section 7.7 "NOP" of ACLE

/// Generates a WFI (wait for interrupt) hint instruction, or nothing.
///
/// The WFI instruction allows (but does not require) the processor to enter a
/// low-power state until one of a number of asynchronous events occurs.
// Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M
// LLVM says "instruction requires: armv6k"
#[cfg(any(target_feature = "v6k", target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn __wfi() {
    hint(HINT_WFI);
}

/// Generates a WFE (wait for event) hint instruction, or nothing.
///
/// The WFE instruction allows (but does not require) the processor to enter a
/// low-power state until some event occurs such as a SEV being issued by
/// another processor.
// Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M
// LLVM says "instruction requires: armv6k"
#[cfg(any(target_feature = "v6k", target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn __wfe() {
    hint(HINT_WFE);
}

/// Generates a SEV (send a global event) hint instruction.
///
/// This causes an event to be signaled to all processors in a multiprocessor
/// system. It is a NOP on a uniprocessor system.
// Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M, 7-M
// LLVM says "instruction requires: armv6k"
#[cfg(any(target_feature = "v6k", target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn __sev() {
    hint(HINT_SEV);
}

/// Generates a send a local event hint instruction.
///
/// This causes an event to be signaled to only the processor executing this
/// instruction. In a multiprocessor system, it is not required to affect the
/// other processors.
// LLVM says "instruction requires: armv8"
#[cfg(target_arch = "aarch64")]
#[inline(always)]
pub unsafe fn __sevl() {
    hint(HINT_SEVL);
}

/// Generates a YIELD hint instruction.
///
/// This enables multithreading software to indicate to the hardware that it is
/// performing a task, for example a spin-lock, that could be swapped out to
/// improve overall system performance.
// Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M
// LLVM says "instruction requires: armv6k"
#[cfg(any(target_feature = "v6k", target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn __yield() {
    hint(HINT_YIELD);
}

/// Generates a DBG instruction.
///
/// This provides a hint to debugging and related systems. The argument must be
/// a constant integer from 0 to 15 inclusive. See implementation documentation
/// for the effect (if any) of this instruction and the meaning of the
/// argument. This is available only when compliling for AArch32.
// Section 10.1 of ACLE says that the supported arches are: 7, 7-M
// "The DBG hint instruction is added in ARMv7. It is UNDEFINED in the ARMv6 base architecture, and
// executes as a NOP instruction in ARMv6K and ARMv6T2." - ARM Architecture Reference Manual ARMv7-A
// and ARMv7-R edition (ARM DDI 0406C.c) sections D12.4.1 "ARM instruction set support" and D12.4.2
// "Thumb instruction set support"
#[cfg(target_feature = "v7")]
#[inline(always)]
#[rustc_args_required_const(0)]
pub unsafe fn __dbg(imm4: u32) {
    macro_rules! call {
        ($imm4:expr) => {
            asm!(concat!("DBG ", stringify!($imm4)) : : : : "volatile")
        }
    }

    match imm4 & 0b1111 {
        0 => call!(0),
        1 => call!(1),
        2 => call!(2),
        3 => call!(3),
        4 => call!(4),
        5 => call!(5),
        6 => call!(6),
        7 => call!(7),
        8 => call!(8),
        9 => call!(9),
        10 => call!(10),
        11 => call!(11),
        12 => call!(12),
        13 => call!(13),
        14 => call!(14),
        _ => call!(15),
    }
}

/// Generates an unspecified no-op instruction.
///
/// Note that not all architectures provide a distinguished NOP instruction. On
/// those that do, it is unspecified whether this intrinsic generates it or
/// another instruction. It is not guaranteed that inserting this instruction
/// will increase execution time.
#[inline(always)]
pub unsafe fn __nop() {
    asm!("NOP" : : : : "volatile")
}

extern "C" {
    #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.hint")]
    #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.hint")]
    fn hint(_: i32);
}

// from LLVM 7.0.1's lib/Target/ARM/{ARMInstrThumb,ARMInstrInfo,ARMInstrThumb2}.td
const HINT_NOP: i32 = 0;
const HINT_YIELD: i32 = 1;
const HINT_WFE: i32 = 2;
const HINT_WFI: i32 = 3;
const HINT_SEV: i32 = 4;
const HINT_SEVL: i32 = 5;
<commit_msg>acle/hints: most hints require 'v6' rather than 'v6k'<commit_after>// # References
//
// - Section 7.4 "Hints" of ACLE
// - Section 7.7 "NOP" of ACLE

/// Generates a WFI (wait for interrupt) hint instruction, or nothing.
///
/// The WFI instruction allows (but does not require) the processor to enter a
/// low-power state until one of a number of asynchronous events occurs.
// Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M
// LLVM says "instruction requires: armv6k"
#[cfg(any(target_feature = "v6", target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn __wfi() {
    hint(HINT_WFI);
}

/// Generates a WFE (wait for event) hint instruction, or nothing.
///
/// The WFE instruction allows (but does not require) the processor to enter a
/// low-power state until some event occurs such as a SEV being issued by
/// another processor.
// Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M
// LLVM says "instruction requires: armv6k"
#[cfg(any(target_feature = "v6", target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn __wfe() {
    hint(HINT_WFE);
}

/// Generates a SEV (send a global event) hint instruction.
///
/// This causes an event to be signaled to all processors in a multiprocessor
/// system. It is a NOP on a uniprocessor system.
// Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M, 7-M
// LLVM says "instruction requires: armv6k"
#[cfg(any(target_feature = "v6", target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn __sev() {
    hint(HINT_SEV);
}

/// Generates a send a local event hint instruction.
///
/// This causes an event to be signaled to only the processor executing this
/// instruction. In a multiprocessor system, it is not required to affect the
/// other processors.
// LLVM says "instruction requires: armv8"
#[cfg(target_arch = "aarch64")]
#[inline(always)]
pub unsafe fn __sevl() {
    hint(HINT_SEVL);
}

/// Generates a YIELD hint instruction.
///
/// This enables multithreading software to indicate to the hardware that it is
/// performing a task, for example a spin-lock, that could be swapped out to
/// improve overall system performance.
// Section 10.1 of ACLE says that the supported arches are: 8, 6K, 6-M
// LLVM says "instruction requires: armv6k"
#[cfg(any(target_feature = "v6", target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn __yield() {
    hint(HINT_YIELD);
}

/// Generates a DBG instruction.
///
/// This provides a hint to debugging and related systems. The argument must be
/// a constant integer from 0 to 15 inclusive. See implementation documentation
/// for the effect (if any) of this instruction and the meaning of the
/// argument. This is available only when compliling for AArch32.
// Section 10.1 of ACLE says that the supported arches are: 7, 7-M
// "The DBG hint instruction is added in ARMv7. It is UNDEFINED in the ARMv6 base architecture, and
// executes as a NOP instruction in ARMv6K and ARMv6T2." - ARM Architecture Reference Manual ARMv7-A
// and ARMv7-R edition (ARM DDI 0406C.c) sections D12.4.1 "ARM instruction set support" and D12.4.2
// "Thumb instruction set support"
#[cfg(target_feature = "v7")]
#[inline(always)]
#[rustc_args_required_const(0)]
pub unsafe fn __dbg(imm4: u32) {
    macro_rules! call {
        ($imm4:expr) => {
            asm!(concat!("DBG ", stringify!($imm4)) : : : : "volatile")
        }
    }

    match imm4 & 0b1111 {
        0 => call!(0),
        1 => call!(1),
        2 => call!(2),
        3 => call!(3),
        4 => call!(4),
        5 => call!(5),
        6 => call!(6),
        7 => call!(7),
        8 => call!(8),
        9 => call!(9),
        10 => call!(10),
        11 => call!(11),
        12 => call!(12),
        13 => call!(13),
        14 => call!(14),
        _ => call!(15),
    }
}

/// Generates an unspecified no-op instruction.
///
/// Note that not all architectures provide a distinguished NOP instruction. On
/// those that do, it is unspecified whether this intrinsic generates it or
/// another instruction. It is not guaranteed that inserting this instruction
/// will increase execution time.
#[inline(always)]
pub unsafe fn __nop() {
    asm!("NOP" : : : : "volatile")
}

extern "C" {
    #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.hint")]
    #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.hint")]
    fn hint(_: i32);
}

// from LLVM 7.0.1's lib/Target/ARM/{ARMInstrThumb,ARMInstrInfo,ARMInstrThumb2}.td
const HINT_NOP: i32 = 0;
const HINT_YIELD: i32 = 1;
const HINT_WFE: i32 = 2;
const HINT_WFI: i32 = 3;
const HINT_SEV: i32 = 4;
const HINT_SEVL: i32 = 5;
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::cmp::min;
use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64 {
    // Stein's binary GCD algorithm
    // Base cases: gcd(n, 0) = gcd(0, n) = n
    if u == 0 {
        return v;
    } else if v == 0 {
        return u;
    }

    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
    // 2ᵏ is the greatest power of two that divides both u and v
    let k = {
        let i = u.trailing_zeros();
        let j = v.trailing_zeros();
        u >>= i;
        v >>= j;
        min(i, j)
    };

    loop {
        // Loop invariant: u and v are odd
        debug_assert!(u % 2 == 1, "u = {} is even", u);
        debug_assert!(v % 2 == 1, "v = {} is even", v);

        // gcd(u, v) = gcd(|u - v|, min(u, v))
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;

        if v == 0 {
            // Reached the base case; gcd is 2ᵏ u
            return u << k;
        }

        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
        v >>= v.trailing_zeros();
    }
}

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

    quickcheck! {
        fn euclidean(a: u64, b: u64) -> bool {
            // Test against the Euclidean algorithm
            let g = {
                let (mut a, mut b) = (a, b);
                while b > 0 {
                    a %= b;
                    swap(&mut a, &mut b);
                }
                a
            };
            gcd(a, b) == g
        }

        fn one(a: u64) -> bool {
            gcd(1, a) == 1
        }

        fn zero(a: u64) -> bool {
            gcd(0, a) == a
        }

        fn divisor(a: u64, b: u64) -> () {
            // Test that gcd(a, b) divides a and b, unless a == b == 0
            if a == 0 && b == 0 { return; }

            let g = gcd(a, b);
            assert_eq!(a % g, 0);
            assert_eq!(b % g, 0);
        }

        fn commutative(a: u64, b: u64) -> bool {
            gcd(a, b) == gcd(b, a)
        }

        fn associative(a: u64, b: u64, c: u64) -> bool {
            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
        }

        fn scalar_multiplication(a: u64, b: u64, k: u64) -> bool {
            gcd(k * a, k * b) == k * gcd(a, b)
        }

        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
        }

        fn linearity(a: u64, b: u64, k: u64) -> bool {
            gcd(a + k * b, b) == gcd(a, b)
        }
    }
}
<commit_msg>tests ~ (factor) refactor `divisor()` to return quickcheck::TestResult<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::cmp::min;
use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64 {
    // Stein's binary GCD algorithm
    // Base cases: gcd(n, 0) = gcd(0, n) = n
    if u == 0 {
        return v;
    } else if v == 0 {
        return u;
    }

    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
    // 2ᵏ is the greatest power of two that divides both u and v
    let k = {
        let i = u.trailing_zeros();
        let j = v.trailing_zeros();
        u >>= i;
        v >>= j;
        min(i, j)
    };

    loop {
        // Loop invariant: u and v are odd
        debug_assert!(u % 2 == 1, "u = {} is even", u);
        debug_assert!(v % 2 == 1, "v = {} is even", v);

        // gcd(u, v) = gcd(|u - v|, min(u, v))
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;

        if v == 0 {
            // Reached the base case; gcd is 2ᵏ u
            return u << k;
        }

        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
        v >>= v.trailing_zeros();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use quickcheck::{quickcheck, TestResult};

    quickcheck! {
        fn euclidean(a: u64, b: u64) -> bool {
            // Test against the Euclidean algorithm
            let g = {
                let (mut a, mut b) = (a, b);
                while b > 0 {
                    a %= b;
                    swap(&mut a, &mut b);
                }
                a
            };
            gcd(a, b) == g
        }

        fn one(a: u64) -> bool {
            gcd(1, a) == 1
        }

        fn zero(a: u64) -> bool {
            gcd(0, a) == a
        }

        fn divisor(a: u64, b: u64) -> TestResult {
            // Test that gcd(a, b) divides a and b, unless a == b == 0
            if a == 0 && b == 0 { return TestResult::discard(); } // restrict test domain to !(a == b == 0)

            let g = gcd(a, b);
            TestResult::from_bool( g != 0 && a % g == 0 && b % g == 0 )
        }

        fn commutative(a: u64, b: u64) -> bool {
            gcd(a, b) == gcd(b, a)
        }

        fn associative(a: u64, b: u64, c: u64) -> bool {
            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
        }

        fn scalar_multiplication(a: u64, b: u64, k: u64) -> bool {
            gcd(k * a, k * b) == k * gcd(a, b)
        }

        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
        }

        fn linearity(a: u64, b: u64, k: u64) -> bool {
            gcd(a + k * b, b) == gcd(a, b)
        }
    }
}
<|endoftext|>


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

use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, ImageMask, ImageRendering};
use api::{LayerPoint, LayerRect, LayoutPoint, LayoutVector2D, LocalClip};
use api::{DevicePixelScale, LayerToWorldTransform};
use border::{BorderCornerClipSource, ensure_no_corner_overlap};
use ellipse::Ellipse;
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
use prim_store::{ClipData, ImageMaskData};
use resource_cache::ResourceCache;
use util::{MaxRect, MatrixHelpers, calculate_screen_bounding_rect, extract_inner_rect_safe};

pub type ClipStore = FreeList<ClipSources>;
pub type ClipSourcesHandle = FreeListHandle<ClipSources>;
pub type ClipSourcesWeakHandle = WeakFreeListHandle<ClipSources>;

#[derive(Clone, Debug)]
pub struct ClipRegion {
    pub main: LayerRect,
    pub image_mask: Option<ImageMask>,
    pub complex_clips: Vec<ComplexClipRegion>,
}

impl ClipRegion {
    pub fn create_for_clip_node(
        rect: LayerRect,
        mut complex_clips: Vec<ComplexClipRegion>,
        mut image_mask: Option<ImageMask>,
        reference_frame_relative_offset: &LayoutVector2D,
    ) -> ClipRegion {
        let rect = rect.translate(reference_frame_relative_offset);

        if let Some(ref mut image_mask) = image_mask {
            image_mask.rect = image_mask.rect.translate(reference_frame_relative_offset);
        }

        for complex_clip in complex_clips.iter_mut() {
            complex_clip.rect = complex_clip.rect.translate(reference_frame_relative_offset);
        }

        ClipRegion {
            main: rect,
            image_mask,
            complex_clips,
        }
    }

    pub fn create_for_clip_node_with_local_clip(
        local_clip: &LocalClip,
        reference_frame_relative_offset: &LayoutVector2D
    ) -> ClipRegion {
        let complex_clips = match local_clip {
            &LocalClip::Rect(_) => Vec::new(),
            &LocalClip::RoundedRect(_, ref region) => vec![region.clone()],
        };
        ClipRegion::create_for_clip_node(
            *local_clip.clip_rect(),
            complex_clips,
            None,
            reference_frame_relative_offset
        )
    }
}

#[derive(Debug)]
pub enum ClipSource {
    Rectangle(LayerRect),
    RoundedRectangle(LayerRect, BorderRadius, ClipMode),
    Image(ImageMask),
    /// TODO(gw): This currently only handles dashed style
    /// clips, where the border style is dashed for both
    /// adjacent border edges. Expand to handle dotted style
    /// and different styles per edge.
    BorderCorner(BorderCornerClipSource),
}

impl From<ClipRegion> for ClipSources {
    fn from(region: ClipRegion) -> ClipSources {
        let mut clips = Vec::new();

        if let Some(info) = region.image_mask {
            clips.push(ClipSource::Image(info));
        }

        clips.push(ClipSource::Rectangle(region.main));

        for complex in region.complex_clips {
            clips.push(ClipSource::new_rounded_rect(
                complex.rect,
                complex.radii,
                complex.mode,
            ));
        }

        ClipSources::new(clips)
    }
}

impl ClipSource {
    pub fn new_rounded_rect(
        rect: LayerRect,
        mut radii: BorderRadius,
        clip_mode: ClipMode
    ) -> ClipSource {
        ensure_no_corner_overlap(&mut radii, &rect);
        ClipSource::RoundedRectangle(
            rect,
            radii,
            clip_mode,
        )
    }

    pub fn contains(&self, point: &LayerPoint) -> bool {
        // We currently do not handle all BorderCorners, because they aren't used for
        // ClipScrollNodes and this method is only used during hit testing.
        match self {
            &ClipSource::Rectangle(ref rectangle) => rectangle.contains(point),
            &ClipSource::RoundedRectangle(rect, radii, ClipMode::Clip) =>
                rounded_rectangle_contains_point(point, &rect, &radii),
            &ClipSource::RoundedRectangle(rect, radii, ClipMode::ClipOut) =>
                !rounded_rectangle_contains_point(point, &rect, &radii),
            &ClipSource::Image(mask) => mask.rect.contains(point),
            &ClipSource::BorderCorner(_) =>
                unreachable!("Tried to call contains on a BorderCornerr."),
        }
    }

}

#[derive(Debug)]
pub struct ClipSources {
    pub clips: Vec<(ClipSource, GpuCacheHandle)>,
    pub local_inner_rect: LayerRect,
    pub local_outer_rect: Option<LayerRect>
}

impl ClipSources {
    pub fn new(clips: Vec<ClipSource>) -> ClipSources {
        let (local_inner_rect, local_outer_rect) = Self::calculate_inner_and_outer_rects(&clips);

        let clips = clips
            .into_iter()
            .map(|clip| (clip, GpuCacheHandle::new()))
            .collect();

        ClipSources {
            clips,
            local_inner_rect,
            local_outer_rect,
        }
    }

    pub fn clips(&self) -> &[(ClipSource, GpuCacheHandle)] {
        &self.clips
    }

    fn calculate_inner_and_outer_rects(clips: &Vec<ClipSource>) -> (LayerRect, Option<LayerRect>) {
        if clips.is_empty() {
            return (LayerRect::zero(), None);
        }

        // Depending on the complexity of the clip, we may either know the outer and/or inner
        // rect, or neither or these.  In the case of a clip-out, we currently set the mask bounds
        // to be unknown. This is conservative, but ensures correctness. In the future we can make
        // this a lot more clever with some proper region handling.
        let mut local_outer = Some(LayerRect::max_rect());
        let mut local_inner = local_outer;
        let mut can_calculate_inner_rect = true;
        let mut can_calculate_outer_rect = true;
        for source in clips {
            match *source {
                ClipSource::Image(ref mask) => {
                    if !mask.repeat {
                        local_outer = local_outer.and_then(|r| r.intersection(&mask.rect));
                        can_calculate_inner_rect = false;
                    } else {
                        can_calculate_inner_rect = false;
                        can_calculate_outer_rect = false;
                        break;
                    }
                    local_inner = None;
                }
                ClipSource::Rectangle(rect) => {
                    local_outer = local_outer.and_then(|r| r.intersection(&rect));
                    local_inner = local_inner.and_then(|r| r.intersection(&rect));
                }
                ClipSource::RoundedRectangle(ref rect, ref radius, mode) => {
                    // Once we encounter a clip-out, we just assume the worst
                    // case clip mask size, for now.
                    if mode == ClipMode::ClipOut {
                        can_calculate_inner_rect = false;
                        can_calculate_outer_rect = false;
                        break;
                    }

                    local_outer = local_outer.and_then(|r| r.intersection(rect));

                    let inner_rect = extract_inner_rect_safe(rect, radius);
                    local_inner = local_inner
                        .and_then(|r| inner_rect.and_then(|ref inner| r.intersection(inner)));
                }
                ClipSource::BorderCorner { .. } => {
                    can_calculate_inner_rect = false;
                    can_calculate_outer_rect = false;
                    break;
                }
            }
        }

        let outer = match can_calculate_outer_rect {
            true => local_outer,
            false => None,
        };

        let inner = match can_calculate_inner_rect {
            true => local_inner.unwrap_or(LayerRect::zero()),
            false => LayerRect::zero(),
        };

        (inner, outer)
    }

    pub fn update(
        &mut self,
        gpu_cache: &mut GpuCache,
        resource_cache: &mut ResourceCache,
    ) {
        for &mut (ref mut source, ref mut handle) in &mut self.clips {
            if let Some(mut request) = gpu_cache.request(handle) {
                match *source {
                    ClipSource::Image(ref mask) => {
                        let data = ImageMaskData { local_rect: mask.rect };
                        data.write_gpu_blocks(request);
                    }
                    ClipSource::Rectangle(rect) => {
                        let data = ClipData::uniform(rect, 0.0, ClipMode::Clip);
                        data.write(&mut request);
                    }
                    ClipSource::RoundedRectangle(ref rect, ref radius, mode) => {
                        let data = ClipData::rounded_rect(rect, radius, mode);
                        data.write(&mut request);
                    }
                    ClipSource::BorderCorner(ref mut source) => {
                        source.write(request);
                    }
                }
            }

            if let ClipSource::Image(ref mask) = *source {
                resource_cache.request_image(mask.image, ImageRendering::Auto, None, gpu_cache);
            }
        }
    }

    /// Whether or not this ClipSources has any clips (does any clipping).
    pub fn has_clips(&self) -> bool {
        !self.clips.is_empty()
    }

    pub fn get_screen_bounds(
        &self,
        transform: &LayerToWorldTransform,
        device_pixel_scale: DevicePixelScale,
    ) -> (DeviceIntRect, Option<DeviceIntRect>) {
        // If this translation isn't axis aligned or has a perspective component, don't try to
        // calculate the inner rectangle. The rectangle that we produce would include potentially
        // clipped screen area.
        // TODO(mrobinson): We should eventually try to calculate an inner region or some inner
        // rectangle so that we can do screen inner rectangle optimizations for these kind of
        // cilps.
        let can_calculate_inner_rect =
            transform.preserves_2d_axis_alignment() && !transform.has_perspective_component();
        let screen_inner_rect = if can_calculate_inner_rect {
            calculate_screen_bounding_rect(transform, &self.local_inner_rect, device_pixel_scale)
        } else {
            DeviceIntRect::zero()
        };

        let screen_outer_rect = self.local_outer_rect.map(|outer_rect|
            calculate_screen_bounding_rect(transform, &outer_rect, device_pixel_scale)
        );

        (screen_inner_rect, screen_outer_rect)
    }
}

/// Represents a local rect and a device space
/// rectangles that are either outside or inside bounds.
#[derive(Clone, Debug, PartialEq)]
pub struct Geometry {
    pub local_rect: LayerRect,
    pub device_rect: DeviceIntRect,
}

impl From<LayerRect> for Geometry {
    fn from(local_rect: LayerRect) -> Self {
        Geometry {
            local_rect,
            device_rect: DeviceIntRect::zero(),
        }
    }
}

pub trait Contains {
    fn contains(&self, point: &LayoutPoint) -> bool;
}

impl Contains for LocalClip {
    fn contains(&self, point: &LayoutPoint) -> bool {
        if !self.clip_rect().contains(point) {
            return false;
        }
        match self {
            &LocalClip::Rect(..) => true,
            &LocalClip::RoundedRect(_, complex_clip) => complex_clip.contains(point),
        }
    }
}

impl Contains for ComplexClipRegion {
    fn contains(&self, point: &LayoutPoint) -> bool {
        rounded_rectangle_contains_point(point, &self.rect, &self.radii)
    }
}

fn rounded_rectangle_contains_point(point: &LayoutPoint,
                                    rect: &LayerRect,
                                    radii: &BorderRadius)
                                    -> bool {
    if !rect.contains(point) {
        return false;
    }

    let top_left_center = rect.origin + radii.top_left.to_vector();
    if top_left_center.x > point.x && top_left_center.y > point.y &&
       !Ellipse::new(radii.top_left).contains(*point - top_left_center.to_vector()) {
        return false;
    }

    let bottom_right_center = rect.bottom_right() - radii.bottom_right.to_vector();
    if bottom_right_center.x < point.x && bottom_right_center.y < point.y &&
       !Ellipse::new(radii.bottom_right).contains(*point - bottom_right_center.to_vector()) {
        return false;
    }

    let top_right_center = rect.top_right() +
                           LayoutVector2D::new(-radii.top_right.width, radii.top_right.height);
    if top_right_center.x < point.x && top_right_center.y > point.y &&
       !Ellipse::new(radii.top_right).contains(*point - top_right_center.to_vector()) {
        return false;
    }

    let bottom_left_center = rect.bottom_left() +
                             LayoutVector2D::new(radii.bottom_left.width, -radii.bottom_left.height);
    if bottom_left_center.x > point.x && bottom_left_center.y < point.y &&
       !Ellipse::new(radii.bottom_left).contains(*point - bottom_left_center.to_vector()) {
        return false;
    }

    true
}
<commit_msg>Less conservative calculation of clip outer rectangle<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, ImageMask, ImageRendering};
use api::{LayerPoint, LayerRect, LayoutPoint, LayoutVector2D, LocalClip};
use api::{DevicePixelScale, LayerToWorldTransform};
use border::{BorderCornerClipSource, ensure_no_corner_overlap};
use ellipse::Ellipse;
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
use prim_store::{ClipData, ImageMaskData};
use resource_cache::ResourceCache;
use util::{MaxRect, MatrixHelpers, calculate_screen_bounding_rect, extract_inner_rect_safe};

pub type ClipStore = FreeList<ClipSources>;
pub type ClipSourcesHandle = FreeListHandle<ClipSources>;
pub type ClipSourcesWeakHandle = WeakFreeListHandle<ClipSources>;

#[derive(Clone, Debug)]
pub struct ClipRegion {
    pub main: LayerRect,
    pub image_mask: Option<ImageMask>,
    pub complex_clips: Vec<ComplexClipRegion>,
}

impl ClipRegion {
    pub fn create_for_clip_node(
        rect: LayerRect,
        mut complex_clips: Vec<ComplexClipRegion>,
        mut image_mask: Option<ImageMask>,
        reference_frame_relative_offset: &LayoutVector2D,
    ) -> ClipRegion {
        let rect = rect.translate(reference_frame_relative_offset);

        if let Some(ref mut image_mask) = image_mask {
            image_mask.rect = image_mask.rect.translate(reference_frame_relative_offset);
        }

        for complex_clip in complex_clips.iter_mut() {
            complex_clip.rect = complex_clip.rect.translate(reference_frame_relative_offset);
        }

        ClipRegion {
            main: rect,
            image_mask,
            complex_clips,
        }
    }

    pub fn create_for_clip_node_with_local_clip(
        local_clip: &LocalClip,
        reference_frame_relative_offset: &LayoutVector2D
    ) -> ClipRegion {
        let complex_clips = match local_clip {
            &LocalClip::Rect(_) => Vec::new(),
            &LocalClip::RoundedRect(_, ref region) => vec![region.clone()],
        };
        ClipRegion::create_for_clip_node(
            *local_clip.clip_rect(),
            complex_clips,
            None,
            reference_frame_relative_offset
        )
    }
}

#[derive(Debug)]
pub enum ClipSource {
    Rectangle(LayerRect),
    RoundedRectangle(LayerRect, BorderRadius, ClipMode),
    Image(ImageMask),
    /// TODO(gw): This currently only handles dashed style
    /// clips, where the border style is dashed for both
    /// adjacent border edges. Expand to handle dotted style
    /// and different styles per edge.
    BorderCorner(BorderCornerClipSource),
}

impl From<ClipRegion> for ClipSources {
    fn from(region: ClipRegion) -> ClipSources {
        let mut clips = Vec::new();

        if let Some(info) = region.image_mask {
            clips.push(ClipSource::Image(info));
        }

        clips.push(ClipSource::Rectangle(region.main));

        for complex in region.complex_clips {
            clips.push(ClipSource::new_rounded_rect(
                complex.rect,
                complex.radii,
                complex.mode,
            ));
        }

        ClipSources::new(clips)
    }
}

impl ClipSource {
    pub fn new_rounded_rect(
        rect: LayerRect,
        mut radii: BorderRadius,
        clip_mode: ClipMode
    ) -> ClipSource {
        ensure_no_corner_overlap(&mut radii, &rect);
        ClipSource::RoundedRectangle(
            rect,
            radii,
            clip_mode,
        )
    }

    pub fn contains(&self, point: &LayerPoint) -> bool {
        // We currently do not handle all BorderCorners, because they aren't used for
        // ClipScrollNodes and this method is only used during hit testing.
        match self {
            &ClipSource::Rectangle(ref rectangle) => rectangle.contains(point),
            &ClipSource::RoundedRectangle(rect, radii, ClipMode::Clip) =>
                rounded_rectangle_contains_point(point, &rect, &radii),
            &ClipSource::RoundedRectangle(rect, radii, ClipMode::ClipOut) =>
                !rounded_rectangle_contains_point(point, &rect, &radii),
            &ClipSource::Image(mask) => mask.rect.contains(point),
            &ClipSource::BorderCorner(_) =>
                unreachable!("Tried to call contains on a BorderCornerr."),
        }
    }

}

#[derive(Debug)]
pub struct ClipSources {
    pub clips: Vec<(ClipSource, GpuCacheHandle)>,
    pub local_inner_rect: LayerRect,
    pub local_outer_rect: Option<LayerRect>
}

impl ClipSources {
    pub fn new(clips: Vec<ClipSource>) -> ClipSources {
        let (local_inner_rect, local_outer_rect) = Self::calculate_inner_and_outer_rects(&clips);

        let clips = clips
            .into_iter()
            .map(|clip| (clip, GpuCacheHandle::new()))
            .collect();

        ClipSources {
            clips,
            local_inner_rect,
            local_outer_rect,
        }
    }

    pub fn clips(&self) -> &[(ClipSource, GpuCacheHandle)] {
        &self.clips
    }

    fn calculate_inner_and_outer_rects(clips: &Vec<ClipSource>) -> (LayerRect, Option<LayerRect>) {
        if clips.is_empty() {
            return (LayerRect::zero(), None);
        }

        // Depending on the complexity of the clip, we may either know the outer and/or inner
        // rect, or neither or these.  In the case of a clip-out, we currently set the mask bounds
        // to be unknown. This is conservative, but ensures correctness. In the future we can make
        // this a lot more clever with some proper region handling.
        let mut local_outer = Some(LayerRect::max_rect());
        let mut local_inner = local_outer;
        let mut can_calculate_inner_rect = true;
        let mut can_calculate_outer_rect = false;
        for source in clips {
            match *source {
                ClipSource::Image(ref mask) => {
                    if !mask.repeat {
                        can_calculate_outer_rect = true;
                        local_outer = local_outer.and_then(|r| r.intersection(&mask.rect));
                    }
                    local_inner = None;
                }
                ClipSource::Rectangle(rect) => {
                    can_calculate_outer_rect = true;
                    local_outer = local_outer.and_then(|r| r.intersection(&rect));
                    local_inner = local_inner.and_then(|r| r.intersection(&rect));
                }
                ClipSource::RoundedRectangle(ref rect, ref radius, mode) => {
                    // Once we encounter a clip-out, we just assume the worst
                    // case clip mask size, for now.
                    if mode == ClipMode::ClipOut {
                        can_calculate_inner_rect = false;
                        break;
                    }

                    can_calculate_outer_rect = true;
                    local_outer = local_outer.and_then(|r| r.intersection(rect));

                    let inner_rect = extract_inner_rect_safe(rect, radius);
                    local_inner = local_inner
                        .and_then(|r| inner_rect.and_then(|ref inner| r.intersection(inner)));
                }
                ClipSource::BorderCorner { .. } => {
                    can_calculate_inner_rect = false;
                    break;
                }
            }
        }

        let outer = match can_calculate_outer_rect {
            true => Some(local_outer.unwrap_or_else(LayerRect::zero)),
            false => None,
        };

        let inner = match can_calculate_inner_rect {
            true => local_inner.unwrap_or_else(LayerRect::zero),
            false => LayerRect::zero(),
        };

        (inner, outer)
    }

    pub fn update(
        &mut self,
        gpu_cache: &mut GpuCache,
        resource_cache: &mut ResourceCache,
    ) {
        for &mut (ref mut source, ref mut handle) in &mut self.clips {
            if let Some(mut request) = gpu_cache.request(handle) {
                match *source {
                    ClipSource::Image(ref mask) => {
                        let data = ImageMaskData { local_rect: mask.rect };
                        data.write_gpu_blocks(request);
                    }
                    ClipSource::Rectangle(rect) => {
                        let data = ClipData::uniform(rect, 0.0, ClipMode::Clip);
                        data.write(&mut request);
                    }
                    ClipSource::RoundedRectangle(ref rect, ref radius, mode) => {
                        let data = ClipData::rounded_rect(rect, radius, mode);
                        data.write(&mut request);
                    }
                    ClipSource::BorderCorner(ref mut source) => {
                        source.write(request);
                    }
                }
            }

            if let ClipSource::Image(ref mask) = *source {
                resource_cache.request_image(mask.image, ImageRendering::Auto, None, gpu_cache);
            }
        }
    }

    /// Whether or not this ClipSources has any clips (does any clipping).
    pub fn has_clips(&self) -> bool {
        !self.clips.is_empty()
    }

    pub fn get_screen_bounds(
        &self,
        transform: &LayerToWorldTransform,
        device_pixel_scale: DevicePixelScale,
    ) -> (DeviceIntRect, Option<DeviceIntRect>) {
        // If this translation isn't axis aligned or has a perspective component, don't try to
        // calculate the inner rectangle. The rectangle that we produce would include potentially
        // clipped screen area.
        // TODO(mrobinson): We should eventually try to calculate an inner region or some inner
        // rectangle so that we can do screen inner rectangle optimizations for these kind of
        // cilps.
        let can_calculate_inner_rect =
            transform.preserves_2d_axis_alignment() && !transform.has_perspective_component();
        let screen_inner_rect = if can_calculate_inner_rect {
            calculate_screen_bounding_rect(transform, &self.local_inner_rect, device_pixel_scale)
        } else {
            DeviceIntRect::zero()
        };

        let screen_outer_rect = self.local_outer_rect.map(|outer_rect|
            calculate_screen_bounding_rect(transform, &outer_rect, device_pixel_scale)
        );

        (screen_inner_rect, screen_outer_rect)
    }
}

/// Represents a local rect and a device space
/// rectangles that are either outside or inside bounds.
#[derive(Clone, Debug, PartialEq)]
pub struct Geometry {
    pub local_rect: LayerRect,
    pub device_rect: DeviceIntRect,
}

impl From<LayerRect> for Geometry {
    fn from(local_rect: LayerRect) -> Self {
        Geometry {
            local_rect,
            device_rect: DeviceIntRect::zero(),
        }
    }
}

pub trait Contains {
    fn contains(&self, point: &LayoutPoint) -> bool;
}

impl Contains for LocalClip {
    fn contains(&self, point: &LayoutPoint) -> bool {
        if !self.clip_rect().contains(point) {
            return false;
        }
        match self {
            &LocalClip::Rect(..) => true,
            &LocalClip::RoundedRect(_, complex_clip) => complex_clip.contains(point),
        }
    }
}

impl Contains for ComplexClipRegion {
    fn contains(&self, point: &LayoutPoint) -> bool {
        rounded_rectangle_contains_point(point, &self.rect, &self.radii)
    }
}

fn rounded_rectangle_contains_point(point: &LayoutPoint,
                                    rect: &LayerRect,
                                    radii: &BorderRadius)
                                    -> bool {
    if !rect.contains(point) {
        return false;
    }

    let top_left_center = rect.origin + radii.top_left.to_vector();
    if top_left_center.x > point.x && top_left_center.y > point.y &&
       !Ellipse::new(radii.top_left).contains(*point - top_left_center.to_vector()) {
        return false;
    }

    let bottom_right_center = rect.bottom_right() - radii.bottom_right.to_vector();
    if bottom_right_center.x < point.x && bottom_right_center.y < point.y &&
       !Ellipse::new(radii.bottom_right).contains(*point - bottom_right_center.to_vector()) {
        return false;
    }

    let top_right_center = rect.top_right() +
                           LayoutVector2D::new(-radii.top_right.width, radii.top_right.height);
    if top_right_center.x < point.x && top_right_center.y > point.y &&
       !Ellipse::new(radii.top_right).contains(*point - top_right_center.to_vector()) {
        return false;
    }

    let bottom_left_center = rect.bottom_left() +
                             LayoutVector2D::new(radii.bottom_left.width, -radii.bottom_left.height);
    if bottom_left_center.x > point.x && bottom_left_center.y < point.y &&
       !Ellipse::new(radii.bottom_left).contains(*point - bottom_left_center.to_vector()) {
        return false;
    }

    true
}
<|endoftext|>