<commit_before>use na::{DefaultAllocator, Real, Unit, Rotation3, Point3};

use traits::{Dimension, Number, Alloc};
use aliases::{TMat, TVec, TVec3, TMat4};

/// The identity matrix.
pub fn identity<N: Number, D: Dimension>() -> TMat<N, D, D>
    where DefaultAllocator: Alloc<N, D, D> {
    TMat::<N, D, D>::identity()
}

/// Build a look at view matrix based on the right handedness.
///
/// # Parameters
///    * `eye`   − Position of the camera
///    * `center` − Position where the camera is looking at
///    * `u` − Normalized up vector, how the camera is oriented. Typically `(0, 1, 0)`
pub fn look_at<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
    look_at_rh(eye, center, up)
}

/// Build a left handed look at view matrix.
///
/// # Parameters
///    * `eye`   − Position of the camera
///    * `center` − Position where the camera is looking at
///    * `u` − Normalized up vector, how the camera is oriented. Typically `(0, 1, 0)`
pub fn look_at_lh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
    TMat::look_at_lh(&Point3::from_coordinates(*eye), &Point3::from_coordinates(*center), up)
}

/// Build a right handed look at view matrix.
///
/// # Parameters
///    * `eye`   − Position of the camera
///    * `center` − Position where the camera is looking at
///    * `u` − Normalized up vector, how the camera is oriented. Typically `(0, 1, 0)`
pub fn look_at_rh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
    TMat::look_at_rh(&Point3::from_coordinates(*eye), &Point3::from_coordinates(*center), up)
}

/// Builds a rotation 4 * 4 matrix created from an axis vector and an angle and right-multiply it to `m`.
///
/// # Parameters
///    * m − Input matrix multiplied by this rotation matrix.
///    * angle − Rotation angle expressed in radians.
///    * axis  − Rotation axis, recommended to be normalized.
pub fn rotate<N: Real>(m: &TMat4<N>, angle: N, axis: &TVec3<N>) -> TMat4<N> {
    m * Rotation3::from_axis_angle(&Unit::new_normalize(*axis), angle).to_homogeneous()
}

/// Builds a rotation 4 * 4 matrix around the X axis and right-multiply it to `m`.
///
/// # Parameters
///    * m − Input matrix multiplied by this rotation matrix.
///    * angle − Rotation angle expressed in radians.
pub fn rotate_x<N: Real>(m: &TMat4<N>, angle: N) -> TMat4<N> {
    rotate(m, angle, &TVec::x())
}

/// Builds a rotation 4 * 4 matrix around the Y axis and right-multiply it to `m`.
///
/// # Parameters
///    * m − Input matrix multiplied by this rotation matrix.
///    * angle − Rotation angle expressed in radians.
pub fn rotate_y<N: Real>(m: &TMat4<N>, angle: N) -> TMat4<N> {
    rotate(m, angle, &TVec::y())
}

/// Builds a rotation 4 * 4 matrix around the Z axis and right-multiply it to `m`.
///
/// # Parameters
///    * m − Input matrix multiplied by this rotation matrix.
///    * angle − Rotation angle expressed in radians.
pub fn rotate_z<N: Real>(m: &TMat4<N>, angle: N) -> TMat4<N> {
    rotate(m, angle, &TVec::z())
}

/// Builds a scale 4 * 4 matrix created from 3 scalars and right-multiply it to `m`.
///
/// # Parameters
///    * m − Input matrix multiplied by this scale matrix.
///    * v − Ratio of scaling for each axis.
pub fn scale<N: Number>(m: &TMat4<N>, v: &TVec3<N>) -> TMat4<N> {
    m.prepend_nonuniform_scaling(v)
}

/// Builds a translation 4 * 4 matrix created from a vector of 3 components and right-multiply it to `m`.
///
/// # Parameters
///    * m − Input matrix multiplied by this translation matrix.
///    * v − Coordinates of a translation vector.
pub fn translate<N: Number>(m: &TMat4<N>, v: &TVec3<N>) -> TMat4<N> {
    m.prepend_translation(v)
}
<commit_msg>glm: Add missing backticks around parameter names.<commit_after>use na::{DefaultAllocator, Real, Unit, Rotation3, Point3};

use traits::{Dimension, Number, Alloc};
use aliases::{TMat, TVec, TVec3, TMat4};

/// The identity matrix.
pub fn identity<N: Number, D: Dimension>() -> TMat<N, D, D>
    where DefaultAllocator: Alloc<N, D, D> {
    TMat::<N, D, D>::identity()
}

/// Build a look at view matrix based on the right handedness.
///
/// # Parameters
///    * `eye`   − Position of the camera
///    * `center` − Position where the camera is looking at
///    * `u` − Normalized up vector, how the camera is oriented. Typically `(0, 1, 0)`
pub fn look_at<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
    look_at_rh(eye, center, up)
}

/// Build a left handed look at view matrix.
///
/// # Parameters
///    * `eye`   − Position of the camera
///    * `center` − Position where the camera is looking at
///    * `u` − Normalized up vector, how the camera is oriented. Typically `(0, 1, 0)`
pub fn look_at_lh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
    TMat::look_at_lh(&Point3::from_coordinates(*eye), &Point3::from_coordinates(*center), up)
}

/// Build a right handed look at view matrix.
///
/// # Parameters
///    * `eye`   − Position of the camera
///    * `center` − Position where the camera is looking at
///    * `u` − Normalized up vector, how the camera is oriented. Typically `(0, 1, 0)`
pub fn look_at_rh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
    TMat::look_at_rh(&Point3::from_coordinates(*eye), &Point3::from_coordinates(*center), up)
}

/// Builds a rotation 4 * 4 matrix created from an axis vector and an angle and right-multiply it to `m`.
///
/// # Parameters
///    * `m` − Input matrix multiplied by this rotation matrix.
///    * `angle` − Rotation angle expressed in radians.
///    * `axis`  − Rotation axis, recommended to be normalized.
pub fn rotate<N: Real>(m: &TMat4<N>, angle: N, axis: &TVec3<N>) -> TMat4<N> {
    m * Rotation3::from_axis_angle(&Unit::new_normalize(*axis), angle).to_homogeneous()
}

/// Builds a rotation 4 * 4 matrix around the X axis and right-multiply it to `m`.
///
/// # Parameters
///    * `m` − Input matrix multiplied by this rotation matrix.
///    * `angle` − Rotation angle expressed in radians.
pub fn rotate_x<N: Real>(m: &TMat4<N>, angle: N) -> TMat4<N> {
    rotate(m, angle, &TVec::x())
}

/// Builds a rotation 4 * 4 matrix around the Y axis and right-multiply it to `m`.
///
/// # Parameters
///    * `m` − Input matrix multiplied by this rotation matrix.
///    * `angle` − Rotation angle expressed in radians.
pub fn rotate_y<N: Real>(m: &TMat4<N>, angle: N) -> TMat4<N> {
    rotate(m, angle, &TVec::y())
}

/// Builds a rotation 4 * 4 matrix around the Z axis and right-multiply it to `m`.
///
/// # Parameters
///    * `m` − Input matrix multiplied by this rotation matrix.
///    * `angle` − Rotation angle expressed in radians.
pub fn rotate_z<N: Real>(m: &TMat4<N>, angle: N) -> TMat4<N> {
    rotate(m, angle, &TVec::z())
}

/// Builds a scale 4 * 4 matrix created from 3 scalars and right-multiply it to `m`.
///
/// # Parameters
///    * `m` − Input matrix multiplied by this scale matrix.
///    * `v` − Ratio of scaling for each axis.
pub fn scale<N: Number>(m: &TMat4<N>, v: &TVec3<N>) -> TMat4<N> {
    m.prepend_nonuniform_scaling(v)
}

/// Builds a translation 4 * 4 matrix created from a vector of 3 components and right-multiply it to `m`.
///
/// # Parameters
///    * `m` − Input matrix multiplied by this translation matrix.
///    * `v` − Coordinates of a translation vector.
pub fn translate<N: Number>(m: &TMat4<N>, v: &TVec3<N>) -> TMat4<N> {
    m.prepend_translation(v)
}
<|endoftext|>


<commit_before>use std::io::prelude::*;

pub struct Socket {
    socket: ::std::net::TcpStream,
}

impl Socket {
    pub fn new(ip: &str, port: u16) -> Self {
        let socket = match ::std::net::TcpStream::connect((ip, port)) {
            Ok(socket) => socket,
            Err(_) => panic!("Unable to connect to {}:{}", ip, port),
        };

        Socket {
            socket: socket,
        }
    }

    pub fn send<D>(&mut self, command: D) where D: ::std::fmt::Display {
        info!("> {}", command);

        self.socket.write(
            format!("{}\r\n", command).as_bytes()
        );
    }

    pub fn receive(&mut self) -> String {
        let mut message = String::new();
        let mut reader = ::std::io::BufReader::new(self.socket.try_clone().unwrap());

        reader.read_line(&mut message);

        let message = message.trim_right_matches("\r\n");

        debug!("< {}", message);

        message.into()
    }
}

impl Clone for Socket {
    fn clone(&self) -> Self {
        Socket {
            socket: self.socket.try_clone().unwrap(),
        }
    }
}
<commit_msg>Supress warnings<commit_after>use std::io::prelude::*;

pub struct Socket {
    socket: ::std::net::TcpStream,
}

impl Socket {
    pub fn new(ip: &str, port: u16) -> Self {
        let socket = match ::std::net::TcpStream::connect((ip, port)) {
            Ok(socket) => socket,
            Err(_) => panic!("Unable to connect to {}:{}", ip, port),
        };

        Socket {
            socket: socket,
        }
    }

    pub fn send<D>(&mut self, command: D) where D: ::std::fmt::Display {
        info!("> {}", command);

        self.socket.write(format!("{}\r\n", command).as_bytes())
            .unwrap();
    }

    pub fn receive(&mut self) -> String {
        let mut message = String::new();
        let mut reader = ::std::io::BufReader::new(self.socket.try_clone().unwrap());

        reader.read_line(&mut message)
            .unwrap();

        let message = message.trim_right_matches("\r\n");

        debug!("< {}", message);

        message.into()
    }
}

impl Clone for Socket {
    fn clone(&self) -> Self {
        Socket {
            socket: self.socket.try_clone().unwrap(),
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::error::Error;
use std::io::ErrorKind::{WouldBlock, BrokenPipe, WriteZero, ConnectionReset};

use rotor::{Response, Scope, Machine, EventSet, PollOpt, Time};
use rotor::void::{Void, unreachable};

use substr::find_substr;
use extensions::{ScopeExt, ResponseExt};
use {Expectation, Protocol, StreamSocket, Stream, StreamImpl};
use {Buf, Transport, Accepted, Exception, Intent};
use {ProtocolStop, SocketError};

#[derive(Debug)]
enum IoOp {
    Done,
    NoOp,
    Eos,
    Error(io::Error),
}

fn to_result
(intent: Intent
)
    -> Result<(P, Expectation, Option<Time>), Option<Box<Error>>>
{
    match intent.0 {
        Ok(x) => Ok((x, intent.1, intent.2)),
        Err(e) => Err(e),
    }
}

impl<S: StreamSocket> StreamImpl<S> {
    fn transport(&mut self) -> Transport<S> {
        Transport {
            sock: &mut self.socket,
            inbuf: &mut self.inbuf,
            outbuf: &mut self.outbuf,
        }
    }
    fn action<M>(self, intent: Intent<M>,
        scope: &mut Scope<M::Context>)
        -> Response<Stream<M>, Void>
        where M: Protocol<Socket=S>
    {
        match self._action(intent, scope) {
            Ok(stream) => {
                let dline = stream.deadline;
                Response::ok(stream).deadline_opt(dline)
            }
            Err(Some(e)) => Response::error(e),
            Err(None) => Response::done(),
        }
    }
    fn _action
(mut self, intent: Intent
,
        scope: &mut Scope
)
        -> Result<Stream
, Option<Box<Error>>>
        where P: Protocol<Socket=S>
    {
        use Expectation::*;
        let mut intent = try!(to_result(intent));
        let mut can_write = match self.write() {
            IoOp::Done => true,
            IoOp::NoOp => false,
            IoOp::Eos => {
                self.outbuf.remove_range(..);
                return Err(intent.0.fatal(
                    Exception::WriteError(io::Error::new(
                        WriteZero, "failed to write whole buffer")),
                    scope));
            }
            IoOp::Error(e) => {
                return Err(intent.0.fatal(
                    Exception::WriteError(e),
                    scope));
            }
        };
        'outer: loop {
            if can_write {
                can_write = match self.write() {
                    IoOp::Done => true,
                    IoOp::NoOp => false,
                    IoOp::Eos => {
                        self.outbuf.remove_range(..);
                        return Err(intent.0.fatal(
                            Exception::WriteError(io::Error::new(
                                WriteZero, "failed to write whole buffer")),
                            scope));
                    }
                    IoOp::Error(e) => {
                        self.outbuf.remove_range(..);
                        return Err(intent.0.fatal(
                            Exception::WriteError(e),
                            scope));
                    }
                };
            }
            match intent.1 {
                Bytes(num) => {
                    loop {
                        if self.inbuf.len() >= num {
                            intent = try!(to_result(intent.0.bytes_read(
                                &mut self.transport(),
                                num, scope)));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, intent));
                            }
                            IoOp::Eos => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope)));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope)));
                                continue 'outer;
                            }
                        }
                    }
                }
                Delimiter(min, delim, max) => {
                    loop {
                        if self.inbuf.len() > min {
                            let opt = find_substr(&self.inbuf[min..], delim);
                            if let Some(num) = opt {
                                intent = try!(to_result(intent.0.bytes_read(
                                    &mut self.transport(),
                                    num, scope)));
                                continue 'outer;
                            }
                        }
                        if self.inbuf.len() > max {
                            intent = try!(to_result(intent.0.exception(
                                &mut self.transport(),
                                Exception::LimitReached,
                                scope)));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, intent));
                            }
                            IoOp::Eos => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope)));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope)));
                                continue 'outer;
                            }
                        }
                    }
                }
                Flush(num) => {
                    if self.outbuf.len() <= num {
                        intent = try!(to_result(intent.0.bytes_flushed(
                            &mut self.transport(), scope)));
                    } else {
                        return Ok(Stream::compose(self, intent));
                    }
                }
                Sleep => {
                    return Ok(Stream::compose(self, intent));
                }
            }
        }
    }
    // Returns Ok(true) to if we have read something, does not loop for reading
    // because this might use whole memory, and we may parse and consume the
    // input instead of buffering it whole.
    fn read(&mut self) -> IoOp {
        match self.inbuf.read_from(&mut self.socket) {
            Ok(0) => IoOp::Eos,
            Ok(_) => IoOp::Done,
            Err(ref e) if e.kind() == BrokenPipe
                       || e.kind() == ConnectionReset
            => return IoOp::Eos,
            Err(ref e) if e.kind() == WouldBlock => IoOp::NoOp,
            Err(e) => IoOp::Error(e),
        }
    }
    fn write(&mut self) -> IoOp {
        loop {
            if self.outbuf.len() == 0 {
                return IoOp::Done;
            }
            match self.outbuf.write_to(&mut self.socket) {
                Ok(0) => return IoOp::Eos,
                Ok(_) => continue,
                Err(ref e) if e.kind() == BrokenPipe
                           || e.kind() == ConnectionReset
                => return IoOp::Eos,
                Err(ref e) if e.kind() == WouldBlock => return IoOp::NoOp,
                Err(e) => return IoOp::Error(e),
            }
        }
    }
}

impl
 Accepted for Stream

    where
::Seed: Clone
{
    type Seed =
::Seed;
    type Socket = P::Socket;
    fn accepted(sock: P::Socket, seed:
::Seed,
        scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>
    {
        Self::new(sock, seed, scope)
    }
}

impl
 Stream
 {
    /// Get a `Transport` object for the stream
    ///
    /// This method is only useful if you want to manipulate buffers
    /// externally (like pushing to the buffer from another thread). Just be
    /// sure to **wake up** state machine after manipulating buffers.
    pub fn transport(&mut self) -> Transport
 {
        Transport {
            sock: &mut self.socket,
            inbuf: &mut self.inbuf,
            outbuf: &mut self.outbuf,
        }
    }
    /// Get a `Protocol` object for the stream
    ///
    /// This method is only useful if you want to adjust protocol dysyr
    /// externally (like update some values after pushing data to buffer).
    /// Just be sure to **wake up** state machine if needed by the protocol.
    pub fn protocol(&mut self) -> &mut P {
        &mut self.fsm
    }
    fn decompose(self) -> (P, Expectation, Option<Time>, StreamImpl
)
    {
        (self.fsm, self.expectation, self.deadline, StreamImpl {
            socket: self.socket,
            connected: self.connected,
            inbuf: self.inbuf,
            outbuf: self.outbuf,
        })
    }
    fn compose(implem: StreamImpl
,
        (fsm, exp, dline): (P, Expectation, Option<Time>))
        -> Stream

    {
        Stream {
            fsm: fsm,
            socket: implem.socket,
            expectation: exp,
            connected: implem.connected,
            deadline: dline,
            inbuf: implem.inbuf,
            outbuf: implem.outbuf,
        }
    }
    pub fn new(mut sock: P::Socket, seed: P::Seed,
        scope: &mut Scope
)
        -> Response<Self, Void>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        if let Err(e) = scope.register(&sock,
            EventSet::readable() | EventSet::writable(), PollOpt::edge())
        {
            // TODO(tailhook) wrap it to more clear error
            return Response::error(Box::new(e));
        }
        let Intent(m, exp, dline) = P::create(seed, &mut sock, scope);
        match m {
            Err(None) => Response::error(Box::new(ProtocolStop)),
            Err(Some(e)) => Response::error(e),
            Ok(m) => {
                Response::ok(Stream {
                    socket: sock,
                    expectation: exp,
                    connected: false,
                    deadline: dline,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                }).deadline_opt(dline)
            }
        }
    }
    pub fn connected(mut sock: P::Socket, seed: P::Seed,
        scope: &mut Scope
)
        -> Response<Self, Void>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        //
        // We reregister here, because we assume that higher level abstraction
        // has the socket already registered (perhaps `Persistent` machine)
        if let Err(e) = scope.reregister(&sock,
            EventSet::readable() | EventSet::writable(), PollOpt::edge())
        {
            // TODO(tailhook) wrap it to more clear error
            return Response::error(Box::new(e));
        }
        let Intent(m, exp, dline) = P::create(seed, &mut sock, scope);
        match m {
            Err(None) => Response::error(Box::new(ProtocolStop)),
            Err(Some(e)) => Response::error(e),
            Ok(m) => {
                Response::ok(Stream {
                    socket: sock,
                    expectation: exp,
                    connected: true,
                    deadline: dline,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                }).deadline_opt(dline)
            }
        }
    }
}

impl
 Machine for Stream

{
    type Context = P::Context;
    type Seed = Void;
    fn create(void: Void, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>
    {
        unreachable(void);
    }
    fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        // TODO(tailhook) use `events` to optimize reading
        let (fsm, exp, dline, mut imp) = self.decompose();
        if !imp.connected && events.is_writable() {
            match imp.socket.take_socket_error() {
                Ok(()) => {}
                Err(e) => {
                    match fsm.fatal(Exception::ConnectError(e), scope) {
                        Some(e) => return Response::error(e),
                        None => return Response::done(),
                    }
                }
            }
            imp.connected = true;
        }
        imp.action(Intent(Ok(fsm), exp, dline), scope)
    }
    fn spawned(self, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        if scope.reached(self.deadline) {
            let (fsm, _exp, _dline, mut imp) = self.decompose();
            let res = fsm.timeout(&mut imp.transport(), scope);
            imp.action(res, scope)
        } else {
            // TODO(tailhook) in rotor 0.6 should be no spurious timeouts
            // anymore, but let's keep it until we remove Scope::timeout_ms()
            Response::ok(self)
        }
    }
    fn wakeup(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        let (fsm, _exp, _dline, mut imp) = self.decompose();
        let res = fsm.wakeup(&mut imp.transport(), scope);
        imp.action(res, scope)
    }
}
<commit_msg>handle hup and error events<commit_after>use std::io;
use std::error::Error;
use std::io::ErrorKind::{WouldBlock, BrokenPipe, WriteZero, ConnectionReset};

use rotor::{Response, Scope, Machine, EventSet, PollOpt, Time};
use rotor::void::{Void, unreachable};

use substr::find_substr;
use extensions::{ScopeExt, ResponseExt};
use {Expectation, Protocol, StreamSocket, Stream, StreamImpl};
use {Buf, Transport, Accepted, Exception, Intent};
use {ProtocolStop, SocketError};

#[derive(Debug)]
enum IoOp {
    Done,
    NoOp,
    Eos,
    Error(io::Error),
}

fn to_result
(intent: Intent
)
    -> Result<(P, Expectation, Option<Time>), Option<Box<Error>>>
{
    match intent.0 {
        Ok(x) => Ok((x, intent.1, intent.2)),
        Err(e) => Err(e),
    }
}

impl<S: StreamSocket> StreamImpl<S> {
    fn transport(&mut self) -> Transport<S> {
        Transport {
            sock: &mut self.socket,
            inbuf: &mut self.inbuf,
            outbuf: &mut self.outbuf,
        }
    }
    fn action<M>(self, intent: Intent<M>,
        scope: &mut Scope<M::Context>)
        -> Response<Stream<M>, Void>
        where M: Protocol<Socket=S>
    {
        match self._action(intent, scope) {
            Ok(stream) => {
                let dline = stream.deadline;
                Response::ok(stream).deadline_opt(dline)
            }
            Err(Some(e)) => Response::error(e),
            Err(None) => Response::done(),
        }
    }
    fn _action
(mut self, intent: Intent
,
        scope: &mut Scope
)
        -> Result<Stream
, Option<Box<Error>>>
        where P: Protocol<Socket=S>
    {
        use Expectation::*;
        let mut intent = try!(to_result(intent));
        let mut can_write = match self.write() {
            IoOp::Done => true,
            IoOp::NoOp => false,
            IoOp::Eos => {
                self.outbuf.remove_range(..);
                return Err(intent.0.fatal(
                    Exception::WriteError(io::Error::new(
                        WriteZero, "failed to write whole buffer")),
                    scope));
            }
            IoOp::Error(e) => {
                return Err(intent.0.fatal(
                    Exception::WriteError(e),
                    scope));
            }
        };
        'outer: loop {
            if can_write {
                can_write = match self.write() {
                    IoOp::Done => true,
                    IoOp::NoOp => false,
                    IoOp::Eos => {
                        self.outbuf.remove_range(..);
                        return Err(intent.0.fatal(
                            Exception::WriteError(io::Error::new(
                                WriteZero, "failed to write whole buffer")),
                            scope));
                    }
                    IoOp::Error(e) => {
                        self.outbuf.remove_range(..);
                        return Err(intent.0.fatal(
                            Exception::WriteError(e),
                            scope));
                    }
                };
            }
            match intent.1 {
                Bytes(num) => {
                    loop {
                        if self.inbuf.len() >= num {
                            intent = try!(to_result(intent.0.bytes_read(
                                &mut self.transport(),
                                num, scope)));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, intent));
                            }
                            IoOp::Eos => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope)));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope)));
                                continue 'outer;
                            }
                        }
                    }
                }
                Delimiter(min, delim, max) => {
                    loop {
                        if self.inbuf.len() > min {
                            let opt = find_substr(&self.inbuf[min..], delim);
                            if let Some(num) = opt {
                                intent = try!(to_result(intent.0.bytes_read(
                                    &mut self.transport(),
                                    num, scope)));
                                continue 'outer;
                            }
                        }
                        if self.inbuf.len() > max {
                            intent = try!(to_result(intent.0.exception(
                                &mut self.transport(),
                                Exception::LimitReached,
                                scope)));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, intent));
                            }
                            IoOp::Eos => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope)));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope)));
                                continue 'outer;
                            }
                        }
                    }
                }
                Flush(num) => {
                    if self.outbuf.len() <= num {
                        intent = try!(to_result(intent.0.bytes_flushed(
                            &mut self.transport(), scope)));
                    } else {
                        return Ok(Stream::compose(self, intent));
                    }
                }
                Sleep => {
                    return Ok(Stream::compose(self, intent));
                }
            }
        }
    }
    // Returns Ok(true) to if we have read something, does not loop for reading
    // because this might use whole memory, and we may parse and consume the
    // input instead of buffering it whole.
    fn read(&mut self) -> IoOp {
        match self.inbuf.read_from(&mut self.socket) {
            Ok(0) => IoOp::Eos,
            Ok(_) => IoOp::Done,
            Err(ref e) if e.kind() == BrokenPipe
                       || e.kind() == ConnectionReset
            => return IoOp::Eos,
            Err(ref e) if e.kind() == WouldBlock => IoOp::NoOp,
            Err(e) => IoOp::Error(e),
        }
    }
    fn write(&mut self) -> IoOp {
        loop {
            if self.outbuf.len() == 0 {
                return IoOp::Done;
            }
            match self.outbuf.write_to(&mut self.socket) {
                Ok(0) => return IoOp::Eos,
                Ok(_) => continue,
                Err(ref e) if e.kind() == BrokenPipe
                           || e.kind() == ConnectionReset
                => return IoOp::Eos,
                Err(ref e) if e.kind() == WouldBlock => return IoOp::NoOp,
                Err(e) => return IoOp::Error(e),
            }
        }
    }
}

impl
 Accepted for Stream

    where
::Seed: Clone
{
    type Seed =
::Seed;
    type Socket = P::Socket;
    fn accepted(sock: P::Socket, seed:
::Seed,
        scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>
    {
        Self::new(sock, seed, scope)
    }
}

impl
 Stream
 {
    /// Get a `Transport` object for the stream
    ///
    /// This method is only useful if you want to manipulate buffers
    /// externally (like pushing to the buffer from another thread). Just be
    /// sure to **wake up** state machine after manipulating buffers.
    pub fn transport(&mut self) -> Transport
 {
        Transport {
            sock: &mut self.socket,
            inbuf: &mut self.inbuf,
            outbuf: &mut self.outbuf,
        }
    }
    /// Get a `Protocol` object for the stream
    ///
    /// This method is only useful if you want to adjust protocol dysyr
    /// externally (like update some values after pushing data to buffer).
    /// Just be sure to **wake up** state machine if needed by the protocol.
    pub fn protocol(&mut self) -> &mut P {
        &mut self.fsm
    }
    fn decompose(self) -> (P, Expectation, Option<Time>, StreamImpl
)
    {
        (self.fsm, self.expectation, self.deadline, StreamImpl {
            socket: self.socket,
            connected: self.connected,
            inbuf: self.inbuf,
            outbuf: self.outbuf,
        })
    }
    fn compose(implem: StreamImpl
,
        (fsm, exp, dline): (P, Expectation, Option<Time>))
        -> Stream

    {
        Stream {
            fsm: fsm,
            socket: implem.socket,
            expectation: exp,
            connected: implem.connected,
            deadline: dline,
            inbuf: implem.inbuf,
            outbuf: implem.outbuf,
        }
    }
    pub fn new(mut sock: P::Socket, seed: P::Seed,
        scope: &mut Scope
)
        -> Response<Self, Void>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        if let Err(e) = scope.register(&sock,
            EventSet::all(), PollOpt::edge())
        {
            // TODO(tailhook) wrap it to more clear error
            return Response::error(Box::new(e));
        }
        let Intent(m, exp, dline) = P::create(seed, &mut sock, scope);
        match m {
            Err(None) => Response::error(Box::new(ProtocolStop)),
            Err(Some(e)) => Response::error(e),
            Ok(m) => {
                Response::ok(Stream {
                    socket: sock,
                    expectation: exp,
                    connected: false,
                    deadline: dline,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                }).deadline_opt(dline)
            }
        }
    }
    pub fn connected(mut sock: P::Socket, seed: P::Seed,
        scope: &mut Scope
)
        -> Response<Self, Void>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        //
        // We reregister here, because we assume that higher level abstraction
        // has the socket already registered (perhaps `Persistent` machine)
        if let Err(e) = scope.reregister(&sock,
            EventSet::all(), PollOpt::edge())
        {
            // TODO(tailhook) wrap it to more clear error
            return Response::error(Box::new(e));
        }
        let Intent(m, exp, dline) = P::create(seed, &mut sock, scope);
        match m {
            Err(None) => Response::error(Box::new(ProtocolStop)),
            Err(Some(e)) => Response::error(e),
            Ok(m) => {
                Response::ok(Stream {
                    socket: sock,
                    expectation: exp,
                    connected: true,
                    deadline: dline,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                }).deadline_opt(dline)
            }
        }
    }
}

impl
 Machine for Stream

{
    type Context = P::Context;
    type Seed = Void;
    fn create(void: Void, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>
    {
        unreachable(void);
    }
    fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        // TODO(tailhook) use `events` to optimize reading
        let (fsm, exp, dline, mut imp) = self.decompose();
        if events.is_hup() || events.is_error() {
            match imp.socket.take_socket_error() {
                Ok(()) => {
                    match fsm.fatal(Exception::EndOfStream, scope) {
                        Some(e) => return Response::error(e),
                        None => return Response::done(),
                    }
                }
                Err(e) => {
                    let exception = if imp.connected {
                        Exception::ReadError(e)
                    } else {
                        Exception::ConnectError(e)
                    };
                    match fsm.fatal(exception, scope) {
                        Some(e) => return Response::error(e),
                        None => return Response::done(),
                    }
                }
            }
        } else if !imp.connected {
            imp.connected = true;
        }
        imp.action(Intent(Ok(fsm), exp, dline), scope)
    }
    fn spawned(self, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        if scope.reached(self.deadline) {
            let (fsm, _exp, _dline, mut imp) = self.decompose();
            let res = fsm.timeout(&mut imp.transport(), scope);
            imp.action(res, scope)
        } else {
            // TODO(tailhook) in rotor 0.6 should be no spurious timeouts
            // anymore, but let's keep it until we remove Scope::timeout_ms()
            Response::ok(self)
        }
    }
    fn wakeup(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        let (fsm, _exp, _dline, mut imp) = self.decompose();
        let res = fsm.wakeup(&mut imp.transport(), scope);
        imp.action(res, scope)
    }
}
<|endoftext|>


<commit_before>//! Raw un-exported bindings to miniz for encoding/decoding

use std::marker;
use std::mem;
use libc::{c_int, c_uint};

use Compression;
use ffi;

pub struct Stream<D: Direction> {
    raw: ffi::mz_stream,
    _marker: marker::PhantomData<D>,
}

pub enum Compress {}
pub enum Decompress {}

pub enum Flush {
    None = ffi::MZ_NO_FLUSH as isize,
    Sync = ffi::MZ_SYNC_FLUSH as isize,
    Finish = ffi::MZ_FINISH as isize,
}

#[doc(hidden)]
pub trait Direction: marker::PhantomFn<Self> {
    unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int;
}

impl Stream<Compress> {
    pub fn new_compress(lvl: Compression, raw: bool) -> Stream<Compress> {
        unsafe {
            let mut state: ffi::mz_stream = mem::zeroed();
            let ret = ffi::mz_deflateInit2(&mut state,
                                           lvl as c_int,
                                           ffi::MZ_DEFLATED,
                                           if raw {
                                               -ffi::MZ_DEFAULT_WINDOW_BITS
                                           } else {
                                               ffi::MZ_DEFAULT_WINDOW_BITS
                                           },
                                           9,
                                           ffi::MZ_DEFAULT_STRATEGY);
            debug_assert_eq!(ret, 0);
            Stream { raw: state, _marker: marker::PhantomData }
        }
    }

    pub fn new_decompress(raw: bool) -> Stream<Decompress> {
        unsafe {
            let mut state: ffi::mz_stream = mem::zeroed();
            let ret = ffi::mz_inflateInit2(&mut state,
                                          if raw {
                                              -ffi::MZ_DEFAULT_WINDOW_BITS
                                          } else {
                                              ffi::MZ_DEFAULT_WINDOW_BITS
                                          });
            debug_assert_eq!(ret, 0);
            Stream { raw: state, _marker: marker::PhantomData }
        }
    }
}

impl<T: Direction> Stream<T> {
    pub fn total_in(&self) -> u64 { self.raw.total_in as u64 }
    pub fn total_out(&self) -> u64 { self.raw.total_out as u64 }
}

impl Stream<Decompress> {
    pub fn decompress(&mut self, input: &[u8], output: &mut [u8],
                      flush: Flush) -> c_int {
        self.raw.next_in = input.as_ptr();
        self.raw.avail_in = input.len() as c_uint;
        self.raw.next_out = output.as_mut_ptr();
        self.raw.avail_out = output.len() as c_uint;
        unsafe { ffi::mz_inflate(&mut self.raw, flush as c_int) }
    }

    pub fn decompress_vec(&mut self, input: &[u8], output: &mut Vec<u8>,
                          flush: Flush) -> c_int {
        let cap = output.capacity();
        let len = output.len();
        self.raw.avail_in = input.len() as c_uint;
        self.raw.next_in = input.as_ptr() as *mut _;
        self.raw.avail_out = (cap - len) as c_uint;

        unsafe {
            self.raw.next_out = output.as_mut_ptr().offset(len as isize);
            let before = self.total_out();
            let rc = ffi::mz_inflate(&mut self.raw, flush as c_int);
            let diff = (self.total_out() - before) as usize;
            output.set_len(len + diff);
            return rc;
        }
    }
}

impl Stream<Compress> {
    pub fn compress(&mut self, input: &[u8], output: &mut [u8],
                    flush: Flush) -> c_int {
        self.raw.next_in = input.as_ptr() as *mut _;
        self.raw.avail_in = input.len() as c_uint;
        self.raw.next_out = output.as_mut_ptr();
        self.raw.avail_out = output.len() as c_uint;
        unsafe { ffi::mz_deflate(&mut self.raw, flush as c_int) }
    }

    pub fn compress_vec(&mut self, input: &[u8], output: &mut Vec<u8>,
                        flush: Flush) -> c_int {
        let cap = output.capacity();
        let len = output.len();
        self.raw.avail_in = input.len() as c_uint;
        self.raw.next_in = input.as_ptr() as *mut _;
        self.raw.avail_out = (cap - len) as c_uint;

        unsafe {
            self.raw.next_out = output.as_mut_ptr().offset(len as isize);

            let before = self.total_out();
            let rc = ffi::mz_deflate(&mut self.raw, flush as c_int);
            let diff = (self.total_out() - before) as usize;
            output.set_len(len + diff);
            return rc;
        }
    }
}

impl Direction for Compress {
    unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int {
        ffi::mz_deflateEnd(stream)
    }
}
impl Direction for Decompress {
    unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int {
        ffi::mz_inflateEnd(stream)
    }
}

impl<D: Direction> Drop for Stream<D> {
    fn drop(&mut self) {
        unsafe {
            let _ = <D as Direction>::destroy(&mut self.raw);
        }
    }
}
<commit_msg>Stop using PhantomFn<commit_after>//! Raw un-exported bindings to miniz for encoding/decoding

use std::marker;
use std::mem;
use libc::{c_int, c_uint};

use Compression;
use ffi;

pub struct Stream<D: Direction> {
    raw: ffi::mz_stream,
    _marker: marker::PhantomData<D>,
}

pub enum Compress {}
pub enum Decompress {}

pub enum Flush {
    None = ffi::MZ_NO_FLUSH as isize,
    Sync = ffi::MZ_SYNC_FLUSH as isize,
    Finish = ffi::MZ_FINISH as isize,
}

#[doc(hidden)]
pub trait Direction {
    unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int;
    fn foo(&self) {}
}

impl Stream<Compress> {
    pub fn new_compress(lvl: Compression, raw: bool) -> Stream<Compress> {
        unsafe {
            let mut state: ffi::mz_stream = mem::zeroed();
            let ret = ffi::mz_deflateInit2(&mut state,
                                           lvl as c_int,
                                           ffi::MZ_DEFLATED,
                                           if raw {
                                               -ffi::MZ_DEFAULT_WINDOW_BITS
                                           } else {
                                               ffi::MZ_DEFAULT_WINDOW_BITS
                                           },
                                           9,
                                           ffi::MZ_DEFAULT_STRATEGY);
            debug_assert_eq!(ret, 0);
            Stream { raw: state, _marker: marker::PhantomData }
        }
    }

    pub fn new_decompress(raw: bool) -> Stream<Decompress> {
        unsafe {
            let mut state: ffi::mz_stream = mem::zeroed();
            let ret = ffi::mz_inflateInit2(&mut state,
                                          if raw {
                                              -ffi::MZ_DEFAULT_WINDOW_BITS
                                          } else {
                                              ffi::MZ_DEFAULT_WINDOW_BITS
                                          });
            debug_assert_eq!(ret, 0);
            Stream { raw: state, _marker: marker::PhantomData }
        }
    }
}

impl<T: Direction> Stream<T> {
    pub fn total_in(&self) -> u64 { self.raw.total_in as u64 }
    pub fn total_out(&self) -> u64 { self.raw.total_out as u64 }
}

impl Stream<Decompress> {
    pub fn decompress(&mut self, input: &[u8], output: &mut [u8],
                      flush: Flush) -> c_int {
        self.raw.next_in = input.as_ptr();
        self.raw.avail_in = input.len() as c_uint;
        self.raw.next_out = output.as_mut_ptr();
        self.raw.avail_out = output.len() as c_uint;
        unsafe { ffi::mz_inflate(&mut self.raw, flush as c_int) }
    }

    pub fn decompress_vec(&mut self, input: &[u8], output: &mut Vec<u8>,
                          flush: Flush) -> c_int {
        let cap = output.capacity();
        let len = output.len();
        self.raw.avail_in = input.len() as c_uint;
        self.raw.next_in = input.as_ptr() as *mut _;
        self.raw.avail_out = (cap - len) as c_uint;

        unsafe {
            self.raw.next_out = output.as_mut_ptr().offset(len as isize);
            let before = self.total_out();
            let rc = ffi::mz_inflate(&mut self.raw, flush as c_int);
            let diff = (self.total_out() - before) as usize;
            output.set_len(len + diff);
            return rc;
        }
    }
}

impl Stream<Compress> {
    pub fn compress(&mut self, input: &[u8], output: &mut [u8],
                    flush: Flush) -> c_int {
        self.raw.next_in = input.as_ptr() as *mut _;
        self.raw.avail_in = input.len() as c_uint;
        self.raw.next_out = output.as_mut_ptr();
        self.raw.avail_out = output.len() as c_uint;
        unsafe { ffi::mz_deflate(&mut self.raw, flush as c_int) }
    }

    pub fn compress_vec(&mut self, input: &[u8], output: &mut Vec<u8>,
                        flush: Flush) -> c_int {
        let cap = output.capacity();
        let len = output.len();
        self.raw.avail_in = input.len() as c_uint;
        self.raw.next_in = input.as_ptr() as *mut _;
        self.raw.avail_out = (cap - len) as c_uint;

        unsafe {
            self.raw.next_out = output.as_mut_ptr().offset(len as isize);

            let before = self.total_out();
            let rc = ffi::mz_deflate(&mut self.raw, flush as c_int);
            let diff = (self.total_out() - before) as usize;
            output.set_len(len + diff);
            return rc;
        }
    }
}

impl Direction for Compress {
    unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int {
        ffi::mz_deflateEnd(stream)
    }
}
impl Direction for Decompress {
    unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int {
        ffi::mz_inflateEnd(stream)
    }
}

impl<D: Direction> Drop for Stream<D> {
    fn drop(&mut self) {
        unsafe {
            let _ = <D as Direction>::destroy(&mut self.raw);
        }
    }
}
<|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/. */

extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;

#[path = "common/boilerplate.rs"]
mod boilerplate;

use boilerplate::{Example, HandyDandyRectBuilder};
use euclid::SideOffsets2D;
use webrender::api::*;
use winit::dpi::LogicalPosition;

struct App {
    cursor_position: WorldPoint,
}

impl Example for App {
    fn render(
        &mut self,
        _api: &RenderApi,
        builder: &mut DisplayListBuilder,
        _txn: &mut Transaction,
        _framebuffer_size: DeviceUintSize,
        _pipeline_id: PipelineId,
        _document_id: DocumentId,
    ) {
        let info = LayoutPrimitiveInfo::new(
            LayoutRect::new(LayoutPoint::zero(), builder.content_size())
        );
        builder.push_stacking_context(
            &info,
            None,
            TransformStyle::Flat,
            MixBlendMode::Normal,
            Vec::new(),
            RasterSpace::Screen,
        );

        if true {
            // scrolling and clips stuff
            // let's make a scrollbox
            let scrollbox = (0, 0).to(300, 400);
            builder.push_stacking_context(
                &LayoutPrimitiveInfo::new((10, 10).by(0, 0)),
                None,
                TransformStyle::Flat,
                MixBlendMode::Normal,
                Vec::new(),
                RasterSpace::Screen,
            );
            // set the scrolling clip
            let clip_id = builder.define_scroll_frame(
                None,
                (0, 0).by(1000, 1000),
                scrollbox,
                vec![],
                None,
                ScrollSensitivity::ScriptAndInputEvents,
            );
            builder.push_clip_id(clip_id);

            // now put some content into it.
            // start with a white background
            let mut info = LayoutPrimitiveInfo::new((0, 0).to(1000, 1000));
            info.tag = Some((0, 1));
            builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0));

            // let's make a 50x50 blue square as a visual reference
            let mut info = LayoutPrimitiveInfo::new((0, 0).to(50, 50));
            info.tag = Some((0, 2));
            builder.push_rect(&info, ColorF::new(0.0, 0.0, 1.0, 1.0));

            // and a 50x50 green square next to it with an offset clip
            // to see what that looks like
            let mut info =
                LayoutPrimitiveInfo::with_clip_rect((50, 0).to(100, 50), (60, 10).to(110, 60));
            info.tag = Some((0, 3));
            builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));

            // Below the above rectangles, set up a nested scrollbox. It's still in
            // the same stacking context, so note that the rects passed in need to
            // be relative to the stacking context.
            let nested_clip_id = builder.define_scroll_frame(
                None,
                (0, 100).to(300, 1000),
                (0, 100).to(200, 300),
                vec![],
                None,
                ScrollSensitivity::ScriptAndInputEvents,
            );
            builder.push_clip_id(nested_clip_id);

            // give it a giant gray background just to distinguish it and to easily
            // visually identify the nested scrollbox
            let mut info = LayoutPrimitiveInfo::new((-1000, -1000).to(5000, 5000));
            info.tag = Some((0, 4));
            builder.push_rect(&info, ColorF::new(0.5, 0.5, 0.5, 1.0));

            // add a teal square to visualize the scrolling/clipping behaviour
            // as you scroll the nested scrollbox
            let mut info = LayoutPrimitiveInfo::new((0, 200).to(50, 250));
            info.tag = Some((0, 5));
            builder.push_rect(&info, ColorF::new(0.0, 1.0, 1.0, 1.0));

            // Add a sticky frame. It will "stick" twice while scrolling, once
            // at a margin of 10px from the bottom, for 40 pixels of scrolling,
            // and once at a margin of 10px from the top, for 60 pixels of
            // scrolling.
            let sticky_id = builder.define_sticky_frame(
                (50, 350).by(50, 50),
                SideOffsets2D::new(Some(10.0), None, Some(10.0), None),
                StickyOffsetBounds::new(-40.0, 60.0),
                StickyOffsetBounds::new(0.0, 0.0),
                LayoutVector2D::new(0.0, 0.0)
            );

            builder.push_clip_id(sticky_id);
            let mut info = LayoutPrimitiveInfo::new((50, 350).by(50, 50));
            info.tag = Some((0, 6));
            builder.push_rect(&info, ColorF::new(0.5, 0.5, 1.0, 1.0));
            builder.pop_clip_id(); // sticky_id

            // just for good measure add another teal square further down and to
            // the right, which can be scrolled into view by the user
            let mut info = LayoutPrimitiveInfo::new((250, 350).to(300, 400));
            info.tag = Some((0, 7));
            builder.push_rect(&info, ColorF::new(0.0, 1.0, 1.0, 1.0));

            builder.pop_clip_id(); // nested_clip_id

            builder.pop_clip_id(); // clip_id
            builder.pop_stacking_context();
        }

        builder.pop_stacking_context();
    }

    fn on_event(&mut self, event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
        let mut txn = Transaction::new();
        match event {
            winit::WindowEvent::KeyboardInput {
                input: winit::KeyboardInput {
                    state: winit::ElementState::Pressed,
                    virtual_keycode: Some(key),
                    ..
                },
                ..
            } => {
                let offset = match key {
                    winit::VirtualKeyCode::Down => (0.0, -10.0),
                    winit::VirtualKeyCode::Up => (0.0, 10.0),
                    winit::VirtualKeyCode::Right => (-10.0, 0.0),
                    winit::VirtualKeyCode::Left => (10.0, 0.0),
                    _ => return false,
                };

                txn.scroll(
                    ScrollLocation::Delta(LayoutVector2D::new(offset.0, offset.1)),
                    self.cursor_position,
                );
            }
            winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => {
                self.cursor_position = WorldPoint::new(x as f32, y as f32);
            }
            winit::WindowEvent::MouseWheel { delta, .. } => {
                const LINE_HEIGHT: f32 = 38.0;
                let (dx, dy) = match delta {
                    winit::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
                    winit::MouseScrollDelta::PixelDelta(pos) => (pos.x as f32, pos.y as f32),
                };

                txn.scroll(
                    ScrollLocation::Delta(LayoutVector2D::new(dx, dy)),
                    self.cursor_position,
                );
            }
            winit::WindowEvent::MouseInput { .. } => {
                let results = api.hit_test(
                    document_id,
                    None,
                    self.cursor_position,
                    HitTestFlags::FIND_ALL
                );

                println!("Hit test results:");
                for item in &results.items {
                    println!("  • {:?}", item);
                }
                println!("");
            }
            _ => (),
        }

        api.send_transaction(document_id, txn);

        false
    }
}

fn main() {
    let mut app = App {
        cursor_position: WorldPoint::zero(),
    };
    boilerplate::main_wrapper(&mut app, None);
}
<commit_msg>Auto merge of #3172 - staktrace:fixscroll, r=gw3583<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/. */

extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;

#[path = "common/boilerplate.rs"]
mod boilerplate;

use boilerplate::{Example, HandyDandyRectBuilder};
use euclid::SideOffsets2D;
use webrender::api::*;
use winit::dpi::LogicalPosition;

struct App {
    cursor_position: WorldPoint,
}

impl Example for App {
    fn render(
        &mut self,
        _api: &RenderApi,
        builder: &mut DisplayListBuilder,
        _txn: &mut Transaction,
        _framebuffer_size: DeviceUintSize,
        _pipeline_id: PipelineId,
        _document_id: DocumentId,
    ) {
        let info = LayoutPrimitiveInfo::new(
            LayoutRect::new(LayoutPoint::zero(), builder.content_size())
        );
        builder.push_stacking_context(
            &info,
            None,
            TransformStyle::Flat,
            MixBlendMode::Normal,
            Vec::new(),
            RasterSpace::Screen,
        );

        if true {
            // scrolling and clips stuff
            // let's make a scrollbox
            let scrollbox = (0, 0).to(300, 400);
            builder.push_stacking_context(
                &LayoutPrimitiveInfo::new((10, 10).by(0, 0)),
                None,
                TransformStyle::Flat,
                MixBlendMode::Normal,
                Vec::new(),
                RasterSpace::Screen,
            );
            // set the scrolling clip
            let clip_id = builder.define_scroll_frame(
                None,
                (0, 0).by(1000, 1000),
                scrollbox,
                vec![],
                None,
                ScrollSensitivity::ScriptAndInputEvents,
            );
            builder.push_clip_id(clip_id);

            // now put some content into it.
            // start with a white background
            let mut info = LayoutPrimitiveInfo::new((0, 0).to(1000, 1000));
            info.tag = Some((0, 1));
            builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0));

            // let's make a 50x50 blue square as a visual reference
            let mut info = LayoutPrimitiveInfo::new((0, 0).to(50, 50));
            info.tag = Some((0, 2));
            builder.push_rect(&info, ColorF::new(0.0, 0.0, 1.0, 1.0));

            // and a 50x50 green square next to it with an offset clip
            // to see what that looks like
            let mut info =
                LayoutPrimitiveInfo::with_clip_rect((50, 0).to(100, 50), (60, 10).to(110, 60));
            info.tag = Some((0, 3));
            builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));

            // Below the above rectangles, set up a nested scrollbox. It's still in
            // the same stacking context, so note that the rects passed in need to
            // be relative to the stacking context.
            let nested_clip_id = builder.define_scroll_frame(
                None,
                (0, 100).to(300, 1000),
                (0, 100).to(200, 300),
                vec![],
                None,
                ScrollSensitivity::ScriptAndInputEvents,
            );
            builder.push_clip_id(nested_clip_id);

            // give it a giant gray background just to distinguish it and to easily
            // visually identify the nested scrollbox
            let mut info = LayoutPrimitiveInfo::new((-1000, -1000).to(5000, 5000));
            info.tag = Some((0, 4));
            builder.push_rect(&info, ColorF::new(0.5, 0.5, 0.5, 1.0));

            // add a teal square to visualize the scrolling/clipping behaviour
            // as you scroll the nested scrollbox
            let mut info = LayoutPrimitiveInfo::new((0, 200).to(50, 250));
            info.tag = Some((0, 5));
            builder.push_rect(&info, ColorF::new(0.0, 1.0, 1.0, 1.0));

            // Add a sticky frame. It will "stick" twice while scrolling, once
            // at a margin of 10px from the bottom, for 40 pixels of scrolling,
            // and once at a margin of 10px from the top, for 60 pixels of
            // scrolling.
            let sticky_id = builder.define_sticky_frame(
                (50, 350).by(50, 50),
                SideOffsets2D::new(Some(10.0), None, Some(10.0), None),
                StickyOffsetBounds::new(-40.0, 60.0),
                StickyOffsetBounds::new(0.0, 0.0),
                LayoutVector2D::new(0.0, 0.0)
            );

            builder.push_clip_id(sticky_id);
            let mut info = LayoutPrimitiveInfo::new((50, 350).by(50, 50));
            info.tag = Some((0, 6));
            builder.push_rect(&info, ColorF::new(0.5, 0.5, 1.0, 1.0));
            builder.pop_clip_id(); // sticky_id

            // just for good measure add another teal square further down and to
            // the right, which can be scrolled into view by the user
            let mut info = LayoutPrimitiveInfo::new((250, 350).to(300, 400));
            info.tag = Some((0, 7));
            builder.push_rect(&info, ColorF::new(0.0, 1.0, 1.0, 1.0));

            builder.pop_clip_id(); // nested_clip_id

            builder.pop_clip_id(); // clip_id
            builder.pop_stacking_context();
        }

        builder.pop_stacking_context();
    }

    fn on_event(&mut self, event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
        let mut txn = Transaction::new();
        match event {
            winit::WindowEvent::KeyboardInput {
                input: winit::KeyboardInput {
                    state: winit::ElementState::Pressed,
                    virtual_keycode: Some(key),
                    ..
                },
                ..
            } => {
                let offset = match key {
                    winit::VirtualKeyCode::Down => (0.0, -10.0),
                    winit::VirtualKeyCode::Up => (0.0, 10.0),
                    winit::VirtualKeyCode::Right => (-10.0, 0.0),
                    winit::VirtualKeyCode::Left => (10.0, 0.0),
                    _ => return false,
                };

                txn.scroll(
                    ScrollLocation::Delta(LayoutVector2D::new(offset.0, offset.1)),
                    self.cursor_position,
                );
                txn.generate_frame();
            }
            winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => {
                self.cursor_position = WorldPoint::new(x as f32, y as f32);
            }
            winit::WindowEvent::MouseWheel { delta, .. } => {
                const LINE_HEIGHT: f32 = 38.0;
                let (dx, dy) = match delta {
                    winit::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
                    winit::MouseScrollDelta::PixelDelta(pos) => (pos.x as f32, pos.y as f32),
                };

                txn.scroll(
                    ScrollLocation::Delta(LayoutVector2D::new(dx, dy)),
                    self.cursor_position,
                );
                txn.generate_frame();
            }
            winit::WindowEvent::MouseInput { .. } => {
                let results = api.hit_test(
                    document_id,
                    None,
                    self.cursor_position,
                    HitTestFlags::FIND_ALL
                );

                println!("Hit test results:");
                for item in &results.items {
                    println!("  • {:?}", item);
                }
                println!("");
            }
            _ => (),
        }

        api.send_transaction(document_id, txn);

        false
    }
}

fn main() {
    let mut app = App {
        cursor_position: WorldPoint::zero(),
    };
    boilerplate::main_wrapper(&mut app, None);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// 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.

//! Raspberry Pi system-related tools.
//!
//! Use `DeviceInfo` to identify what Raspberry Pi model and SoC the software is
//! running on. This information is used internally to calculate the correct memory
//! locations for the various BCM283x peripherals.

use std::fmt;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::result;

const PERIPHERAL_BASE_RPI: u32 = 0x20000000;
const PERIPHERAL_BASE_RPI2: u32 = 0x3f000000;
const GPIO_OFFSET: u32 = 0x200000;

quick_error! {
    #[derive(Debug)]
/// Errors that can occur when trying to identify the Raspberry Pi hardware.
    pub enum Error {
/// Unknown SoC.
///
/// Based on the output of `/proc/cpuinfo`, it wasn't possible to identify the SoC used by the
/// Raspberry Pi. While running the library on an unknown Raspberry Pi model is acceptable,
/// identifying the SoC is required because the memory address for the GPIO peripheral
/// depends on it.
        UnknownSoC { description("unknown SoC") }
/// Can't access `/proc/cpuinfo`.
///
/// Unable to read the contents of `/proc/cpuinfo`. This could be an issue with permissions, or
/// a Linux distribution is used that doesn't provide access to this virtual file.
        CantAccessProcCpuInfo { description("can't access /proc/cpuinfo") }
    }
}

/// Result type returned from methods that can have `system::Error`s.
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, PartialEq, Copy, Clone)]
/// Identifiable Raspberry Pi models.
pub enum Model {
    RaspberryPiA,
    RaspberryPiAPlus,
    RaspberryPiB,
    RaspberryPiBPlus,
    RaspberryPi2B,
    RaspberryPi3B,
    RaspberryPi3BPlus,
    RaspberryPiComputeModule,
    RaspberryPiComputeModule3,
    RaspberryPiZero,
    RaspberryPiZeroW,
    Unknown,
}

impl fmt::Display for Model {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Model::RaspberryPiA => write!(f, "Raspberry Pi A"),
            Model::RaspberryPiAPlus => write!(f, "Raspberry Pi A+"),
            Model::RaspberryPiB => write!(f, "Raspberry Pi B"),
            Model::RaspberryPiBPlus => write!(f, "Raspberry Pi B+"),
            Model::RaspberryPi2B => write!(f, "Raspberry Pi 2 B"),
            Model::RaspberryPi3B => write!(f, "Raspberry Pi 3 B"),
            Model::RaspberryPi3BPlus => write!(f, "Raspberry Pi 3 B+"),
            Model::RaspberryPiComputeModule => write!(f, "Raspberry Pi Compute Module"),
            Model::RaspberryPiComputeModule3 => write!(f, "Raspberry Pi Compute Module 3"),
            Model::RaspberryPiZero => write!(f, "Raspberry Pi Zero"),
            Model::RaspberryPiZeroW => write!(f, "Raspberry Pi Zero W"),
            Model::Unknown => write!(f, "Unknown"),
        }
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
/// Identifiable Raspberry Pi SoCs.
pub enum SoC {
    Bcm2835,
    Bcm2836,
    Bcm2837,
}

impl fmt::Display for SoC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SoC::Bcm2835 => write!(f, "BCM2835"),
            SoC::Bcm2836 => write!(f, "BCM2836"),
            SoC::Bcm2837 => write!(f, "BCM2837"),
        }
    }
}

/// Retrieves Raspberry Pi device information.
pub struct DeviceInfo {
    model: Model,
    soc: SoC,
    peripheral_base: u32,
    gpio_offset: u32,
}

impl DeviceInfo {
    /// Constructs a new `DeviceInfo`.
    pub fn new() -> Result<DeviceInfo> {
        // Parse hardware/revision from /proc/cpuinfo to figure out model/SoC
        let proc_cpuinfo = BufReader::new(match File::open("/proc/cpuinfo") {
            Err(_) => return Err(Error::CantAccessProcCpuInfo),
            Ok(file) => file,
        });

        let mut hardware: String = String::new();
        let mut revision: String = String::new();
        for line_result in proc_cpuinfo.lines() {
            if let Ok(line) = line_result {
                if line.starts_with("Hardware\t: ") {
                    hardware = String::from(&line[11..]);
                } else if line.starts_with("Revision\t: ") {
                    revision = String::from(&line[11..]).to_lowercase();
                }
            }
        }

        let model = if revision.len() >= 6 {
            // Newer revisions consist of at least 6 characters
            match &revision[revision.len() - 3..revision.len() - 1] {
                "00" => Model::RaspberryPiA,
                "01" => Model::RaspberryPiB,
                "02" => Model::RaspberryPiAPlus,
                "03" => Model::RaspberryPiBPlus,
                "04" => Model::RaspberryPi2B,
                "06" => Model::RaspberryPiComputeModule,
                "08" => Model::RaspberryPi3B,
                "09" => Model::RaspberryPiZero,
                "0a" => Model::RaspberryPiComputeModule3,
                "0c" => Model::RaspberryPiZeroW,
                "0d" => Model::RaspberryPi3BPlus,
                _ => Model::Unknown,
            }
        } else if revision.len() == 4 {
            // Older revisions are 4 characters long
            match &revision[..] {
                "0007" | "0008" | "0009" | "0015" => Model::RaspberryPiA,
                "Beta" | "0002" | "0003" | "0004" | "0005" | "0006" | "000d" | "000e" | "000f" => {
                    Model::RaspberryPiB
                }
                "0012" => Model::RaspberryPiAPlus,
                "0010" | "0013" => Model::RaspberryPiBPlus,
                "0011" | "0014" => Model::RaspberryPiComputeModule,
                _ => Model::Unknown,
            }
        } else {
            Model::Unknown
        };

        // Make sure we're actually running on a supported SoC
        let soc = match &hardware[..] {
            "BCM2708" | "BCM2835" => SoC::Bcm2835,
            "BCM2709" | "BCM2836" => SoC::Bcm2836,
            "BCM2710" | "BCM2837" => SoC::Bcm2837,
            _ => return Err(Error::UnknownSoC),
        };

        // Set memory offsets based on hardware model
        match model {
            Model::RaspberryPiA
            | Model::RaspberryPiAPlus
            | Model::RaspberryPiB
            | Model::RaspberryPiBPlus
            | Model::RaspberryPiComputeModule
            | Model::RaspberryPiZero
            | Model::RaspberryPiZeroW => Ok(DeviceInfo {
                model: model,
                soc: soc,
                peripheral_base: PERIPHERAL_BASE_RPI,
                gpio_offset: GPIO_OFFSET,
            }),
            Model::RaspberryPi2B
            | Model::RaspberryPi3B
            | Model::RaspberryPi3BPlus
            | Model::RaspberryPiComputeModule3 => Ok(DeviceInfo {
                model: model,
                soc: soc,
                peripheral_base: PERIPHERAL_BASE_RPI2,
                gpio_offset: GPIO_OFFSET,
            }),
            _ => Err(Error::UnknownSoC),
        }
    }

    /// Returns a reference to the Raspberry Pi model identified by parsing the
    /// contents of `/proc/cpuinfo`.
    pub fn model(&self) -> &Model {
        &self.model
    }

    /// Returns a reference to the SoC identified by parsing the contents of `/proc/cpuinfo`.
    pub fn soc(&self) -> &SoC {
        &self.soc
    }

    /// Returns the base memory address for the BCM283x peripherals.
    pub fn peripheral_base(&self) -> u32 {
        self.peripheral_base
    }

    /// Returns the offset memory address for the GPIO section.
    pub fn gpio_offset(&self) -> u32 {
        self.gpio_offset
    }
}
<commit_msg>Cleanup Raspberry Pi model identification<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// 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.

//! Raspberry Pi system-related tools.
//!
//! Use `DeviceInfo` to identify what Raspberry Pi model and SoC the software is
//! running on. This information is used internally to calculate the correct memory
//! locations for the various BCM283x peripherals.

use std::fmt;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::result;

const PERIPHERAL_BASE_RPI: u32 = 0x20000000;
const PERIPHERAL_BASE_RPI2: u32 = 0x3f000000;
const GPIO_OFFSET: u32 = 0x200000;

quick_error! {
    #[derive(Debug)]
/// Errors that can occur when trying to identify the Raspberry Pi hardware.
    pub enum Error {
/// Unknown model.
///
/// Based on the output of `/proc/cpuinfo`, it wasn't possible to identify the Raspberry Pi
/// model.
        UnknownModel { description("unknown Raspberry Pi model") }
/// Unknown SoC.
///
/// Based on the output of `/proc/cpuinfo`, it wasn't possible to identify the SoC used by the
/// Raspberry Pi.
        UnknownSoC { description("unknown SoC") }
/// Can't access `/proc/cpuinfo`.
///
/// Unable to read the contents of `/proc/cpuinfo`. This could be an issue with permissions, or
/// a Linux distribution is used that doesn't provide access to this virtual file.
        CantAccessProcCpuInfo { description("can't access /proc/cpuinfo") }
    }
}

/// Result type returned from methods that can have `system::Error`s.
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, PartialEq, Copy, Clone)]
/// Identifiable Raspberry Pi models.
pub enum Model {
    RaspberryPiA,
    RaspberryPiAPlus,
    RaspberryPiB,
    RaspberryPiBPlus,
    RaspberryPi2B,
    RaspberryPi3B,
    RaspberryPi3BPlus,
    RaspberryPiComputeModule,
    RaspberryPiComputeModule3,
    RaspberryPiZero,
    RaspberryPiZeroW,
}

impl fmt::Display for Model {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Model::RaspberryPiA => write!(f, "Raspberry Pi A"),
            Model::RaspberryPiAPlus => write!(f, "Raspberry Pi A+"),
            Model::RaspberryPiB => write!(f, "Raspberry Pi B"),
            Model::RaspberryPiBPlus => write!(f, "Raspberry Pi B+"),
            Model::RaspberryPi2B => write!(f, "Raspberry Pi 2 B"),
            Model::RaspberryPi3B => write!(f, "Raspberry Pi 3 B"),
            Model::RaspberryPi3BPlus => write!(f, "Raspberry Pi 3 B+"),
            Model::RaspberryPiComputeModule => write!(f, "Raspberry Pi Compute Module"),
            Model::RaspberryPiComputeModule3 => write!(f, "Raspberry Pi Compute Module 3"),
            Model::RaspberryPiZero => write!(f, "Raspberry Pi Zero"),
            Model::RaspberryPiZeroW => write!(f, "Raspberry Pi Zero W"),
        }
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
/// Identifiable Raspberry Pi SoCs.
pub enum SoC {
    Bcm2835,
    Bcm2836,
    Bcm2837,
}

impl fmt::Display for SoC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SoC::Bcm2835 => write!(f, "BCM2835"),
            SoC::Bcm2836 => write!(f, "BCM2836"),
            SoC::Bcm2837 => write!(f, "BCM2837"),
        }
    }
}

/// Retrieves Raspberry Pi device information.
pub struct DeviceInfo {
    model: Model,
    soc: SoC,
    peripheral_base: u32,
    gpio_offset: u32,
}

impl DeviceInfo {
    /// Constructs a new `DeviceInfo`.
    pub fn new() -> Result<DeviceInfo> {
        // Parse hardware/revision from /proc/cpuinfo to figure out model/SoC
        let proc_cpuinfo = BufReader::new(match File::open("/proc/cpuinfo") {
            Err(_) => return Err(Error::CantAccessProcCpuInfo),
            Ok(file) => file,
        });

        let mut hardware: String = String::new();
        let mut revision: String = String::new();
        for line_result in proc_cpuinfo.lines() {
            if let Ok(line) = line_result {
                if line.starts_with("Hardware\t: ") {
                    hardware = String::from(&line[11..]);
                } else if line.starts_with("Revision\t: ") {
                    revision = String::from(&line[11..]).to_lowercase();
                }
            }
        }

        let model = if revision.len() >= 6 {
            // Newer revisions consist of at least 6 characters
            match &revision[revision.len() - 3..revision.len() - 1] {
                "00" => Model::RaspberryPiA,
                "01" => Model::RaspberryPiB,
                "02" => Model::RaspberryPiAPlus,
                "03" => Model::RaspberryPiBPlus,
                "04" => Model::RaspberryPi2B,
                "06" => Model::RaspberryPiComputeModule,
                "08" => Model::RaspberryPi3B,
                "09" => Model::RaspberryPiZero,
                "0a" => Model::RaspberryPiComputeModule3,
                "0c" => Model::RaspberryPiZeroW,
                "0d" => Model::RaspberryPi3BPlus,
                _ => return Err(Error::UnknownModel),
            }
        } else if revision.len() == 4 {
            // Older revisions are 4 characters long
            match &revision[..] {
                "0007" | "0008" | "0009" | "0015" => Model::RaspberryPiA,
                "Beta" | "0002" | "0003" | "0004" | "0005" | "0006" | "000d" | "000e" | "000f" => {
                    Model::RaspberryPiB
                }
                "0012" => Model::RaspberryPiAPlus,
                "0010" | "0013" => Model::RaspberryPiBPlus,
                "0011" | "0014" => Model::RaspberryPiComputeModule,
                _ => return Err(Error::UnknownModel),
            }
        } else {
            return Err(Error::UnknownModel);
        };

        // Make sure we're actually running on a supported SoC
        let soc = match &hardware[..] {
            "BCM2708" | "BCM2835" => SoC::Bcm2835,
            "BCM2709" | "BCM2836" => SoC::Bcm2836,
            "BCM2710" | "BCM2837" => SoC::Bcm2837,
            _ => return Err(Error::UnknownSoC),
        };

        // Set memory offsets based on hardware model
        match model {
            Model::RaspberryPiA
            | Model::RaspberryPiAPlus
            | Model::RaspberryPiB
            | Model::RaspberryPiBPlus
            | Model::RaspberryPiComputeModule
            | Model::RaspberryPiZero
            | Model::RaspberryPiZeroW => Ok(DeviceInfo {
                model: model,
                soc: soc,
                peripheral_base: PERIPHERAL_BASE_RPI,
                gpio_offset: GPIO_OFFSET,
            }),
            Model::RaspberryPi2B
            | Model::RaspberryPi3B
            | Model::RaspberryPi3BPlus
            | Model::RaspberryPiComputeModule3 => Ok(DeviceInfo {
                model: model,
                soc: soc,
                peripheral_base: PERIPHERAL_BASE_RPI2,
                gpio_offset: GPIO_OFFSET,
            }),
        }
    }

    /// Returns a reference to the Raspberry Pi model identified by parsing the
    /// contents of `/proc/cpuinfo`.
    pub fn model(&self) -> &Model {
        &self.model
    }

    /// Returns a reference to the SoC identified by parsing the contents of `/proc/cpuinfo`.
    pub fn soc(&self) -> &SoC {
        &self.soc
    }

    /// Returns the base memory address for the BCM283x peripherals.
    pub fn peripheral_base(&self) -> u32 {
        self.peripheral_base
    }

    /// Returns the offset memory address for the GPIO section.
    pub fn gpio_offset(&self) -> u32 {
        self.gpio_offset
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::io;
use std::path::{Path, PathBuf};
#[cfg(unix)]
use std::os::unix::prelude::*;
#[cfg(windows)]
use std::os::windows::prelude::*;

use tar::Header;

// TODO #25: Replace this function with a call to header.link_name() when tar crate is updated.
pub fn link_name(header: &Header) -> io::Result<Option<Cow<Path>>> {
    match link_name_bytes(header) {
        Some(bytes) => bytes2path(bytes).map(Some),
        None => Ok(None),
    }
}

fn link_name_bytes(header: &Header) -> Option<Cow<[u8]>> {
    if header.linkname[0] == 0 { None } else { Some(deslash(&header.linkname)) }
}

fn deslash(bytes: &[u8]) -> Cow<[u8]> {
    if !bytes.contains(&b'\\') {
        Cow::Borrowed(truncate(bytes))
    } else {
        fn noslash(b: &u8) -> u8 {
            if *b == b'\\' { b'/' } else { *b }
        }
        Cow::Owned(truncate(bytes).iter().map(noslash).collect())
    }
}

fn truncate<'a>(slice: &'a [u8]) -> &'a [u8] {
    match slice.iter().position(|i| *i == 0) {
        Some(i) => &slice[..i],
        None => slice,
    }
}

#[cfg(windows)]
fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
    return match bytes {
        Cow::Borrowed(bytes) => {
            let s = try!(str::from_utf8(bytes).map_err(|_| not_unicode()));
            Ok(Cow::Borrowed(Path::new(s)))
        }
        Cow::Owned(bytes) => {
            let s = try!(String::from_utf8(bytes).map_err(|_| not_unicode()));
            Ok(Cow::Owned(PathBuf::from(s)))
        }
    };

    fn not_unicode() -> io::Error {
        other("only unicode paths are supported on windows")
    }
}

#[cfg(unix)]
fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
    use std::ffi::{OsStr, OsString};

    Ok(match bytes {
        Cow::Borrowed(bytes) => {
            Cow::Borrowed({
                Path::new(OsStr::from_bytes(bytes))
            })
        }
        Cow::Owned(bytes) => {
            Cow::Owned({
                PathBuf::from(OsString::from_vec(bytes))
            })
        }
    })
}
<commit_msg>Fixed windows build<commit_after>use std::borrow::Cow;
use std::io;
use std::path::{Path, PathBuf};

use tar::Header;

// TODO #25: Replace this function with a call to header.link_name() when tar crate is updated.
pub fn link_name(header: &Header) -> io::Result<Option<Cow<Path>>> {
    match link_name_bytes(header) {
        Some(bytes) => bytes2path(bytes).map(Some),
        None => Ok(None),
    }
}

fn link_name_bytes(header: &Header) -> Option<Cow<[u8]>> {
    if header.linkname[0] == 0 { None } else { Some(deslash(&header.linkname)) }
}

fn deslash(bytes: &[u8]) -> Cow<[u8]> {
    if !bytes.contains(&b'\\') {
        Cow::Borrowed(truncate(bytes))
    } else {
        fn noslash(b: &u8) -> u8 {
            if *b == b'\\' { b'/' } else { *b }
        }
        Cow::Owned(truncate(bytes).iter().map(noslash).collect())
    }
}

fn truncate<'a>(slice: &'a [u8]) -> &'a [u8] {
    match slice.iter().position(|i| *i == 0) {
        Some(i) => &slice[..i],
        None => slice,
    }
}

#[cfg(windows)]
fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
    use std::os::windows::prelude::*;
    use std::str;

    return match bytes {
        Cow::Borrowed(bytes) => {
            let s = try!(str::from_utf8(bytes).map_err(|_| not_unicode()));
            Ok(Cow::Borrowed(Path::new(s)))
        }
        Cow::Owned(bytes) => {
            let s = try!(String::from_utf8(bytes).map_err(|_| not_unicode()));
            Ok(Cow::Owned(PathBuf::from(s)))
        }
    };

    fn not_unicode() -> io::Error {
        other("only unicode paths are supported on windows")
    }

    fn other(msg: &str) -> io::Error {
        io::Error::new(io::ErrorKind::Other, msg)
    }
}

#[cfg(unix)]
fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
    use std::ffi::{OsStr, OsString};
    use std::os::unix::prelude::*;

    Ok(match bytes {
        Cow::Borrowed(bytes) => {
            Cow::Borrowed({
                Path::new(OsStr::from_bytes(bytes))
            })
        }
        Cow::Owned(bytes) => {
            Cow::Owned({
                PathBuf::from(OsString::from_vec(bytes))
            })
        }
    })
}
<|endoftext|>


<commit_before>/// Check if an expression matches a refutable pattern.
///
/// Syntax: `matches!(` *expression* `,` *pattern* `)`
///
/// Return a boolean, true if the expression matches the pattern, false otherwise.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// pub enum Foo<T> {
///     A,
///     B(T),
/// }
///
/// impl<T> Foo<T> {
///     pub fn is_a(&self) -> bool {
///         matches!(*self, Foo::A)
///     }
///
///     pub fn is_b(&self) -> bool {
///         matches!(*self, Foo::B(_))
///     }
/// }
///
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => true,
            _ => false
        }
    }
}

/// Assert that an expression matches a refutable pattern.
///
/// Syntax: `assert_matches!(` *expression* `,` *pattern* `)`
///
/// Panic with a message that shows the expression if it does not match the
/// pattern.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! assert_matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => (),
            ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
        }
    }
}

/// Assert that an expression matches a refutable pattern using debug assertions.
///
/// Syntax: `debug_assert_matches!(` *expression* `,` *pattern* `)`
///
/// If debug assertions are enabled, panic with a message that shows the
/// expression if it does not match the pattern.
///
/// When debug assertions are not enabled, this macro does nothing.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     debug_assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! debug_assert_matches {
    ($expression:expr, $($pattern:tt)+) => {
        if cfg!(debug_assertions) {
            match $expression {
                $($pattern)+ => (),
                ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
            }
        }
    }
}

#[test]
fn matches_works() {
    let foo = Some("-12");
    assert!(matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    ));
}

#[test]
fn assert_matches_works() {
    let foo = Some("-12");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}

#[test]
#[should_panic(expected = "assertion failed: `Some(\"-AB\")` does not match ")]
fn assert_matches_panics() {
    let foo = Some("-AB");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}
<commit_msg>Make matches crate no_std compatible<commit_after>#![no_std]

/// Check if an expression matches a refutable pattern.
///
/// Syntax: `matches!(` *expression* `,` *pattern* `)`
///
/// Return a boolean, true if the expression matches the pattern, false otherwise.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// pub enum Foo<T> {
///     A,
///     B(T),
/// }
///
/// impl<T> Foo<T> {
///     pub fn is_a(&self) -> bool {
///         matches!(*self, Foo::A)
///     }
///
///     pub fn is_b(&self) -> bool {
///         matches!(*self, Foo::B(_))
///     }
/// }
///
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => true,
            _ => false
        }
    }
}

/// Assert that an expression matches a refutable pattern.
///
/// Syntax: `assert_matches!(` *expression* `,` *pattern* `)`
///
/// Panic with a message that shows the expression if it does not match the
/// pattern.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! assert_matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => (),
            ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
        }
    }
}

/// Assert that an expression matches a refutable pattern using debug assertions.
///
/// Syntax: `debug_assert_matches!(` *expression* `,` *pattern* `)`
///
/// If debug assertions are enabled, panic with a message that shows the
/// expression if it does not match the pattern.
///
/// When debug assertions are not enabled, this macro does nothing.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     debug_assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! debug_assert_matches {
    ($expression:expr, $($pattern:tt)+) => {
        if cfg!(debug_assertions) {
            match $expression {
                $($pattern)+ => (),
                ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
            }
        }
    }
}

#[test]
fn matches_works() {
    let foo = Some("-12");
    assert!(matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    ));
}

#[test]
fn assert_matches_works() {
    let foo = Some("-12");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}

#[test]
#[should_panic(expected = "assertion failed: `Some(\"-AB\")` does not match ")]
fn assert_matches_panics() {
    let foo = Some("-AB");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}
<|endoftext|>


<commit_before>
use ndarray::{RcArray, Dimension};

/// Equation of motion (EOM)
pub trait EOM<D: Dimension> {
    /// calculate right hand side (rhs) of EOM from current state
    fn rhs(&self, RcArray<f64, D>) -> RcArray<f64, D>;
}

/// Stiff equation with diagonalized linear part
pub trait StiffDiag<D: Dimension>: EOM<D> {
    /// Non-Linear part of EOM
    fn nonlinear(&self, RcArray<f64, D>) -> RcArray<f64, D>;
    /// Linear part of EOM (assume to be diagonalized)
    fn linear_diagonal(&self) -> RcArray<f64, D>;

    fn rhs(&self, x: RcArray<f64, D>) -> RcArray<f64, D> {
        let nlin = self.nonlinear(x.clone());
        let a = self.linear_diagonal();
        nlin + a * x
    }
}

/// Time-evolution operator
pub trait TimeEvolution<D: Dimension> {
    /// calculate next step
    fn iterate(&self, RcArray<f64, D>) -> RcArray<f64, D>;
    fn get_dt(&self) -> f64;
}
<commit_msg>Add math-traits RMod, Ring, Exponental and utility trait OdeScalar<commit_after>
use ndarray::{RcArray, Dimension, LinalgScalar};
use std::ops::*;

/// Equation of motion (EOM)
pub trait EOM<A, D>
    where A: LinalgScalar,
          D: Dimension
{
    /// calculate right hand side (rhs) of EOM from current state
    fn rhs(&self, RcArray<A, D>) -> RcArray<A, D>;
}

/// Stiff equation with diagonalized linear part
pub trait StiffDiag<A, D>: EOM<A, D>
    where A: LinalgScalar,
          D: Dimension
{
    /// Non-Linear part of EOM
    fn nonlinear(&self, RcArray<A, D>) -> RcArray<A, D>;
    /// Linear part of EOM (assume to be diagonalized)
    fn linear_diagonal(&self) -> RcArray<A, D>;

    fn rhs(&self, x: RcArray<A, D>) -> RcArray<A, D> {
        let nlin = self.nonlinear(x.clone());
        let a = self.linear_diagonal();
        nlin + a * x
    }
}

/// Time-evolution operator
pub trait TimeEvolution<A, D>
    where A: LinalgScalar,
          D: Dimension
{
    /// calculate next step
    fn iterate(&self, RcArray<A, D>) -> RcArray<A, D>;
    fn get_dt(&self) -> f64;
}

pub trait Ring:
    Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self>
    + AddAssign + SubAssign + MulAssign + Sized {}
impl <A> Ring for A
where A: Add<Output=A> + Sub<Output=A> + Mul<Output=A>
    + AddAssign + SubAssign + MulAssign + Sized {}

/// R-module
pub trait RMod<R: Ring>: Mul<R, Output = Self> + MulAssign<R> + Sized {}
impl<A, R: Ring> RMod<R> for A where A: Mul<R, Output = A> + MulAssign<R> + Sized {}

pub trait Exponential: Clone + Copy + Sized {
    fn exp_(&self) -> Self;
}

impl Exponential for f64 {
    fn exp_(&self) -> f64 {
        self.exp()
    }
}

pub trait OdeScalar<R: Ring>: LinalgScalar + Ring + RMod<R> + Exponential {}
impl<A, R: Ring> OdeScalar<R> for A where A: LinalgScalar + Ring + RMod<R> + Exponential {}
<|endoftext|>