<commit_before>//! Asynchronous sinks
//!
//! This crate contains the `Sink` trait which allows values to be sent
//! asynchronously.

#![no_std]
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/futures-sink/0.2.0-beta")]

#[cfg(feature = "std")]
extern crate std;

extern crate futures_core;
#[cfg(feature = "std")]
extern crate futures_channel;

macro_rules! if_std {
    ($($i:item)*) => ($(
        #[cfg(feature = "std")]
        $i
    )*)
}

use futures_core::{Poll, task};

if_std! {
    mod channel_impls;

    use futures_core::Async;
    use futures_core::never::Never;

    impl<T> Sink for ::std::vec::Vec<T> {
        type SinkItem = T;
        type SinkError = Never;

        fn poll_ready(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> {
            Ok(Async::Ready(()))
        }

        fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> {
            self.push(item);
            Ok(())
        }

        fn poll_flush(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> {
            Ok(Async::Ready(()))
        }

        fn poll_close(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> {
            Ok(Async::Ready(()))
        }
    }

    impl<S: ?Sized + Sink> Sink for ::std::boxed::Box<S> {
        type SinkItem = S::SinkItem;
        type SinkError = S::SinkError;

        fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
            (**self).poll_ready(cx)
        }

        fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> {
            (**self).start_send(item)
        }

        fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
            (**self).poll_flush(cx)
        }

        fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
            (**self).poll_close(cx)
        }
    }
}

/// A `Sink` is a value into which other values can be sent, asynchronously.
///
/// Basic examples of sinks include the sending side of:
///
/// - Channels
/// - Sockets
/// - Pipes
///
/// In addition to such "primitive" sinks, it's typical to layer additional
/// functionality, such as buffering, on top of an existing sink.
///
/// Sending to a sink is "asynchronous" in the sense that the value may not be
/// sent in its entirety immediately. Instead, values are sent in a two-phase
/// way: first by initiating a send, and then by polling for completion. This
/// two-phase setup is analogous to buffered writing in synchronous code, where
/// writes often succeed immediately, but internally are buffered and are
/// *actually* written only upon flushing.
///
/// In addition, the `Sink` may be *full*, in which case it is not even possible
/// to start the sending process.
///
/// As with `Future` and `Stream`, the `Sink` trait is built from a few core
/// required methods, and a host of default methods for working in a
/// higher-level way. The `Sink::send_all` combinator is of particular
/// importance: you can use it to send an entire stream to a sink, which is
/// the simplest way to ultimately consume a sink.
///
/// You can find more information/tutorials about streams [online at
/// https://tokio.rs][online]
///
/// [online]: https://tokio.rs/docs/going-deeper/futures-mechanics/
pub trait Sink {
    /// The type of value that the sink accepts.
    type SinkItem;

    /// The type of value produced by the sink when an error occurs.
    type SinkError;

    /// Attempts to prepare the `Sink` to receive a value.
    ///
    /// This method must be called and return `Ok(Async::Ready(()))` prior to
    /// each call to `start_send`.
    ///
    /// This method returns `Async::Ready` once the underlying sink is ready to
    /// receive data. If this method returns `Async::Pending`, the current task
    /// is registered to be notified (via `cx.waker()`) when `poll_ready`
    /// should be called again.
    ///
    /// In most cases, if the sink encounters an error, the sink will
    /// permanently be unable to receive items.
    fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>;

    /// Begin the process of sending a value to the sink.
    /// Each call to this function must be proceeded by a successful call to
    /// `poll_ready` which returned `Ok(Async::Ready(()))`.
    ///
    /// As the name suggests, this method only *begins* the process of sending
    /// the item. If the sink employs buffering, the item isn't fully processed
    /// until the buffer is fully flushed. Since sinks are designed to work with
    /// asynchronous I/O, the process of actually writing out the data to an
    /// underlying object takes place asynchronously. **You *must* use
    /// `poll_flush` or `poll_close` in order to guarantee completion of a
    /// send**.
    ///
    /// Implementations of `poll_ready` and `start_send` will usually involve
    /// flushing behind the scenes in order to make room for new messages.
    /// It is only necessary to call `poll_flush` if you need to guarantee that
    /// *all* of the items placed into the `Sink` have been sent.
    ///
    /// In most cases, if the sink encounters an error, the sink will
    /// permanently be unable to receive items.
    fn start_send(&mut self, item: Self::SinkItem)
                  -> Result<(), Self::SinkError>;

    /// Flush any remaining output from this sink.
    ///
    /// Returns `Ok(Async::Ready(()))` when no buffered items remain. If this
    /// value is returned then it is guaranteed that all previous values sent
    /// via `start_send` have been flushed.
    ///
    /// Returns `Ok(Async::Pending)` if there is more work left to do, in which
    /// case the current task is scheduled (via `cx.waker()`) to wake up when
    /// `poll_flush` should be called again.
    ///
    /// In most cases, if the sink encounters an error, the sink will
    /// permanently be unable to receive items.
    fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>;

    /// Flush any remaining output and close this sink, if necessary.
    ///
    /// Returns `Ok(Async::Ready(()))` when no buffered items remain and the sink
    /// has been successfully closed.
    ///
    /// Returns `Ok(Async::Pending)` if there is more work left to do, in which
    /// case the current task is scheduled (via `cx.waker()`) to wake up when
    /// `poll_close` should be called again.
    ///
    /// If this function encounters an error, the sink should be considered to
    /// have failed permanently, and no more `Sink` methods should be called.
    fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>;
}

impl<'a, S: ?Sized + Sink> Sink for &'a mut S {
    type SinkItem = S::SinkItem;
    type SinkError = S::SinkError;

    fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
        (**self).poll_ready(cx)
    }

    fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> {
        (**self).start_send(item)
    }

    fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
        (**self).poll_flush(cx)
    }

    fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
        (**self).poll_close(cx)
    }
}
<commit_msg>Completely remove tokio link<commit_after>//! Asynchronous sinks
//!
//! This crate contains the `Sink` trait which allows values to be sent
//! asynchronously.

#![no_std]
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/futures-sink/0.2.0-beta")]

#[cfg(feature = "std")]
extern crate std;

extern crate futures_core;
#[cfg(feature = "std")]
extern crate futures_channel;

macro_rules! if_std {
    ($($i:item)*) => ($(
        #[cfg(feature = "std")]
        $i
    )*)
}

use futures_core::{Poll, task};

if_std! {
    mod channel_impls;

    use futures_core::Async;
    use futures_core::never::Never;

    impl<T> Sink for ::std::vec::Vec<T> {
        type SinkItem = T;
        type SinkError = Never;

        fn poll_ready(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> {
            Ok(Async::Ready(()))
        }

        fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> {
            self.push(item);
            Ok(())
        }

        fn poll_flush(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> {
            Ok(Async::Ready(()))
        }

        fn poll_close(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> {
            Ok(Async::Ready(()))
        }
    }

    impl<S: ?Sized + Sink> Sink for ::std::boxed::Box<S> {
        type SinkItem = S::SinkItem;
        type SinkError = S::SinkError;

        fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
            (**self).poll_ready(cx)
        }

        fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> {
            (**self).start_send(item)
        }

        fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
            (**self).poll_flush(cx)
        }

        fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
            (**self).poll_close(cx)
        }
    }
}

/// A `Sink` is a value into which other values can be sent, asynchronously.
///
/// Basic examples of sinks include the sending side of:
///
/// - Channels
/// - Sockets
/// - Pipes
///
/// In addition to such "primitive" sinks, it's typical to layer additional
/// functionality, such as buffering, on top of an existing sink.
///
/// Sending to a sink is "asynchronous" in the sense that the value may not be
/// sent in its entirety immediately. Instead, values are sent in a two-phase
/// way: first by initiating a send, and then by polling for completion. This
/// two-phase setup is analogous to buffered writing in synchronous code, where
/// writes often succeed immediately, but internally are buffered and are
/// *actually* written only upon flushing.
///
/// In addition, the `Sink` may be *full*, in which case it is not even possible
/// to start the sending process.
///
/// As with `Future` and `Stream`, the `Sink` trait is built from a few core
/// required methods, and a host of default methods for working in a
/// higher-level way. The `Sink::send_all` combinator is of particular
/// importance: you can use it to send an entire stream to a sink, which is
/// the simplest way to ultimately consume a sink.
pub trait Sink {
    /// The type of value that the sink accepts.
    type SinkItem;

    /// The type of value produced by the sink when an error occurs.
    type SinkError;

    /// Attempts to prepare the `Sink` to receive a value.
    ///
    /// This method must be called and return `Ok(Async::Ready(()))` prior to
    /// each call to `start_send`.
    ///
    /// This method returns `Async::Ready` once the underlying sink is ready to
    /// receive data. If this method returns `Async::Pending`, the current task
    /// is registered to be notified (via `cx.waker()`) when `poll_ready`
    /// should be called again.
    ///
    /// In most cases, if the sink encounters an error, the sink will
    /// permanently be unable to receive items.
    fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>;

    /// Begin the process of sending a value to the sink.
    /// Each call to this function must be proceeded by a successful call to
    /// `poll_ready` which returned `Ok(Async::Ready(()))`.
    ///
    /// As the name suggests, this method only *begins* the process of sending
    /// the item. If the sink employs buffering, the item isn't fully processed
    /// until the buffer is fully flushed. Since sinks are designed to work with
    /// asynchronous I/O, the process of actually writing out the data to an
    /// underlying object takes place asynchronously. **You *must* use
    /// `poll_flush` or `poll_close` in order to guarantee completion of a
    /// send**.
    ///
    /// Implementations of `poll_ready` and `start_send` will usually involve
    /// flushing behind the scenes in order to make room for new messages.
    /// It is only necessary to call `poll_flush` if you need to guarantee that
    /// *all* of the items placed into the `Sink` have been sent.
    ///
    /// In most cases, if the sink encounters an error, the sink will
    /// permanently be unable to receive items.
    fn start_send(&mut self, item: Self::SinkItem)
                  -> Result<(), Self::SinkError>;

    /// Flush any remaining output from this sink.
    ///
    /// Returns `Ok(Async::Ready(()))` when no buffered items remain. If this
    /// value is returned then it is guaranteed that all previous values sent
    /// via `start_send` have been flushed.
    ///
    /// Returns `Ok(Async::Pending)` if there is more work left to do, in which
    /// case the current task is scheduled (via `cx.waker()`) to wake up when
    /// `poll_flush` should be called again.
    ///
    /// In most cases, if the sink encounters an error, the sink will
    /// permanently be unable to receive items.
    fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>;

    /// Flush any remaining output and close this sink, if necessary.
    ///
    /// Returns `Ok(Async::Ready(()))` when no buffered items remain and the sink
    /// has been successfully closed.
    ///
    /// Returns `Ok(Async::Pending)` if there is more work left to do, in which
    /// case the current task is scheduled (via `cx.waker()`) to wake up when
    /// `poll_close` should be called again.
    ///
    /// If this function encounters an error, the sink should be considered to
    /// have failed permanently, and no more `Sink` methods should be called.
    fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>;
}

impl<'a, S: ?Sized + Sink> Sink for &'a mut S {
    type SinkItem = S::SinkItem;
    type SinkError = S::SinkError;

    fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
        (**self).poll_ready(cx)
    }

    fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> {
        (**self).start_send(item)
    }

    fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
        (**self).poll_flush(cx)
    }

    fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> {
        (**self).poll_close(cx)
    }
}
<|endoftext|>


<commit_before>use internal::ColorComponent;
use quack::{ GetFrom, Get, SetAt, Set, Pair };
use context::{ Transform, ViewTransform };
use vecmath::{
    get_scale,
    hsv,
    identity,
    margin_rectangle,
    multiply,
    orient,
    relative_rectangle,
    relative_source_rectangle,
    rotate_radians,
    scale,
    shear,
    translate,
    Matrix2d,
    Scalar,
    Vec2d,
};
use radians::Radians;
use Color;
use Rect;
use SrcRect;

/// Implemented by contexts that contains color.
pub trait RelativeColor: Get<Color> + Set<Color> + Clone {
    /// Multiplies with red, green, blue and alpha values.
    #[inline(always)]
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self {
        let Color(col) = self.get();
        self.clone().set(Color([col[0] * r, col[1] * g, col[2] * b, col[3] * a]))
    }

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&self, f: ColorComponent) -> Self {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&self, f: ColorComponent) -> Self {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(&self, angle: ColorComponent) -> Self {
        let pi: ColorComponent = Radians::_180();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    #[inline(always)]
    fn hue_rad(&self, angle: ColorComponent) -> Self {
        let Color(val) = self.get();
        self.clone().set(Color(hsv(val, angle, 1.0, 1.0)))
    }
}

impl<T: Get<Color> + Set<Color> + Clone> RelativeColor for T {}

/// Should be implemented by contexts that have rectangle information.
pub trait RelativeRectangle: Get<Rect> + Set<Rect> + Clone {
    /// Shrinks the current rectangle equally by all sides.
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(margin_rectangle(val, m)))
    }

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(relative_rectangle(val, [x, y])))
    }
}

impl<T: Get<Rect> + Set<Rect> + Clone> RelativeRectangle for T {}

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait RelativeSourceRectangle: Get<SrcRect> + Set<SrcRect> + Clone {
    /// Adds a source rectangle.
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.clone().set(SrcRect([x, y, w, h]))
    }

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        let SrcRect(val) = self.get();
        self.clone().set(SrcRect(
            relative_source_rectangle(val, x, y)
        ))
    }

    /// Flips the source rectangle horizontally.
    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ]))
    }

    /// Flips the source rectangle vertically.
    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ]))
    }

    /// Flips the source rectangle horizontally and vertically.
    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ]))
    }
}

impl<T: Get<SrcRect>
      + Set<SrcRect>
      + Clone
> RelativeSourceRectangle for T {}

/// Implemented by contexts that can transform.
pub trait RelativeTransform: Clone
    where
        (Transform, Self): Pair<Data = Transform, Object = Self>
            + GetFrom + SetAt
{
    /// Appends transform to the current one.
    #[inline(always)]
    fn append_transform(&self, transform: Matrix2d) -> Self {
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, transform)))
    }

    /// Prepends transform to the current one.
    #[inline(always)]
    fn prepend_transform(&self, transform: Matrix2d) -> Self {
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(transform, mat)))
    }

    /// Translate x an y in local coordinates.
    #[inline(always)]
    fn trans(&self, x: Scalar, y: Scalar) -> Self {
        let trans = translate([x, y]);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, trans)))
    }

    /// Rotates degrees in local coordinates.
    #[inline(always)]
    fn rot_deg(&self, angle: Scalar) -> Self {
        let pi: Scalar = Radians::_180();
        self.rot_rad(angle * pi / 180.0)
    }

    /// Rotate radians in local coordinates.
    #[inline(always)]
    fn rot_rad(&self, angle: Scalar) -> Self {
        let rot = rotate_radians(angle);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, rot)))
    }

    /// Orients x axis to look at point locally.
    ///
    /// Leaves x axis unchanged if the point to
    /// look at is the origin.
    #[inline(always)]
    fn orient(&self, x: Scalar, y: Scalar) -> Self {
        let orient = orient(x, y);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, orient)))
    }

    /// Scales in local coordinates.
    #[inline(always)]
    fn scale(&self, sx: Scalar, sy: Scalar) -> Self {
        let scale = scale(sx, sy);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, scale)))
    }

    /// Scales in both directions in local coordinates.
    #[inline(always)]
    fn zoom(&self, s: Scalar) -> Self {
        self.scale(s, s)
    }

    /// Flips vertically in local coordinates.
    #[inline(always)]
    fn flip_v(&self) -> Self {
        self.scale(1.0, -1.0)
    }

    /// Flips horizontally in local coordinates.
    #[inline(always)]
    fn flip_h(&self) -> Self {
        self.scale(-1.0, 1.0)
    }

    /// Flips horizontally and vertically in local coordinates.
    #[inline(always)]
    fn flip_hv(&self) -> Self {
        self.scale(-1.0, -1.0)
    }

    /// Shears in local coordinates.
    #[inline(always)]
    fn shear(&self, v: Vec2d) -> Self {
        let shear = shear(v);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, shear)))
    }
}

impl<T: Clone> RelativeTransform for T
    where
        (Transform, Self): Pair<Data = Transform, Object = Self>
            + GetFrom + SetAt
{}

/// Should be implemented by contexts that
/// draws something relative to view.
pub trait RelativeViewTransform: Clone
    where
        (ViewTransform, Self): Pair<Data = ViewTransform, Object = Self>
            + GetFrom + SetAt,
        (Transform, Self): Pair<Data = Transform, Object = Self>
            + GetFrom + SetAt
{
    /// Moves the current transform to the view coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the upper left corner
    /// with the x axis pointing to the right
    /// and the y axis pointing down.
    #[inline(always)]
    fn view(&self) -> Self {
        let ViewTransform(mat) = self.get();
        self.clone().set(Transform(mat))
    }

    /// Moves the current transform to the default coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the center
    /// with the x axis pointing to the right
    /// and the y axis pointing up.
    #[inline(always)]
    fn reset(&self) -> Self {
        self.clone().set(Transform(identity()))
    }

    /// Stores the current transform as new view.
    #[inline(always)]
    fn store_view(&self) -> Self {
        let Transform(mat) = self.get();
        self.clone().set(ViewTransform(mat))
    }

    /// Computes the current view size.
    #[inline(always)]
    fn get_view_size(&self) -> (Scalar, Scalar) {
        let ViewTransform(mat) = self.get();
        let scale = get_scale(mat);
        (2.0 / scale[0], 2.0 / scale[1])
    }
}

impl<T: Clone> RelativeViewTransform for T
    where
        (ViewTransform, Self): Pair<Data = ViewTransform, Object = Self>
            + GetFrom + SetAt,
        (Transform, Self): Pair<Data = Transform, Object = Self>
            + GetFrom + SetAt,
{}

<commit_msg>Moved default trait methods to impls<commit_after>use internal::ColorComponent;
use quack::{ GetFrom, Get, SetAt, Set, Pair };
use context::{ Transform, ViewTransform };
use vecmath::{
    get_scale,
    hsv,
    identity,
    margin_rectangle,
    multiply,
    orient,
    relative_rectangle,
    relative_source_rectangle,
    rotate_radians,
    scale,
    shear,
    translate,
    Matrix2d,
    Scalar,
    Vec2d,
};
use radians::Radians;
use Color;
use Rect;
use SrcRect;

/// Implemented by contexts that contains color.
pub trait RelativeColor: Sized {
    /// Multiplies with red, green, blue and alpha values.
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self;

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&self, f: ColorComponent) -> Self {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&self, f: ColorComponent) -> Self {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(&self, angle: ColorComponent) -> Self {
        let pi: ColorComponent = Radians::_180();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    fn hue_rad(&self, angle: ColorComponent) -> Self;
}

impl<T: Get<Color> + Set<Color> + Clone> RelativeColor for T {
    #[inline(always)]
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self {
        let Color(col) = self.get();
        self.clone().set(Color([col[0] * r, col[1] * g, col[2] * b, col[3] * a]))
    }

    #[inline(always)]
    fn hue_rad(&self, angle: ColorComponent) -> Self {
        let Color(val) = self.get();
        self.clone().set(Color(hsv(val, angle, 1.0, 1.0)))
    }
}

/// Should be implemented by contexts that have rectangle information.
pub trait RelativeRectangle: Sized {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&self, m: Scalar) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&self, x: Scalar, y: Scalar) -> Self;
}

impl<T: Get<Rect> + Set<Rect> + Clone> RelativeRectangle for T {
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(margin_rectangle(val, m)))
    }

    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(relative_rectangle(val, [x, y])))
    }
}

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait RelativeSourceRectangle {
    /// Adds a source rectangle.
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self;

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    fn src_rel(&self, x: i32, y: i32) -> Self;

    /// Flips the source rectangle horizontally.
    fn src_flip_h(&self) -> Self;

    /// Flips the source rectangle vertically.
    fn src_flip_v(&self) -> Self;

    /// Flips the source rectangle horizontally and vertically.
    fn src_flip_hv(&self) -> Self;
}

impl<T: Get<SrcRect>
      + Set<SrcRect>
      + Clone
> RelativeSourceRectangle for T {
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.clone().set(SrcRect([x, y, w, h]))
    }

    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        let SrcRect(val) = self.get();
        self.clone().set(SrcRect(
            relative_source_rectangle(val, x, y)
        ))
    }

    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ]))
    }
}

/// Implemented by contexts that can transform.
pub trait RelativeTransform: Sized {
    /// Appends transform to the current one.
    fn append_transform(&self, transform: Matrix2d) -> Self;

    /// Prepends transform to the current one.
    fn prepend_transform(&self, transform: Matrix2d) -> Self;

    /// Translate x an y in local coordinates.
    fn trans(&self, x: Scalar, y: Scalar) -> Self;

    /// Rotates degrees in local coordinates.
    #[inline(always)]
    fn rot_deg(&self, angle: Scalar) -> Self {
        let pi: Scalar = Radians::_180();
        self.rot_rad(angle * pi / 180.0)
    }

    /// Rotate radians in local coordinates.
    fn rot_rad(&self, angle: Scalar) -> Self;

    /// Orients x axis to look at point locally.
    ///
    /// Leaves x axis unchanged if the point to
    /// look at is the origin.
    fn orient(&self, x: Scalar, y: Scalar) -> Self;

    /// Scales in local coordinates.
    fn scale(&self, sx: Scalar, sy: Scalar) -> Self;

    /// Scales in both directions in local coordinates.
    #[inline(always)]
    fn zoom(&self, s: Scalar) -> Self {
        self.scale(s, s)
    }

    /// Flips vertically in local coordinates.
    #[inline(always)]
    fn flip_v(&self) -> Self {
        self.scale(1.0, -1.0)
    }

    /// Flips horizontally in local coordinates.
    #[inline(always)]
    fn flip_h(&self) -> Self {
        self.scale(-1.0, 1.0)
    }

    /// Flips horizontally and vertically in local coordinates.
    #[inline(always)]
    fn flip_hv(&self) -> Self {
        self.scale(-1.0, -1.0)
    }

    /// Shears in local coordinates.
    fn shear(&self, v: Vec2d) -> Self;
}

impl<T: Clone> RelativeTransform for T
    where
        (Transform, Self): Pair<Data = Transform, Object = Self>
            + GetFrom + SetAt
{
    #[inline(always)]
    fn append_transform(&self, transform: Matrix2d) -> Self {
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, transform)))
    }

    #[inline(always)]
    fn prepend_transform(&self, transform: Matrix2d) -> Self {
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(transform, mat)))
    }

    #[inline(always)]
    fn trans(&self, x: Scalar, y: Scalar) -> Self {
        let trans = translate([x, y]);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, trans)))
    }

    #[inline(always)]
    fn rot_rad(&self, angle: Scalar) -> Self {
        let rot = rotate_radians(angle);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, rot)))
    }

    #[inline(always)]
    fn orient(&self, x: Scalar, y: Scalar) -> Self {
        let orient = orient(x, y);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, orient)))
    }

    #[inline(always)]
    fn scale(&self, sx: Scalar, sy: Scalar) -> Self {
        let scale = scale(sx, sy);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, scale)))
    }

    #[inline(always)]
    fn shear(&self, v: Vec2d) -> Self {
        let shear = shear(v);
        let Transform(mat) = self.get();
        self.clone().set(Transform(multiply(mat, shear)))
    }
}

/// Should be implemented by contexts that
/// draws something relative to view.
pub trait RelativeViewTransform {
    /// Moves the current transform to the view coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the upper left corner
    /// with the x axis pointing to the right
    /// and the y axis pointing down.
    #[inline(always)]
    fn view(&self) -> Self;

    /// Moves the current transform to the default coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the center
    /// with the x axis pointing to the right
    /// and the y axis pointing up.
    fn reset(&self) -> Self;

    /// Stores the current transform as new view.
    fn store_view(&self) -> Self;

    /// Computes the current view size.
    fn get_view_size(&self) -> (Scalar, Scalar);
}

impl<T: Clone> RelativeViewTransform for T
    where
        (ViewTransform, Self): Pair<Data = ViewTransform, Object = Self>
            + GetFrom + SetAt,
        (Transform, Self): Pair<Data = Transform, Object = Self>
            + GetFrom + SetAt,
{
    #[inline(always)]
    fn view(&self) -> Self {
        let ViewTransform(mat) = self.get();
        self.clone().set(Transform(mat))
    }

    #[inline(always)]
    fn reset(&self) -> Self {
        self.clone().set(Transform(identity()))
    }

    #[inline(always)]
    fn store_view(&self) -> Self {
        let Transform(mat) = self.get();
        self.clone().set(ViewTransform(mat))
    }

    #[inline(always)]
    fn get_view_size(&self) -> (Scalar, Scalar) {
        let ViewTransform(mat) = self.get();
        let scale = get_scale(mat);
        (2.0 / scale[0], 2.0 / scale[1])
    }
}

<|endoftext|>


<commit_before>#[cfg(target_arch = "wasm32")]
compile_error!("This module should not be included when compiling to wasm");

use std::sync::mpsc::{self, TryRecvError};
use std::thread;
use std::path;

use piston_window::{clear, context, line, polygon, AdvancedWindow, Event as PistonEvent, G2d,
    Input, PistonWindow, WindowSettings};

use svg;
use svg::node::element::{Line as SvgLine, Polygon as SvgPolygon, Rectangle as SvgRect};

use crate::app::TurtleApp;
use crate::event::from_piston_event;
use crate::extensions::ConvertScreenCoordinates;
use crate::query::DrawingCommand;
use crate::state::{DrawingState, Path, Pen, Polygon, TurtleState};
use crate::{color, Color, Event, Point};

fn update_window(window: &mut PistonWindow, current: DrawingState, next: DrawingState) -> DrawingState {
    if next.title != current.title {
        window.set_title(next.title.clone());
    }
    if next.width != current.width || next.height != current.height {
        window.set_size((next.width, next.height));
    }
    if next.maximized != current.maximized {
        window.window.ctx.window().set_maximized(next.maximized);
    }
    if next.fullscreen != current.fullscreen {
        if next.fullscreen {
            window
                .window
                .ctx
                .window()
                .set_fullscreen(Some(window.window.ctx.window().get_current_monitor()));
        } else {
            window.window.ctx.window().set_fullscreen(None);
        }
    }
    next
}

#[derive(Debug)]
pub enum Drawing {
    Path(Path),
    Polygon(Polygon),
}

pub struct Renderer {
    app: TurtleApp,
    drawings: Vec<Drawing>,
    /// Polygon that is currently in the process of being filled
    /// Removed when EndFill is sent
    fill_polygon: Option<(Vec<Path>, Polygon)>,
}

impl Renderer {
    pub fn new(app: TurtleApp) -> Renderer {
        Self {
            app,
            drawings: Vec::new(),
            fill_polygon: None,
        }
    }

    pub fn run(&mut self, drawing_rx: mpsc::Receiver<DrawingCommand>, events_tx: mpsc::Sender<Event>) {
        let state = self.app.read_only();

        // This check isn't foolproof. Someone can always create a thread named "main".
        if thread::current().name().unwrap_or("") != "main" {
            // In order to maintain compatibility with MacOS, we need to make sure that windows are
            // only created on the main thread. We do this check on all platforms so that no one
            // can accidentally make a change that creates the window off of the main thread.
            unreachable!("bug: windows can only be created on the main thread");
        }

        let mut window: PistonWindow = WindowSettings::new(
            &*state.drawing().title,
            (state.drawing().width, state.drawing().height)
        ).exit_on_esc(true).build().expect("bug: could not build window");

        // We keep a copy of the DrawingState so that we can tell when it is updated and we need
        // to change something on the window
        let mut current_drawing = DrawingState::default();

        let mut center = state.drawing().center;

        'renderloop: while let Some(event) = window.next() {
            match event {
                PistonEvent::Input(Input::Resize(args), _) => {
                    let [width, height] = args.draw_size;
                    let width = width as u32;
                    let height = height as u32;
                    if width != current_drawing.width || height != current_drawing.height {
                        let mut drawing = self.app.drawing_mut();
                        drawing.width = width;
                        drawing.height = height;
                    }
                }
                _ => {}
            }

            if let Some(event) = from_piston_event(&event, |pt| pt.to_local_coords(center)) {
                match events_tx.send(event) {
                    Ok(_) => {}
                    // Quit - the server thread must have quit
                    Err(_) => break,
                }
            }

            // Need to handle all of the queries we receive at once so that any lag caused by
            // how long rendering takes doesn't cause any problems
            loop {
                match drawing_rx.try_recv() {
                    Ok(cmd) => self.handle_drawing_command(cmd),
                    Err(TryRecvError::Empty) => break,                    // Do nothing
                    Err(TryRecvError::Disconnected) => break 'renderloop, // Quit
                }
            }

            // Update the window based on any changes in the DrawingState
            current_drawing = update_window(&mut window, current_drawing, state.drawing().clone());

            window.draw_2d(&event, |c, g, _d| {
                let view = c.get_view_size();
                let width = view[0] as f64;
                let height = view[1] as f64;
                center = state.drawing().center.to_screen_coords(Point {
                    x: width * 0.5,
                    y: height * 0.5,
                });

                // We clone the relevant state before rendering so that the rendering thread
                // doesn't need to keep locking, waiting or making the main thread wait
                let drawing = state.drawing().clone();
                let temporary_path = state.temporary_path().clone();
                let turtle = state.turtle().clone();

                self.render(c, g, center, &drawing, &temporary_path, &turtle);
            });
        }
    }

    /// Handles a drawing command sent from the main thread
    fn handle_drawing_command(&mut self, command: DrawingCommand) {
        //NOTE: Do not pass the ReadOnly state to this function. By the time a DrawingCommand is
        // handled, that state may be completely out of date
        use DrawingCommand::*;
        match command {
            StorePath(path) => {
                if self.fill_polygon.is_some() {
                    let &mut (ref mut border, ref mut poly) = self.fill_polygon.as_mut().unwrap();
                    border.push(path.clone());

                    let Path { start, end, .. } = path;
                    if poly.vertices.last().map_or(true, |&v| v != start) {
                        poly.vertices.push(start);
                    }
                    poly.vertices.push(end);
                } else if path.pen.enabled {
                    self.drawings.push(Drawing::Path(path));
                }
            },
            BeginFill(fill_color) => {
                // Calling begin_fill multiple times is okay, it just won't do anything until
                // end_fill is called
                self.fill_polygon = self.fill_polygon.take().or_else(|| {
                    Some((
                        Vec::new(),
                        Polygon {
                            vertices: Vec::new(),
                            fill_color,
                        },
                    ))
                });
            },
            // Calling end_fill multiple times is not a problem
            EndFill => if let Some((border, poly)) = self.fill_polygon.take() {
                // Always add the border over the filled polygon so the border is drawn on top
                self.drawings.push(Drawing::Polygon(poly));
                self.drawings.extend(
                    border
                        .into_iter()
                        .filter_map(|p| if p.pen.enabled { Some(Drawing::Path(p)) } else { None }),
                );
            },
            Clear => {
                self.drawings.clear();
                // Because clear doesn't actually shorten the capacity of the vector
                // We don't want to leak memory by leaving this Vec at whatever its size was before
                self.drawings.shrink_to_fit();
                self.fill_polygon.take();
            },
            SaveSVG(path_buf) => self.save_svg(&path_buf),
        }
    }

    /// The main rendering route. Dispatches to other functions as needed.
    fn render(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        drawing: &DrawingState,
        temporary_path: &Option<Path>,
        turtle: &TurtleState,
    ) {
        let background = drawing.background;
        clear(background.into(), g);

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => self.render_path(c, g, center, path),
                Drawing::Polygon(ref poly) => self.render_polygon(c, g, center, poly.fill_color, poly.vertices.iter()),
            }
        }

        if let Some(&(ref border, ref poly)) = self.fill_polygon.as_ref() {
            // If the temporary_path is not None, we need to add it to the polygon being
            // filled or else the polygon will fall one edge behind in the animation
            let extra = temporary_path.as_ref().map_or(Vec::new(), |&Path { start, end, .. }| {
                if poly.vertices.last().map_or(true, |&v| v != start) {
                    vec![start, end]
                } else {
                    vec![end]
                }
            });
            self.render_polygon(c, g, center, poly.fill_color, poly.vertices.iter().chain(extra.iter()));

            for path in border {
                if path.pen.enabled {
                    self.render_path(c, g, center, path);
                }
            }
        }

        if let Some(ref path) = *temporary_path {
            if path.pen.enabled {
                self.render_path(c, g, center, path);
            }
        }

        self.render_shell(c, g, center, turtle);
    }

    /// Render a path assuming that its pen is enabled
    fn render_path(&self, c: context::Context, g: &mut G2d<'_>, center: Point, path: &Path) {
        let &Path { start, end, ref pen } = path;
        let &Pen { thickness, color, enabled } = pen;
        debug_assert!(enabled, "bug: attempt to render path when pen was not enabled");

        let start = start.to_screen_coords(center);
        let end = end.to_screen_coords(center);

        line(color.into(), thickness, [start.x, start.y, end.x, end.y], c.transform, g);
    }

    /// Render a polygon given its vertices
    fn render_polygon<'a, T: Iterator<Item = &'a Point>>(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        fill_color: Color,
        verts: T,
    ) {
        // Performance note: Why make this function generic instead of just taking Polygon?
        // Answer: render_polygon is called multiple times. It's called repeatedly in a loop, and
        // it is also called when drawing the current fill_polygon. Rather than moving the
        // code to *maybe* add the temporary_path to the rendered polygon into this method, we
        // avoid branching unnecessarily by allowing the repeated caller to do what is fast, then
        // doing the slow thing (checking if the path is None) only once when it is needed.
        //
        // We pass in the points as an Iterator so that they do not need to be collected into any
        // struct. This avoids an allocation that really isn't needed since these are all temporary
        // anyway. Everything is going to get copied anyway on the next line. No need to do it
        // twice.
        //
        // See the commit before this comment was added for the approach that would have required
        // branching in every iteration of the loop where render_polygon is called over and over
        // again.
        let verts = verts.map(|p| p.to_screen_coords(center).into()).collect::<Vec<_>>();
        polygon(fill_color.into(), &verts, c.transform, g);
    }

    /// Draw the turtle's shell
    fn render_shell(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        &TurtleState {
            position,
            heading,
            visible,
            ..
        }: &TurtleState,
    ) {
        // Calculate all the points on the shell by rotating the shell shape by the turtle's
        // heading and moving it to the turtle's position
        if !visible {
            return;
        }

        let cos = heading.cos();
        let sin = heading.sin();
        let turtle_x = position.x;
        let turtle_y = position.y;
        let shell: Vec<_> = [[0., 15.], [10., 0.], [0., -15.]]
            .into_iter()
            .map(|pt| {
                // Rotate each point by the heading and add the current turtle position
                let x = cos * pt[0] - sin * pt[1] + turtle_x;
                let y = sin * pt[0] + cos * pt[1] + turtle_y;
                Point { x, y }.to_screen_coords(center).into()
            })
            .collect();

        // Draw the turtle shell with its background first, then its border
        polygon(color::WHITE.into(), &shell, c.transform, g);
        for i in 0..shell.len() {
            let start = shell[i];
            let end = shell[(i + 1) % shell.len()];

            line(color::BLACK.into(), 1., [start[0], start[1], end[0], end[1]], c.transform, g);
        }
    }

    /// Save the drawings to SVG
    fn save_svg(&mut self, path: &path::Path) {
        // Returns rgba string of Color in CSS functional syntax
        fn rgba_string(color: Color) -> String {
            format!("rgba({}, {}, {}, {})", color.red as u8, color.green as u8, color.blue as u8, color.alpha)
        }

        let drawing_state = self.app.drawing();
        let mut document = svg::Document::new()
            .set("viewBox", (0, 0, drawing_state.width, drawing_state.height));

        // set background color - https://stackoverflow.com/a/11293812/9276882
        let bg_color = drawing_state.background;
        let background = SvgRect::new()
            .set("width", "100%")
            .set("height", "100%")
            .set("fill", rgba_string(bg_color));

        document = document.add(background);

        let center = drawing_state.center.to_screen_coords(Point {
            x: drawing_state.width as f64 * 0.5,
            y: drawing_state.height as f64 * 0.5,
        });

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => {
                    let &Path { start, end, ref pen } = path;
                    let &Pen { thickness, color, enabled: _ } = pen;

                    let start = start.to_screen_coords(center);
                    let end = end.to_screen_coords(center);

                    let line = SvgLine::new()
                        .set("x1", start.x)
                        .set("y1", start.y)
                        .set("x2", end.x)
                        .set("y2", end.y)
                        .set("stroke", rgba_string(color))
                        .set("stroke-width", format!("{}px", thickness * 2.0));

                    // Note that in above code `stroke-width` is twice the `thickness`.
                    // As per https://docs.piston.rs/piston_window/piston_window/fn.line.html,
                    // second param of piston_window::line is radius.
                    // So radius (thickness) = 1 takes 2 pixels on screen.
                    // Hence, stroke-width of svg element is double the thickness.

                    document = document.add(line);
                },
                Drawing::Polygon(ref poly) => {
                    let points = poly.vertices.iter()
                        .map(|p| {
                            let point = p.to_screen_coords(center);
                            format!("{},{} ", point.x, point.y)
                        })
                        .fold("".to_string(), |acc, x| acc + &x);

                    let polygon = SvgPolygon::new()
                        .set("fill", rgba_string(poly.fill_color))
                        .set("points", points);

                    document = document.add(polygon);
                },
            }
        }

        let export_to_svg = svg::save(path, &document);
        match export_to_svg {
            Ok(()) => (),
            Err(error) => eprintln!("Error saving SVG file : {:#?}", error),
        }
    }
}
<commit_msg>Changed into_iter -> iter to fix compiler warning<commit_after>#[cfg(target_arch = "wasm32")]
compile_error!("This module should not be included when compiling to wasm");

use std::sync::mpsc::{self, TryRecvError};
use std::thread;
use std::path;

use piston_window::{clear, context, line, polygon, AdvancedWindow, Event as PistonEvent, G2d,
    Input, PistonWindow, WindowSettings};

use svg;
use svg::node::element::{Line as SvgLine, Polygon as SvgPolygon, Rectangle as SvgRect};

use crate::app::TurtleApp;
use crate::event::from_piston_event;
use crate::extensions::ConvertScreenCoordinates;
use crate::query::DrawingCommand;
use crate::state::{DrawingState, Path, Pen, Polygon, TurtleState};
use crate::{color, Color, Event, Point};

fn update_window(window: &mut PistonWindow, current: DrawingState, next: DrawingState) -> DrawingState {
    if next.title != current.title {
        window.set_title(next.title.clone());
    }
    if next.width != current.width || next.height != current.height {
        window.set_size((next.width, next.height));
    }
    if next.maximized != current.maximized {
        window.window.ctx.window().set_maximized(next.maximized);
    }
    if next.fullscreen != current.fullscreen {
        if next.fullscreen {
            window
                .window
                .ctx
                .window()
                .set_fullscreen(Some(window.window.ctx.window().get_current_monitor()));
        } else {
            window.window.ctx.window().set_fullscreen(None);
        }
    }
    next
}

#[derive(Debug)]
pub enum Drawing {
    Path(Path),
    Polygon(Polygon),
}

pub struct Renderer {
    app: TurtleApp,
    drawings: Vec<Drawing>,
    /// Polygon that is currently in the process of being filled
    /// Removed when EndFill is sent
    fill_polygon: Option<(Vec<Path>, Polygon)>,
}

impl Renderer {
    pub fn new(app: TurtleApp) -> Renderer {
        Self {
            app,
            drawings: Vec::new(),
            fill_polygon: None,
        }
    }

    pub fn run(&mut self, drawing_rx: mpsc::Receiver<DrawingCommand>, events_tx: mpsc::Sender<Event>) {
        let state = self.app.read_only();

        // This check isn't foolproof. Someone can always create a thread named "main".
        if thread::current().name().unwrap_or("") != "main" {
            // In order to maintain compatibility with MacOS, we need to make sure that windows are
            // only created on the main thread. We do this check on all platforms so that no one
            // can accidentally make a change that creates the window off of the main thread.
            unreachable!("bug: windows can only be created on the main thread");
        }

        let mut window: PistonWindow = WindowSettings::new(
            &*state.drawing().title,
            (state.drawing().width, state.drawing().height)
        ).exit_on_esc(true).build().expect("bug: could not build window");

        // We keep a copy of the DrawingState so that we can tell when it is updated and we need
        // to change something on the window
        let mut current_drawing = DrawingState::default();

        let mut center = state.drawing().center;

        'renderloop: while let Some(event) = window.next() {
            match event {
                PistonEvent::Input(Input::Resize(args), _) => {
                    let [width, height] = args.draw_size;
                    let width = width as u32;
                    let height = height as u32;
                    if width != current_drawing.width || height != current_drawing.height {
                        let mut drawing = self.app.drawing_mut();
                        drawing.width = width;
                        drawing.height = height;
                    }
                }
                _ => {}
            }

            if let Some(event) = from_piston_event(&event, |pt| pt.to_local_coords(center)) {
                match events_tx.send(event) {
                    Ok(_) => {}
                    // Quit - the server thread must have quit
                    Err(_) => break,
                }
            }

            // Need to handle all of the queries we receive at once so that any lag caused by
            // how long rendering takes doesn't cause any problems
            loop {
                match drawing_rx.try_recv() {
                    Ok(cmd) => self.handle_drawing_command(cmd),
                    Err(TryRecvError::Empty) => break,                    // Do nothing
                    Err(TryRecvError::Disconnected) => break 'renderloop, // Quit
                }
            }

            // Update the window based on any changes in the DrawingState
            current_drawing = update_window(&mut window, current_drawing, state.drawing().clone());

            window.draw_2d(&event, |c, g, _d| {
                let view = c.get_view_size();
                let width = view[0] as f64;
                let height = view[1] as f64;
                center = state.drawing().center.to_screen_coords(Point {
                    x: width * 0.5,
                    y: height * 0.5,
                });

                // We clone the relevant state before rendering so that the rendering thread
                // doesn't need to keep locking, waiting or making the main thread wait
                let drawing = state.drawing().clone();
                let temporary_path = state.temporary_path().clone();
                let turtle = state.turtle().clone();

                self.render(c, g, center, &drawing, &temporary_path, &turtle);
            });
        }
    }

    /// Handles a drawing command sent from the main thread
    fn handle_drawing_command(&mut self, command: DrawingCommand) {
        //NOTE: Do not pass the ReadOnly state to this function. By the time a DrawingCommand is
        // handled, that state may be completely out of date
        use DrawingCommand::*;
        match command {
            StorePath(path) => {
                if self.fill_polygon.is_some() {
                    let &mut (ref mut border, ref mut poly) = self.fill_polygon.as_mut().unwrap();
                    border.push(path.clone());

                    let Path { start, end, .. } = path;
                    if poly.vertices.last().map_or(true, |&v| v != start) {
                        poly.vertices.push(start);
                    }
                    poly.vertices.push(end);
                } else if path.pen.enabled {
                    self.drawings.push(Drawing::Path(path));
                }
            },
            BeginFill(fill_color) => {
                // Calling begin_fill multiple times is okay, it just won't do anything until
                // end_fill is called
                self.fill_polygon = self.fill_polygon.take().or_else(|| {
                    Some((
                        Vec::new(),
                        Polygon {
                            vertices: Vec::new(),
                            fill_color,
                        },
                    ))
                });
            },
            // Calling end_fill multiple times is not a problem
            EndFill => if let Some((border, poly)) = self.fill_polygon.take() {
                // Always add the border over the filled polygon so the border is drawn on top
                self.drawings.push(Drawing::Polygon(poly));
                self.drawings.extend(
                    border
                        .into_iter()
                        .filter_map(|p| if p.pen.enabled { Some(Drawing::Path(p)) } else { None }),
                );
            },
            Clear => {
                self.drawings.clear();
                // Because clear doesn't actually shorten the capacity of the vector
                // We don't want to leak memory by leaving this Vec at whatever its size was before
                self.drawings.shrink_to_fit();
                self.fill_polygon.take();
            },
            SaveSVG(path_buf) => self.save_svg(&path_buf),
        }
    }

    /// The main rendering route. Dispatches to other functions as needed.
    fn render(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        drawing: &DrawingState,
        temporary_path: &Option<Path>,
        turtle: &TurtleState,
    ) {
        let background = drawing.background;
        clear(background.into(), g);

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => self.render_path(c, g, center, path),
                Drawing::Polygon(ref poly) => self.render_polygon(c, g, center, poly.fill_color, poly.vertices.iter()),
            }
        }

        if let Some(&(ref border, ref poly)) = self.fill_polygon.as_ref() {
            // If the temporary_path is not None, we need to add it to the polygon being
            // filled or else the polygon will fall one edge behind in the animation
            let extra = temporary_path.as_ref().map_or(Vec::new(), |&Path { start, end, .. }| {
                if poly.vertices.last().map_or(true, |&v| v != start) {
                    vec![start, end]
                } else {
                    vec![end]
                }
            });
            self.render_polygon(c, g, center, poly.fill_color, poly.vertices.iter().chain(extra.iter()));

            for path in border {
                if path.pen.enabled {
                    self.render_path(c, g, center, path);
                }
            }
        }

        if let Some(ref path) = *temporary_path {
            if path.pen.enabled {
                self.render_path(c, g, center, path);
            }
        }

        self.render_shell(c, g, center, turtle);
    }

    /// Render a path assuming that its pen is enabled
    fn render_path(&self, c: context::Context, g: &mut G2d<'_>, center: Point, path: &Path) {
        let &Path { start, end, ref pen } = path;
        let &Pen { thickness, color, enabled } = pen;
        debug_assert!(enabled, "bug: attempt to render path when pen was not enabled");

        let start = start.to_screen_coords(center);
        let end = end.to_screen_coords(center);

        line(color.into(), thickness, [start.x, start.y, end.x, end.y], c.transform, g);
    }

    /// Render a polygon given its vertices
    fn render_polygon<'a, T: Iterator<Item = &'a Point>>(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        fill_color: Color,
        verts: T,
    ) {
        // Performance note: Why make this function generic instead of just taking Polygon?
        // Answer: render_polygon is called multiple times. It's called repeatedly in a loop, and
        // it is also called when drawing the current fill_polygon. Rather than moving the
        // code to *maybe* add the temporary_path to the rendered polygon into this method, we
        // avoid branching unnecessarily by allowing the repeated caller to do what is fast, then
        // doing the slow thing (checking if the path is None) only once when it is needed.
        //
        // We pass in the points as an Iterator so that they do not need to be collected into any
        // struct. This avoids an allocation that really isn't needed since these are all temporary
        // anyway. Everything is going to get copied anyway on the next line. No need to do it
        // twice.
        //
        // See the commit before this comment was added for the approach that would have required
        // branching in every iteration of the loop where render_polygon is called over and over
        // again.
        let verts = verts.map(|p| p.to_screen_coords(center).into()).collect::<Vec<_>>();
        polygon(fill_color.into(), &verts, c.transform, g);
    }

    /// Draw the turtle's shell
    fn render_shell(
        &self,
        c: context::Context,
        g: &mut G2d<'_>,
        center: Point,
        &TurtleState {
            position,
            heading,
            visible,
            ..
        }: &TurtleState,
    ) {
        // Calculate all the points on the shell by rotating the shell shape by the turtle's
        // heading and moving it to the turtle's position
        if !visible {
            return;
        }

        let cos = heading.cos();
        let sin = heading.sin();
        let turtle_x = position.x;
        let turtle_y = position.y;
        let shell: Vec<_> = [[0., 15.], [10., 0.], [0., -15.]]
            .iter()
            .map(|pt| {
                // Rotate each point by the heading and add the current turtle position
                let x = cos * pt[0] - sin * pt[1] + turtle_x;
                let y = sin * pt[0] + cos * pt[1] + turtle_y;
                Point { x, y }.to_screen_coords(center).into()
            })
            .collect();

        // Draw the turtle shell with its background first, then its border
        polygon(color::WHITE.into(), &shell, c.transform, g);
        for i in 0..shell.len() {
            let start = shell[i];
            let end = shell[(i + 1) % shell.len()];

            line(color::BLACK.into(), 1., [start[0], start[1], end[0], end[1]], c.transform, g);
        }
    }

    /// Save the drawings to SVG
    fn save_svg(&mut self, path: &path::Path) {
        // Returns rgba string of Color in CSS functional syntax
        fn rgba_string(color: Color) -> String {
            format!("rgba({}, {}, {}, {})", color.red as u8, color.green as u8, color.blue as u8, color.alpha)
        }

        let drawing_state = self.app.drawing();
        let mut document = svg::Document::new()
            .set("viewBox", (0, 0, drawing_state.width, drawing_state.height));

        // set background color - https://stackoverflow.com/a/11293812/9276882
        let bg_color = drawing_state.background;
        let background = SvgRect::new()
            .set("width", "100%")
            .set("height", "100%")
            .set("fill", rgba_string(bg_color));

        document = document.add(background);

        let center = drawing_state.center.to_screen_coords(Point {
            x: drawing_state.width as f64 * 0.5,
            y: drawing_state.height as f64 * 0.5,
        });

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => {
                    let &Path { start, end, ref pen } = path;
                    let &Pen { thickness, color, enabled: _ } = pen;

                    let start = start.to_screen_coords(center);
                    let end = end.to_screen_coords(center);

                    let line = SvgLine::new()
                        .set("x1", start.x)
                        .set("y1", start.y)
                        .set("x2", end.x)
                        .set("y2", end.y)
                        .set("stroke", rgba_string(color))
                        .set("stroke-width", format!("{}px", thickness * 2.0));

                    // Note that in above code `stroke-width` is twice the `thickness`.
                    // As per https://docs.piston.rs/piston_window/piston_window/fn.line.html,
                    // second param of piston_window::line is radius.
                    // So radius (thickness) = 1 takes 2 pixels on screen.
                    // Hence, stroke-width of svg element is double the thickness.

                    document = document.add(line);
                },
                Drawing::Polygon(ref poly) => {
                    let points = poly.vertices.iter()
                        .map(|p| {
                            let point = p.to_screen_coords(center);
                            format!("{},{} ", point.x, point.y)
                        })
                        .fold("".to_string(), |acc, x| acc + &x);

                    let polygon = SvgPolygon::new()
                        .set("fill", rgba_string(poly.fill_color))
                        .set("points", points);

                    document = document.add(polygon);
                },
            }
        }

        let export_to_svg = svg::save(path, &document);
        match export_to_svg {
            Ok(()) => (),
            Err(error) => eprintln!("Error saving SVG file : {:#?}", error),
        }
    }
}
<|endoftext|>


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

//! The standard RNG

use {RngCore, CryptoRng, Error, SeedableRng};
use rand_hc::Hc128Rng;

/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient
/// on the current platform, to be statistically strong and unpredictable
/// (meaning a cryptographically secure PRNG).
///
/// The current algorithm used on all platforms is [HC-128].
///
/// Reproducibility of output from this generator is however not required, thus
/// future library versions may use a different internal generator with
/// different output. Further, this generator may not be portable and can
/// produce different output depending on the architecture. If you require
/// reproducible output, use a named RNG, for example [`ChaChaRng`].
///
/// [HC-128]: rand_hc::Hc128Rng
/// [`ChaChaRng`]: rand_chacha::ChaChaRng
#[derive(Clone, Debug)]
pub struct StdRng(Hc128Rng);

impl RngCore for StdRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        self.0.next_u32()
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        self.0.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.0.fill_bytes(dest);
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.0.try_fill_bytes(dest)
    }
}

impl SeedableRng for StdRng {
    type Seed = <Hc128Rng as SeedableRng>::Seed;

    fn from_seed(seed: Self::Seed) -> Self {
        StdRng(Hc128Rng::from_seed(seed))
    }

    fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
        Hc128Rng::from_rng(rng).map(StdRng)
    }
}

impl CryptoRng for StdRng {}

#[cfg(test)]
mod test {
    use {RngCore, SeedableRng};
    use rngs::StdRng;

    #[test]
    fn test_stdrng_construction() {
        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
                    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
        let mut rng1 = StdRng::from_seed(seed);
        assert_eq!(rng1.next_u64(), 15759097995037006553);

        let mut rng2 = StdRng::from_rng(rng1).unwrap();
        assert_eq!(rng2.next_u64(), 6766915756997287454);
    }
}
<commit_msg>Add links to the crate pages for the rngs mentioned in StdRng docs<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The standard RNG

use {RngCore, CryptoRng, Error, SeedableRng};
use rand_hc::Hc128Rng;

/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient
/// on the current platform, to be statistically strong and unpredictable
/// (meaning a cryptographically secure PRNG).
///
/// The current algorithm used on all platforms is [HC-128], found in the
/// [rand_hc] crate.
///
/// Reproducibility of output from this generator is however not required, thus
/// future library versions may use a different internal generator with
/// different output. Further, this generator may not be portable and can
/// produce different output depending on the architecture. If you require
/// reproducible output, use a named RNG, for example [`ChaChaRng`] from the
/// [rand_chacha] crate.
///
/// [HC-128]: rand_hc::Hc128Rng
/// [`ChaChaRng`]: rand_chacha::ChaChaRng
/// [rand_hc]: https://crates.io/crates/rand_hc
/// [rand_chacha]: https://crates.io/crates/rand_chacha
#[derive(Clone, Debug)]
pub struct StdRng(Hc128Rng);

impl RngCore for StdRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        self.0.next_u32()
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        self.0.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.0.fill_bytes(dest);
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.0.try_fill_bytes(dest)
    }
}

impl SeedableRng for StdRng {
    type Seed = <Hc128Rng as SeedableRng>::Seed;

    fn from_seed(seed: Self::Seed) -> Self {
        StdRng(Hc128Rng::from_seed(seed))
    }

    fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
        Hc128Rng::from_rng(rng).map(StdRng)
    }
}

impl CryptoRng for StdRng {}

#[cfg(test)]
mod test {
    use {RngCore, SeedableRng};
    use rngs::StdRng;

    #[test]
    fn test_stdrng_construction() {
        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
                    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
        let mut rng1 = StdRng::from_seed(seed);
        assert_eq!(rng1.next_u64(), 15759097995037006553);

        let mut rng2 = StdRng::from_rng(rng1).unwrap();
        assert_eq!(rng2.next_u64(), 6766915756997287454);
    }
}
<|endoftext|>


<commit_before>use libz_sys;
use miniz_sys;
use libc::c_int;
use std::cmp::max;
#[cfg(test)]
use quickcheck::TestResult;

/// Decompress a data stream using the DEFLATE algorithm
pub fn inflate(data: &[u8]) -> Result<Vec<u8>, String> {
    let mut input = data.to_owned();
    let mut stream = super::libz_stream::Stream::new_decompress();
    let mut output = Vec::with_capacity(data.len());
    loop {
        match stream.decompress_vec(input.as_mut(), output.as_mut()) {
            libz_sys::Z_OK => output.reserve(data.len()),
            libz_sys::Z_STREAM_END => break,
            c => return Err(format!("Error code on decompress: {}", c)),
        }
    }
    output.shrink_to_fit();

    Ok(output)
}

/// Compress a data stream using the zlib implementation of the DEFLATE algorithm
pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result<Vec<u8>, String> {
    let mut input = data.to_owned();
    // Compressed input should be smaller than decompressed, so allocate less than data.len()
    // However, it needs a minimum capacity in order to handle very small images
    let mut output = Vec::with_capacity(max(1024, data.len() / 20));
    if zs == 0 || zs == 1 {
        // Miniz performs 1-2 orders of magnitude better for strategies 0 and 1
        let mut stream = super::miniz_stream::Stream::new_compress(zc as c_int,
                                                                   zw as c_int,
                                                                   zm as c_int,
                                                                   zs as c_int);
        loop {
            match stream.compress_vec(input.as_mut(), output.as_mut()) {
                miniz_sys::MZ_OK => output.reserve(max(1024, data.len() / 20)),
                miniz_sys::MZ_STREAM_END => break,
                c => return Err(format!("Error code on compress: {}", c)),
            }
        }
    } else {
        // libz performs an order of magnitude better for strategies 2 and 3
        let mut stream = super::libz_stream::Stream::new_compress(zc as c_int,
                                                                  zw as c_int,
                                                                  zm as c_int,
                                                                  zs as c_int);
        loop {
            match stream.compress_vec(input.as_mut(), output.as_mut()) {
                libz_sys::Z_OK => output.reserve(max(1024, data.len() / 20)),
                libz_sys::Z_STREAM_END => break,
                c => return Err(format!("Error code on compress: {}", c)),
            }
        }
    }

    output.shrink_to_fit();

    Ok(output)
}
<commit_msg>Fix tests<commit_after>use libz_sys;
use miniz_sys;
use libc::c_int;
use std::cmp::max;

/// Decompress a data stream using the DEFLATE algorithm
pub fn inflate(data: &[u8]) -> Result<Vec<u8>, String> {
    let mut input = data.to_owned();
    let mut stream = super::libz_stream::Stream::new_decompress();
    let mut output = Vec::with_capacity(data.len());
    loop {
        match stream.decompress_vec(input.as_mut(), output.as_mut()) {
            libz_sys::Z_OK => output.reserve(data.len()),
            libz_sys::Z_STREAM_END => break,
            c => return Err(format!("Error code on decompress: {}", c)),
        }
    }
    output.shrink_to_fit();

    Ok(output)
}

/// Compress a data stream using the zlib implementation of the DEFLATE algorithm
pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result<Vec<u8>, String> {
    let mut input = data.to_owned();
    // Compressed input should be smaller than decompressed, so allocate less than data.len()
    // However, it needs a minimum capacity in order to handle very small images
    let mut output = Vec::with_capacity(max(1024, data.len() / 20));
    if zs == 0 || zs == 1 {
        // Miniz performs 1-2 orders of magnitude better for strategies 0 and 1
        let mut stream = super::miniz_stream::Stream::new_compress(zc as c_int,
                                                                   zw as c_int,
                                                                   zm as c_int,
                                                                   zs as c_int);
        loop {
            match stream.compress_vec(input.as_mut(), output.as_mut()) {
                miniz_sys::MZ_OK => output.reserve(max(1024, data.len() / 20)),
                miniz_sys::MZ_STREAM_END => break,
                c => return Err(format!("Error code on compress: {}", c)),
            }
        }
    } else {
        // libz performs an order of magnitude better for strategies 2 and 3
        let mut stream = super::libz_stream::Stream::new_compress(zc as c_int,
                                                                  zw as c_int,
                                                                  zm as c_int,
                                                                  zs as c_int);
        loop {
            match stream.compress_vec(input.as_mut(), output.as_mut()) {
                libz_sys::Z_OK => output.reserve(max(1024, data.len() / 20)),
                libz_sys::Z_STREAM_END => break,
                c => return Err(format!("Error code on compress: {}", c)),
            }
        }
    }

    output.shrink_to_fit();

    Ok(output)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Enumerations and structs to represent instructions.
//! Shared by the SSA representation and the intermediate representation of the
//! ESIL parser.

use std::fmt;

pub type Address = u64;

/// Used to describe the width of an operand/operation in a SSA Node.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum WidthSpec {
    /// Takes whatever width the other operation takes
    Adaptive,
    Known(u16),
    Unknown,
}

impl WidthSpec {
    pub fn get_width(&self) -> Option<u16> {
        match self {
            &WidthSpec::Known(ref w) => Some(*w),
            _ => None,
        }
    }

    pub fn new_known(w: u16) -> WidthSpec {
        assert!(&[0, 1, 2, 4, 8, 16, 32, 64, 128].contains(&w));
        WidthSpec::Known(w)
    }
}

impl From<u16> for WidthSpec {
    fn from(other: u16) -> WidthSpec {
        if other < u16::max_value() {
            assert!(&[0, 1, 2, 4, 8, 16, 32, 64, 128].contains(&other));
            WidthSpec::Known(other)
        } else {
            WidthSpec::Unknown
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
// New address struct
pub struct MAddress {
    pub address: u64,
    pub offset: u64,
}

impl MAddress {
    pub fn new(address: u64, offset: u64) -> MAddress {
        MAddress {
            address: address,
            offset: offset,
        }
    }

    pub fn invalid_address() -> MAddress {
        MAddress {
            address: u64::max_value(),
            offset: u64::max_value(),
        }
    }
}

impl fmt::UpperHex for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#08X}.{:04X}", self.address, self.offset)
    }
}

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

impl From<u64> for MAddress {
    fn from(other: u64) -> MAddress {
        MAddress {
            address: other,
            offset: 0,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MArity {
    Binary,
    Ternary,
    Unary,
    Zero,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MOpcode {
    OpAdd,
    OpAnd,
    OpCJmp,
    OpCall,
    OpCmp,
    OpConst(u64),
    OpDiv,
    OpEq,
    OpGt,
    // If - Then - Else
    OpITE,
    OpIf,
    OpInvalid,
    OpJmp,
    OpLoad,
    OpLsl,
    OpLsr,
    OpLt,
    OpMod,
    OpMul,
    OpNarrow(u16),
    OpNop,
    OpNot,
    OpOr,
    // Rotate Shift Left
    OpRol,
    // Rotate Shift Right
    OpRor,
    // Sign Extend to width
    OpSignExt(u16),
    OpStore,
    OpSub,
    OpXor,
    // Zero Extend to width
    OpZeroExt(u16),
}

impl MOpcode {
    pub fn is_binary(&self) -> bool {
        self.arity() == MArity::Binary
    }

    pub fn is_unary(&self) -> bool {
        self.arity() == MArity::Unary
    }

    pub fn arity(&self) -> MArity {
        self.info().1
    }

    pub fn to_string(&self) -> String {
        self.info().0
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            MOpcode::OpAdd |
            MOpcode::OpMul |
            MOpcode::OpAnd |
            MOpcode::OpOr |
            MOpcode::OpXor |
            MOpcode::OpCmp |
            MOpcode::OpGt |
            MOpcode::OpLt => true,
            _ => false,
        }
    }

    pub fn has_sideeffects(&self) -> bool {
        match *self {
            MOpcode::OpStore |
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpCall |
            MOpcode::OpITE => true,
            _ => false,
        }
    }

    pub fn allowed_in_ssa(&self) -> bool {
        match *self {
            MOpcode::OpCJmp |
            MOpcode::OpITE |
            MOpcode::OpInvalid |
            MOpcode::OpJmp |
            MOpcode::OpNop => false,
            _ => true,
        }
    }

    fn info(&self) -> (String, MArity) {
        match *self {
            MOpcode::OpAdd => ("OpAdd".to_owned(), MArity::Binary),
            MOpcode::OpAnd => ("OpAnd".to_owned(), MArity::Binary),
            MOpcode::OpCJmp => ("OpJmpIf".to_owned(), MArity::Binary),
            MOpcode::OpCall => ("OpCall".to_owned(), MArity::Unary),
            MOpcode::OpCmp => ("OpCmp".to_owned(), MArity::Binary),
            MOpcode::OpConst(c) => (format!("OpCost({})", c), MArity::Zero),
            MOpcode::OpDiv => ("OpDiv".to_owned(), MArity::Binary),
            MOpcode::OpEq => ("OpEq".to_owned(), MArity::Binary),
            MOpcode::OpGt => ("OpGt".to_owned(), MArity::Binary),
            MOpcode::OpITE => ("ITE".to_owned(), MArity::Ternary),
            MOpcode::OpIf => ("OpIf".to_owned(), MArity::Unary),
            MOpcode::OpInvalid => ("OpInvalid".to_owned(), MArity::Zero),
            MOpcode::OpJmp => ("OpJmp".to_owned(), MArity::Unary),
            MOpcode::OpLoad => ("OpLoad".to_owned(), MArity::Binary),
            MOpcode::OpLsl => ("OpLsl".to_owned(), MArity::Binary),
            MOpcode::OpLsr => ("OpLsr".to_owned(), MArity::Binary),
            MOpcode::OpLt => ("OpLt".to_owned(), MArity::Binary),
            MOpcode::OpMod => ("OpMod".to_owned(), MArity::Binary),
            MOpcode::OpMul => ("OpMul".to_owned(), MArity::Binary),
            MOpcode::OpNarrow(_) => ("OpNarrow".to_owned(), MArity::Unary),
            MOpcode::OpNop => ("OpNop".to_owned(), MArity::Zero),
            MOpcode::OpNot => ("OpNot".to_owned(), MArity::Unary),
            MOpcode::OpOr => ("OpOr".to_owned(), MArity::Binary),
            MOpcode::OpRol => ("OpRol".to_owned(), MArity::Binary),
            MOpcode::OpRor => ("OpRor".to_owned(), MArity::Binary),
            MOpcode::OpSignExt(_) => ("OpZeroExt".to_owned(), MArity::Unary),
            MOpcode::OpStore => ("OpStore".to_owned(), MArity::Binary),
            MOpcode::OpSub => ("OpSub".to_owned(), MArity::Binary),
            MOpcode::OpXor => ("OpXor".to_owned(), MArity::Binary),
            MOpcode::OpZeroExt(_) => ("OpZeroExt".to_owned(), MArity::Unary),
        }
    }
}

impl fmt::Display for MOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}
<commit_msg>Minor Optimizations<commit_after>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Enumerations and structs to represent instructions.
//! Shared by the SSA representation and the intermediate representation of the
//! ESIL parser.

use std::fmt;
use std::borrow::Cow;

pub type Address = u64;

/// Used to describe the width of an operand/operation in a SSA Node.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum WidthSpec {
    /// Takes whatever width the other operation takes
    Adaptive,
    Known(u16),
    Unknown,
}

impl WidthSpec {
    pub fn get_width(&self) -> Option<u16> {
        match self {
            &WidthSpec::Known(ref w) => Some(*w),
            _ => None,
        }
    }

    pub fn new_known(w: u16) -> WidthSpec {
        assert!(&[0, 1, 2, 4, 8, 16, 32, 64, 128].contains(&w));
        WidthSpec::Known(w)
    }
}

impl From<u16> for WidthSpec {
    fn from(other: u16) -> WidthSpec {
        if other < u16::max_value() {
            assert!(&[0, 1, 2, 4, 8, 16, 32, 64, 128].contains(&other));
            WidthSpec::Known(other)
        } else {
            WidthSpec::Unknown
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
// New address struct
pub struct MAddress {
    pub address: u64,
    pub offset: u64,
}

impl MAddress {
    pub fn new(address: u64, offset: u64) -> MAddress {
        MAddress {
            address: address,
            offset: offset,
        }
    }

    pub fn invalid_address() -> MAddress {
        MAddress {
            address: u64::max_value(),
            offset: u64::max_value(),
        }
    }
}

impl fmt::UpperHex for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#08X}.{:04X}", self.address, self.offset)
    }
}

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

impl From<u64> for MAddress {
    fn from(other: u64) -> MAddress {
        MAddress {
            address: other,
            offset: 0,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MArity {
    Binary,
    Ternary,
    Unary,
    Zero,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MOpcode {
    OpAdd,
    OpAnd,
    OpCJmp,
    OpCall,
    OpCmp,
    OpConst(u64),
    OpDiv,
    OpEq,
    OpGt,
    // If - Then - Else
    OpITE,
    OpIf,
    OpInvalid,
    OpJmp,
    OpLoad,
    OpLsl,
    OpLsr,
    OpLt,
    OpMod,
    OpMul,
    OpNarrow(u16),
    OpNop,
    OpNot,
    OpOr,
    // Rotate Shift Left
    OpRol,
    // Rotate Shift Right
    OpRor,
    // Sign Extend to width
    OpSignExt(u16),
    OpStore,
    OpSub,
    OpXor,
    // Zero Extend to width
    OpZeroExt(u16),
}

impl MOpcode {
    pub fn is_binary(&self) -> bool {
        self.arity() == MArity::Binary
    }

    pub fn is_unary(&self) -> bool {
        self.arity() == MArity::Unary
    }

    pub fn arity(&self) -> MArity {
        self.info().1
    }

    pub fn to_string(&self) -> Cow<str> {
        self.info().0
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            MOpcode::OpAdd |
            MOpcode::OpMul |
            MOpcode::OpAnd |
            MOpcode::OpOr |
            MOpcode::OpXor |
            MOpcode::OpCmp |
            MOpcode::OpGt |
            MOpcode::OpLt => true,
            _ => false,
        }
    }

    pub fn has_sideeffects(&self) -> bool {
        match *self {
            MOpcode::OpStore |
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpCall |
            MOpcode::OpITE => true,
            _ => false,
        }
    }

    pub fn allowed_in_ssa(&self) -> bool {
        match *self {
            MOpcode::OpCJmp |
            MOpcode::OpITE |
            MOpcode::OpInvalid |
            MOpcode::OpJmp |
            MOpcode::OpNop => false,
            _ => true,
        }
    }

    fn info(&self) -> (Cow<str>, MArity) {
        match *self {
            MOpcode::OpAdd => (Cow::from("OpAdd"), MArity::Binary),
            MOpcode::OpAnd => (Cow::from("OpAnd"), MArity::Binary),
            MOpcode::OpCJmp => (Cow::from("OpJmpIf"), MArity::Binary),
            MOpcode::OpCall => (Cow::from("OpCall"), MArity::Unary),
            MOpcode::OpCmp => (Cow::from("OpCmp"), MArity::Binary),
            MOpcode::OpConst(c) => (Cow::from(format!("OpCost({})", c)), MArity::Zero),
            MOpcode::OpDiv => (Cow::from("OpDiv"), MArity::Binary),
            MOpcode::OpEq => (Cow::from("OpEq"), MArity::Binary),
            MOpcode::OpGt => (Cow::from("OpGt"), MArity::Binary),
            MOpcode::OpITE => (Cow::from("OpITE"), MArity::Ternary),
            MOpcode::OpIf => (Cow::from("OpIf"), MArity::Unary),
            MOpcode::OpInvalid => (Cow::from("OpInvalid"), MArity::Zero),
            MOpcode::OpJmp => (Cow::from("OpJmp"), MArity::Unary),
            MOpcode::OpLoad => (Cow::from("OpLoad"), MArity::Binary),
            MOpcode::OpLsl => (Cow::from("OpLsl"), MArity::Binary),
            MOpcode::OpLsr => (Cow::from("OpLsr"), MArity::Binary),
            MOpcode::OpLt => (Cow::from("OpLt"), MArity::Binary),
            MOpcode::OpMod => (Cow::from("OpMod"), MArity::Binary),
            MOpcode::OpMul => (Cow::from("OpMul"), MArity::Binary),
            MOpcode::OpNarrow(_) => (Cow::from("OpNarrow"), MArity::Unary),
            MOpcode::OpNop => (Cow::from("OpNop"), MArity::Zero),
            MOpcode::OpNot => (Cow::from("OpNot"), MArity::Unary),
            MOpcode::OpOr => (Cow::from("OpOr"), MArity::Binary),
            MOpcode::OpRol => (Cow::from("OpRol"), MArity::Binary),
            MOpcode::OpRor => (Cow::from("OpRor"), MArity::Binary),
            MOpcode::OpSignExt(_) => (Cow::from("OpSignExt"), MArity::Unary),
            MOpcode::OpStore => (Cow::from("OpStore"), MArity::Binary),
            MOpcode::OpSub => (Cow::from("OpSub"), MArity::Binary),
            MOpcode::OpXor => (Cow::from("OpXor"), MArity::Binary),
            MOpcode::OpZeroExt(_) => (Cow::from("OpZeroExt"), MArity::Unary),
        }
    }
}

impl fmt::Display for MOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}
<|endoftext|>