<commit_before>
use geometry::Point;
use core::rand::RngUtil;
mod geometry;

//
// Cellule
//

struct Cell {
    center: Point,
    id: uint,
    radius: float,
    velocity: [float,..3],
    acc: [float,..3],
    generation: int,
    age: int
}

pub impl Cell {
    fn new(ident: uint) -> Cell {
        let radius = 1.0;
        //let r=rand::random::<float>();
        //io::println(fmt!("%f\n", r));
        let center : Point =rand::random();

        Cell{ center: center, id: ident, radius: radius, velocity: [0.0,0.0,0.0], acc: [0.0,0.0,0.0], generation: 0, age:0}
    }

    fn move(&self, tumeur: ~Crowd, dt: float) {
        io::println(fmt!("%d @ %f\n",tumeur.size() as int, dt));
    }

    fn replicate(&mut self, tumeur: ~Crowd, dt: float) {
        io::println(fmt!("%d @ %f\n",tumeur.size() as int, dt));

        self.age+=1;
    }
}

impl ToStr for Cell {
    fn to_str(&self) -> ~str {
        fmt!("%d @ (%f, %f)", self.id as int, self.center.x as float, self.center.y as float)
    }
}

#[test]
fn test_new() {
    let cell1=Cell::new(0);
    let cell2=Cell::new(1);
    assert!(cell1.center != cell2.center);
}
//
// Population
//

struct Crowd {
    cells : ~[@mut Cell],
    time : float
}

pub impl Crowd {
    fn new(init_pop : uint) -> Crowd {
        io::println(fmt!("Population initiale : %d\n",init_pop as int));

        let mut pop : ~[@mut Cell]=~[];
        for uint::range(1,init_pop+1) |num| {
            let lonely_one = @mut Cell::new(num);
            io::println(lonely_one.to_str());
            pop.push(copy lonely_one);
        }
        Crowd{ cells : pop, time: 0.0}
    }

    fn size(&self) -> uint {
        self.cells.len()
    }

    fn evolve(&self) {
        for self.cells.each |cell| {
            io::println(fmt!("Cell %d has moved !", cell.id as int));
        }
    }
}

#[test]
fn test_size() {
    let crowd=Crowd::new(13);
    assert!(crowd.size()==13);
}
<commit_msg>On code la mise à jour de la position vitesse etc qui sont maintenant des Point<commit_after>
use geometry::Point;
use core::rand::RngUtil;
mod geometry;

//
// Cellule
//

struct Cell {
    center: Point,
    id: uint,
    radius: float,
    velocity: Point,
    acc: Point,
    generation: int,
    age: int
}

pub impl Cell {
    fn new(ident: uint) -> Cell {
        let radius = 1.0;
        //let r=rand::random::<float>();
        //io::println(fmt!("%f\n", r));
        let center : Point =rand::random();

        Cell{ center: center, id: ident, radius: radius, velocity: Point::new(), acc: Point::new(), generation: 0, age:0}
    }

    fn move(&mut self, tumeur: &Crowd, dt: f64) {
        let old_acc = copy self.acc;

        // Nouvelle position
        self.center+=self.velocity+self.acc*(0.5*float::pow(dt,2.0) as f64);

        // Force aléatoire
        let F_alea: Point=rand::random();
        self.acc=F_alea*(0.0005 as f64);

        // Nouvelle vitesse
        let lambda : f64=5.0;
        let denom : f64 = 1.0/(1.0+lambda*dt/2.0);
        self.velocity=(self.velocity*(1.0-lambda*dt/2.0)+(self.acc+old_acc)*dt/(2.0 as f64))*denom;

    }

    fn replicate(&mut self, tumeur: &Crowd, dt: f64) {
        io::println(fmt!("%d @ %f\n",tumeur.size() as int, dt as float));

        self.age+=1;
    }
}

impl ToStr for Cell {
    fn to_str(&self) -> ~str {
        fmt!("%d @ (%f, %f)", self.id as int, self.center.x as float, self.center.y as float)
    }
}

#[test]
fn test_new() {
    let cell1=Cell::new(0);
    let cell2=Cell::new(1);
    assert!(cell1.center != cell2.center);
}
//
// Population
//

struct Crowd {
    cells : ~[@mut Cell],
    time : float
}

pub impl Crowd {
    fn new(init_pop : uint) -> Crowd {
        io::println(fmt!("Population initiale : %d\n",init_pop as int));

        let mut pop : ~[@mut Cell]=~[];
        for uint::range(1,init_pop+1) |num| {
            let lonely_one = @mut Cell::new(num);
            io::println(lonely_one.to_str());
            pop.push(copy lonely_one);
        }
        Crowd{ cells : pop, time: 0.0}
    }

    fn size(&self) -> uint {
        self.cells.len()
    }

    fn evolve(&self) {
        for self.cells.each |cell| {
            io::println(fmt!("Cell %d has moved !", cell.id as int));
        }
    }
}

#[test]
fn test_size() {
    let crowd=Crowd::new(13);
    assert!(crowd.size()==13);
}
<|endoftext|>


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

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

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

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

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

#[allow(ctypes)];

// Built-in traits

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

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

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

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

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

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

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

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

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

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

// Operator overloading

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// String utilities

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

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

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

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

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

    transmute(string)
}

// Legacy junk

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

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

// Failure

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

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

// Memory allocation

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

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

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

// Entry point

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

// The nonexistent garbage collector

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

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

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

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

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

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

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

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

// libc dependencies

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

// Rust intrinsic dependencies

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

<commit_msg>Add vector_exchange_malloc lang item<commit_after>// Copyright (c) 2006-2009 Graydon Hoare
// Copyright (c) 2009-2013 Mozilla Foundation

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

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

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

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

#[allow(ctypes)];

// Built-in traits

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

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

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

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

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

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

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

#[lang="vector_exchange_malloc"]

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

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

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

// Operator overloading

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// String utilities

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

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

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

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

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

    transmute(string)
}

// Legacy junk

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

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

// Failure

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

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

// Memory allocation

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

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

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

// Entry point

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

// The nonexistent garbage collector

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

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

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

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

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

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

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

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

// libc dependencies

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

// Rust intrinsic dependencies

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

<|endoftext|>


<commit_before>use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::str;
use std::fmt;

use curl::ErrCode;
use curl::http;

use regex::Regex;

use gateway::Gateway;

// Content of the external ip request.
const EXTERNAL_IP_REQUEST: &'static str =
"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">
    <SOAP-ENV:Body>
        <m:GetExternalIPAddress xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
        </m:GetExternalIPAddress>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>";

// Content of the external ip SOAPAction request header.
const SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress\"";

// Content of the add port mapping SOAPAction request header.
const ADD_PORT_SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping\"";

// Content of the delete port mapping SOAPAction request header.
const DELETE_PORT_SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping\"";

// Errors
#[derive(Debug)]
pub enum RequestError {
    ErrCode(ErrCode),
    InvalidResponse,
    IoError(io::Error),
}

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum PortMappingProtocol {
    TCP,
    UDP,
}

impl fmt::Display for PortMappingProtocol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            PortMappingProtocol::TCP => "TCP",
            PortMappingProtocol::UDP => "UDP",
        })
    }
}

impl From<ErrCode> for RequestError {
    fn from(err: ErrCode) -> RequestError {
        RequestError::ErrCode(err)
    }
}

impl From<io::Error> for RequestError {
    fn from(err: io::Error) -> RequestError {
        RequestError::IoError(err)
    }
}

// Get the external IP address.
pub fn get_external_ip(gateway: &Gateway) -> Result<Ipv4Addr, RequestError>  {
    let addr = gateway.addr.clone();
    let url = format!("http://{}:{}{}", addr.ip(), addr.port(),
                      gateway.control_url);
    let resp = try!(http::handle()
        .post(url, EXTERNAL_IP_REQUEST)
        .header("SOAPAction", SOAP_ACTION)
        .exec());
    let text = str::from_utf8(resp.get_body()).unwrap(); // TODO Shouldn't, but can fail.
    extract_address(text)
}

// Extract the address from the text.
fn extract_address(text: &str) -> Result<Ipv4Addr, RequestError> {
    let re = Regex::new(r"<NewExternalIPAddress>(\d+\.\d+\.\d+\.\d+)</NewExternalIPAddress>").unwrap();
    match re.captures(text) {
        None => Err(RequestError::InvalidResponse),
        Some(cap) => {
            match cap.at(1) {
                None => Err(RequestError::InvalidResponse),
                Some(ip) => Ok(ip.parse::<Ipv4Addr>().unwrap()),
            }
        },
    }
}

pub fn add_port(gateway: &Gateway, protocol: PortMappingProtocol,
                external_port: u16, local_addr: SocketAddr, lease_duration: u32,
                description: &str) -> Result<(), RequestError> {
    let url = format!("{}", gateway);
    let body = format!("<?xml version=\"1.0\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
<s:Body>
    <u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
        <NewProtocol>{}</NewProtocol>
        <NewExternalPort>{}</NewExternalPort>
        <NewInternalClient>{}</NewInternalClient>
        <NewInternalPort>{}</NewInternalPort>
        <NewLeaseDuration>{}</NewLeaseDuration>
        <NewPortMappingDescription>{}</NewPortMappingDescription>
        <NewEnabled>1</NewEnabled>
        <NewRemoteHost></NewRemoteHost>
    </u:AddPortMapping>
</s:Body>
</s:Envelope>
",
                       protocol, external_port, local_addr.ip(),
                       local_addr.port(), lease_duration, description);
    let resp = try!(http::handle()
                    .post(url, &body)
                    .header("Content-Type", "text/xml; charset=\"utf-8\"")
                    .header("SOAPAction", ADD_PORT_SOAP_ACTION)
                    .exec());
    let text = try!(str::from_utf8(resp.get_body())
                    .map_err(|_| RequestError::InvalidResponse));

    {
        let re = regex!("u:AddPortMappingResponse");
        if re.is_match(text) {
            Ok(())
        } else {
            Err(RequestError::InvalidResponse)
        }
    }
}

pub fn remove_port(gateway: &Gateway, protocol: PortMappingProtocol,
                   external_port: u16) -> Result<(), RequestError> {
    let url = format!("{}", gateway);
    let body = format!("<?xml version=\"1.0\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
  <s:Body>
    <u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
      <NewProtocol>{}</NewProtocol>
      <NewExternalPort>{}</NewExternalPort>
      <NewRemoteHost>
      </NewRemoteHost>
    </u:DeletePortMapping>
  </s:Body>
</s:Envelope>
", protocol, external_port);
    let resp = try!(http::handle()
                    .post(url, &body)
                    .header("Content-Type", "text/xml; charset=\"utf-8\"")
                    .header("SOAPAction", DELETE_PORT_SOAP_ACTION)
                    .exec());
    let text = try!(str::from_utf8(resp.get_body())
                    .map_err(|_| RequestError::InvalidResponse));

    {
        let re = regex!("u:DeletePortMappingResponse");
        if re.is_match(text) {
            Ok(())
        } else {
            Err(RequestError::InvalidResponse)
        }
    }
}
<commit_msg>Use Regex::new instead of regex!<commit_after>use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::str;
use std::fmt;

use curl::ErrCode;
use curl::http;

use regex::Regex;

use gateway::Gateway;

// Content of the external ip request.
const EXTERNAL_IP_REQUEST: &'static str =
"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">
    <SOAP-ENV:Body>
        <m:GetExternalIPAddress xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
        </m:GetExternalIPAddress>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>";

// Content of the external ip SOAPAction request header.
const SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress\"";

// Content of the add port mapping SOAPAction request header.
const ADD_PORT_SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping\"";

// Content of the delete port mapping SOAPAction request header.
const DELETE_PORT_SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping\"";

// Errors
#[derive(Debug)]
pub enum RequestError {
    ErrCode(ErrCode),
    InvalidResponse,
    IoError(io::Error),
}

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum PortMappingProtocol {
    TCP,
    UDP,
}

impl fmt::Display for PortMappingProtocol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            PortMappingProtocol::TCP => "TCP",
            PortMappingProtocol::UDP => "UDP",
        })
    }
}

impl From<ErrCode> for RequestError {
    fn from(err: ErrCode) -> RequestError {
        RequestError::ErrCode(err)
    }
}

impl From<io::Error> for RequestError {
    fn from(err: io::Error) -> RequestError {
        RequestError::IoError(err)
    }
}

// Get the external IP address.
pub fn get_external_ip(gateway: &Gateway) -> Result<Ipv4Addr, RequestError>  {
    let addr = gateway.addr.clone();
    let url = format!("http://{}:{}{}", addr.ip(), addr.port(),
                      gateway.control_url);
    let resp = try!(http::handle()
        .post(url, EXTERNAL_IP_REQUEST)
        .header("SOAPAction", SOAP_ACTION)
        .exec());
    let text = str::from_utf8(resp.get_body()).unwrap(); // TODO Shouldn't, but can fail.
    extract_address(text)
}

// Extract the address from the text.
fn extract_address(text: &str) -> Result<Ipv4Addr, RequestError> {
    let re = Regex::new(r"<NewExternalIPAddress>(\d+\.\d+\.\d+\.\d+)</NewExternalIPAddress>").unwrap();
    match re.captures(text) {
        None => Err(RequestError::InvalidResponse),
        Some(cap) => {
            match cap.at(1) {
                None => Err(RequestError::InvalidResponse),
                Some(ip) => Ok(ip.parse::<Ipv4Addr>().unwrap()),
            }
        },
    }
}

pub fn add_port(gateway: &Gateway, protocol: PortMappingProtocol,
                external_port: u16, local_addr: SocketAddr, lease_duration: u32,
                description: &str) -> Result<(), RequestError> {
    let url = format!("{}", gateway);
    let body = format!("<?xml version=\"1.0\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
<s:Body>
    <u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
        <NewProtocol>{}</NewProtocol>
        <NewExternalPort>{}</NewExternalPort>
        <NewInternalClient>{}</NewInternalClient>
        <NewInternalPort>{}</NewInternalPort>
        <NewLeaseDuration>{}</NewLeaseDuration>
        <NewPortMappingDescription>{}</NewPortMappingDescription>
        <NewEnabled>1</NewEnabled>
        <NewRemoteHost></NewRemoteHost>
    </u:AddPortMapping>
</s:Body>
</s:Envelope>
",
                       protocol, external_port, local_addr.ip(),
                       local_addr.port(), lease_duration, description);
    let resp = try!(http::handle()
                    .post(url, &body)
                    .header("Content-Type", "text/xml; charset=\"utf-8\"")
                    .header("SOAPAction", ADD_PORT_SOAP_ACTION)
                    .exec());
    let text = try!(str::from_utf8(resp.get_body())
                    .map_err(|_| RequestError::InvalidResponse));

    {
        let re = Regex::new("u:AddPortMappingResponse").unwrap();
        if re.is_match(text) {
            Ok(())
        } else {
            Err(RequestError::InvalidResponse)
        }
    }
}

pub fn remove_port(gateway: &Gateway, protocol: PortMappingProtocol,
                   external_port: u16) -> Result<(), RequestError> {
    let url = format!("{}", gateway);
    let body = format!("<?xml version=\"1.0\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
  <s:Body>
    <u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
      <NewProtocol>{}</NewProtocol>
      <NewExternalPort>{}</NewExternalPort>
      <NewRemoteHost>
      </NewRemoteHost>
    </u:DeletePortMapping>
  </s:Body>
</s:Envelope>
", protocol, external_port);
    let resp = try!(http::handle()
                    .post(url, &body)
                    .header("Content-Type", "text/xml; charset=\"utf-8\"")
                    .header("SOAPAction", DELETE_PORT_SOAP_ACTION)
                    .exec());
    let text = try!(str::from_utf8(resp.get_body())
                    .map_err(|_| RequestError::InvalidResponse));

    {
        let re = Regex::new("u:DeletePortMappingResponse").unwrap();
        if re.is_match(text) {
            Ok(())
        } else {
            Err(RequestError::InvalidResponse)
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Debug)]
enum FileSize {
    B,
    KB,
    MB,
    GB,
    TB,
}

impl fmt::Display for FileSize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl FileSize {
    fn value(&self) -> u64 {
        match *self {
            FileSize::B => 1,
            FileSize::KB => 1_024,
            FileSize::MB => 1_048_576,
            FileSize::GB => 1_073_741_824,
            FileSize::TB => 1_099_511_627_776,
        }
    }
}

pub fn format_filesize(size: u64) -> String {

    let (file_size, unit) = match size {
        0...999 => (size as f64, FileSize::B),
        1_000...999_999 => (size as f64 / FileSize::KB.value() as f64, FileSize::KB),
        1_000_000...999_999_999 => (size as f64 / FileSize::MB.value() as f64, FileSize::MB),
        1_000_000_000...999_999_999_999 => {
            (size as f64 / FileSize::GB.value() as f64, FileSize::GB)
        }
        _ => (size as f64 / FileSize::TB.value() as f64, FileSize::TB),
    };

    format!("{:.2} {}", file_size, unit)
}
<commit_msg>Implemented From trait for the new StringFileType type<commit_after>use std::fmt;

#[derive(Debug)]
enum FileSize {
    B,
    KB,
    MB,
    GB,
    TB,
}

impl fmt::Display for FileSize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl FileSize {
    fn value(&self) -> u64 {
        match *self {
            FileSize::B => 1,
            FileSize::KB => 1_024,
            FileSize::MB => 1_048_576,
            FileSize::GB => 1_073_741_824,
            FileSize::TB => 1_099_511_627_776,
        }
    }
}

#[derive(Debug)]
pub struct StringFileType(String);

impl fmt::Display for StringFileType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl From<u64> for StringFileType {
    fn from(size: u64) -> Self {
        let (file_size, unit) = match size {
        0...999 => (size as f64, FileSize::B),
        1_000...999_999 => (size as f64 / FileSize::KB.value() as f64, FileSize::KB),
        1_000_000...999_999_999 => (size as f64 / FileSize::MB.value() as f64, FileSize::MB),
        1_000_000_000...999_999_999_999 => {
            (size as f64 / FileSize::GB.value() as f64, FileSize::GB)
        }
        _ => (size as f64 / FileSize::TB.value() as f64, FileSize::TB),
    };

        StringFileType(
            format!("{:.2} {}", file_size, unit)
        )
    }
}

<|endoftext|>


<commit_before>use glob::glob;
use reqwest;
use reqwest::header::Authorization;
use serde_json;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use structs::{CliError, Config, Member, PublicKey, Sector, SectorGroup, Team};

pub struct GithubClient {
    client: reqwest::Client,
    conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { client: match config.proxy_url {
                           Some(ref proxy_url) => {
                               let p = reqwest::Proxy::all(proxy_url).unwrap();
                               reqwest::Client::builder().proxy(p).build().unwrap()
                           }
                           None => reqwest::Client::new(),
                       },
                       conf: config.clone(), }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let token = String::from("token ") + &self.conf.token;
        let res = self.client.get(url).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_content_from_url(url) {
                            Ok(content_from_url) => Ok(content_from_url),
                            Err(_) => Ok(cache_content),
                        }
                    } else {
                        Ok(cache_content)
                    }
                }
                Err(_) => Ok(cache_content),
            },
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone())
               .collect::<Vec<String>>()
               .join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors();
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Vec<SectorGroup> { self.get_teams_result().unwrap_or(Vec::new()) }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let ghteams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(ghteam) = &ghteams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(ghteam.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(ghteam.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter()
                  .map(|m| (m.login.clone(), m.clone()))
                  .collect())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache/**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<commit_msg>Add functionality to authenticate repository collaborators<commit_after>use glob::glob;
use reqwest;
use reqwest::header::Authorization;
use serde_json;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use structs::{CliError, Config, Member, PublicKey, Repo, Sector, SectorGroup, Team};

pub struct GithubClient {
    client: reqwest::Client,
    conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { client: match config.proxy_url {
                           Some(ref proxy_url) => {
                               let p = reqwest::Proxy::all(proxy_url).unwrap();
                               reqwest::Client::builder().proxy(p).build().unwrap()
                           }
                           None => reqwest::Client::new(),
                       },
                       conf: config.clone(), }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let token = String::from("token ") + &self.conf.token;
        let res = self.client.get(url).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_content_from_url(url) {
                            Ok(content_from_url) => Ok(content_from_url),
                            Err(_) => Ok(cache_content),
                        }
                    } else {
                        Ok(cache_content)
                    }
                }
                Err(_) => Ok(cache_content),
            },
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone())
               .collect::<Vec<String>>()
               .join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors();
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Vec<SectorGroup> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result().unwrap_or(Vec::new());
        sectors.append(&mut self.get_repos_result().unwrap_or(Vec::new()));
        sectors
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let ghteams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(ghteam) = &ghteams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(ghteam.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(ghteam.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter()
                  .map(|m| (m.login.clone(), m.clone()))
                  .collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let ghrepos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(ghrepo) = &ghrepos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(ghrepo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&ghrepo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&content)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter()
                  .map(|m| (m.login.clone(), m.clone()))
                  .collect())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache/**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fmt::{self, Debug, Formatter};
use std::ops::Deref;
use std::path::{Path, PathBuf};

use dirs::home_dir;

use crate::env_name::NMK_HOME;

/// Home directory of dotfiles
#[derive(Clone)]
pub struct NmkHome(PathBuf);

impl Debug for NmkHome {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

fn find_path_from_homedir() -> Option<PathBuf> {
    home_dir().map(|p| p.join(".nmk"))
}

fn find_path_from_env() -> Option<PathBuf> {
    env::var_os(NMK_HOME).map(PathBuf::from)
}

impl NmkHome {
    pub fn is_git(&self) -> bool {
        self.0.join(".git").exists()
    }

    /// Attempt to find correct NMK_HOME candidate
    /// - if NMK_HOME is set, canonicalize it
    /// - otherwise default to $HOME/.nmk
    ///
    /// Canonicalization is necessary because we use this value in vendored zsh which required
    /// absolute path.
    pub fn find() -> Option<Self> {
        find_path_from_env()
            .and_then(|p| p.canonicalize().ok())
            .or_else(find_path_from_homedir)
            .map(Self::from)
    }

    /// Like find but don't canonicalize (it fail if directory doesn't exist)
    pub fn find_for_install() -> Option<Self> {
        find_path_from_env()
            .or_else(find_path_from_homedir)
            .map(Self::from)
    }
}

impl From<PathBuf> for NmkHome {
    fn from(inner: PathBuf) -> Self {
        Self(inner)
    }
}

impl Deref for NmkHome {
    type Target = Path;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl AsRef<Path> for NmkHome {
    fn as_ref(&self) -> &Path {
        self.0.as_ref()
    }
}
<commit_msg>filter empty NMK_HOME<commit_after>use std::env;
use std::fmt::{self, Debug, Formatter};
use std::ops::Deref;
use std::path::{Path, PathBuf};

use dirs::home_dir;
use nix::NixPath;

use crate::env_name::NMK_HOME;

/// Home directory of dotfiles
#[derive(Clone)]
pub struct NmkHome(PathBuf);

impl Debug for NmkHome {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

fn find_path_from_homedir() -> Option<PathBuf> {
    home_dir().map(|p| p.join(".nmk"))
}

fn find_path_from_env() -> Option<PathBuf> {
    env::var_os(NMK_HOME)
        .map(PathBuf::from)
        .filter(PathBuf::is_empty)
}

impl NmkHome {
    pub fn is_git(&self) -> bool {
        self.0.join(".git").exists()
    }

    /// Attempt to find correct NMK_HOME candidate
    /// - if NMK_HOME is set, canonicalize it
    /// - otherwise default to $HOME/.nmk
    ///
    /// Canonicalization is necessary because we use this value in vendored zsh which required
    /// absolute path.
    pub fn find() -> Option<Self> {
        find_path_from_env()
            .and_then(|p| p.canonicalize().ok())
            .or_else(find_path_from_homedir)
            .map(Self::from)
    }

    /// Like find but don't canonicalize (it fail if directory doesn't exist)
    pub fn find_for_install() -> Option<Self> {
        find_path_from_env()
            .or_else(find_path_from_homedir)
            .map(Self::from)
    }
}

impl From<PathBuf> for NmkHome {
    fn from(inner: PathBuf) -> Self {
        Self(inner)
    }
}

impl Deref for NmkHome {
    type Target = Path;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl AsRef<Path> for NmkHome {
    fn as_ref(&self) -> &Path {
        self.0.as_ref()
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{
    BlockSize, Crc32, GptPartitionEntry, GptPartitionEntrySize, Lba, U32Le,
};
use core::fmt::{self, Display, Formatter};
use core::mem;
use core::ops::Range;

#[cfg(feature = "bytemuck")]
use bytemuck::{from_bytes, from_bytes_mut};

/// Disk layout of a GPT partition entry array.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct GptPartitionEntryArrayLayout {
    /// First block of the array.
    pub start_lba: Lba,

    /// Size in bytes of each entry.
    pub entry_size: GptPartitionEntrySize,

    /// Number of entries in the array.
    pub num_entries: u32,
}

impl GptPartitionEntryArrayLayout {
    /// Get the number of blocks needed for this layout. Returns `None`
    /// if overflow occurs.
    #[must_use]
    pub fn num_blocks(&self, block_size: BlockSize) -> Option<u64> {
        let block_size = block_size.to_u64();
        let num_bytes_exact = self.num_bytes_exact()?;

        let mut num_blocks = num_bytes_exact / block_size;
        if num_bytes_exact % block_size != 0 {
            num_blocks = num_blocks.checked_add(1)?;
        }

        Some(num_blocks)
    }

    /// Get the number of blocks needed for this layout. Returns `None`
    /// if overflow occurs.
    #[must_use]
    pub fn num_blocks_as_usize(&self, block_size: BlockSize) -> Option<usize> {
        self.num_blocks(block_size)?.try_into().ok()
    }

    /// Get the number of bytes needed for the entries in this layout,
    /// ignoring any padding needed at the end to match the block
    /// size. This corresponds to the number of bytes that are covered
    /// by the [`partition_entry_array_crc32`].
    ///
    /// Returns `None` if overflow occurs.
    ///
    /// [`partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
    #[must_use]
    pub fn num_bytes_exact(&self) -> Option<u64> {
        let entry_size = self.entry_size.to_u64();
        let num_entries = u64::from(self.num_entries);
        entry_size.checked_mul(num_entries)
    }

    /// Get the number of bytes needed for the entries in this layout,
    /// ignoring any padding needed at the end to match the block
    /// size. This corresponds to the number of bytes that are covered
    /// by the [`partition_entry_array_crc32`].
    ///
    /// Returns `None` if overflow occurs.
    ///
    /// [`partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
    #[must_use]
    pub fn num_bytes_exact_as_usize(&self) -> Option<usize> {
        self.num_bytes_exact()?.try_into().ok()
    }

    /// Get the number of bytes needed for this layout, rounded up to
    /// the nearest block. This is equivalent to [`num_blocks`] *
    /// `block_size`.
    ///
    /// Returns `None` if overflow occurs.
    ///
    /// [`num_blocks`]: Self::num_blocks
    #[must_use]
    pub fn num_bytes_rounded_to_block(
        &self,
        block_size: BlockSize,
    ) -> Option<u64> {
        let num_blocks = self.num_blocks(block_size)?;
        num_blocks.checked_mul(block_size.to_u64())
    }

    /// Get the number of bytes needed for this layout, rounded up to
    /// the nearest block. This is equivalent to [`num_blocks`] *
    /// `block_size`.
    ///
    /// Returns `None` if overflow occurs.
    ///
    /// [`num_blocks`]: Self::num_blocks
    #[must_use]
    pub fn num_bytes_rounded_to_block_as_usize(
        &self,
        block_size: BlockSize,
    ) -> Option<usize> {
        self.num_bytes_rounded_to_block(block_size)?.try_into().ok()
    }
}

impl Display for GptPartitionEntryArrayLayout {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "start_lba={}/entry_size={}/num_entries={}",
            self.start_lba, self.entry_size, self.num_entries
        )
    }
}

/// Errors used by [`GptPartitionEntryArray`].
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum GptPartitionEntryArrayError {
    /// The storage buffer is not large enough. It must be at least
    /// [`layout.num_bytes_rounded_to_block`] in size.
    ///
    /// [`layout.num_bytes_rounded_to_block`]: GptPartitionEntryArrayLayout::num_bytes_rounded_to_block
    BufferTooSmall,

    /// Numeric overflow occurred.
    Overflow,
}

impl Display for GptPartitionEntryArrayError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Self::BufferTooSmall => f.write_str("storage buffer is too small"),
            Self::Overflow => f.write_str("numeric overflow occurred"),
        }
    }
}

/// Storage for a GPT partition entry array.
#[allow(missing_debug_implementations)]
pub struct GptPartitionEntryArray<'a> {
    layout: GptPartitionEntryArrayLayout,
    num_bytes_exact: usize,
    storage: &'a mut [u8],
}

impl<'a> GptPartitionEntryArray<'a> {
    /// Create a new `GptPartitionEntryArray` with the given
    /// `layout`. The length of `storage` must be at least
    /// [`layout.num_bytes_rounded_to_block`].
    ///
    /// [`layout.num_bytes_rounded_to_block`]: GptPartitionEntryArrayLayout::num_bytes_rounded_to_block
    pub fn new(
        layout: GptPartitionEntryArrayLayout,
        block_size: BlockSize,
        storage: &'a mut [u8],
    ) -> Result<Self, GptPartitionEntryArrayError> {
        let num_bytes_required = layout
            .num_bytes_rounded_to_block_as_usize(block_size)
            .ok_or(GptPartitionEntryArrayError::Overflow)?;

        let num_bytes_exact = layout
            .num_bytes_exact_as_usize()
            .ok_or(GptPartitionEntryArrayError::Overflow)?;

        let storage = storage
            .get_mut(..num_bytes_required)
            .ok_or(GptPartitionEntryArrayError::BufferTooSmall)?;

        Ok(Self {
            layout,
            num_bytes_exact,
            storage,
        })
    }

    /// Get a reference to the storage buffer.
    #[must_use]
    pub fn storage(&self) -> &[u8] {
        self.storage
    }

    /// Get a mutable reference to the storage buffer.
    #[must_use]
    pub fn storage_mut(&mut self) -> &mut [u8] {
        self.storage
    }

    /// Get the partition entry array layout.
    #[must_use]
    pub fn layout(&self) -> &GptPartitionEntryArrayLayout {
        &self.layout
    }

    /// Change the partition entry array's start [`Lba`].
    pub fn set_start_lba(&mut self, start_lba: Lba) {
        self.layout.start_lba = start_lba;
    }

    #[cfg(feature = "bytemuck")]
    fn get_entry_byte_range(&self, index: u32) -> Option<Range<usize>> {
        if index >= self.layout.num_entries {
            return None;
        }

        let start = usize::try_from(
            u64::from(index) * u64::from(self.layout.entry_size.to_u32()),
        )
        .ok()?;
        Some(start..start + mem::size_of::<GptPartitionEntry>())
    }

    /// Get a partition entry reference. The `index` is zero-based.
    #[cfg(feature = "bytemuck")]
    #[must_use]
    pub fn get_partition_entry(
        &self,
        index: u32,
    ) -> Option<&GptPartitionEntry> {
        Some(from_bytes(&self.storage[self.get_entry_byte_range(index)?]))
    }

    /// Get a mutable partition entry reference. The `index` is zero-based.
    #[cfg(feature = "bytemuck")]
    #[must_use]
    pub fn get_partition_entry_mut(
        &mut self,
        index: u32,
    ) -> Option<&mut GptPartitionEntry> {
        let range = self.get_entry_byte_range(index)?;
        Some(from_bytes_mut(&mut self.storage[range]))
    }

    /// Calculate the CRC32 checksum for the partition entry array. The
    /// return value can then be set in the
    /// [`GptHeader::partition_entry_array_crc32`] field.
    ///
    /// [`GptHeader::partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
    #[must_use]
    pub fn calculate_crc32(&self) -> Crc32 {
        let crc = crc::Crc::<u32>::new(&Crc32::ALGORITHM);
        let mut digest = crc.digest();
        digest.update(&self.storage[..self.num_bytes_exact]);
        Crc32(U32Le(digest.finalize().to_le_bytes()))
    }
}
<commit_msg>Fix warnings with bytemuck disabled<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{BlockSize, Crc32, GptPartitionEntrySize, Lba, U32Le};
use core::fmt::{self, Display, Formatter};

#[cfg(feature = "bytemuck")]
use {
    crate::GptPartitionEntry,
    bytemuck::{from_bytes, from_bytes_mut},
    core::mem,
    core::ops::Range,
};

/// Disk layout of a GPT partition entry array.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct GptPartitionEntryArrayLayout {
    /// First block of the array.
    pub start_lba: Lba,

    /// Size in bytes of each entry.
    pub entry_size: GptPartitionEntrySize,

    /// Number of entries in the array.
    pub num_entries: u32,
}

impl GptPartitionEntryArrayLayout {
    /// Get the number of blocks needed for this layout. Returns `None`
    /// if overflow occurs.
    #[must_use]
    pub fn num_blocks(&self, block_size: BlockSize) -> Option<u64> {
        let block_size = block_size.to_u64();
        let num_bytes_exact = self.num_bytes_exact()?;

        let mut num_blocks = num_bytes_exact / block_size;
        if num_bytes_exact % block_size != 0 {
            num_blocks = num_blocks.checked_add(1)?;
        }

        Some(num_blocks)
    }

    /// Get the number of blocks needed for this layout. Returns `None`
    /// if overflow occurs.
    #[must_use]
    pub fn num_blocks_as_usize(&self, block_size: BlockSize) -> Option<usize> {
        self.num_blocks(block_size)?.try_into().ok()
    }

    /// Get the number of bytes needed for the entries in this layout,
    /// ignoring any padding needed at the end to match the block
    /// size. This corresponds to the number of bytes that are covered
    /// by the [`partition_entry_array_crc32`].
    ///
    /// Returns `None` if overflow occurs.
    ///
    /// [`partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
    #[must_use]
    pub fn num_bytes_exact(&self) -> Option<u64> {
        let entry_size = self.entry_size.to_u64();
        let num_entries = u64::from(self.num_entries);
        entry_size.checked_mul(num_entries)
    }

    /// Get the number of bytes needed for the entries in this layout,
    /// ignoring any padding needed at the end to match the block
    /// size. This corresponds to the number of bytes that are covered
    /// by the [`partition_entry_array_crc32`].
    ///
    /// Returns `None` if overflow occurs.
    ///
    /// [`partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
    #[must_use]
    pub fn num_bytes_exact_as_usize(&self) -> Option<usize> {
        self.num_bytes_exact()?.try_into().ok()
    }

    /// Get the number of bytes needed for this layout, rounded up to
    /// the nearest block. This is equivalent to [`num_blocks`] *
    /// `block_size`.
    ///
    /// Returns `None` if overflow occurs.
    ///
    /// [`num_blocks`]: Self::num_blocks
    #[must_use]
    pub fn num_bytes_rounded_to_block(
        &self,
        block_size: BlockSize,
    ) -> Option<u64> {
        let num_blocks = self.num_blocks(block_size)?;
        num_blocks.checked_mul(block_size.to_u64())
    }

    /// Get the number of bytes needed for this layout, rounded up to
    /// the nearest block. This is equivalent to [`num_blocks`] *
    /// `block_size`.
    ///
    /// Returns `None` if overflow occurs.
    ///
    /// [`num_blocks`]: Self::num_blocks
    #[must_use]
    pub fn num_bytes_rounded_to_block_as_usize(
        &self,
        block_size: BlockSize,
    ) -> Option<usize> {
        self.num_bytes_rounded_to_block(block_size)?.try_into().ok()
    }
}

impl Display for GptPartitionEntryArrayLayout {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "start_lba={}/entry_size={}/num_entries={}",
            self.start_lba, self.entry_size, self.num_entries
        )
    }
}

/// Errors used by [`GptPartitionEntryArray`].
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum GptPartitionEntryArrayError {
    /// The storage buffer is not large enough. It must be at least
    /// [`layout.num_bytes_rounded_to_block`] in size.
    ///
    /// [`layout.num_bytes_rounded_to_block`]: GptPartitionEntryArrayLayout::num_bytes_rounded_to_block
    BufferTooSmall,

    /// Numeric overflow occurred.
    Overflow,
}

impl Display for GptPartitionEntryArrayError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Self::BufferTooSmall => f.write_str("storage buffer is too small"),
            Self::Overflow => f.write_str("numeric overflow occurred"),
        }
    }
}

/// Storage for a GPT partition entry array.
#[allow(missing_debug_implementations)]
pub struct GptPartitionEntryArray<'a> {
    layout: GptPartitionEntryArrayLayout,
    num_bytes_exact: usize,
    storage: &'a mut [u8],
}

impl<'a> GptPartitionEntryArray<'a> {
    /// Create a new `GptPartitionEntryArray` with the given
    /// `layout`. The length of `storage` must be at least
    /// [`layout.num_bytes_rounded_to_block`].
    ///
    /// [`layout.num_bytes_rounded_to_block`]: GptPartitionEntryArrayLayout::num_bytes_rounded_to_block
    pub fn new(
        layout: GptPartitionEntryArrayLayout,
        block_size: BlockSize,
        storage: &'a mut [u8],
    ) -> Result<Self, GptPartitionEntryArrayError> {
        let num_bytes_required = layout
            .num_bytes_rounded_to_block_as_usize(block_size)
            .ok_or(GptPartitionEntryArrayError::Overflow)?;

        let num_bytes_exact = layout
            .num_bytes_exact_as_usize()
            .ok_or(GptPartitionEntryArrayError::Overflow)?;

        let storage = storage
            .get_mut(..num_bytes_required)
            .ok_or(GptPartitionEntryArrayError::BufferTooSmall)?;

        Ok(Self {
            layout,
            num_bytes_exact,
            storage,
        })
    }

    /// Get a reference to the storage buffer.
    #[must_use]
    pub fn storage(&self) -> &[u8] {
        self.storage
    }

    /// Get a mutable reference to the storage buffer.
    #[must_use]
    pub fn storage_mut(&mut self) -> &mut [u8] {
        self.storage
    }

    /// Get the partition entry array layout.
    #[must_use]
    pub fn layout(&self) -> &GptPartitionEntryArrayLayout {
        &self.layout
    }

    /// Change the partition entry array's start [`Lba`].
    pub fn set_start_lba(&mut self, start_lba: Lba) {
        self.layout.start_lba = start_lba;
    }

    #[cfg(feature = "bytemuck")]
    fn get_entry_byte_range(&self, index: u32) -> Option<Range<usize>> {
        if index >= self.layout.num_entries {
            return None;
        }

        let start = usize::try_from(
            u64::from(index) * u64::from(self.layout.entry_size.to_u32()),
        )
        .ok()?;
        Some(start..start + mem::size_of::<GptPartitionEntry>())
    }

    /// Get a partition entry reference. The `index` is zero-based.
    #[cfg(feature = "bytemuck")]
    #[must_use]
    pub fn get_partition_entry(
        &self,
        index: u32,
    ) -> Option<&GptPartitionEntry> {
        Some(from_bytes(&self.storage[self.get_entry_byte_range(index)?]))
    }

    /// Get a mutable partition entry reference. The `index` is zero-based.
    #[cfg(feature = "bytemuck")]
    #[must_use]
    pub fn get_partition_entry_mut(
        &mut self,
        index: u32,
    ) -> Option<&mut GptPartitionEntry> {
        let range = self.get_entry_byte_range(index)?;
        Some(from_bytes_mut(&mut self.storage[range]))
    }

    /// Calculate the CRC32 checksum for the partition entry array. The
    /// return value can then be set in the
    /// [`GptHeader::partition_entry_array_crc32`] field.
    ///
    /// [`GptHeader::partition_entry_array_crc32`]: crate::GptHeader::partition_entry_array_crc32
    #[must_use]
    pub fn calculate_crc32(&self) -> Crc32 {
        let crc = crc::Crc::<u32>::new(&Crc32::ALGORITHM);
        let mut digest = crc.digest();
        digest.update(&self.storage[..self.num_bytes_exact]);
        Crc32(U32Le(digest.finalize().to_le_bytes()))
    }
}
<|endoftext|>


<commit_before>use glut;
use azure;
use geom;

import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import layers::*;
import rendergl::*;
import util::convert_rgb32_to_rgb24;

import glut::{create_window, display_func, init};
import glut::bindgen::{glutInitDisplayMode, glutMainLoop, glutPostRedisplay, glutSwapBuffers};

import azure::cairo::CAIRO_FORMAT_RGB24;
import CairoContext = azure::cairo_hl::Context;
import azure::azure_hl::{Color, ColorPattern, DrawTarget};
import azure::cairo_hl::ImageSurface;

import comm::{chan, port, recv, send};
import libc::c_uint;
import os::{getenv, setenv};
import task::{builder, get_opts, run_listener, set_opts};

class Renderer {
    let image: @Image;
    let mut image_layer: ImageLayer;
    let mut t: f32;
    let mut delta: f32;
    let mut render_context: option<RenderContext>;

    new() {
        let cairo_image = ImageSurface(CAIRO_FORMAT_RGB24, 500, 704);

        let draw_target = DrawTarget(cairo_image);
        draw_target.fill_rect(Rect(Point2D(50.0f32, 50.0f32), Size2D(300.0f32, 284.0f32)),
                              ColorPattern(Color(1.0f32, 1.0f32, 0.0f32, 1.0f32)));
        draw_target.flush();

        self.image = @Image(cairo_image.width() as uint, cairo_image.height() as uint, RGB24Format,
                            convert_rgb32_to_rgb24(cairo_image.data()));
        io::println(#fmt("image is %ux%u", self.image.width, self.image.height));

        self.image_layer = ImageLayer(self.image);

        self.t = 1.0f32;
        self.delta = -0.001f32;

        self.render_context = none;
    }

    fn get_display_callback(this: @Renderer) -> fn@() {
        fn@() {
            (*this).display_callback();
        }
    }

    fn display_callback() {
        alt self.render_context {
            none {
                self.render_context = some(init_render_context());
            }
            some(_) {
                // Nothing to do.
            }
        }
        let context = alt self.render_context {
            none { fail }
            some(ctx) { ctx }
        };

        let t = self.t;
        self.image_layer.common.transform = Matrix4(1.0f32 * t, 0.0f32,     0.0f32, 0.0f32,
                                                    0.0f32,     1.0f32 * t, 0.0f32, 0.0f32,
                                                    0.0f32,     0.0f32,     1.0f32, 0.0f32,
                                                    0.0f32,     0.0f32,     0.0f32, 1.0f32);

        render_scene(context, self.image_layer);

        self.t += self.delta;
        if self.t < 0.0f32 || self.t > 1.0f32 {
            self.delta = -self.delta;
        }

        glutSwapBuffers();

        glutPostRedisplay();
    }
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = builder();
    let opts = {
        sched: some({ mode: task::osmain, foreign_stack_size: none })
        with get_opts(builder)
    };
    set_opts(builder, opts);

    let port: port<()> = port();
    let chan = chan(port);
    let _result_ch: chan<()> = do run_listener(builder) |port| {
        let renderer = @Renderer();

        init();
        glutInitDisplayMode(0 as c_uint);
        create_window("Rust Layers");
        display_func(renderer.get_display_callback(renderer));
        glutMainLoop();

        send(chan, ());
    };

    recv(port);
}

<commit_msg>Make the test go away after 2.5 seconds<commit_after>use glut;
use azure;
use geom;

import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import layers::*;
import rendergl::*;
import util::convert_rgb32_to_rgb24;

import glut::{check_loop, create_window, destroy_window, display_func, init, init_display_mode, post_redisplay, swap_buffers, timer_func};

import azure::cairo::CAIRO_FORMAT_RGB24;
import CairoContext = azure::cairo_hl::Context;
import azure::azure_hl::{Color, ColorPattern, DrawTarget};
import azure::cairo_hl::ImageSurface;

import comm::{chan, peek, port, recv, send};
import libc::c_uint;
import os::{getenv, setenv};
import task::{builder, get_opts, run_listener, set_opts};

class Renderer {
    let image: @Image;
    let mut image_layer: ImageLayer;
    let mut t: f32;
    let mut delta: f32;
    let mut render_context: option<RenderContext>;

    new() {
        let cairo_image = ImageSurface(CAIRO_FORMAT_RGB24, 500, 704);

        let draw_target = DrawTarget(cairo_image);
        draw_target.fill_rect(Rect(Point2D(50.0f32, 50.0f32), Size2D(300.0f32, 284.0f32)),
                              ColorPattern(Color(1.0f32, 1.0f32, 0.0f32, 1.0f32)));
        draw_target.flush();

        self.image = @Image(cairo_image.width() as uint, cairo_image.height() as uint, RGB24Format,
                            convert_rgb32_to_rgb24(cairo_image.data()));
        io::println(#fmt("image is %ux%u", self.image.width, self.image.height));

        self.image_layer = ImageLayer(self.image);

        self.t = 1.0f32;
        self.delta = -0.001f32;

        self.render_context = none;
    }

    fn get_display_callback(this: @Renderer) -> fn@() {
        fn@() {
            (*this).display_callback();
        }
    }

    fn display_callback() {
        alt self.render_context {
            none {
                self.render_context = some(init_render_context());
            }
            some(_) {
                // Nothing to do.
            }
        }
        let context = alt self.render_context {
            none { fail }
            some(ctx) { ctx }
        };

        let t = self.t;
        self.image_layer.common.transform = Matrix4(1.0f32 * t, 0.0f32,     0.0f32, 0.0f32,
                                                    0.0f32,     1.0f32 * t, 0.0f32, 0.0f32,
                                                    0.0f32,     0.0f32,     1.0f32, 0.0f32,
                                                    0.0f32,     0.0f32,     0.0f32, 1.0f32);

        render_scene(context, self.image_layer);

        self.t += self.delta;
        if self.t < 0.0f32 || self.t > 1.0f32 {
            self.delta = -self.delta;
        }

        swap_buffers();

        post_redisplay();
    }
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = builder();
    let opts = {
        sched: some({ mode: task::osmain, foreign_stack_size: none })
        with get_opts(builder)
    };
    set_opts(builder, opts);

    let po: port<()> = port();
    let ch = chan(po);
    let _result_ch: chan<()> = do run_listener(builder) |_po| {
        let renderer = @Renderer();

        init();
        init_display_mode(0 as c_uint);
        let window = create_window("Rust Layers");
        display_func(renderer.get_display_callback(renderer));

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        do timer_func(2500) {
            send(wakeup_chan, ());
        }

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }

        send(ch, ());
    };

    recv(po);
}

<|endoftext|>


<commit_before>use glut;
use azure;
use geom;

import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import geom::matrix::Mat4;
import layers::*;
import scene::*;
import rendergl::*;
import util::convert_rgb32_to_rgb24;

import glut::{DOUBLE, check_loop, create_window, destroy_window, display_func, init};
import glut::{init_display_mode, post_redisplay, swap_buffers, timer_func};

import azure::cairo::CAIRO_FORMAT_RGB24;
import CairoContext = azure::cairo_hl::Context;
import azure::azure_hl::{Color, ColorPattern, DrawTarget};
import azure::cairo_hl::ImageSurface;

import comm::{chan, peek, port, recv, send};
import libc::c_uint;
import os::{getenv, setenv};
import task::task_builder;

struct Renderer {
    mut layer: @TiledImageLayer;
    //mut layer: @ImageLayer;
    mut t: f32;
    mut delta: f32;
    mut render_context: option<RenderContext>;
    mut image: option<@Image>;

    new() {
        let cairo_image = ImageSurface(CAIRO_FORMAT_RGB24, 500, 704);

        self.image = none;

        let draw_target = DrawTarget(cairo_image);
        draw_target.fill_rect(Rect(Point2D(50.0f32, 50.0f32), Size2D(300.0f32, 284.0f32)),
                              ColorPattern(Color(1.0f32, 1.0f32, 0.0f32, 1.0f32)));
        draw_target.flush();

        let (width, height) = (cairo_image.width() as uint, cairo_image.height() as uint);
        let (tile_width, tile_height) = (width / 4, height / 4);
        let cairo_data = cairo_image.data();

        let tiles = dvec();
        for 4.timesi |y| {
            for 4.timesi |x| {
                // Extract the relevant part of the image.
                let data = dvec();

                let mut scanline_start = (y * tile_height * width + x * tile_width) * 4;
                for tile_height.times {
                    for (tile_width * 4).timesi |offset| {
                        data.push(cairo_data[scanline_start + offset]);
                    }

                    scanline_start += width * 4;
                }

                let data = convert_rgb32_to_rgb24(vec::from_mut(dvec::unwrap(data)));
                let image = @Image(tile_width, tile_height, RGB24Format, data);
                self.image = some(image);
                tiles.push(image);
            }
        }

        let tiles = dvec::unwrap(tiles);
        self.layer = @TiledImageLayer(tiles, 4);

        self.t = 1.0f32;
        self.delta = -0.001f32;

        self.render_context = none;
    }

    fn get_display_callback(this: @Renderer) -> fn@() {
        fn@() {
            (*this).display_callback();
        }
    }

    fn display_callback() {
        match self.render_context {
            none => {
                self.render_context = some(init_render_context());
            }
            some(_) => {
                // Nothing to do.
            }
        }
        let context = match self.render_context {
            none => fail,
            some(ctx) => ctx
        };

        let t = self.t;
        self.layer.common.transform = Mat4(400.0f32 * t, 0.0f32,       0.0f32, 0.0f32,
                                           0.0f32,       300.0f32 * t, 0.0f32, 0.0f32,
                                           0.0f32,       0.0f32,       1.0f32, 0.0f32,
                                           0.0f32,       0.0f32,       0.0f32, 1.0f32);

        let mut scene = Scene(TiledImageLayerKind(self.layer), Size2D(400.0f32, 300.0f32));
        //let mut scene = Scene(ImageLayerKind(self.layer), Size2D(400.0f32, 300.0f32));
        render_scene(context, scene);

        //self.t += self.delta;
        if self.t < 0.0f32 || self.t > 1.0f32 {
            self.delta = -self.delta;
        }

        swap_buffers();

        post_redisplay();
    }
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::platform_thread);

    let po: port<()> = port();
    let ch = chan(po);
    let _result_ch: chan<()> = do builder.spawn_listener |_po| {
        let renderer = @Renderer();

        init();
        init_display_mode(DOUBLE as c_uint);
        let window = create_window(~"Rust Layers");
        display_func(renderer.get_display_callback(renderer));

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        do timer_func(30000) {
            send(wakeup_chan, ());
        }

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }

        send(ch, ());
    };

    recv(po);
}

<commit_msg>Change back a name changed to work around a compile bug<commit_after>use glut;
use azure;
use geom;

import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import geom::matrix::Matrix4;
import layers::*;
import scene::*;
import rendergl::*;
import util::convert_rgb32_to_rgb24;

import glut::{DOUBLE, check_loop, create_window, destroy_window, display_func, init};
import glut::{init_display_mode, post_redisplay, swap_buffers, timer_func};

import azure::cairo::CAIRO_FORMAT_RGB24;
import CairoContext = azure::cairo_hl::Context;
import azure::azure_hl::{Color, ColorPattern, DrawTarget};
import azure::cairo_hl::ImageSurface;

import comm::{chan, peek, port, recv, send};
import libc::c_uint;
import os::{getenv, setenv};
import task::task_builder;

struct Renderer {
    mut layer: @TiledImageLayer;
    //mut layer: @ImageLayer;
    mut t: f32;
    mut delta: f32;
    mut render_context: option<RenderContext>;
    mut image: option<@Image>;

    new() {
        let cairo_image = ImageSurface(CAIRO_FORMAT_RGB24, 500, 704);

        self.image = none;

        let draw_target = DrawTarget(cairo_image);
        draw_target.fill_rect(Rect(Point2D(50.0f32, 50.0f32), Size2D(300.0f32, 284.0f32)),
                              ColorPattern(Color(1.0f32, 1.0f32, 0.0f32, 1.0f32)));
        draw_target.flush();

        let (width, height) = (cairo_image.width() as uint, cairo_image.height() as uint);
        let (tile_width, tile_height) = (width / 4, height / 4);
        let cairo_data = cairo_image.data();

        let tiles = dvec();
        for 4.timesi |y| {
            for 4.timesi |x| {
                // Extract the relevant part of the image.
                let data = dvec();

                let mut scanline_start = (y * tile_height * width + x * tile_width) * 4;
                for tile_height.times {
                    for (tile_width * 4).timesi |offset| {
                        data.push(cairo_data[scanline_start + offset]);
                    }

                    scanline_start += width * 4;
                }

                let data = convert_rgb32_to_rgb24(vec::from_mut(dvec::unwrap(data)));
                let image = @Image(tile_width, tile_height, RGB24Format, data);
                self.image = some(image);
                tiles.push(image);
            }
        }

        let tiles = dvec::unwrap(tiles);
        self.layer = @TiledImageLayer(tiles, 4);

        self.t = 1.0f32;
        self.delta = -0.001f32;

        self.render_context = none;
    }

    fn get_display_callback(this: @Renderer) -> fn@() {
        fn@() {
            (*this).display_callback();
        }
    }

    fn display_callback() {
        match self.render_context {
            none => {
                self.render_context = some(init_render_context());
            }
            some(_) => {
                // Nothing to do.
            }
        }
        let context = match self.render_context {
            none => fail,
            some(ctx) => ctx
        };

        let t = self.t;
        self.layer.common.transform = Matrix4(400.0f32 * t, 0.0f32,       0.0f32, 0.0f32,
                                              0.0f32,       300.0f32 * t, 0.0f32, 0.0f32,
                                              0.0f32,       0.0f32,       1.0f32, 0.0f32,
                                              0.0f32,       0.0f32,       0.0f32, 1.0f32);

        let mut scene = Scene(TiledImageLayerKind(self.layer), Size2D(400.0f32, 300.0f32));
        //let mut scene = Scene(ImageLayerKind(self.layer), Size2D(400.0f32, 300.0f32));
        render_scene(context, scene);

        //self.t += self.delta;
        if self.t < 0.0f32 || self.t > 1.0f32 {
            self.delta = -self.delta;
        }

        swap_buffers();

        post_redisplay();
    }
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::platform_thread);

    let po: port<()> = port();
    let ch = chan(po);
    let _result_ch: chan<()> = do builder.spawn_listener |_po| {
        let renderer = @Renderer();

        init();
        init_display_mode(DOUBLE as c_uint);
        let window = create_window(~"Rust Layers");
        display_func(renderer.get_display_callback(renderer));

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        do timer_func(30000) {
            send(wakeup_chan, ());
        }

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }

        send(ch, ());
    };

    recv(po);
}

<|endoftext|>


<commit_before>/*!
Selector matching

Select matching is performed on generic node types. Client-specific details
about the DOM are encapsulated in the `SelectHandler` type which the `SelectCtx`
uses to query various DOM and UA properties.
*/

use stylesheet::Stylesheet;
use computed::ComputedStyle;
use util::VoidPtrLike;
use lwcstr_from_rust_str = wapcaplet::from_rust_string;
use n::u::{rust_str_to_net_qname, net_qname_to_rust_str};
use types::StylesheetOrigin;

pub struct SelectCtx {
    inner: n::s::CssSelectCtx
}

/**
The SelectCtx, used for performing selector matching.

The `SelectCtx` takes ownership of any number of `Stylesheet` objects,
encapsulates the cascade. Individual node styles can be requested with
the `select_style` method.
*/
impl SelectCtx {
    static fn new() -> SelectCtx {
        SelectCtx {
            inner: n::s::css_select_ctx_create()
        }
    }

    /**
    Add `Stylesheet`s to the selection context, where they will participate in the cascade
    during future selector matching
    */
    fn append_sheet(&mut self, sheet: Stylesheet, origin: StylesheetOrigin) {
        let sheet = match move sheet {
            Stylesheet { inner: move inner } => move inner
        };

        self.inner.append_sheet(move sheet, origin.to_net(), n::ll::t::CSS_MEDIA_SCREEN)
    }

    /**
    Select the style for a single node. `handler` is used to query the client for
    a wide range of client-specific details like node relationships, names, and UA
    defaults.
    */
    fn select_style<N: VoidPtrLike, H: SelectHandler<N>>(&self, node: &N, handler: &H) -> SelectResults {
        let inner_handler = SelectHandlerWrapper {
            inner: ptr::to_unsafe_ptr(handler)
        };
        SelectResults {
            inner: self.inner.select_style::<N, SelectHandlerWrapper<N, H>>(node, n::ll::t::CSS_MEDIA_SCREEN, None, &inner_handler)
        }
    }
}

/**
Represents the 'style' of a single node, including it's pseudo-elements.
*/
pub struct SelectResults {
    inner: n::s::CssSelectResults
}

impl SelectResults {
    /** Retrieve the computed style of a single pseudo-element */
    fn computed_style(&self) -> ComputedStyle/&self {
        ComputedStyle {
            inner: self.inner.computed_style(n::s::CssPseudoElementNone)
        }
    }
}

/**
Callbacks used to query the implementation-specific DOM
*/
pub trait SelectHandler<N> {
    fn node_name(node: &N) -> ~str;
    fn named_parent_node(node: &N, name: &str) -> Option<N>;
    fn parent_node(node: &N) -> Option<N>;
    fn node_is_root(node: &N) -> bool;
}

/** Used to convert the netsurfcss CssSelectHandler callbacks to out SelectHandler callbacks */
struct SelectHandlerWrapper<N, H: SelectHandler<N>> {
    // FIXME: Can't encode region variables
    inner: *H
}

priv impl<N, H: SelectHandler<N>> SelectHandlerWrapper<N, H> {
    priv fn inner_ref() -> &self/H {
        unsafe { &*self.inner }
    }
}

impl<N, H: SelectHandler<N>> SelectHandlerWrapper<N, H>: n::s::CssSelectHandler<N> {
    fn node_name(node: &N) -> n::t::CssQName {
        rust_str_to_net_qname(self.inner_ref().node_name(node))
    }

    fn named_parent_node(node: &N, qname: &n::t::CssQName) -> Option<N> {
        self.inner_ref().named_parent_node(node, net_qname_to_rust_str(qname))
    }

    fn parent_node(node: &N) -> Option<N> {
        self.inner_ref().parent_node(node)
    }

    fn node_is_root(node: &N) -> bool {
        self.inner_ref().node_is_root(node)
    }

    fn ua_default_for_property(property: n::p::CssProperty) -> n::h::CssHint {
        warn!("not specifiying ua default for property %?", property);
        n::h::CssHintDefault
    }
}
<commit_msg>Stub out more handlers<commit_after>/*!
Selector matching

Select matching is performed on generic node types. Client-specific details
about the DOM are encapsulated in the `SelectHandler` type which the `SelectCtx`
uses to query various DOM and UA properties.
*/

use stylesheet::Stylesheet;
use computed::ComputedStyle;
use util::VoidPtrLike;
use lwcstr_from_rust_str = wapcaplet::from_rust_string;
use n::u::{rust_str_to_net_qname, net_qname_to_rust_str};
use types::StylesheetOrigin;

pub struct SelectCtx {
    inner: n::s::CssSelectCtx
}

/**
The SelectCtx, used for performing selector matching.

The `SelectCtx` takes ownership of any number of `Stylesheet` objects,
encapsulates the cascade. Individual node styles can be requested with
the `select_style` method.
*/
impl SelectCtx {
    static fn new() -> SelectCtx {
        SelectCtx {
            inner: n::s::css_select_ctx_create()
        }
    }

    /**
    Add `Stylesheet`s to the selection context, where they will participate in the cascade
    during future selector matching
    */
    fn append_sheet(&mut self, sheet: Stylesheet, origin: StylesheetOrigin) {
        let sheet = match move sheet {
            Stylesheet { inner: move inner } => move inner
        };

        self.inner.append_sheet(move sheet, origin.to_net(), n::ll::t::CSS_MEDIA_SCREEN)
    }

    /**
    Select the style for a single node. `handler` is used to query the client for
    a wide range of client-specific details like node relationships, names, and UA
    defaults.
    */
    fn select_style<N: VoidPtrLike, H: SelectHandler<N>>(&self, node: &N, handler: &H) -> SelectResults {
        let inner_handler = SelectHandlerWrapper {
            inner: ptr::to_unsafe_ptr(handler)
        };
        SelectResults {
            inner: self.inner.select_style::<N, SelectHandlerWrapper<N, H>>(node, n::ll::t::CSS_MEDIA_SCREEN, None, &inner_handler)
        }
    }
}

/**
Represents the 'style' of a single node, including it's pseudo-elements.
*/
pub struct SelectResults {
    inner: n::s::CssSelectResults
}

impl SelectResults {
    /** Retrieve the computed style of a single pseudo-element */
    fn computed_style(&self) -> ComputedStyle/&self {
        ComputedStyle {
            inner: self.inner.computed_style(n::s::CssPseudoElementNone)
        }
    }
}

/**
Callbacks used to query the implementation-specific DOM
*/
pub trait SelectHandler<N> {
    fn node_name(node: &N) -> ~str;
    fn named_parent_node(node: &N, name: &str) -> Option<N>;
    fn parent_node(node: &N) -> Option<N>;
    fn node_is_root(node: &N) -> bool;
}

/** Used to convert the netsurfcss CssSelectHandler callbacks to out SelectHandler callbacks */
struct SelectHandlerWrapper<N, H: SelectHandler<N>> {
    // FIXME: Can't encode region variables
    inner: *H
}

priv impl<N, H: SelectHandler<N>> SelectHandlerWrapper<N, H> {
    priv fn inner_ref() -> &self/H {
        unsafe { &*self.inner }
    }
}

impl<N, H: SelectHandler<N>> SelectHandlerWrapper<N, H>: n::s::CssSelectHandler<N> {
    fn node_name(node: &N) -> n::t::CssQName {
        rust_str_to_net_qname(self.inner_ref().node_name(node))
    }

    fn named_parent_node(node: &N, qname: &n::t::CssQName) -> Option<N> {
        self.inner_ref().named_parent_node(node, net_qname_to_rust_str(qname))
    }

    fn parent_node(node: &N) -> Option<N> {
        self.inner_ref().parent_node(node)
    }

    fn node_is_root(node: &N) -> bool {
        self.inner_ref().node_is_root(node)
    }

    fn node_is_link(_node: &N) -> bool {
        // FIXME
        warn_unimpl("node_is_link");
        false
    }

    fn ua_default_for_property(property: n::p::CssProperty) -> n::h::CssHint {
        warn!("not specifiying ua default for property %?", property);
        n::h::CssHintDefault
    }
}

fn warn_unimpl(what: &str) {
    warn!("unimplemented select handler: %?", what);
}<|endoftext|>


<commit_before>use na::Translate;
use na;
use shape::{Shape, ConcaveShape};
use bounding_volume::{HasAABB, AABB};
use ray::{LocalRayCast, Ray};
use partitioning::BVTCostFn;
use geometry::time_of_impact_internal;
use math::{Scalar, Point, Vect, Isometry};

/// Time Of Impact of a composite shape with any other shape, under translational movement.
pub fn concave_shape_against_shape<N, P, V, M, G1, G2>(m1: &M, vel1: &V, g1: &G1,
                                                       m2: &M, vel2: &V, g2: &G2)
                                                       -> Option<N>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> ,
          M:  Isometry<N, P, V>,
          G1: ConcaveShape<N, P, V, M>,
          G2: Shape<N, P, V, M> {
    let mut cost_fn = ConcaveShapeAgainstShapeTOICostFn::new(m1, vel1, g1, m2, vel2, g2);

    g1.bvt().best_first_search(&mut cost_fn).map(|(_, res)| res)
}

/// Time Of Impact of any shape with a composite shape, under translational movement.
pub fn shape_against_concave_shape<N, P, V, M, G1, G2>(m1: &M, vel1: &V, g1: &G1,
                                                       m2: &M, vel2: &V, g2: &G2)
                                                       -> Option<N>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> ,
          M:  Isometry<N, P, V>,
          G1: Shape<N, P, V, M>,
          G2: ConcaveShape<N, P, V, M> {
    concave_shape_against_shape(m2, vel2, g2, m1, vel1, g1)
}

struct ConcaveShapeAgainstShapeTOICostFn<'a, P, V: 'a, M: 'a, G1: 'a, G2: 'a> {
    msum_shift:  V,
    msum_margin: V,
    ray:         Ray<P, V>,

    m1:   &'a M,
    vel1: &'a V,
    g1:   &'a G1,
    m2:   &'a M,
    vel2: &'a V,
    g2:   &'a G2
}

impl<'a, N, P, V, M, G1, G2> ConcaveShapeAgainstShapeTOICostFn<'a, P, V, M, G1, G2>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> ,
          M:  Isometry<N, P, V>,
          G1: ConcaveShape<N, P, V, M>,
          G2: Shape<N, P, V, M> {
    pub fn new(m1: &'a M, vel1: &'a V, g1: &'a G1, m2: &'a M, vel2: &'a V, g2: &'a G2)
        -> ConcaveShapeAgainstShapeTOICostFn<'a, P, V, M, G1, G2> {

        let ls_m2 = na::inv(m1).expect("The transformation `m1` must be inversible.") * *m2;
        let ls_aabb2 = g2.aabb(&ls_m2);

        ConcaveShapeAgainstShapeTOICostFn {
            msum_shift:  -ls_aabb2.center().to_vec(),
            msum_margin: ls_aabb2.half_extents(),
            ray:         Ray::new(na::orig(), *vel2 - *vel1),
            m1:          m1,
            vel1:        vel1,
            g1:          g1,
            m2:          m2,
            vel2:        vel2,
            g2:          g2
        }
    }
}

impl<'a, N, P, V, M, G1, G2> BVTCostFn<N, uint, AABB<P>, N>
for ConcaveShapeAgainstShapeTOICostFn<'a, P, V, M, G1, G2>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> ,
          M:  Isometry<N, P, V>,
          G1: ConcaveShape<N, P, V, M>,
          G2: Shape<N, P, V, M> {
    #[inline]
    fn compute_bv_cost(&mut self, bv: &AABB<P>) -> Option<N> {
        // Compute the minkowski sum of the two AABBs.
        let msum = AABB::new(*bv.mins() + self.msum_shift + (-self.msum_margin),
                             *bv.maxs() + self.msum_shift + self.msum_margin);

        // Compute the TOI.
        msum.toi_with_ray(&self.ray, true)
    }

    #[inline]
    fn compute_b_cost(&mut self, b: &uint) -> Option<(N, N)> {
        self.g1.map_transformed_part_at(self.m1, *b, |m1, g1|
            time_of_impact_internal::shape_against_shape(m1, self.vel1, g1, self.m2, self.vel2, self.g2)
            .map(|toi| (toi, toi))
        )
    }
}
<commit_msg>Fix TOI computation for ConcaveShape against Shape.<commit_after>use na::Translate;
use na;
use shape::{Shape, ConcaveShape};
use bounding_volume::{HasAABB, AABB};
use ray::{LocalRayCast, Ray};
use partitioning::BVTCostFn;
use geometry::time_of_impact_internal;
use math::{Scalar, Point, Vect, Isometry};

/// Time Of Impact of a composite shape with any other shape, under translational movement.
pub fn concave_shape_against_shape<N, P, V, M, G1, G2>(m1: &M, vel1: &V, g1: &G1,
                                                       m2: &M, vel2: &V, g2: &G2)
                                                       -> Option<N>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> ,
          M:  Isometry<N, P, V>,
          G1: ConcaveShape<N, P, V, M>,
          G2: Shape<N, P, V, M> {
    let mut cost_fn = ConcaveShapeAgainstShapeTOICostFn::new(m1, vel1, g1, m2, vel2, g2);

    g1.bvt().best_first_search(&mut cost_fn).map(|(_, res)| res)
}

/// Time Of Impact of any shape with a composite shape, under translational movement.
pub fn shape_against_concave_shape<N, P, V, M, G1, G2>(m1: &M, vel1: &V, g1: &G1,
                                                       m2: &M, vel2: &V, g2: &G2)
                                                       -> Option<N>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> ,
          M:  Isometry<N, P, V>,
          G1: Shape<N, P, V, M>,
          G2: ConcaveShape<N, P, V, M> {
    concave_shape_against_shape(m2, vel2, g2, m1, vel1, g1)
}

struct ConcaveShapeAgainstShapeTOICostFn<'a, P, V: 'a, M: 'a, G1: 'a, G2: 'a> {
    msum_shift:  V,
    msum_margin: V,
    ray:         Ray<P, V>,

    m1:   &'a M,
    vel1: &'a V,
    g1:   &'a G1,
    m2:   &'a M,
    vel2: &'a V,
    g2:   &'a G2
}

impl<'a, N, P, V, M, G1, G2> ConcaveShapeAgainstShapeTOICostFn<'a, P, V, M, G1, G2>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> ,
          M:  Isometry<N, P, V>,
          G1: ConcaveShape<N, P, V, M>,
          G2: Shape<N, P, V, M> {
    pub fn new(m1: &'a M, vel1: &'a V, g1: &'a G1, m2: &'a M, vel2: &'a V, g2: &'a G2)
        -> ConcaveShapeAgainstShapeTOICostFn<'a, P, V, M, G1, G2> {

        let ls_m2 = na::inv(m1).expect("The transformation `m1` must be inversible.") * *m2;
        let ls_aabb2 = g2.aabb(&ls_m2);

        ConcaveShapeAgainstShapeTOICostFn {
            msum_shift:  -ls_aabb2.center().to_vec(),
            msum_margin: ls_aabb2.half_extents(),
            ray:         Ray::new(na::orig(), m1.inv_rotate(&(*vel2 - *vel1))),
            m1:          m1,
            vel1:        vel1,
            g1:          g1,
            m2:          m2,
            vel2:        vel2,
            g2:          g2
        }
    }
}

impl<'a, N, P, V, M, G1, G2> BVTCostFn<N, uint, AABB<P>, N>
for ConcaveShapeAgainstShapeTOICostFn<'a, P, V, M, G1, G2>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> ,
          M:  Isometry<N, P, V>,
          G1: ConcaveShape<N, P, V, M>,
          G2: Shape<N, P, V, M> {
    #[inline]
    fn compute_bv_cost(&mut self, bv: &AABB<P>) -> Option<N> {
        // Compute the minkowski sum of the two AABBs.
        let msum = AABB::new(*bv.mins() + self.msum_shift + (-self.msum_margin),
                             *bv.maxs() + self.msum_shift + self.msum_margin);

        // Compute the TOI.
        msum.toi_with_ray(&self.ray, true)
    }

    #[inline]
    fn compute_b_cost(&mut self, b: &uint) -> Option<(N, N)> {
        self.g1.map_transformed_part_at(self.m1, *b, |m1, g1|
            time_of_impact_internal::shape_against_shape(m1, self.vel1, g1, self.m2, self.vel2, self.g2)
            .map(|toi| (toi, toi))
        )
    }
}
<|endoftext|>