<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use handle_table::{HandleTable, Handle};

struct Observer {
    read_overlapped: *mut ::miow::Overlapped,
    write_overlapped: *mut ::miow::Overlapped,
    read_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
}

impl Observer {
    pub fn when_read_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_write_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

pub struct Reactor {
    cp: ::miow::iocp::CompletionPort,
    observers: HandleTable<Observer>,
    statuses: Vec<::miow::iocp::CompletionStatus>,
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            cp: try!(::miow::iocp::CompletionPort::new(1)),
            observers: HandleTable::new(),
            statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024]
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow

        match self.cp.get_many(&mut self.statuses[..], timeout) {
            Err(ref e) if e.raw_os_error() == Some(258) => Ok(()), // winapi::WAIT_TIMEOUT
            Err(e) => Err(e),
            Ok(statuses) => {
                for status in statuses {
                    let token = status.token();
                    let overlapped = status.overlapped();
                    let bytes_transferred = status.bytes_transferred();
                    let handle = Handle { val: token };
                    if self.observers[handle].read_overlapped == overlapped {
                        match self.observers[handle].read_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                    if self.observers[handle].write_overlapped == overlapped {
                        match self.observers[handle].write_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                }
                Ok(())
            }
        }

    }

    fn add_socket<T>(&mut self, sock: &T,
                     read_overlapped: *mut ::miow::Overlapped,
                     write_overlapped: *mut ::miow::Overlapped)
                     -> Result<Handle, ::std::io::Error>
        where T : ::std::os::windows::io::AsRawSocket
    {
        let observer = Observer {
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            read_fulfiller: None,
            write_fulfiller: None,
        };
        let handle = self.observers.push(observer);
        try!(self.cp.add_socket(handle.val, sock));
        Ok(handle)
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: ::std::net::SocketAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr)
                   -> SocketAddressInner
    {
        SocketAddressInner {
            reactor: reactor,
            addr: addr,
        }
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        use miow::net::TcpBuilderExt;
        let builder = match self.addr {
            ::std::net::SocketAddr::V4(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v4());
                pry!(builder.bind("0.0.0.0:0"));
                builder
            }
            ::std::net::SocketAddr::V6(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v6());
                pry!(builder.bind("[::]:0")); // TODO: does this work?
                builder
            }
        };

        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = pry!(
            self.reactor.borrow_mut().add_socket(&builder, &mut *read_overlapped,
                                                 &mut *write_overlapped));

        let (stream, _ready) = unsafe {
            pry!(builder.connect_overlapped(&self.addr, &mut *write_overlapped))
        };

        let reactor2 = self.reactor.clone();
        let result = self.reactor.borrow_mut().observers[handle].when_write_done().map(move |_| {
            Ok(SocketStreamInner::new_already_registered(
                reactor2, stream,
                read_overlapped, write_overlapped,
                handle))
        });

        result
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error> {
        let listener = try!(::std::net::TcpListener::bind(self.addr));
        SocketListenerInner::new(self.reactor.clone(), listener, self.addr)
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    listener: ::std::net::TcpListener,
    addr: ::std::net::SocketAddr,
    read_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub queue: Option<Promise<(),()>>,
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<Reactor>>, listener: ::std::net::TcpListener,
           addr: ::std::net::SocketAddr)
           -> Result<SocketListenerInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped,
                                            ::std::ptr::null_mut()));

        Ok(SocketListenerInner {
            reactor: reactor,
            listener: listener,
            addr: addr,
            read_overlapped: read_overlapped,
            handle: handle,
            queue: None,
        })
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                           -> Promise<SocketStreamInner, ::std::io::Error>
    {
        use miow::net::TcpListenerExt;
        let builder = match inner.borrow().addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };

        let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new();

        let &mut SocketListenerInner {
            ref reactor, ref mut listener, ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let (stream, _ready) = unsafe {
            pry!(listener.accept_overlapped(&builder,
                                            &mut accept_addrs,
                                            read_overlapped))
        };

        let reactor2 = reactor.clone();
        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| {
            println!("accepted!");
            SocketStreamInner::new(reactor2, stream)
        });

        result
    }
}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    stream: ::std::net::TcpStream,
    read_overlapped: Box<::miow::Overlapped>,
    write_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream)
           -> Result<SocketStreamInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped,
                                            &mut *write_overlapped));
        Ok(SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        })
    }

    fn new_already_registered(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream,
                              read_overlapped: Box<::miow::Overlapped>,
                              write_overlapped: Box<::miow::Overlapped>,
                              handle: Handle)
           -> SocketStreamInner
    {
        SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        }
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                                mut buf: T,
                                already_read: usize,
                                min_bytes: usize)
                                -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_read >= min_bytes {
            return Promise::ok((buf, already_read));
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor, ref mut stream,
            ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.read_overlapped(&mut buf.as_mut()[already_read..], read_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_read_done().then(move |n| {
            println!("read transferred this many bytes: {}", n);
            let total_read = n as usize + already_read;
            if n == 0 {
                println!("EOF");
                Promise::ok((buf, total_read))
            } else {
                SocketStreamInner::try_read_internal(inner2, buf, total_read, min_bytes)
            }
        });

        result
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                             buf: T,
                             already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_written == buf.as_ref().len() {
            return Promise::ok(buf)
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor,
            ref stream,
            ref mut write_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.write_overlapped(&buf.as_ref()[already_written ..], write_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_write_done().then(move |n| {
            println!("write transferred this many bytes: {}", n);
            let total_written = n as usize + already_written;
            if n == 0 {
                println!("wrote zero bytes!?");
            }

            SocketStreamInner::write_internal(inner2, buf, total_written)
        });

        result
    }
}
<commit_msg>Drop impls<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use handle_table::{HandleTable, Handle};

struct Observer {
    read_overlapped: *mut ::miow::Overlapped,
    write_overlapped: *mut ::miow::Overlapped,
    read_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
}

impl Observer {
    pub fn when_read_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_write_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

pub struct Reactor {
    cp: ::miow::iocp::CompletionPort,
    observers: HandleTable<Observer>,
    statuses: Vec<::miow::iocp::CompletionStatus>,
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            cp: try!(::miow::iocp::CompletionPort::new(1)),
            observers: HandleTable::new(),
            statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024]
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow

        match self.cp.get_many(&mut self.statuses[..], timeout) {
            Err(ref e) if e.raw_os_error() == Some(258) => Ok(()), // winapi::WAIT_TIMEOUT
            Err(e) => Err(e),
            Ok(statuses) => {
                for status in statuses {
                    let token = status.token();
                    let overlapped = status.overlapped();
                    let bytes_transferred = status.bytes_transferred();
                    let handle = Handle { val: token };
                    if self.observers[handle].read_overlapped == overlapped {
                        match self.observers[handle].read_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                    if self.observers[handle].write_overlapped == overlapped {
                        match self.observers[handle].write_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                }
                Ok(())
            }
        }

    }

    fn add_socket<T>(&mut self, sock: &T,
                     read_overlapped: *mut ::miow::Overlapped,
                     write_overlapped: *mut ::miow::Overlapped)
                     -> Result<Handle, ::std::io::Error>
        where T : ::std::os::windows::io::AsRawSocket
    {
        let observer = Observer {
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            read_fulfiller: None,
            write_fulfiller: None,
        };
        let handle = self.observers.push(observer);
        try!(self.cp.add_socket(handle.val, sock));
        Ok(handle)
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: ::std::net::SocketAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr)
                   -> SocketAddressInner
    {
        SocketAddressInner {
            reactor: reactor,
            addr: addr,
        }
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        use miow::net::TcpBuilderExt;
        let builder = match self.addr {
            ::std::net::SocketAddr::V4(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v4());
                pry!(builder.bind("0.0.0.0:0"));
                builder
            }
            ::std::net::SocketAddr::V6(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v6());
                pry!(builder.bind("[::]:0")); // TODO: does this work?
                builder
            }
        };

        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = pry!(
            self.reactor.borrow_mut().add_socket(&builder, &mut *read_overlapped,
                                                 &mut *write_overlapped));

        let (stream, _ready) = unsafe {
            pry!(builder.connect_overlapped(&self.addr, &mut *write_overlapped))
        };

        let reactor2 = self.reactor.clone();
        let result = self.reactor.borrow_mut().observers[handle].when_write_done().map(move |_| {
            Ok(SocketStreamInner::new_already_registered(
                reactor2, stream,
                read_overlapped, write_overlapped,
                handle))
        });

        result
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error> {
        let listener = try!(::std::net::TcpListener::bind(self.addr));
        SocketListenerInner::new(self.reactor.clone(), listener, self.addr)
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    listener: ::std::net::TcpListener,
    addr: ::std::net::SocketAddr,
    read_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub queue: Option<Promise<(),()>>,
}

impl Drop for SocketListenerInner {
    fn drop(&mut self) {
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<Reactor>>, listener: ::std::net::TcpListener,
           addr: ::std::net::SocketAddr)
           -> Result<SocketListenerInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped,
                                            ::std::ptr::null_mut()));

        Ok(SocketListenerInner {
            reactor: reactor,
            listener: listener,
            addr: addr,
            read_overlapped: read_overlapped,
            handle: handle,
            queue: None,
        })
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                           -> Promise<SocketStreamInner, ::std::io::Error>
    {
        use miow::net::TcpListenerExt;
        let builder = match inner.borrow().addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };

        let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new();

        let &mut SocketListenerInner {
            ref reactor, ref mut listener, ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let (stream, _ready) = unsafe {
            pry!(listener.accept_overlapped(&builder,
                                            &mut accept_addrs,
                                            read_overlapped))
        };

        let reactor2 = reactor.clone();
        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| {
            println!("accepted!");
            SocketStreamInner::new(reactor2, stream)
        });

        result
    }
}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    stream: ::std::net::TcpStream,
    read_overlapped: Box<::miow::Overlapped>,
    write_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl Drop for SocketStreamInner {
    fn drop(&mut self) {
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream)
           -> Result<SocketStreamInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped,
                                            &mut *write_overlapped));
        Ok(SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        })
    }

    fn new_already_registered(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream,
                              read_overlapped: Box<::miow::Overlapped>,
                              write_overlapped: Box<::miow::Overlapped>,
                              handle: Handle)
           -> SocketStreamInner
    {
        SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        }
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                                mut buf: T,
                                already_read: usize,
                                min_bytes: usize)
                                -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_read >= min_bytes {
            return Promise::ok((buf, already_read));
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor, ref mut stream,
            ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.read_overlapped(&mut buf.as_mut()[already_read..], read_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_read_done().then(move |n| {
            println!("read transferred this many bytes: {}", n);
            let total_read = n as usize + already_read;
            if n == 0 {
                println!("EOF");
                Promise::ok((buf, total_read))
            } else {
                SocketStreamInner::try_read_internal(inner2, buf, total_read, min_bytes)
            }
        });

        result
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                             buf: T,
                             already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_written == buf.as_ref().len() {
            return Promise::ok(buf)
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor,
            ref stream,
            ref mut write_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.write_overlapped(&buf.as_ref()[already_written ..], write_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_write_done().then(move |n| {
            println!("write transferred this many bytes: {}", n);
            let total_written = n as usize + already_written;
            if n == 0 {
                println!("wrote zero bytes!?");
            }

            SocketStreamInner::write_internal(inner2, buf, total_written)
        });

        result
    }
}
<|endoftext|>


<commit_before>include!("header.rs");

macro_rules! impl_test{
    ($modname:ident, $clone:ident) => {
mod $modname {
    use super::random_square;
    use ndarray::prelude::*;
    use ndarray_linalg::prelude::*;
    #[test]
    fn inv_random() {
        let a = random_square(3);
        let ai = a.$clone().inv().unwrap();
        let id = Array::eye(3);
        all_close_l2(&ai.dot(&a), &id, 1e-7).unwrap();
    }

    #[test]
    fn inv_random_t() {
        let a = random_square(3).reversed_axes();
        let ai = a.$clone().inv().unwrap();
        let id = Array::eye(3);
        all_close_l2(&ai.dot(&a), &id, 1e-7).unwrap();
    }

    #[test]
    #[should_panic]
    fn inv_error() {
        // do not have inverse
        let a = Array::range(1., 10., 1.).into_shape((3, 3)).unwrap();
        let _ = a.$clone().inv().unwrap();
    }
}
}} // impl_test

impl_test!(owned, clone);
impl_test!(shared, to_shared);
<commit_msg>TEST: Use zero matrix for non-invertible matrix<commit_after>include!("header.rs");

macro_rules! impl_test{
    ($modname:ident, $clone:ident) => {
mod $modname {
    use super::random_square;
    use ndarray::prelude::*;
    use ndarray_linalg::prelude::*;
    #[test]
    fn inv_random() {
        let a = random_square(3);
        let ai = a.$clone().inv().unwrap();
        let id = Array::eye(3);
        all_close_l2(&ai.dot(&a), &id, 1e-7).unwrap();
    }

    #[test]
    fn inv_random_t() {
        let a = random_square(3).reversed_axes();
        let ai = a.$clone().inv().unwrap();
        let id = Array::eye(3);
        all_close_l2(&ai.dot(&a), &id, 1e-7).unwrap();
    }

    #[test]
    #[should_panic]
    fn inv_error() {
        // do not have inverse
        let a = Array::<f64, _>::zeros(9).into_shape((3, 3)).unwrap();
        let a_inv = a.$clone().inv().unwrap();
        println!("{:?}", a_inv);
    }
}
}} // impl_test

impl_test!(owned, clone);
impl_test!(shared, to_shared);
<|endoftext|>


<commit_before><commit_msg>added tests crate stub<commit_after><|endoftext|>


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

use bincode::deserialize;
use byteorder::{LittleEndian, ReadBytesExt};
use clap;
use std::any::TypeId;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::{mem, process};
use webrender::WEBRENDER_RECORDING_HEADER;
use webrender::api::{ApiMsg, DocumentMsg};
use wrench::{Wrench, WrenchThing};

#[derive(Clone)]
enum Item {
    Message(ApiMsg),
    Data(Vec<u8>),
}

pub struct BinaryFrameReader {
    file: File,
    eof: bool,
    frame_offsets: Vec<u64>,

    skip_uploads: bool,
    replay_api: bool,
    play_through: bool,

    frame_data: Vec<Item>,
    frame_num: u32,
    frame_read: bool,
}

impl BinaryFrameReader {
    pub fn new(file_path: &Path) -> BinaryFrameReader {
        let mut file = File::open(&file_path).expect("Can't open recording file");
        let header = file.read_u64::<LittleEndian>().unwrap();
        assert_eq!(
            header,
            WEBRENDER_RECORDING_HEADER,
            "Binary recording is missing recording header!"
        );

        let apimsg_type_id = unsafe {
            assert_eq!(mem::size_of::<TypeId>(), mem::size_of::<u64>());
            mem::transmute::<TypeId, u64>(TypeId::of::<ApiMsg>())
        };

        let written_apimsg_type_id = file.read_u64::<LittleEndian>().unwrap();
        if written_apimsg_type_id != apimsg_type_id {
            println!(
                "Warning: binary file ApiMsg type mismatch: expected 0x{:x}, found 0x{:x}",
                apimsg_type_id,
                written_apimsg_type_id
            );
        }

        BinaryFrameReader {
            file,
            eof: false,
            frame_offsets: vec![],

            skip_uploads: false,
            replay_api: false,
            play_through: false,

            frame_data: vec![],
            frame_num: 0,
            frame_read: false,
        }
    }

    pub fn new_from_args(args: &clap::ArgMatches) -> BinaryFrameReader {
        let bin_file = args.value_of("INPUT").map(|s| PathBuf::from(s)).unwrap();
        let mut r = BinaryFrameReader::new(&bin_file);
        r.skip_uploads = args.is_present("skip-uploads");
        r.replay_api = args.is_present("api");
        r.play_through = args.is_present("play");
        r
    }

    // FIXME I don't think we can skip uploads without also skipping
    // payload (I think? Unused payload ranges may also be ignored.). But
    // either way we'd need to track image updates and deletions -- if we
    // delete an image, we can't go back to a previous frame.
    //
    // We could probably introduce a mode where going backwards replays all
    // frames up until that frame, so that we know we can be accurate.
    fn should_skip_upload_msg(&self, msg: &ApiMsg) -> bool {
        if !self.skip_uploads {
            return false;
        }

        match *msg {
            ApiMsg::UpdateResources(..) => true,
            _ => false,
        }
    }

    // a frame exists if we either haven't hit eof yet, or if
    // we have, then if we've seen its offset.
    fn frame_exists(&self, frame: u32) -> bool {
        !self.eof || (frame as usize) < self.frame_offsets.len()
    }
}

impl WrenchThing for BinaryFrameReader {
    fn do_frame(&mut self, wrench: &mut Wrench) -> u32 {
        // save where the frame begins as we read through the file
        if self.frame_num as usize >= self.frame_offsets.len() {
            self.frame_num = self.frame_offsets.len() as u32;
            let pos = self.file.seek(SeekFrom::Current(0)).unwrap();
            println!("Frame {} offset: {}", self.frame_offsets.len(), pos);
            self.frame_offsets.push(pos);
        }

        let first_time = !self.frame_read;
        if first_time {
            let offset = self.frame_offsets[self.frame_num as usize];
            self.file.seek(SeekFrom::Start(offset)).unwrap();

            wrench.set_title(&format!("frame {}", self.frame_num));

            self.frame_data.clear();
            let mut found_frame_marker = false;
            let mut found_display_list = false;
            let mut found_pipeline = false;
            while let Ok(mut len) = self.file.read_u32::<LittleEndian>() {
                if len > 0 {
                    let mut buffer = vec![0; len as usize];
                    self.file.read_exact(&mut buffer).unwrap();
                    let msg = deserialize(&buffer).unwrap();
                    // In order to detect the first valid frame, we
                    // need to find:
                    // (a) SetRootPipeline
                    // (b) SetDisplayList
                    // (c) GenerateFrame that occurs *after* (a) and (b)
                    match msg {
                        ApiMsg::UpdateDocument(_, DocumentMsg::GenerateFrame(..)) => {
                            found_frame_marker = true;
                        }
                        ApiMsg::UpdateDocument(_, DocumentMsg::SetDisplayList { .. }) => {
                            found_frame_marker = false;
                            found_display_list = true;
                        }
                        ApiMsg::UpdateDocument(_, DocumentMsg::SetRootPipeline(..)) => {
                            found_frame_marker = false;
                            found_pipeline = true;
                        }
                        _ => {}
                    }
                    self.frame_data.push(Item::Message(msg));
                    // Frames are marked by the GenerateFrame message.
                    // On the first frame, we additionally need to find at least
                    // a SetDisplayList and a SetRootPipeline.
                    // After the first frame, any GenerateFrame message marks a new
                    // frame being rendered.
                    if found_frame_marker && (self.frame_num > 0 || (found_display_list && found_pipeline)) {
                        break;
                    }
                } else {
                    len = self.file.read_u32::<LittleEndian>().unwrap();
                    let mut buffer = vec![0; len as usize];
                    self.file.read_exact(&mut buffer).unwrap();
                    self.frame_data.push(Item::Data(buffer));
                }
            }

            if self.eof == false &&
                self.file.seek(SeekFrom::Current(0)).unwrap() == self.file.metadata().unwrap().len()
            {
                self.eof = true;
            }

            self.frame_read = true;
        }

        if first_time || self.replay_api {
            wrench.begin_frame();
            let frame_items = self.frame_data.clone();
            for item in frame_items {
                match item {
                    Item::Message(msg) => if !self.should_skip_upload_msg(&msg) {
                        wrench.api.send_message(msg);
                    },
                    Item::Data(buf) => {
                        wrench.api.send_payload(&buf);
                    }
                }
            }
        } else if self.play_through {
            if !self.frame_exists(self.frame_num + 1) {
                process::exit(0);
            }
            self.next_frame();
            self.do_frame(wrench);
        } else {
            wrench.refresh();
        }

        self.frame_num
    }

    // note that we don't loop here; we could, but that'll require
    // some tracking to avoid reuploading resources every run.  We
    // sort of try in should_skip_upload_msg, but this needs work.
    fn next_frame(&mut self) {
        if self.frame_exists(self.frame_num + 1) {
            self.frame_num += 1;
            self.frame_read = false;
        }
    }

    fn prev_frame(&mut self) {
        if self.frame_num > 0 {
            self.frame_num -= 1;
            self.frame_read = false;
        }
    }
}
<commit_msg>Ignore DeleteDocument during playback of last frame to avoid crashing<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use bincode::deserialize;
use byteorder::{LittleEndian, ReadBytesExt};
use clap;
use std::any::TypeId;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::{mem, process};
use webrender::WEBRENDER_RECORDING_HEADER;
use webrender::api::{ApiMsg, DocumentMsg};
use wrench::{Wrench, WrenchThing};

#[derive(Clone)]
enum Item {
    Message(ApiMsg),
    Data(Vec<u8>),
}

pub struct BinaryFrameReader {
    file: File,
    eof: bool,
    frame_offsets: Vec<u64>,

    skip_uploads: bool,
    replay_api: bool,
    play_through: bool,

    frame_data: Vec<Item>,
    frame_num: u32,
    frame_read: bool,
}

impl BinaryFrameReader {
    pub fn new(file_path: &Path) -> BinaryFrameReader {
        let mut file = File::open(&file_path).expect("Can't open recording file");
        let header = file.read_u64::<LittleEndian>().unwrap();
        assert_eq!(
            header,
            WEBRENDER_RECORDING_HEADER,
            "Binary recording is missing recording header!"
        );

        let apimsg_type_id = unsafe {
            assert_eq!(mem::size_of::<TypeId>(), mem::size_of::<u64>());
            mem::transmute::<TypeId, u64>(TypeId::of::<ApiMsg>())
        };

        let written_apimsg_type_id = file.read_u64::<LittleEndian>().unwrap();
        if written_apimsg_type_id != apimsg_type_id {
            println!(
                "Warning: binary file ApiMsg type mismatch: expected 0x{:x}, found 0x{:x}",
                apimsg_type_id,
                written_apimsg_type_id
            );
        }

        BinaryFrameReader {
            file,
            eof: false,
            frame_offsets: vec![],

            skip_uploads: false,
            replay_api: false,
            play_through: false,

            frame_data: vec![],
            frame_num: 0,
            frame_read: false,
        }
    }

    pub fn new_from_args(args: &clap::ArgMatches) -> BinaryFrameReader {
        let bin_file = args.value_of("INPUT").map(|s| PathBuf::from(s)).unwrap();
        let mut r = BinaryFrameReader::new(&bin_file);
        r.skip_uploads = args.is_present("skip-uploads");
        r.replay_api = args.is_present("api");
        r.play_through = args.is_present("play");
        r
    }

    // FIXME I don't think we can skip uploads without also skipping
    // payload (I think? Unused payload ranges may also be ignored.). But
    // either way we'd need to track image updates and deletions -- if we
    // delete an image, we can't go back to a previous frame.
    //
    // We could probably introduce a mode where going backwards replays all
    // frames up until that frame, so that we know we can be accurate.
    fn should_skip_upload_msg(&self, msg: &ApiMsg) -> bool {
        if !self.skip_uploads {
            return false;
        }

        match *msg {
            ApiMsg::UpdateResources(..) => true,
            _ => false,
        }
    }

    // a frame exists if we either haven't hit eof yet, or if
    // we have, then if we've seen its offset.
    fn frame_exists(&self, frame: u32) -> bool {
        !self.eof || (frame as usize) < self.frame_offsets.len()
    }
}

impl WrenchThing for BinaryFrameReader {
    fn do_frame(&mut self, wrench: &mut Wrench) -> u32 {
        // save where the frame begins as we read through the file
        if self.frame_num as usize >= self.frame_offsets.len() {
            self.frame_num = self.frame_offsets.len() as u32;
            let pos = self.file.seek(SeekFrom::Current(0)).unwrap();
            println!("Frame {} offset: {}", self.frame_offsets.len(), pos);
            self.frame_offsets.push(pos);
        }

        let first_time = !self.frame_read;
        if first_time {
            let offset = self.frame_offsets[self.frame_num as usize];
            self.file.seek(SeekFrom::Start(offset)).unwrap();

            wrench.set_title(&format!("frame {}", self.frame_num));

            self.frame_data.clear();
            let mut found_frame_marker = false;
            let mut found_display_list = false;
            let mut found_pipeline = false;
            while let Ok(mut len) = self.file.read_u32::<LittleEndian>() {
                if len > 0 {
                    let mut buffer = vec![0; len as usize];
                    self.file.read_exact(&mut buffer).unwrap();
                    let msg = deserialize(&buffer).unwrap();
                    let mut store_message = true;
                    // In order to detect the first valid frame, we
                    // need to find:
                    // (a) SetRootPipeline
                    // (b) SetDisplayList
                    // (c) GenerateFrame that occurs *after* (a) and (b)
                    match msg {
                        ApiMsg::UpdateDocument(_, DocumentMsg::GenerateFrame(..)) => {
                            found_frame_marker = true;
                        }
                        ApiMsg::UpdateDocument(_, DocumentMsg::SetDisplayList { .. }) => {
                            found_frame_marker = false;
                            found_display_list = true;
                        }
                        ApiMsg::UpdateDocument(_, DocumentMsg::SetRootPipeline(..)) => {
                            found_frame_marker = false;
                            found_pipeline = true;
                        }
                        // Wrench depends on the document always existing
                        ApiMsg::DeleteDocument(_) => {
                            store_message = false;
                        }
                        _ => {}
                    }
                    if store_message {
                        self.frame_data.push(Item::Message(msg));
                    }
                    // Frames are marked by the GenerateFrame message.
                    // On the first frame, we additionally need to find at least
                    // a SetDisplayList and a SetRootPipeline.
                    // After the first frame, any GenerateFrame message marks a new
                    // frame being rendered.
                    if found_frame_marker && (self.frame_num > 0 || (found_display_list && found_pipeline)) {
                        break;
                    }
                } else {
                    len = self.file.read_u32::<LittleEndian>().unwrap();
                    let mut buffer = vec![0; len as usize];
                    self.file.read_exact(&mut buffer).unwrap();
                    self.frame_data.push(Item::Data(buffer));
                }
            }

            if self.eof == false &&
                self.file.seek(SeekFrom::Current(0)).unwrap() == self.file.metadata().unwrap().len()
            {
                self.eof = true;
            }

            self.frame_read = true;
        }

        if first_time || self.replay_api {
            wrench.begin_frame();
            let frame_items = self.frame_data.clone();
            for item in frame_items {
                match item {
                    Item::Message(msg) => if !self.should_skip_upload_msg(&msg) {
                        wrench.api.send_message(msg);
                    },
                    Item::Data(buf) => {
                        wrench.api.send_payload(&buf);
                    }
                }
            }
        } else if self.play_through {
            if !self.frame_exists(self.frame_num + 1) {
                process::exit(0);
            }
            self.next_frame();
            self.do_frame(wrench);
        } else {
            wrench.refresh();
        }

        self.frame_num
    }

    // note that we don't loop here; we could, but that'll require
    // some tracking to avoid reuploading resources every run.  We
    // sort of try in should_skip_upload_msg, but this needs work.
    fn next_frame(&mut self) {
        if self.frame_exists(self.frame_num + 1) {
            self.frame_num += 1;
            self.frame_read = false;
        }
    }

    fn prev_frame(&mut self) {
        if self.frame_num > 0 {
            self.frame_num -= 1;
            self.frame_read = false;
        }
    }
}
<|endoftext|>


<commit_before>use crate::constants::*;

#[derive(Clone, Debug, PartialEq)]
pub enum Style {
    Old,
    OldInverse,
    New,
    NewInverse,
    Error,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StyledToken {
    token: String,
    style: Style,
}

impl StyledToken {
    pub fn new(token: String, style: Style) -> StyledToken {
        return StyledToken { token, style };
    }

    pub fn is_whitespace(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        if chars_iterator.next().is_some() {
            // Multiple chars found in this token, but whitespace will only be
            // one per token.
            return false;
        }

        return first_char.is_whitespace();
    }
}

pub struct TokenCollector {
    line_prefix: StyledToken,
    rendered: String,
    current_row: Vec<StyledToken>,
    bytes_count: usize,
    highlighted_bytes_count: usize,
}

impl Style {
    #[must_use]
    pub fn is_inverse(&self) -> bool {
        match self {
            Style::OldInverse | Style::NewInverse | Style::Error => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    #[must_use]
    pub fn color<'a>(&self) -> &'a str {
        match self {
            Style::Old => {
                return OLD;
            }
            Style::OldInverse => {
                return OLD;
            }
            Style::New => {
                return NEW;
            }
            Style::NewInverse => {
                return NEW;
            }
            Style::Error => {
                return ERROR;
            }
        }
    }
}

impl TokenCollector {
    #[must_use]
    pub fn create(line_prefix: StyledToken) -> Self {
        return TokenCollector {
            line_prefix,
            rendered: String::new(),
            current_row: Vec::new(),
            bytes_count: 0,
            highlighted_bytes_count: 0,
        };
    }

    pub fn push(&mut self, token: StyledToken) {
        self.bytes_count += token.token.len();
        if token.style.is_inverse() {
            self.highlighted_bytes_count += 1;
        }

        if token.token == "\n" {
            self.commit();
            self.rendered.push('\n');
            return;
        }

        self.current_row.push(token);
    }

    fn commit(&mut self) {
        if self.current_row.is_empty() {
            return;
        }

        if self.line_prefix.style == Style::New {
            highlight_trailing_whitespace(&mut self.current_row);
            highlight_nonleading_tab(&mut self.current_row);
        }

        // Set inverse from prefix
        let mut is_inverse = self.line_prefix.style.is_inverse();
        if is_inverse {
            self.rendered.push_str(INVERSE_VIDEO);
        }

        // Set line color from prefix
        let mut color = self.line_prefix.style.color();
        self.rendered.push_str(self.line_prefix.style.color());

        // Render prefix
        self.rendered.push_str(&self.line_prefix.token);

        for token in &self.current_row {
            if token.style.is_inverse() && !is_inverse {
                self.rendered.push_str(INVERSE_VIDEO);
            }
            if is_inverse && !token.style.is_inverse() {
                self.rendered.push_str(NOT_INVERSE_VIDEO);
            }
            is_inverse = token.style.is_inverse();

            if token.style.color() != color {
                self.rendered.push_str(token.style.color());
                color = token.style.color();
            }

            self.rendered.push_str(&token.token);
        }

        self.rendered.push_str(NORMAL);
        self.current_row.clear();
    }

    #[must_use]
    pub fn render(&mut self) -> String {
        self.commit();

        return self.rendered.clone();
    }

    pub fn chars_count(&self) -> usize {
        return self.bytes_count;
    }

    pub fn highlighted_chars_count(&self) -> usize {
        return self.highlighted_bytes_count;
    }
}

fn highlight_trailing_whitespace(row: &mut [StyledToken]) {
    for token in row.iter_mut().rev() {
        if !token.is_whitespace() {
            return;
        }

        token.style = Style::Error;
    }
}

fn highlight_nonleading_tab(row: &mut [StyledToken]) {
    let mut token_iter = row.iter_mut();

    // Skip leading TABs
    loop {
        let next = token_iter.next();
        if next.is_none() {
            // Done!
            return;
        }

        let token = next.unwrap();
        if token.token != "\t" {
            // Not a TAB, this means we're out of skipping the leading TABs
            break;
        }
    }

    // Scan the rest of the line for non-leading TABs
    for token in token_iter {
        if token.token != "\t" {
            // Not a TAB, never mind
            continue;
        }

        // Non-leading TAB, mark it!
        token.style = Style::Error;
    }
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_basic() {
        let mut test_me = TokenCollector::create(StyledToken {
            token: "+".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "hej".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "\n".to_string(),
            style: Style::New,
        });

        assert_eq!(test_me.render(), format!("{}+hej{}\n", NEW, NORMAL));
    }

    #[test]
    fn test_add_trailing_whitespace() {
        // Just a whitespace
        let mut row = [StyledToken::new(" ".to_string(), Style::New)];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(row, [StyledToken::new(" ".to_string(), Style::Error)]);

        // Trailing whitespace
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new(" ".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new(" ".to_string(), Style::Error),
            ]
        );

        // Leading whitespace
        let mut row = [
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new(" ".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );
    }

    #[test]
    fn test_removed_trailing_whitespace() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new(" ".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}- {}", OLD, NORMAL));
    }

    #[test]
    fn test_add_nonleading_tab() {
        // Trailing TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
            ]
        );

        // Middle TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("y".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
                StyledToken::new("y".to_string(), Style::New),
            ]
        );

        // Leading TAB (don't highlight)
        let mut row = [
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("\t".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );

        // Single TAB (don't highlight because it is leading)
        let mut row = [StyledToken::new("\t".to_string(), Style::New)];
        highlight_nonleading_tab(&mut row);
        assert_eq!(row, [StyledToken::new("\t".to_string(), Style::New),]);
    }

    #[test]
    fn test_removed_nonleading_tab() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new("x".to_string(), Style::Old));
        test_me.push(StyledToken::new("\t".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}-x\t{}", OLD, NORMAL));
    }
}
<commit_msg>Refactoring to enable unhighlighting lines<commit_after>use crate::constants::*;

#[derive(Clone, Debug, PartialEq)]
pub enum Style {
    Old,
    OldInverse,
    New,
    NewInverse,
    Error,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StyledToken {
    token: String,
    style: Style,
}

impl StyledToken {
    pub fn new(token: String, style: Style) -> StyledToken {
        return StyledToken { token, style };
    }

    pub fn is_whitespace(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        if chars_iterator.next().is_some() {
            // Multiple chars found in this token, but whitespace will only be
            // one per token.
            return false;
        }

        return first_char.is_whitespace();
    }
}

pub struct TokenCollector {
    line_prefix: StyledToken,
    tokens: Vec<StyledToken>,
    bytes_count: usize,
    highlighted_bytes_count: usize,
}

impl Style {
    #[must_use]
    pub fn is_inverse(&self) -> bool {
        match self {
            Style::OldInverse | Style::NewInverse | Style::Error => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    #[must_use]
    pub fn color<'a>(&self) -> &'a str {
        match self {
            Style::Old => {
                return OLD;
            }
            Style::OldInverse => {
                return OLD;
            }
            Style::New => {
                return NEW;
            }
            Style::NewInverse => {
                return NEW;
            }
            Style::Error => {
                return ERROR;
            }
        }
    }
}

impl TokenCollector {
    #[must_use]
    pub fn create(line_prefix: StyledToken) -> Self {
        return TokenCollector {
            line_prefix,
            tokens: Vec::new(),
            bytes_count: 0,
            highlighted_bytes_count: 0,
        };
    }

    pub fn push(&mut self, token: StyledToken) {
        self.tokens.push(token);
    }

    #[must_use]
    fn render_row(&self, row: &mut [StyledToken]) -> String {
        let mut rendered = String::new();

        if row.is_empty() {
            return rendered;
        }

        if self.line_prefix.style == Style::New {
            highlight_trailing_whitespace(row);
            highlight_nonleading_tab(row);
        }

        // Set inverse from prefix
        let mut is_inverse = self.line_prefix.style.is_inverse();
        if is_inverse {
            rendered.push_str(INVERSE_VIDEO);
        }

        // Set line color from prefix
        let mut color = self.line_prefix.style.color();
        rendered.push_str(self.line_prefix.style.color());

        // Render prefix
        rendered.push_str(&self.line_prefix.token);

        for token in row {
            if token.style.is_inverse() && !is_inverse {
                rendered.push_str(INVERSE_VIDEO);
            }
            if is_inverse && !token.style.is_inverse() {
                rendered.push_str(NOT_INVERSE_VIDEO);
            }
            is_inverse = token.style.is_inverse();

            if token.style.color() != color {
                rendered.push_str(token.style.color());
                color = token.style.color();
            }

            rendered.push_str(&token.token);
        }

        rendered.push_str(NORMAL);

        return rendered;
    }

    #[must_use]
    pub fn render(&mut self) -> String {
        let mut current_row: Vec<StyledToken> = Vec::new();
        let mut rendered = String::new();

        for token in &self.tokens {
            self.bytes_count += token.token.len();
            if token.style.is_inverse() {
                self.highlighted_bytes_count += token.token.len();
            }

            if token.token == "\n" {
                let rendered_row = &self.render_row(&mut current_row);
                rendered.push_str(rendered_row);
                rendered.push('\n');
                current_row.clear();
                continue;
            }

            current_row.push(token.clone());
        }

        if !current_row.is_empty() {
            let rendered_row = &self.render_row(&mut current_row);
            rendered.push_str(rendered_row);
        }

        return rendered;
    }

    pub fn chars_count(&self) -> usize {
        return self.bytes_count;
    }

    pub fn highlighted_chars_count(&self) -> usize {
        return self.highlighted_bytes_count;
    }
}

fn highlight_trailing_whitespace(row: &mut [StyledToken]) {
    for token in row.iter_mut().rev() {
        if !token.is_whitespace() {
            return;
        }

        token.style = Style::Error;
    }
}

fn highlight_nonleading_tab(row: &mut [StyledToken]) {
    let mut token_iter = row.iter_mut();

    // Skip leading TABs
    loop {
        let next = token_iter.next();
        if next.is_none() {
            // Done!
            return;
        }

        let token = next.unwrap();
        if token.token != "\t" {
            // Not a TAB, this means we're out of skipping the leading TABs
            break;
        }
    }

    // Scan the rest of the line for non-leading TABs
    for token in token_iter {
        if token.token != "\t" {
            // Not a TAB, never mind
            continue;
        }

        // Non-leading TAB, mark it!
        token.style = Style::Error;
    }
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_basic() {
        let mut test_me = TokenCollector::create(StyledToken {
            token: "+".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "hej".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "\n".to_string(),
            style: Style::New,
        });

        let rendered = test_me.render();
        assert_eq!(rendered, format!("{}+hej{}\n", NEW, NORMAL));
    }

    #[test]
    fn test_add_trailing_whitespace() {
        // Just a whitespace
        let mut row = [StyledToken::new(" ".to_string(), Style::New)];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(row, [StyledToken::new(" ".to_string(), Style::Error)]);

        // Trailing whitespace
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new(" ".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new(" ".to_string(), Style::Error),
            ]
        );

        // Leading whitespace
        let mut row = [
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new(" ".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );
    }

    #[test]
    fn test_removed_trailing_whitespace() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new(" ".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}- {}", OLD, NORMAL));
    }

    #[test]
    fn test_add_nonleading_tab() {
        // Trailing TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
            ]
        );

        // Middle TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("y".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
                StyledToken::new("y".to_string(), Style::New),
            ]
        );

        // Leading TAB (don't highlight)
        let mut row = [
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("\t".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );

        // Single TAB (don't highlight because it is leading)
        let mut row = [StyledToken::new("\t".to_string(), Style::New)];
        highlight_nonleading_tab(&mut row);
        assert_eq!(row, [StyledToken::new("\t".to_string(), Style::New),]);
    }

    #[test]
    fn test_removed_nonleading_tab() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new("x".to_string(), Style::Old));
        test_me.push(StyledToken::new("\t".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}-x\t{}", OLD, NORMAL));
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

use crossbeam_deque::{self as deque, Pop, Steal, Stealer, Worker};
use threadpool::ThreadPool;

use gc::root::Slot;
use gc::{Address, Region};

pub fn start(rootset: &[Slot], heap: Region, perm: Region, number_workers: usize) {
    let mut workers = Vec::with_capacity(number_workers);
    let mut stealers = Vec::with_capacity(number_workers);

    for _ in 0..number_workers {
        let (w, s) = deque::lifo();
        workers.push(w);
        stealers.push(s);
    }

    for root in rootset {
        let root_ptr = root.get();

        if heap.contains(root_ptr) {
            let root_obj = root_ptr.to_mut_obj();

            if !root_obj.header().is_marked_non_atomic() {
                root_obj.header_mut().mark_non_atomic();
                workers[0].push(root_ptr);
            }
        } else {
            debug_assert!(root_ptr.is_null() || perm.contains(root_ptr));
        }
    }

    let pool = ThreadPool::with_name("gc-worker".to_string(), number_workers);
    let nworkers_stage = Arc::new(AtomicUsize::new(number_workers));

    for (task_id, worker) in workers.into_iter().enumerate() {
        let heap_region = heap.clone();
        let perm_region = perm.clone();

        let stealers = stealers.clone();
        let nworkers_stage = nworkers_stage.clone();

        pool.execute(move || {
            let mut local_segment = Segment::new();

            loop {
                let object_addr = if !local_segment.is_empty() {
                    local_segment.pop().expect("should be non-empty")
                } else {
                    if let Some(address) = pop(task_id, &worker, &stealers) {
                        address
                    } else if try_terminate(&nworkers_stage) {
                        break;
                    } else {
                        continue;
                    }
                };

                let object = object_addr.to_mut_obj();

                object.visit_reference_fields(|field| {
                    let field_addr = field.get();

                    if heap_region.contains(field_addr) {
                        let field_obj = field_addr.to_mut_obj();

                        if field_obj.header().try_mark() {
                            if local_segment.has_capacity() {
                                local_segment.push(field_addr);
                            } else {
                                // let new_local_segment = Segment::with(field_addr);
                                // let old_local_segment =
                                    // mem::replace(&mut local_segment, new_local_segment);
                                worker.push(field_addr);
                            }
                        }
                    } else {
                        debug_assert!(field_addr.is_null() || perm_region.contains(field_addr));
                    }
                });
            }
        });
    }

    pool.join();
}

fn pop(task_id: usize, worker: &Worker<Address>, stealers: &[Stealer<Address>]) -> Option<Address> {
    loop {
        match worker.pop() {
            Pop::Empty => break,
            Pop::Data(address) => {
                return Some(address)
            }
            Pop::Retry => continue,
        }
    }

    for stealer in stealers {
        loop {
            match stealer.steal() {
                Steal::Empty => break,
                Steal::Data(address) => {
                    return Some(address)
                }
                Steal::Retry => continue,
            }
        }
    }

    None
}

fn try_terminate(nworkers_stage: &AtomicUsize) -> bool {
    enter_stage(nworkers_stage);
    thread::sleep_ms(1);
    !try_exit(nworkers_stage)
}

fn enter_stage(atomic: &AtomicUsize) -> bool {
    atomic.fetch_sub(1, Ordering::SeqCst) == 1
}

fn try_exit(atomic: &AtomicUsize) -> bool {
    let mut nworkers = atomic.load(Ordering::Relaxed);

    loop {
        if nworkers == 0 {
            return false;
        }
        let prev_nworkers = atomic.compare_and_swap(nworkers, nworkers + 1, Ordering::SeqCst);

        if nworkers == prev_nworkers {
            return true;
        }

        nworkers = prev_nworkers;
    }
}

const SEGMENT_SIZE: usize = 8;

struct Segment {
    data: Vec<Address>,
}

impl Segment {
    fn new() -> Segment {
        Segment {
            data: Vec::with_capacity(SEGMENT_SIZE),
        }
    }

    fn empty() -> Segment {
        Segment { data: Vec::new() }
    }

    fn with(addr: Address) -> Segment {
        let mut segment = Segment::new();
        segment.data.push(addr);

        segment
    }

    fn has_capacity(&self) -> bool {
        self.data.len() < SEGMENT_SIZE
    }

    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    fn push(&mut self, addr: Address) {
        debug_assert!(self.has_capacity());
        self.data.push(addr);
    }

    fn pop(&mut self) -> Option<Address> {
        self.data.pop()
    }
}
<commit_msg>swiper: fix warnings<commit_after>use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::thread;

use crossbeam_deque::{self as deque, Pop, Steal, Stealer, Worker};
use threadpool::ThreadPool;

use gc::root::Slot;
use gc::{Address, Region};

pub fn start(rootset: &[Slot], heap: Region, perm: Region, number_workers: usize) {
    let mut workers = Vec::with_capacity(number_workers);
    let mut stealers = Vec::with_capacity(number_workers);

    for _ in 0..number_workers {
        let (w, s) = deque::lifo();
        workers.push(w);
        stealers.push(s);
    }

    for root in rootset {
        let root_ptr = root.get();

        if heap.contains(root_ptr) {
            let root_obj = root_ptr.to_mut_obj();

            if !root_obj.header().is_marked_non_atomic() {
                root_obj.header_mut().mark_non_atomic();
                workers[0].push(root_ptr);
            }
        } else {
            debug_assert!(root_ptr.is_null() || perm.contains(root_ptr));
        }
    }

    let pool = ThreadPool::with_name("gc-worker".to_string(), number_workers);
    let nworkers_stage = Arc::new(AtomicUsize::new(number_workers));

    for (task_id, worker) in workers.into_iter().enumerate() {
        let heap_region = heap.clone();
        let perm_region = perm.clone();

        let stealers = stealers.clone();
        let nworkers_stage = nworkers_stage.clone();

        pool.execute(move || {
            let mut local_segment = Segment::new();

            loop {
                let object_addr = if !local_segment.is_empty() {
                    local_segment.pop().expect("should be non-empty")
                } else {
                    if let Some(address) = pop(task_id, &worker, &stealers) {
                        address
                    } else if try_terminate(&nworkers_stage) {
                        break;
                    } else {
                        continue;
                    }
                };

                let object = object_addr.to_mut_obj();

                object.visit_reference_fields(|field| {
                    let field_addr = field.get();

                    if heap_region.contains(field_addr) {
                        let field_obj = field_addr.to_mut_obj();

                        if field_obj.header().try_mark() {
                            if local_segment.has_capacity() {
                                local_segment.push(field_addr);
                            } else {
                                // let new_local_segment = Segment::with(field_addr);
                                // let old_local_segment =
                                    // mem::replace(&mut local_segment, new_local_segment);
                                worker.push(field_addr);
                            }
                        }
                    } else {
                        debug_assert!(field_addr.is_null() || perm_region.contains(field_addr));
                    }
                });
            }
        });
    }

    pool.join();
}

fn pop(_task_id: usize, worker: &Worker<Address>, stealers: &[Stealer<Address>]) -> Option<Address> {
    loop {
        match worker.pop() {
            Pop::Empty => break,
            Pop::Data(address) => {
                return Some(address)
            }
            Pop::Retry => continue,
        }
    }

    for stealer in stealers {
        loop {
            match stealer.steal() {
                Steal::Empty => break,
                Steal::Data(address) => {
                    return Some(address)
                }
                Steal::Retry => continue,
            }
        }
    }

    None
}

fn try_terminate(nworkers_stage: &AtomicUsize) -> bool {
    enter_stage(nworkers_stage);
    thread::sleep(Duration::from_millis(1));
    !try_exit(nworkers_stage)
}

fn enter_stage(atomic: &AtomicUsize) -> bool {
    atomic.fetch_sub(1, Ordering::SeqCst) == 1
}

fn try_exit(atomic: &AtomicUsize) -> bool {
    let mut nworkers = atomic.load(Ordering::Relaxed);

    loop {
        if nworkers == 0 {
            return false;
        }
        let prev_nworkers = atomic.compare_and_swap(nworkers, nworkers + 1, Ordering::SeqCst);

        if nworkers == prev_nworkers {
            return true;
        }

        nworkers = prev_nworkers;
    }
}

const SEGMENT_SIZE: usize = 8;

struct Segment {
    data: Vec<Address>,
}

impl Segment {
    fn new() -> Segment {
        Segment {
            data: Vec::with_capacity(SEGMENT_SIZE),
        }
    }

    fn empty() -> Segment {
        Segment { data: Vec::new() }
    }

    fn with(addr: Address) -> Segment {
        let mut segment = Segment::new();
        segment.data.push(addr);

        segment
    }

    fn has_capacity(&self) -> bool {
        self.data.len() < SEGMENT_SIZE
    }

    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    fn push(&mut self, addr: Address) {
        debug_assert!(self.has_capacity());
        self.data.push(addr);
    }

    fn pop(&mut self) -> Option<Address> {
        self.data.pop()
    }
}
<|endoftext|>


<commit_before>// http://dev.w3.org/csswg/css3-syntax/#tree-construction
//
// The input to the tree construction stage is a sequence of tokens
// from the tokenization stage.
// The output is a tree of items with a stylesheet at the root
// and all other nodes being at-rules, style rules, or declarations.

use tokens;

#[deriving_eq]
enum Primitive {
    // Preserved tokens. Same as in the tokenizer.
    Ident(~str),
    AtKeyword(~str),
    Hash(~str),
    String(~str),
    URL(~str),
    Delim(char),
    Number(NumericValue, ~str),  // value, representation
    Percentage(NumericValue, ~str),  // value, representation
    Dimension(NumericValue, ~str, ~str),  // value, representation, unit
    UnicodeRange(char, char),  // start, end
    EmptyUnicodeRange,
    WhiteSpace,
    Comment,
    CDO,  // <!--
    CDC,  // -->
    Colon,  // :
    Semicolon,  // ;
    CloseBraket, // ]
    CloseParen, // )
    CloseBrace, // }

    // Function
    Function(~str, ~[~[Primitive]]),  // name, arguments

    // Simple block
    BraketBlock(~[Primitive]),  // […]
    ParenBlock(~[Primitive]),  // (…)
    BraceBlock(~[Primitive]),  // {…}
}

struct Declaration {
    name: ~str,
    value: ~[Primitive],
    important: bool,
}

struct StyleRule {
    selector: ~[Primitive],
    value: ~[DeclarationListItem],
}

struct AtRule {
    name: ~str,
    selector: ~[Primitive],
    value: AtRuleValue,
}

enum AtRuleValue {
    EmptyAtRule,  // @foo…;
    DeclarationFilled(~[DeclarationListItem]),
    RuleFilled(~[RuleListItem]),
}

enum DeclarationListItem {
    Declaration(Declaration),
    // A better idea for a name that means "at-rule" but is not "AtRule"?
    Decl_AtRule(AtRule),
}

enum RuleListItem {
    StyleRule(StyleRule),
    AtRule(AtRule),
}

pub struct Parser {
    priv tokenizer: ~tokens::Tokenizer,
    priv quirks_mode: bool,
    priv mut current_token: Option<tokens::Token>,
    priv mut errors: ~[~str],
}

impl Parser {
    static fn from_tokenizer(
            tokenizer: ~tokens::Tokenizer, quirks_mode: bool) -> ~Parser {
        ~Parser {
            tokenizer: tokenizer,
            quirks_mode: quirks_mode,
            current_token: None,
            errors: ~[],
        }
    }
    static fn from_str(input: &str, transform_function_whitespace: bool,
                      quirks_mode: bool) -> ~Parser {
        Parser::from_tokenizer(
            tokens::Tokenizer::from_str(input, transform_function_whitespace),
            quirks_mode)
    }
}

// Consume the whole input and return a list of primitives.
// Could be used for parsing eg. a stand-alone media query.
// This is similar to consume_simple_block(), but there is no ending token.
fn consume_primitive_list(parser: &Parser) -> ~[Primitive] {
    let mut value: ~[Primitive] = ~[];
    loop {
        match parser.consume_token() {
            tokens::Comment => (),
            tokens::EOF => break,
            token => {
                parser.reconsume_token(token);
                value.push(consume_primitive(parser))
            }
        }
    }
    value
}

//  ***********  End of public API  ***********

impl Parser {
    priv fn consume_token(&self) -> tokens::Token {
        let mut current_token = None;
        current_token <-> self.current_token;
        match current_token {
            Some(token) => token,
            None => {
                let (token, err) = self.tokenizer.next_token();
                match err {
                    Some(ParseError{message: message}) =>
                        // TODO more contextual error handling?
                        self.errors.push(message),
                    None => ()
                }
                token
            }
        }
    }

    // Fail if the is already a "current token".
    // The easiest way to ensure this does not fail it to call it only once
    // just after calling parser.consume_token()
    priv fn reconsume_token(&self, token: tokens::Token) {
        assert self.current_token.is_none();
        self.current_token = Some(token)
    }
}

// Convert a token from the tokenizer to a primitive.
// Fails if it is not a preserved token. XXX do something else.
fn preserved_token_to_primitive(token: tokens::Token) -> Primitive {
    match token {
        tokens::Ident(string) => Ident(string),
        tokens::AtKeyword(string) => AtKeyword(string),
        tokens::Hash(string) => Hash(string),
        tokens::String(string) => String(string),
        tokens::URL(string) => URL(string),
        tokens::Delim(ch) => Delim(ch),
        tokens::Number(value, repr) => Number(value, repr),
        tokens::Percentage(value, repr) => Percentage(value, repr),
        tokens::Dimension(value, repr, unit) => Dimension(value, repr, unit),
        tokens::UnicodeRange(start, end) => UnicodeRange(start, end),
        tokens::EmptyUnicodeRange => EmptyUnicodeRange,
        tokens::WhiteSpace => WhiteSpace,
        tokens::Colon => Colon,
        tokens::Semicolon => Semicolon,
        _ => fail,   // XXX
        // These are special-cased in consume_primitive()
//        tokens::Function(string) => fail,
//        tokens::OpenBraket => fail,
//        tokens::OpenParen => fail,
//        tokens::OpenBrace => fail,

        // These still need to be dealt with somehow.
//        tokens::BadString => fail,
//        tokens::BadURL => fail,
//        tokens::Comment => fail,
//        tokens::CDO => fail,
//        tokens::CDC => fail,
//        tokens::CloseBraket => fail,
//        tokens::CloseParen => fail,
//        tokens::CloseBrace => fail,
//        tokens::EOF => fail,
    }
}

// 3.5.15. Consume a primitive
fn consume_primitive(parser: &Parser) -> Primitive {
    match parser.consume_token() {
        tokens::OpenBraket =>
            BraketBlock(consume_simple_block(parser, tokens::CloseBraket)),
        tokens::OpenParen =>
            ParenBlock(consume_simple_block(parser, tokens::CloseParen)),
        tokens::OpenBrace =>
            BraceBlock(consume_simple_block(parser, tokens::CloseBrace)),
        tokens::Function(string) => consume_function(parser, string),
        token => preserved_token_to_primitive(token),
    }
}

// 3.5.18. Consume a simple block  (kind of)
fn consume_simple_block(parser: &Parser, ending_token: tokens::Token)
        -> ~[Primitive] {
    let mut value: ~[Primitive] = ~[];
    loop {
        match parser.consume_token() {
            tokens::Comment => (),
            tokens::EOF => break,
            token => {
                if token == ending_token { break }
                else {
                    parser.reconsume_token(token);
                    value.push(consume_primitive(parser))
                }
            }
        }
    }
    value
}

// 3.5.19. Consume a function
fn consume_function(parser: &Parser, name: ~str)
        -> Primitive {
    let mut current_argument: ~[Primitive] = ~[];
    let mut arguments: ~[~[Primitive]] = ~[];
    loop {
        match parser.consume_token() {
            tokens::Comment => (),
            tokens::EOF | tokens::CloseParen => break,
            tokens::Delim(',') => {
                arguments.push(current_argument);
                current_argument = ~[];
            },
            tokens::Number(value, repr) => current_argument.push(
                // XXX case-sensitive or ASCII case-insensitive? See
            // http://lists.w3.org/Archives/Public/www-style/2013Jan/0480.html
                if parser.quirks_mode && ascii_lower(name) == ~"rect" {
                    // 3.5.17. Consume a primitive
                    // with the unitless length quirk
                    Dimension(value, repr, ~"px")
                } else {
                    Number(value, repr)
                }
            ),
            token => {
                parser.reconsume_token(token);
                current_argument.push(consume_primitive(parser))
            }
        }
    }
    arguments.push(current_argument);
    Function(name, arguments)
}

#[test]
fn test_primitives() {
    fn assert_primitives(input: &str, expected_primitives: &[Primitive],
                         expected_errors: &[~str]) {
        assert_primitives_flags(
            input, expected_primitives, expected_errors, false)
    }
    fn assert_primitives_flags(input: &str, expected_primitives: &[Primitive],
                               expected_errors: &[~str], quirks_mode: bool) {
        let parser = Parser::from_str(input, false, quirks_mode);
        let primitives: &[Primitive] = consume_primitive_list(parser);
        let errors: &[~str] = parser.errors;
        if primitives != expected_primitives {
            fail fmt!("%?\n!=\n%?", primitives, expected_primitives);
        }
        if errors != expected_errors {
            fail fmt!("%?\n!=\n%?", errors, expected_errors);
        }
    }

    assert_primitives("", [], []);
    assert_primitives("42 foo([aa ()b], -){\n  }", [
        Number(Integer(42), ~"42"), WhiteSpace,
        Function(~"foo", ~[
            ~[BraketBlock(~[
                Ident(~"aa"), WhiteSpace, ParenBlock(~[]), Ident(~"b")])],
            ~[WhiteSpace, Delim('-')]]),
        BraceBlock(~[
            WhiteSpace])], [])
}
<commit_msg>Quirks mode is indeed ASCII case-insensitive.<commit_after>// http://dev.w3.org/csswg/css3-syntax/#tree-construction
//
// The input to the tree construction stage is a sequence of tokens
// from the tokenization stage.
// The output is a tree of items with a stylesheet at the root
// and all other nodes being at-rules, style rules, or declarations.

use tokens;

#[deriving_eq]
enum Primitive {
    // Preserved tokens. Same as in the tokenizer.
    Ident(~str),
    AtKeyword(~str),
    Hash(~str),
    String(~str),
    URL(~str),
    Delim(char),
    Number(NumericValue, ~str),  // value, representation
    Percentage(NumericValue, ~str),  // value, representation
    Dimension(NumericValue, ~str, ~str),  // value, representation, unit
    UnicodeRange(char, char),  // start, end
    EmptyUnicodeRange,
    WhiteSpace,
    Comment,
    CDO,  // <!--
    CDC,  // -->
    Colon,  // :
    Semicolon,  // ;
    CloseBraket, // ]
    CloseParen, // )
    CloseBrace, // }

    // Function
    Function(~str, ~[~[Primitive]]),  // name, arguments

    // Simple block
    BraketBlock(~[Primitive]),  // […]
    ParenBlock(~[Primitive]),  // (…)
    BraceBlock(~[Primitive]),  // {…}
}

struct Declaration {
    name: ~str,
    value: ~[Primitive],
    important: bool,
}

struct StyleRule {
    selector: ~[Primitive],
    value: ~[DeclarationListItem],
}

struct AtRule {
    name: ~str,
    selector: ~[Primitive],
    value: AtRuleValue,
}

enum AtRuleValue {
    EmptyAtRule,  // @foo…;
    DeclarationFilled(~[DeclarationListItem]),
    RuleFilled(~[RuleListItem]),
}

enum DeclarationListItem {
    Declaration(Declaration),
    // A better idea for a name that means "at-rule" but is not "AtRule"?
    Decl_AtRule(AtRule),
}

enum RuleListItem {
    StyleRule(StyleRule),
    AtRule(AtRule),
}

pub struct Parser {
    priv tokenizer: ~tokens::Tokenizer,
    priv quirks_mode: bool,
    priv mut current_token: Option<tokens::Token>,
    priv mut errors: ~[~str],
}

impl Parser {
    static fn from_tokenizer(
            tokenizer: ~tokens::Tokenizer, quirks_mode: bool) -> ~Parser {
        ~Parser {
            tokenizer: tokenizer,
            quirks_mode: quirks_mode,
            current_token: None,
            errors: ~[],
        }
    }
    static fn from_str(input: &str, transform_function_whitespace: bool,
                      quirks_mode: bool) -> ~Parser {
        Parser::from_tokenizer(
            tokens::Tokenizer::from_str(input, transform_function_whitespace),
            quirks_mode)
    }
}

// Consume the whole input and return a list of primitives.
// Could be used for parsing eg. a stand-alone media query.
// This is similar to consume_simple_block(), but there is no ending token.
fn consume_primitive_list(parser: &Parser) -> ~[Primitive] {
    let mut value: ~[Primitive] = ~[];
    loop {
        match parser.consume_token() {
            tokens::Comment => (),
            tokens::EOF => break,
            token => {
                parser.reconsume_token(token);
                value.push(consume_primitive(parser))
            }
        }
    }
    value
}

//  ***********  End of public API  ***********

impl Parser {
    priv fn consume_token(&self) -> tokens::Token {
        let mut current_token = None;
        current_token <-> self.current_token;
        match current_token {
            Some(token) => token,
            None => {
                let (token, err) = self.tokenizer.next_token();
                match err {
                    Some(ParseError{message: message}) =>
                        // TODO more contextual error handling?
                        self.errors.push(message),
                    None => ()
                }
                token
            }
        }
    }

    // Fail if the is already a "current token".
    // The easiest way to ensure this does not fail it to call it only once
    // just after calling parser.consume_token()
    priv fn reconsume_token(&self, token: tokens::Token) {
        assert self.current_token.is_none();
        self.current_token = Some(token)
    }
}

// Convert a token from the tokenizer to a primitive.
// Fails if it is not a preserved token. XXX do something else.
fn preserved_token_to_primitive(token: tokens::Token) -> Primitive {
    match token {
        tokens::Ident(string) => Ident(string),
        tokens::AtKeyword(string) => AtKeyword(string),
        tokens::Hash(string) => Hash(string),
        tokens::String(string) => String(string),
        tokens::URL(string) => URL(string),
        tokens::Delim(ch) => Delim(ch),
        tokens::Number(value, repr) => Number(value, repr),
        tokens::Percentage(value, repr) => Percentage(value, repr),
        tokens::Dimension(value, repr, unit) => Dimension(value, repr, unit),
        tokens::UnicodeRange(start, end) => UnicodeRange(start, end),
        tokens::EmptyUnicodeRange => EmptyUnicodeRange,
        tokens::WhiteSpace => WhiteSpace,
        tokens::Colon => Colon,
        tokens::Semicolon => Semicolon,
        _ => fail,   // XXX
        // These are special-cased in consume_primitive()
//        tokens::Function(string) => fail,
//        tokens::OpenBraket => fail,
//        tokens::OpenParen => fail,
//        tokens::OpenBrace => fail,

        // These still need to be dealt with somehow.
//        tokens::BadString => fail,
//        tokens::BadURL => fail,
//        tokens::Comment => fail,
//        tokens::CDO => fail,
//        tokens::CDC => fail,
//        tokens::CloseBraket => fail,
//        tokens::CloseParen => fail,
//        tokens::CloseBrace => fail,
//        tokens::EOF => fail,
    }
}

// 3.5.15. Consume a primitive
fn consume_primitive(parser: &Parser) -> Primitive {
    match parser.consume_token() {
        tokens::OpenBraket =>
            BraketBlock(consume_simple_block(parser, tokens::CloseBraket)),
        tokens::OpenParen =>
            ParenBlock(consume_simple_block(parser, tokens::CloseParen)),
        tokens::OpenBrace =>
            BraceBlock(consume_simple_block(parser, tokens::CloseBrace)),
        tokens::Function(string) => consume_function(parser, string),
        token => preserved_token_to_primitive(token),
    }
}

// 3.5.18. Consume a simple block  (kind of)
fn consume_simple_block(parser: &Parser, ending_token: tokens::Token)
        -> ~[Primitive] {
    let mut value: ~[Primitive] = ~[];
    loop {
        match parser.consume_token() {
            tokens::Comment => (),
            tokens::EOF => break,
            token => {
                if token == ending_token { break }
                else {
                    parser.reconsume_token(token);
                    value.push(consume_primitive(parser))
                }
            }
        }
    }
    value
}

// 3.5.19. Consume a function
fn consume_function(parser: &Parser, name: ~str)
        -> Primitive {
    let mut current_argument: ~[Primitive] = ~[];
    let mut arguments: ~[~[Primitive]] = ~[];
    loop {
        match parser.consume_token() {
            tokens::Comment => (),
            tokens::EOF | tokens::CloseParen => break,
            tokens::Delim(',') => {
                arguments.push(current_argument);
                current_argument = ~[];
            },
            tokens::Number(value, repr) => current_argument.push(
                if parser.quirks_mode && ascii_lower(name) == ~"rect" {
                    // 3.5.17. Consume a primitive
                    // with the unitless length quirk
                    Dimension(value, repr, ~"px")
                } else {
                    Number(value, repr)
                }
            ),
            token => {
                parser.reconsume_token(token);
                current_argument.push(consume_primitive(parser))
            }
        }
    }
    arguments.push(current_argument);
    Function(name, arguments)
}

#[test]
fn test_primitives() {
    fn assert_primitives(input: &str, expected_primitives: &[Primitive],
                         expected_errors: &[~str]) {
        assert_primitives_flags(
            input, expected_primitives, expected_errors, false)
    }
    fn assert_primitives_flags(input: &str, expected_primitives: &[Primitive],
                               expected_errors: &[~str], quirks_mode: bool) {
        let parser = Parser::from_str(input, false, quirks_mode);
        let primitives: &[Primitive] = consume_primitive_list(parser);
        let errors: &[~str] = parser.errors;
        if primitives != expected_primitives {
            fail fmt!("%?\n!=\n%?", primitives, expected_primitives);
        }
        if errors != expected_errors {
            fail fmt!("%?\n!=\n%?", errors, expected_errors);
        }
    }

    assert_primitives("", [], []);
    assert_primitives("42 foo([aa ()b], -){\n  }", [
        Number(Integer(42), ~"42"), WhiteSpace,
        Function(~"foo", ~[
            ~[BraketBlock(~[
                Ident(~"aa"), WhiteSpace, ParenBlock(~[]), Ident(~"b")])],
            ~[WhiteSpace, Delim('-')]]),
        BraceBlock(~[
            WhiteSpace])], [])
}
<|endoftext|>


<commit_before>use std::fs;
use std::path::PathBuf;
use std::sync::Arc;

use config::Config;
use dir_pool::{DirPool, HeldDir};
use git::Git;
use github;

// clones git repos with given github session into a managed directory pool
pub struct GitCloneManager {
    dir_pool: Arc<DirPool>,
    github_session: Arc<github::api::Session>,
}

impl GitCloneManager {
    pub fn new(github_session: Arc<github::api::Session>, config: Arc<Config>) -> GitCloneManager {
        let clone_root_dir = config.main.clone_root_dir.to_string();

        GitCloneManager {
            dir_pool: Arc::new(DirPool::new(&clone_root_dir)),
            github_session: github_session.clone(),
        }
    }

    pub fn clone(&self, owner: &str, repo: &str) -> Result<HeldDir, String> {
        let held_clone_dir = self.dir_pool.take_directory(self.github_session.github_host(), owner, repo);
        try!(self.clone_repo(owner, repo, &held_clone_dir.dir()));

        Ok(held_clone_dir)
    }

    fn clone_repo(&self, owner: &str, repo: &str, clone_dir: &PathBuf) -> Result<(), String> {
        let url = format!("https://{}@{}/{}/{}",
                          self.github_session.user().login(),
                          self.github_session.github_host(),
                          owner,
                          repo);

        let git = Git::new(self.github_session.github_host(),
                           self.github_session.github_token(),
                           clone_dir);

        if clone_dir.join(".git").exists() {
            // prune local tags deleted from remotes: important to avoid stale/bad version tags
            try!(git.run(&["fetch", "--prune", "+refs/tags/*:refs/tags/*"]));
        } else {
            if let Err(e) = fs::create_dir_all(&clone_dir) {
                return Err(format!("Error creating clone directory '{:?}': {}", clone_dir, e));
            }
            try!(git.run(&["clone", &url, "."]));
        }

        // always fetch latest tags
        try!(git.run(&["fetch", "--tags"]));
        // clean up state
        try!(git.clean());

        Ok(())
    }
}
<commit_msg>Fix git clone (#120)<commit_after>use std::fs;
use std::path::PathBuf;
use std::sync::Arc;

use config::Config;
use dir_pool::{DirPool, HeldDir};
use git::Git;
use github;

// clones git repos with given github session into a managed directory pool
pub struct GitCloneManager {
    dir_pool: Arc<DirPool>,
    github_session: Arc<github::api::Session>,
}

impl GitCloneManager {
    pub fn new(github_session: Arc<github::api::Session>, config: Arc<Config>) -> GitCloneManager {
        let clone_root_dir = config.main.clone_root_dir.to_string();

        GitCloneManager {
            dir_pool: Arc::new(DirPool::new(&clone_root_dir)),
            github_session: github_session.clone(),
        }
    }

    pub fn clone(&self, owner: &str, repo: &str) -> Result<HeldDir, String> {
        let held_clone_dir = self.dir_pool.take_directory(self.github_session.github_host(), owner, repo);
        try!(self.clone_repo(owner, repo, &held_clone_dir.dir()));

        Ok(held_clone_dir)
    }

    fn clone_repo(&self, owner: &str, repo: &str, clone_dir: &PathBuf) -> Result<(), String> {
        let url = format!("https://{}@{}/{}/{}",
                          self.github_session.user().login(),
                          self.github_session.github_host(),
                          owner,
                          repo);

        let git = Git::new(self.github_session.github_host(),
                           self.github_session.github_token(),
                           clone_dir);

        if clone_dir.join(".git").exists() {
            // prune local tags deleted from remotes: important to avoid stale/bad version tags
            try!(git.run(&["fetch", "--prune", "origin", "+refs/tags/*:refs/tags/*"]));
        } else {
            if let Err(e) = fs::create_dir_all(&clone_dir) {
                return Err(format!("Error creating clone directory '{:?}': {}", clone_dir, e));
            }
            try!(git.run(&["clone", &url, "."]));
        }

        // always fetch latest tags
        try!(git.run(&["fetch", "--tags"]));
        // clean up state
        try!(git.clean());

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::env;

pub mod articles;
pub mod likes;
pub mod notes;
pub mod pictures;

pub use articles::*;
pub use likes::*;
pub use notes::*;
pub use pictures::*;

pub fn asset_base_uri() -> String {
    let mut base = env::var("BASE_URI").unwrap();
    base.push_str("static/");
    base
}

pub fn asset_uri(asset: &str) -> String {
    let mut base = asset_base_uri();
    if !base.ends_with("/") {
        base.push_str("/");
    }

    base.push_str(asset.trim_start_matches("/"));
    base
}

pub fn root_uri() -> String {
    env::var("BASE_URI").unwrap()
}

pub fn page_uri(page: &str) -> String {
    let mut uri = root_uri();
    if !uri.ends_with("/") {
        uri.push_str("/");
    }

    uri.push_str(page.trim_start_matches("/"));
    uri
}

pub fn whatsnew_atom_uri() -> String {
    page_uri("whatsnew.atom")
}

pub fn login_uri() -> String {
    let mut uri = root_uri();
    if !uri.ends_with("/") {
        uri.push_str("/");
    }

    uri.push_str("login");

    uri
}

pub fn logout_uri() -> String {
    let mut uri = root_uri();
    if !uri.ends_with("/") {
        uri.push_str("/");
    }

    uri.push_str("logout");

    uri
}

pub fn webmentions_endpoint_uri() -> String {
    let mut uri = root_uri();
    if !uri.ends_with("/") {
        uri.push_str("/");
    }

    uri.push_str("webmentions");
    uri
}
<commit_msg>use expect instead of unwrap for better error messages<commit_after>use std::env;

pub mod articles;
pub mod likes;
pub mod notes;
pub mod pictures;

pub use articles::*;
pub use likes::*;
pub use notes::*;
pub use pictures::*;

pub fn asset_base_uri() -> String {
    let mut base = env::var("BASE_URI").expect("BASE_URI is not set");
    base.push_str("static/");
    base
}

pub fn asset_uri(asset: &str) -> String {
    let mut base = asset_base_uri();
    if !base.ends_with("/") {
        base.push_str("/");
    }

    base.push_str(asset.trim_start_matches("/"));
    base
}

pub fn root_uri() -> String {
    env::var("BASE_URI").expect("BASE_URI is not set")
}

pub fn page_uri(page: &str) -> String {
    let mut uri = root_uri();
    if !uri.ends_with("/") {
        uri.push_str("/");
    }

    uri.push_str(page.trim_start_matches("/"));
    uri
}

pub fn whatsnew_atom_uri() -> String {
    page_uri("whatsnew.atom")
}

pub fn login_uri() -> String {
    let mut uri = root_uri();
    if !uri.ends_with("/") {
        uri.push_str("/");
    }

    uri.push_str("login");

    uri
}

pub fn logout_uri() -> String {
    let mut uri = root_uri();
    if !uri.ends_with("/") {
        uri.push_str("/");
    }

    uri.push_str("logout");

    uri
}

pub fn webmentions_endpoint_uri() -> String {
    let mut uri = root_uri();
    if !uri.ends_with("/") {
        uri.push_str("/");
    }

    uri.push_str("webmentions");
    uri
}
<|endoftext|>