<commit_before>use crate::printer::Printer;
use crate::vec::Vec2;
use crate::view::{SizeConstraint, View, ViewWrapper};
use crate::With;
use crate::XY;

/// Wrapper around another view, with a controlled size.
///
/// Each axis can independently be set to:
///
/// * Keep a **fixed** size
/// * Use **all** available size
/// * Use **at most** a given size
/// * Use **at least** a given size
/// * Let the wrapped view decide.
///
/// # Examples
///
/// ```
/// # use cursive::views::{BoxView,TextView};
/// // Creates a 20x4 BoxView with a TextView content.
/// let view = BoxView::with_fixed_size((20,4), TextView::new("Hello!"));
/// ```
pub struct BoxView<T: View> {
    /// Constraint on each axis
    size: XY<SizeConstraint>,

    /// `true` if the view can be squished.
    ///
    /// This means if the required size is less than the computed size,
    /// consider returning a smaller size.
    /// For instance, try to return the child's desired size.
    squishable: bool, // TODO: remove?

    /// Set to `true` whenever we change some settings. Means we should re-layout just in case.
    invalidated: bool,

    /// The actual view we're wrapping.
    view: T,
}

impl<T: View> BoxView<T> {
    /// Creates a new `BoxView` with the given width and height requirements.
    ///
    /// `None` values will use the wrapped view's preferences.
    pub fn new(
        width: SizeConstraint,
        height: SizeConstraint,
        view: T,
    ) -> Self {
        BoxView {
            size: (width, height).into(),
            squishable: false,
            invalidated: true,
            view,
        }
    }

    /// Sets the size constraints for this view.
    pub fn set_constraints(
        &mut self,
        width: SizeConstraint,
        height: SizeConstraint,
    ) {
        self.set_width(width);
        self.set_height(height);
    }

    /// Sets the width constraint for this view.
    ///
    /// Leaves the height unchanged.
    pub fn set_width(&mut self, width: SizeConstraint) {
        self.size.x = width;
        self.invalidate();
    }

    /// Sets the height constraint for this view.
    ///
    /// Leaves the width unchanged.
    pub fn set_height(&mut self, height: SizeConstraint) {
        self.size.y = height;
        self.invalidate();
    }

    /// Sets `self` to be squishable.
    ///
    /// A squishable `BoxView` will take a smaller size than it should when
    /// the available space is too small. In that case, it will allow the
    /// child view to contract, if it can.
    ///
    /// More specifically, if the available space is less than the size we
    /// would normally ask for, return the child size.
    pub fn squishable(self) -> Self {
        self.with(|s| s.set_squishable(true))
    }

    /// Controls the "squishability" of `self`.
    pub fn set_squishable(&mut self, squishable: bool) {
        self.squishable = squishable;
        self.invalidate();
    }

    /// Wraps `view` in a new `BoxView` with the given size.
    pub fn with_fixed_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::Fixed(size.x),
            SizeConstraint::Fixed(size.y),
            view,
        )
    }

    /// Wraps `view` in a new `BoxView` with fixed width.
    pub fn with_fixed_width(width: usize, view: T) -> Self {
        BoxView::new(SizeConstraint::Fixed(width), SizeConstraint::Free, view)
    }

    /// Wraps `view` in a new `BoxView` with fixed height.
    pub fn with_fixed_height(height: usize, view: T) -> Self {
        BoxView::new(SizeConstraint::Free, SizeConstraint::Fixed(height), view)
    }

    /// Wraps `view` in a `BoxView` which will take all available space.
    pub fn with_full_screen(view: T) -> Self {
        BoxView::new(SizeConstraint::Full, SizeConstraint::Full, view)
    }

    /// Wraps `view` in a `BoxView` which will take all available width.
    pub fn with_full_width(view: T) -> Self {
        BoxView::new(SizeConstraint::Full, SizeConstraint::Free, view)
    }

    /// Wraps `view` in a `BoxView` which will take all available height.
    pub fn with_full_height(view: T) -> Self {
        BoxView::new(SizeConstraint::Free, SizeConstraint::Full, view)
    }

    /// Wraps `view` in a `BoxView` which will never be bigger than `size`.
    pub fn with_max_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::AtMost(size.x),
            SizeConstraint::AtMost(size.y),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a maximum width.
    ///
    /// The resulting width will never be more than `max_width`.
    pub fn with_max_width(max_width: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::AtMost(max_width),
            SizeConstraint::Free,
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a maximum height.
    ///
    /// The resulting height will never be more than `max_height`.
    pub fn with_max_height(max_height: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::Free,
            SizeConstraint::AtMost(max_height),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will never be smaller than `size`.
    pub fn with_min_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::AtLeast(size.x),
            SizeConstraint::AtLeast(size.y),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a minimum width.
    ///
    /// The resulting width will never be less than `min_width`.
    pub fn with_min_width(min_width: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::AtLeast(min_width),
            SizeConstraint::Free,
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a minimum height.
    ///
    /// The resulting height will never be less than `min_height`.
    pub fn with_min_height(min_height: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::Free,
            SizeConstraint::AtLeast(min_height),
            view,
        )
    }

    /// Should be called anytime something changes.
    fn invalidate(&mut self) {
        self.invalidated = true;
    }

    inner_getters!(self.view: T);
}

impl<T: View> ViewWrapper for BoxView<T> {
    wrap_impl!(self.view: T);

    fn wrap_draw(&self, printer: &Printer) {
        self.view.draw(&printer.inner_size(
            self.size.zip_map(printer.size, |c, s| c.result((s, s))),
        ));
    }

    fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
        // This is what the child will see as request.
        let req = self.size.zip_map(req, SizeConstraint::available);

        // This is the size the child would like to have.
        // Given the constraints of our box.
        let child_size = self.size.zip_map(req, |c, s| c.result((s, s)));

        // Some of this request will be granted, but maybe not all.
        let result = self
            .size
            .zip_map(child_size.zip(req), SizeConstraint::result);

        if self.squishable {
            // When we're squishable, special behaviour:
            //

            // We respect the request if we're less or equal.
            let respect_req = result.zip_map(req, |res, req| res <= req);

            // If we respect the request, keep the result
            // Otherwise, take the child as squish attempt.
            respect_req.select_or(result, child_size)
        } else {
            result
        }
    }

    fn wrap_layout(&mut self, size: Vec2) {
        self.invalidated = false;
        self.view.layout(size);
    }

    fn wrap_needs_relayout(&self) -> bool {
        self.invalidated || self.view.needs_relayout()
    }
}

#[cfg(test)]
mod tests {

    use crate::vec::Vec2;
    use crate::view::{Boxable, View};
    use crate::views::DummyView;

    // No need to test `draw()` method as it's directly forwarded.

    #[test]
    fn min_size() {
        let mut min_w = DummyView.full_screen().min_width(5);

        assert_eq!(Vec2::new(5, 1), min_w.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(5, 10), min_w.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), min_w.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_w.required_size(Vec2::new(10, 10)));

        let mut min_h = DummyView.full_screen().min_height(5);

        assert_eq!(Vec2::new(1, 5), min_h.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), min_h.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 5), min_h.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_h.required_size(Vec2::new(10, 10)));

        let mut min_s = DummyView.full_screen().min_size((5, 5));

        assert_eq!(Vec2::new(5, 5), min_s.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(5, 10), min_s.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 5), min_s.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_s.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn max_size() {
        let mut max_w = DummyView.full_screen().max_width(5);

        assert_eq!(Vec2::new(1, 1), max_w.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), max_w.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(5, 1), max_w.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(5, 10), max_w.required_size(Vec2::new(10, 10)));

        let mut max_h = DummyView.full_screen().max_height(5);

        assert_eq!(Vec2::new(1, 1), max_h.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 5), max_h.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), max_h.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 5), max_h.required_size(Vec2::new(10, 10)));

        let mut max_s = DummyView.full_screen().max_size((5, 5));

        assert_eq!(Vec2::new(1, 1), max_s.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 5), max_s.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(5, 1), max_s.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(5, 5), max_s.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn full_screen() {
        let mut full = DummyView.full_screen();

        assert_eq!(Vec2::new(1, 1), full.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), full.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), full.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), full.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn test_get_inner() {
        use crate::views::TextView;

        let parent = TextView::new("abc").full_screen();
        let child = parent.get_inner();
        assert_eq!(child.get_content().source(), "abc");
    }
    #[test]
    fn test_get_inner_mut() {
        use crate::views::TextView;

        let mut parent = TextView::new("").full_screen();
        let new_value = "new";
        let child = parent.get_inner_mut();

        child.set_content(new_value);

        assert_eq!(child.get_content().source(), new_value);
    }
}
<commit_msg>Fix BoxView<commit_after>use crate::printer::Printer;
use crate::vec::Vec2;
use crate::view::{SizeConstraint, View, ViewWrapper};
use crate::With;
use crate::XY;

/// Wrapper around another view, with a controlled size.
///
/// Each axis can independently be set to:
///
/// * Keep a **fixed** size
/// * Use **all** available size
/// * Use **at most** a given size
/// * Use **at least** a given size
/// * Let the wrapped view decide.
///
/// # Examples
///
/// ```
/// # use cursive::views::{BoxView,TextView};
/// // Creates a 20x4 BoxView with a TextView content.
/// let view = BoxView::with_fixed_size((20,4), TextView::new("Hello!"));
/// ```
pub struct BoxView<T: View> {
    /// Constraint on each axis
    size: XY<SizeConstraint>,

    /// `true` if the view can be squished.
    ///
    /// This means if the required size is less than the computed size,
    /// consider returning a smaller size.
    /// For instance, try to return the child's desired size.
    squishable: bool, // TODO: remove?

    /// Set to `true` whenever we change some settings. Means we should re-layout just in case.
    invalidated: bool,

    /// The actual view we're wrapping.
    view: T,
}

impl<T: View> BoxView<T> {
    /// Creates a new `BoxView` with the given width and height requirements.
    ///
    /// `None` values will use the wrapped view's preferences.
    pub fn new(
        width: SizeConstraint,
        height: SizeConstraint,
        view: T,
    ) -> Self {
        BoxView {
            size: (width, height).into(),
            squishable: false,
            invalidated: true,
            view,
        }
    }

    /// Sets the size constraints for this view.
    pub fn set_constraints(
        &mut self,
        width: SizeConstraint,
        height: SizeConstraint,
    ) {
        self.set_width(width);
        self.set_height(height);
    }

    /// Sets the width constraint for this view.
    ///
    /// Leaves the height unchanged.
    pub fn set_width(&mut self, width: SizeConstraint) {
        self.size.x = width;
        self.invalidate();
    }

    /// Sets the height constraint for this view.
    ///
    /// Leaves the width unchanged.
    pub fn set_height(&mut self, height: SizeConstraint) {
        self.size.y = height;
        self.invalidate();
    }

    /// Sets `self` to be squishable.
    ///
    /// A squishable `BoxView` will take a smaller size than it should when
    /// the available space is too small. In that case, it will allow the
    /// child view to contract, if it can.
    ///
    /// More specifically, if the available space is less than the size we
    /// would normally ask for, return the child size.
    pub fn squishable(self) -> Self {
        self.with(|s| s.set_squishable(true))
    }

    /// Controls the "squishability" of `self`.
    pub fn set_squishable(&mut self, squishable: bool) {
        self.squishable = squishable;
        self.invalidate();
    }

    /// Wraps `view` in a new `BoxView` with the given size.
    pub fn with_fixed_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::Fixed(size.x),
            SizeConstraint::Fixed(size.y),
            view,
        )
    }

    /// Wraps `view` in a new `BoxView` with fixed width.
    pub fn with_fixed_width(width: usize, view: T) -> Self {
        BoxView::new(SizeConstraint::Fixed(width), SizeConstraint::Free, view)
    }

    /// Wraps `view` in a new `BoxView` with fixed height.
    pub fn with_fixed_height(height: usize, view: T) -> Self {
        BoxView::new(SizeConstraint::Free, SizeConstraint::Fixed(height), view)
    }

    /// Wraps `view` in a `BoxView` which will take all available space.
    pub fn with_full_screen(view: T) -> Self {
        BoxView::new(SizeConstraint::Full, SizeConstraint::Full, view)
    }

    /// Wraps `view` in a `BoxView` which will take all available width.
    pub fn with_full_width(view: T) -> Self {
        BoxView::new(SizeConstraint::Full, SizeConstraint::Free, view)
    }

    /// Wraps `view` in a `BoxView` which will take all available height.
    pub fn with_full_height(view: T) -> Self {
        BoxView::new(SizeConstraint::Free, SizeConstraint::Full, view)
    }

    /// Wraps `view` in a `BoxView` which will never be bigger than `size`.
    pub fn with_max_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::AtMost(size.x),
            SizeConstraint::AtMost(size.y),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a maximum width.
    ///
    /// The resulting width will never be more than `max_width`.
    pub fn with_max_width(max_width: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::AtMost(max_width),
            SizeConstraint::Free,
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a maximum height.
    ///
    /// The resulting height will never be more than `max_height`.
    pub fn with_max_height(max_height: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::Free,
            SizeConstraint::AtMost(max_height),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will never be smaller than `size`.
    pub fn with_min_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::AtLeast(size.x),
            SizeConstraint::AtLeast(size.y),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a minimum width.
    ///
    /// The resulting width will never be less than `min_width`.
    pub fn with_min_width(min_width: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::AtLeast(min_width),
            SizeConstraint::Free,
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a minimum height.
    ///
    /// The resulting height will never be less than `min_height`.
    pub fn with_min_height(min_height: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::Free,
            SizeConstraint::AtLeast(min_height),
            view,
        )
    }

    /// Should be called anytime something changes.
    fn invalidate(&mut self) {
        self.invalidated = true;
    }

    inner_getters!(self.view: T);
}

impl<T: View> ViewWrapper for BoxView<T> {
    wrap_impl!(self.view: T);

    fn wrap_draw(&self, printer: &Printer) {
        self.view.draw(&printer.inner_size(
            self.size.zip_map(printer.size, |c, s| c.result((s, s))),
        ));
    }

    fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
        // This is what the child will see as request.
        let req = self.size.zip_map(req, SizeConstraint::available);

        // This is the size the child would like to have.
        // Given the constraints of our box.
        let child_size = self.view.required_size(req);

        // Some of this request will be granted, but maybe not all.
        let result = self
            .size
            .zip_map(child_size.zip(req), SizeConstraint::result);

        if self.squishable {
            // When we're squishable, special behaviour:
            //

            // We respect the request if we're less or equal.
            let respect_req = result.zip_map(req, |res, req| res <= req);

            // If we respect the request, keep the result
            // Otherwise, take the child as squish attempt.
            respect_req.select_or(result, child_size)
        } else {
            result
        }
    }

    fn wrap_layout(&mut self, size: Vec2) {
        self.invalidated = false;
        self.view.layout(size);
    }

    fn wrap_needs_relayout(&self) -> bool {
        self.invalidated || self.view.needs_relayout()
    }
}

#[cfg(test)]
mod tests {

    use crate::vec::Vec2;
    use crate::view::{Boxable, View};
    use crate::views::DummyView;

    // No need to test `draw()` method as it's directly forwarded.

    #[test]
    fn min_size() {
        let mut min_w = DummyView.full_screen().min_width(5);

        assert_eq!(Vec2::new(5, 1), min_w.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(5, 10), min_w.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), min_w.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_w.required_size(Vec2::new(10, 10)));

        let mut min_h = DummyView.full_screen().min_height(5);

        assert_eq!(Vec2::new(1, 5), min_h.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), min_h.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 5), min_h.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_h.required_size(Vec2::new(10, 10)));

        let mut min_s = DummyView.full_screen().min_size((5, 5));

        assert_eq!(Vec2::new(5, 5), min_s.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(5, 10), min_s.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 5), min_s.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_s.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn max_size() {
        let mut max_w = DummyView.full_screen().max_width(5);

        assert_eq!(Vec2::new(1, 1), max_w.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), max_w.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(5, 1), max_w.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(5, 10), max_w.required_size(Vec2::new(10, 10)));

        let mut max_h = DummyView.full_screen().max_height(5);

        assert_eq!(Vec2::new(1, 1), max_h.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 5), max_h.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), max_h.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 5), max_h.required_size(Vec2::new(10, 10)));

        let mut max_s = DummyView.full_screen().max_size((5, 5));

        assert_eq!(Vec2::new(1, 1), max_s.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 5), max_s.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(5, 1), max_s.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(5, 5), max_s.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn full_screen() {
        let mut full = DummyView.full_screen();

        assert_eq!(Vec2::new(1, 1), full.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), full.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), full.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), full.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn test_get_inner() {
        use crate::views::TextView;

        let parent = TextView::new("abc").full_screen();
        let child = parent.get_inner();
        assert_eq!(child.get_content().source(), "abc");
    }
    #[test]
    fn test_get_inner_mut() {
        use crate::views::TextView;

        let mut parent = TextView::new("").full_screen();
        let new_value = "new";
        let child = parent.get_inner_mut();

        child.set_content(new_value);

        assert_eq!(child.get_content().source(), new_value);
    }
}
<|endoftext|>


<commit_before>

use visit::IntoNeighbors;
use visit::{VisitMap, Visitable};

/// Strictly monotonically increasing event time for a depth first search.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Default)]
pub struct Time(pub u64);

/// A depth first search (DFS) visitor event.
#[derive(Copy, Clone, Debug)]
pub enum DfsEvent<N> {
    Discover(N, Time),
    /// An edge of the tree formed by the traversal.
    TreeEdge(N, N),
    /// An edge to an already visited node.
    BackEdge(N, N),
    /// A cross or forward edge.
    ///
    /// For an edge *(u, v)*, if the discover time of *v* is greater than *u*,
    /// then it is a forward edge, else a cross edge.
    CrossForwardEdge(N, N),
    Finish(N, Time),
}

macro_rules! control {
    ($e:expr) => {
        match $e {
            x => if x.should_break() {
                return x;
            } else {
            }
        }
    }
}

/// Control flow for visitor callbacks.
#[derive(Copy, Clone, Debug)]
pub enum Control<B> {
    Continue,
    Break(B),
}

impl<B> Control<B> {
    /// Get the value in `Control::Break(_)`, if present.
    pub fn break_value(self) -> Option<B> {
        match self {
            Control::Continue => None,
            Control::Break(b) => Some(b),
        }
    }
}

/// The default is `Continue`.
impl<B> Default for Control<B> {
    fn default() -> Self { Control::Continue }
}

/// Control flow for visitor callbacks.
///
/// The empty return value `()` will continue until the visit is done.
pub trait ControlFlow : Default {
    #[inline]
    fn should_break(&self) -> bool { false }
}

impl ControlFlow for () { }

impl<B> ControlFlow for Control<B> {
    fn should_break(&self) -> bool {
        if let Control::Break(_) = *self { true } else { false }
    }
}

/// A recursive depth first search.
///
/// Starting points are the nodes in the iterator `starts` (specify just one
/// start vertex *x* by using `Some(x)`).
///
/// The visit emits discovery and finish events for each reachable vertex,
/// and edge classification of each reachable edge. `visitor` is called for each
/// event, see [`DfsEvent`][de] for possible values.
///
/// If the return value of the visitor is simply `()`, the visit runs until it
/// is finished. If the return value is a `Control<B>`, it can be used to
/// break the visit early, and the last control value is returned by the
/// function.
///
/// [de]: enum.DfsEvent.html
///
/// # Example
///
/// Find a path from vertex 0 to 5, and exit the visit as soon as we reach
/// the goal vertex.
///
/// ```
/// use petgraph::prelude::*;
/// use petgraph::graph::node_index as n;
/// use petgraph::visit::depth_first_search;
/// use petgraph::visit::{DfsEvent, Control};
///
/// let gr: Graph<(), ()> = Graph::from_edges(&[
///     (0, 1), (0, 2), (0, 3),
///     (1, 3),
///     (2, 3), (2, 4),
///     (4, 0), (4, 5),
/// ]);
///
/// // record each predecessor, mapping node → node
/// let mut predecessor = vec![NodeIndex::end(); gr.node_count()];
/// let start = n(0);
/// let goal = n(5);
/// let ret = depth_first_search(&gr, Some(start), |event| {
///     if let DfsEvent::TreeEdge(u, v) = event {
///         predecessor[v.index()] = u;
///         if v == goal {
///             return Control::Break(v);
///         }
///     }
///     Control::Continue
/// });
///
/// let mut next = goal;
/// let mut path = vec![next];
/// while next != start {
///     let pred = predecessor[next.index()];
///     path.push(pred);
///     next = pred;
/// }
/// path.reverse();
/// assert_eq!(&path, &[n(0), n(2), n(4), n(5)]);
/// ```
pub fn depth_first_search<G, F, C, I>(graph: G, starts: I, mut visitor: F) -> C
    where G: IntoNeighbors + Visitable,
          F: FnMut(DfsEvent<G::NodeId>) -> C,
          I: IntoIterator<Item=G::NodeId>,
          C: ControlFlow,
{
    let mut time = Time(0);
    let mut discovered = graph.visit_map();
    let mut finished = graph.visit_map();

    for start in starts {
        control!(dfs_visitor(graph, start, &mut visitor, &mut discovered, &mut
                             finished, &mut time));
    }
    C::default()
}

fn dfs_visitor<G, F, C>(graph: G, u: G::NodeId, visitor: &mut F,
                     discovered: &mut G::Map, finished: &mut G::Map,
                     time: &mut Time) -> C
    where G: IntoNeighbors + Visitable,
          F: FnMut(DfsEvent<G::NodeId>) -> C,
          C: ControlFlow,
{
    if !discovered.visit(u) {
        return C::default();
    }
    control!(visitor(DfsEvent::Discover(u, time_post_inc(time))));
    for v in graph.neighbors(u) {
        if !discovered.is_visited(&v) {
            control!(visitor(DfsEvent::TreeEdge(u, v)));
            control!(dfs_visitor(graph, v, visitor, discovered, finished, time));
        } else if !finished.is_visited(&v) {
            control!(visitor(DfsEvent::BackEdge(u, v)));
        } else {
            control!(visitor(DfsEvent::CrossForwardEdge(u, v)));
        }
    }
    let first_finish = finished.visit(u);
    debug_assert!(first_finish);
    control!(visitor(DfsEvent::Finish(u, time_post_inc(time))));
    C::default()
}

fn time_post_inc(x: &mut Time) -> Time {
    let v = *x;
    x.0 += 1;
    v
}
<commit_msg>Edit doc<commit_after>

use visit::IntoNeighbors;
use visit::{VisitMap, Visitable};

/// Strictly monotonically increasing event time for a depth first search.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Default)]
pub struct Time(pub u64);

/// A depth first search (DFS) visitor event.
#[derive(Copy, Clone, Debug)]
pub enum DfsEvent<N> {
    Discover(N, Time),
    /// An edge of the tree formed by the traversal.
    TreeEdge(N, N),
    /// An edge to an already visited node.
    BackEdge(N, N),
    /// A cross or forward edge.
    ///
    /// For an edge *(u, v)*, if the discover time of *v* is greater than *u*,
    /// then it is a forward edge, else a cross edge.
    CrossForwardEdge(N, N),
    Finish(N, Time),
}

macro_rules! control {
    ($e:expr) => {
        match $e {
            x => if x.should_break() {
                return x;
            } else {
            }
        }
    }
}

/// Control flow for visitor callbacks.
#[derive(Copy, Clone, Debug)]
pub enum Control<B> {
    Continue,
    Break(B),
}

impl<B> Control<B> {
    /// Get the value in `Control::Break(_)`, if present.
    pub fn break_value(self) -> Option<B> {
        match self {
            Control::Continue => None,
            Control::Break(b) => Some(b),
        }
    }
}

/// The default is `Continue`.
impl<B> Default for Control<B> {
    fn default() -> Self { Control::Continue }
}

/// Control flow for visitor callbacks.
///
/// The empty return value `()` will continue until the visit is done.
pub trait ControlFlow : Default {
    #[inline]
    fn should_break(&self) -> bool { false }
}

impl ControlFlow for () { }

impl<B> ControlFlow for Control<B> {
    fn should_break(&self) -> bool {
        if let Control::Break(_) = *self { true } else { false }
    }
}

/// A recursive depth first search.
///
/// Starting points are the nodes in the iterator `starts` (specify just one
/// start vertex *x* by using `Some(x)`).
///
/// The traversal emits discovery and finish events for each reachable vertex,
/// and edge classification of each reachable edge. `visitor` is called for each
/// event, see [`DfsEvent`][de] for possible values.
///
/// If the return value of the visitor is simply `()`, the visit runs until it
/// is finished. If the return value is a `Control<B>`, it can be used to
/// break the visit early, and the last control value is returned by the
/// function.
///
/// [de]: enum.DfsEvent.html
///
/// # Example
///
/// Find a path from vertex 0 to 5, and exit the visit as soon as we reach
/// the goal vertex.
///
/// ```
/// use petgraph::prelude::*;
/// use petgraph::graph::node_index as n;
/// use petgraph::visit::depth_first_search;
/// use petgraph::visit::{DfsEvent, Control};
///
/// let gr: Graph<(), ()> = Graph::from_edges(&[
///     (0, 1), (0, 2), (0, 3),
///     (1, 3),
///     (2, 3), (2, 4),
///     (4, 0), (4, 5),
/// ]);
///
/// // record each predecessor, mapping node → node
/// let mut predecessor = vec![NodeIndex::end(); gr.node_count()];
/// let start = n(0);
/// let goal = n(5);
/// let ret = depth_first_search(&gr, Some(start), |event| {
///     if let DfsEvent::TreeEdge(u, v) = event {
///         predecessor[v.index()] = u;
///         if v == goal {
///             return Control::Break(v);
///         }
///     }
///     Control::Continue
/// });
///
/// let mut next = goal;
/// let mut path = vec![next];
/// while next != start {
///     let pred = predecessor[next.index()];
///     path.push(pred);
///     next = pred;
/// }
/// path.reverse();
/// assert_eq!(&path, &[n(0), n(2), n(4), n(5)]);
/// ```
pub fn depth_first_search<G, F, C, I>(graph: G, starts: I, mut visitor: F) -> C
    where G: IntoNeighbors + Visitable,
          F: FnMut(DfsEvent<G::NodeId>) -> C,
          I: IntoIterator<Item=G::NodeId>,
          C: ControlFlow,
{
    let mut time = Time(0);
    let mut discovered = graph.visit_map();
    let mut finished = graph.visit_map();

    for start in starts {
        control!(dfs_visitor(graph, start, &mut visitor, &mut discovered, &mut
                             finished, &mut time));
    }
    C::default()
}

fn dfs_visitor<G, F, C>(graph: G, u: G::NodeId, visitor: &mut F,
                     discovered: &mut G::Map, finished: &mut G::Map,
                     time: &mut Time) -> C
    where G: IntoNeighbors + Visitable,
          F: FnMut(DfsEvent<G::NodeId>) -> C,
          C: ControlFlow,
{
    if !discovered.visit(u) {
        return C::default();
    }
    control!(visitor(DfsEvent::Discover(u, time_post_inc(time))));
    for v in graph.neighbors(u) {
        if !discovered.is_visited(&v) {
            control!(visitor(DfsEvent::TreeEdge(u, v)));
            control!(dfs_visitor(graph, v, visitor, discovered, finished, time));
        } else if !finished.is_visited(&v) {
            control!(visitor(DfsEvent::BackEdge(u, v)));
        } else {
            control!(visitor(DfsEvent::CrossForwardEdge(u, v)));
        }
    }
    let first_finish = finished.visit(u);
    debug_assert!(first_finish);
    control!(visitor(DfsEvent::Finish(u, time_post_inc(time))));
    C::default()
}

fn time_post_inc(x: &mut Time) -> Time {
    let v = *x;
    x.0 += 1;
    v
}
<|endoftext|>


<commit_before>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::{abi, ast, codemap, ext};
use syntax::ext::base::ItemDecorator;
use syntax::ext::build::AstBuilder;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token;
use syntax::ptr::P;

#[derive(Copy, PartialEq, Debug)]
enum Param {
    Uniform,
    Block,
    Texture,
    Special,
}

#[derive(Copy, Debug)]
enum ParamError {
    DeprecatedTexture,
}

/// Classify variable types (`i32`, `TextureParam`, etc) into the `Param`
fn classify(node: &ast::Ty_) -> Result<Param, ParamError> {
    match *node {
        ast::TyPath(_,ref path) => match path.segments.last() {
            Some(segment) => match segment.identifier.name.as_str() {
                "RawBufferHandle" => Ok(Param::Block),
                "TextureParam" => Ok(Param::Texture),
                "TextureHandle" => Err(ParamError::DeprecatedTexture),
                "PhantomData"   => Ok(Param::Special),
                _ => Ok(Param::Uniform),
            },
            None => Ok(Param::Uniform),
        },
        _ => Ok(Param::Uniform),
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::create_link`
fn method_create(cx: &mut ext::base::ExtCtxt,
                 span: codemap::Span,
                 definition: &ast::StructDef,
                 input: ast::Ident,
                 link_ident: ast::Ident,
                 path_root: ast::Ident)
                 -> P<ast::Block> {
    let init_expr = cx.expr_struct_ident(
        span, link_ident,
        definition.fields.iter().scan((), |_, field| {
            field.node.ident().map(|name|
                cx.field_imm(field.span, name, cx.expr_none(field.span))
            )
        }).collect()
    );
    let class_info: Vec<(Param, P<ast::Expr>)> = definition.fields.iter().scan((), |_, field|
        match (field.node.ident(), classify(&field.node.ty.node)) {
            (None, _) => {
                cx.span_err(field.span, "Named fields are required for `ShaderParam`");
                None
            },
            (Some(fname), Ok(c)) => {
                let name = match super::find_name(cx, field.span, &field.node.attrs) {
                    Some(name) => name,
                    None => token::get_ident(fname),
                };
                Some((c, cx.expr_str(field.span, name)))
            },
            (Some(fname), Err(e)) => {
                cx.span_err(field.span, &format!(
                    "Unrecognized parameter ({:?}) type {:?}",
                    fname.as_str(), e
                ));
                None
            },
        }
    ).collect();
    let gen_arms = |ptype: Param, var: ast::Ident| -> Vec<ast::Arm> {
        class_info.iter().zip(definition.fields.iter())
                  .filter(|&(&(ref class, _), _)| *class == ptype)
                  .scan((), |_, (&(_, ref name_expr), field)|
            field.node.ident().map(|name| quote_arm!(cx,
                $name_expr => {out.$name = Some(i as $path_root::gfx::shade::$var)}
            ))
        ).collect()
    };
    let uniform_arms = gen_arms(Param::Uniform, cx.ident_of("VarUniform"));
    let block_arms = gen_arms(Param::Block, cx.ident_of("VarBlock"));
    let texture_arms = gen_arms(Param::Texture, cx.ident_of("VarTexture"));
    let expr = quote_expr!(cx, {
        let mut out = $init_expr;
        for (i, u) in $input.uniforms.iter().enumerate() {
            let _ = i; // suppress warning about unused i
            match &u.name[..] {
                $uniform_arms
                _ => return Err($path_root::gfx::shade::
                    ParameterError::MissingUniform(u.name.clone())),
            }
        }
        for (i, b) in $input.blocks.iter().enumerate() {
            let _ = i; // suppress warning about unused i
            match &b.name[..] {
                $block_arms
                _ => return Err($path_root::gfx::shade::
                    ParameterError::MissingBlock(b.name.clone())),
            }
        }
        for (i, t) in $input.textures.iter().enumerate() {
            let _ = i; // suppress warning about unused i
            match &t.name[..] {
                $texture_arms
                _ => return Err($path_root::gfx::shade::
                    ParameterError::MissingTexture(t.name.clone())),
            }
        }
        Ok(out)
    });
    cx.block_expr(expr)
}

/// Generates the the method body for `gfx::shade::ParamValues::fill_params`
fn method_fill(cx: &mut ext::base::ExtCtxt,
               span: codemap::Span,
               definition: &ast::StructDef,
               path_root: ast::Ident)
               -> P<ast::Block> {
    let max_num = cx.expr_usize(span, definition.fields.len());
    let mut calls = vec![
        quote_stmt!(cx, use self::$path_root::gfx::shade::ToUniform;),
        quote_stmt!(cx, out.uniforms.reserve($max_num);),
        quote_stmt!(cx, out.blocks.reserve($max_num);),
        quote_stmt!(cx, out.textures.reserve($max_num);),
    ];
    calls.extend(definition.fields.iter().scan((), |_, field| {
        let name = match field.node.ident() {
            Some(n) => n,
            None => {
                cx.span_err(span, "Named fields are required for `ShaderParam`");
                return None
            }
        };
        classify(&field.node.ty.node).ok().map(|param| match param {
            Param::Uniform => quote_stmt!(cx,
                link.$name.map_or((), |id| {
                    if out.uniforms.len() <= id as usize {
                        unsafe { out.uniforms.set_len(id as usize + 1) }
                    }
                    *out.uniforms.get_mut(id as usize).unwrap() = self.$name.to_uniform()
                })
            ),
            Param::Block   => quote_stmt!(cx,
                link.$name.map_or((), |id| {
                    if out.blocks.len() <= id as usize {
                        unsafe { out.blocks.set_len(id as usize + 1) }
                    }
                    *out.blocks.get_mut(id as usize).unwrap() = {self.$name}
                })
            ),
            Param::Texture => quote_stmt!(cx,
                link.$name.map_or((), |id| {
                    if out.textures.len() <= id as usize {
                        unsafe { out.textures.set_len(id as usize + 1) }
                    }
                    *out.textures.get_mut(id as usize).unwrap() = {self.$name}
                })
            ),
            Param::Special => quote_stmt!(cx, ()),
        })
    }));
    cx.block_all(span, calls, None)
}

/// A helper function that translates variable type (`i32`, `TextureHandle`, etc)
/// into the corresponding shader var id type (`VarUniform`, `VarBlock`, or `VarTexture`)
fn node_to_var_type(cx: &mut ext::base::ExtCtxt,
                    span: codemap::Span, node: &ast::Ty_,
                    path_root: ast::Ident) -> P<ast::Ty> {
    let id = cx.ident_of(match classify(node) {
        Ok(Param::Uniform) => "VarUniform",
        Ok(Param::Block)   => "VarBlock",
        Ok(Param::Texture) => "VarTexture",
        Ok(Param::Special) => return quote_ty!(cx, Option<()>),
        Err(ParamError::DeprecatedTexture) => {
            cx.span_err(span, "Use gfx::shade::TextureParam for texture vars instead of gfx::shade::TextureHandle");
            ""
        },
    });
    quote_ty!(cx, Option<$path_root::gfx::shade::$id>)
}

fn impl_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span, name: &str, type_ident: ast::Ident) -> ast::ImplItem {
    ast::TypeImplItem(P(ast::Typedef {
        id: ast::DUMMY_NODE_ID,
        span: span,
        ident: cx.ident_of(name),
        vis: ast::Visibility::Inherited,
        attrs: Vec::new(),
        typ: cx.ty_ident(span, type_ident),
    }))
}

fn impl_method(cx: &mut ext::base::ExtCtxt, span: codemap::Span, name: &str,
               with_self: bool, declaration: P<ast::FnDecl>, body: P<ast::Block>)
               -> ast::ImplItem {
    ast::MethodImplItem(P(ast::Method {
        attrs: Vec::new(),
        id: ast::DUMMY_NODE_ID,
        span: span,
        node: ast::MethDecl(
            cx.ident_of(name),
            ast::Generics {
                lifetimes: Vec::new(),
                ty_params: OwnedSlice::empty(),
                where_clause: ast::WhereClause {
                    id: ast::DUMMY_NODE_ID,
                    predicates: Vec::new(),
                },
            },
            abi::Abi::Rust,
            codemap::Spanned {
                node: if with_self {
                        ast::SelfRegion(None, ast::MutImmutable, cx.ident_of("self"))
                    }else {
                        ast::SelfStatic
                },
                span: span,
            },
            ast::Unsafety::Normal,
            declaration,
            body,
            ast::Visibility::Inherited
        )
    }))
}

#[derive(Copy)]
pub struct ShaderParam;
impl ItemDecorator for ShaderParam {
    /// Decorator for `shader_param` attribute
    fn expand(&self, context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: &mut FnMut(P<ast::Item>)) {
        // Insert the `gfx` reexport module
        let extern_hack = context.ident_of(super::EXTERN_CRATE_HACK);
        let path_root = super::extern_crate_hack(context, span, |i| (*push)(i));

        // constructing the Link struct
        let (base_def, generics, link_def) = match item.node {
            ast::ItemStruct(ref definition, ref generics) => {
                (definition, generics.clone(), ast::StructDef {
                    fields: definition.fields.iter()
                        .map(|f| codemap::Spanned {
                            node: ast::StructField_ {
                                kind: f.node.kind,
                                id: f.node.id,
                                ty: node_to_var_type(context, f.span, &f.node.ty.node, path_root),
                                attrs: Vec::new(),
                            },
                            span: f.span,
                        }).collect(),
                    ctor_id: None,
                })
            },
            _ => {
                context.span_err(span, "Only free-standing named structs allowed to derive ShaderParam");
                return;
            }
        };

        // derive and push
        let link_name = format!("_{}Link", item.ident.as_str());
        let link_ident = context.ident_of(&link_name);
        let link_item = context.item_struct(span, link_ident, link_def)
                               .map(|mut item| {
            item.attrs.push(context.attribute(span,
                context.meta_list(span, token::InternedString::new("derive"), vec![
                        context.meta_word(span, token::InternedString::new("Copy")),
                        context.meta_word(span, token::InternedString::new("Debug")),
                ])
            ));
            item
        });
        (*push)(link_item);

        // process meta parameters (expecting none)
        match meta_item.node {
            ast::MetaWord(_) => (), //expected
            _ => {
                context.span_err(meta_item.span, "#[shader_param] needs no param");
            }
        }

        // find the generic `Resources` bound
        let resource_ident = match generics.ty_params.iter().find(|typ|
            typ.bounds.iter().find(|b| match **b {
                ast::TraitTyParamBound(ref poly_trait, _) =>
                    poly_trait.trait_ref.path.segments.last().unwrap().identifier.as_str() == "Resources",
                ast::RegionTyParamBound(_) => false,
            }).is_some()
        ){
            Some(typ) => typ.ident,
            None => {
                context.span_err(meta_item.span, "#[shader_param] unable to find generic `gfx::Resources` bound");
                context.ident_of("R")
            }
        };

        // construct `create_link()`
        let lifetimes = generics.lifetimes.iter().map(|ld| ld.lifetime).collect();
        let generic_parameters = generics.ty_params.iter().map(|ty|
            context.ty_ident(span, ty.ident)
        ).collect();
        let struct_ty = context.ty_path(context.path_all(
            span, false,
            vec![item.ident],
            lifetimes,
            generic_parameters,
            Vec::new(),
        ));
        let create_param = context.ident_of("params");
        let body_create = method_create(context, span, base_def, create_param, link_ident, path_root);
        let decl_create = context.fn_decl(
            vec![
                ast::Arg {
                    ty: quote_ty!(context, Option<&$struct_ty>),
                    pat: context.pat_wild(span),
                    id: ast::DUMMY_NODE_ID,
                },
                ast::Arg {
                    ty: quote_ty!(context, &$extern_hack::gfx::ProgramInfo),
                    pat: context.pat_ident(span, create_param),
                    id: ast::DUMMY_NODE_ID,
                },
            ],
            context.ty_path(context.path_all(
                span, false, vec![context.ident_of("Result")],
                Vec::new(), vec![
                    context.ty_ident(span, link_ident),
                    quote_ty!(context, $extern_hack::gfx::shade::ParameterError),
                ], Vec::new()
            )),
        );

        // construct `fill_params()`
        let body_fill = method_fill(context, span, base_def, path_root);
        let decl_fill = context.fn_decl(
             vec![
                ast::Arg::new_self(span, ast::MutImmutable, context.ident_of("self")),
                ast::Arg {
                    ty: quote_ty!(context, &$link_ident),
                    pat: context.pat_ident(span, context.ident_of("link")),
                    id: ast::DUMMY_NODE_ID,
                },
                ast::Arg {
                    ty: quote_ty!(context, $extern_hack::gfx::shade::ParamValues<$resource_ident>),
                    pat: context.pat_ident(span, context.ident_of("out")),
                    id: ast::DUMMY_NODE_ID,
                },
            ],
            quote_ty!(context, ())
        );

        // construct implementations for types and methods
        let impls = vec![
            impl_type(context, span, "Resources", resource_ident),
            impl_type(context, span, "Link", link_ident),
            impl_method(context, span, "create_link", false, decl_create, body_create),
            impl_method(context, span, "fill_params", true, decl_fill, body_fill),
        ];

        // final implementation item
        let item = context.item(span, item.ident, Vec::new(), ast::Item_::ItemImpl(
                ast::Unsafety::Normal,
                ast::ImplPolarity::Positive,
                generics,
                Some(context.trait_ref(context.path(span, vec![
                    extern_hack,
                    context.ident_of("gfx"),
                    context.ident_of("shade"),
                    context.ident_of("ShaderParam"),
                ]))),
                struct_ty,
                impls
        ));
        (*push)(super::fixup_extern_crate_paths(item, path_root));
    }
}
<commit_msg>Fixed misleading shader_param comments<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::{abi, ast, codemap, ext};
use syntax::ext::base::ItemDecorator;
use syntax::ext::build::AstBuilder;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token;
use syntax::ptr::P;

#[derive(Copy, PartialEq, Debug)]
enum Param {
    Uniform,
    Block,
    Texture,
    Special,
}

#[derive(Copy, Debug)]
enum ParamError {
    DeprecatedTexture,
}

/// Classify variable types (`i32`, `TextureParam`, etc) into the `Param`
fn classify(node: &ast::Ty_) -> Result<Param, ParamError> {
    match *node {
        ast::TyPath(_,ref path) => match path.segments.last() {
            Some(segment) => match segment.identifier.name.as_str() {
                "RawBufferHandle" => Ok(Param::Block),
                "TextureParam" => Ok(Param::Texture),
                "TextureHandle" => Err(ParamError::DeprecatedTexture),
                "PhantomData"   => Ok(Param::Special),
                _ => Ok(Param::Uniform),
            },
            None => Ok(Param::Uniform),
        },
        _ => Ok(Param::Uniform),
    }
}

/// Generates the the method body for `gfx::shade::ShaderParam::create_link`
fn method_create(cx: &mut ext::base::ExtCtxt,
                 span: codemap::Span,
                 definition: &ast::StructDef,
                 input: ast::Ident,
                 link_ident: ast::Ident,
                 path_root: ast::Ident)
                 -> P<ast::Block> {
    let init_expr = cx.expr_struct_ident(
        span, link_ident,
        definition.fields.iter().scan((), |_, field| {
            field.node.ident().map(|name|
                cx.field_imm(field.span, name, cx.expr_none(field.span))
            )
        }).collect()
    );
    let class_info: Vec<(Param, P<ast::Expr>)> = definition.fields.iter().scan((), |_, field|
        match (field.node.ident(), classify(&field.node.ty.node)) {
            (None, _) => {
                cx.span_err(field.span, "Named fields are required for `ShaderParam`");
                None
            },
            (Some(fname), Ok(c)) => {
                let name = match super::find_name(cx, field.span, &field.node.attrs) {
                    Some(name) => name,
                    None => token::get_ident(fname),
                };
                Some((c, cx.expr_str(field.span, name)))
            },
            (Some(fname), Err(e)) => {
                cx.span_err(field.span, &format!(
                    "Unrecognized parameter ({:?}) type {:?}",
                    fname.as_str(), e
                ));
                None
            },
        }
    ).collect();
    let gen_arms = |ptype: Param, var: ast::Ident| -> Vec<ast::Arm> {
        class_info.iter().zip(definition.fields.iter())
                  .filter(|&(&(ref class, _), _)| *class == ptype)
                  .scan((), |_, (&(_, ref name_expr), field)|
            field.node.ident().map(|name| quote_arm!(cx,
                $name_expr => {out.$name = Some(i as $path_root::gfx::shade::$var)}
            ))
        ).collect()
    };
    let uniform_arms = gen_arms(Param::Uniform, cx.ident_of("VarUniform"));
    let block_arms = gen_arms(Param::Block, cx.ident_of("VarBlock"));
    let texture_arms = gen_arms(Param::Texture, cx.ident_of("VarTexture"));
    let expr = quote_expr!(cx, {
        let mut out = $init_expr;
        for (i, u) in $input.uniforms.iter().enumerate() {
            let _ = i; // suppress warning about unused i
            match &u.name[..] {
                $uniform_arms
                _ => return Err($path_root::gfx::shade::
                    ParameterError::MissingUniform(u.name.clone())),
            }
        }
        for (i, b) in $input.blocks.iter().enumerate() {
            let _ = i; // suppress warning about unused i
            match &b.name[..] {
                $block_arms
                _ => return Err($path_root::gfx::shade::
                    ParameterError::MissingBlock(b.name.clone())),
            }
        }
        for (i, t) in $input.textures.iter().enumerate() {
            let _ = i; // suppress warning about unused i
            match &t.name[..] {
                $texture_arms
                _ => return Err($path_root::gfx::shade::
                    ParameterError::MissingTexture(t.name.clone())),
            }
        }
        Ok(out)
    });
    cx.block_expr(expr)
}

/// Generates the the method body for `gfx::shade::ShaderParam::fill_params`
fn method_fill(cx: &mut ext::base::ExtCtxt,
               span: codemap::Span,
               definition: &ast::StructDef,
               path_root: ast::Ident)
               -> P<ast::Block> {
    let max_num = cx.expr_usize(span, definition.fields.len());
    let mut calls = vec![
        quote_stmt!(cx, use self::$path_root::gfx::shade::ToUniform;),
        quote_stmt!(cx, out.uniforms.reserve($max_num);),
        quote_stmt!(cx, out.blocks.reserve($max_num);),
        quote_stmt!(cx, out.textures.reserve($max_num);),
    ];
    calls.extend(definition.fields.iter().scan((), |_, field| {
        let name = match field.node.ident() {
            Some(n) => n,
            None => {
                cx.span_err(span, "Named fields are required for `ShaderParam`");
                return None
            }
        };
        classify(&field.node.ty.node).ok().map(|param| match param {
            Param::Uniform => quote_stmt!(cx,
                link.$name.map_or((), |id| {
                    if out.uniforms.len() <= id as usize {
                        unsafe { out.uniforms.set_len(id as usize + 1) }
                    }
                    *out.uniforms.get_mut(id as usize).unwrap() = self.$name.to_uniform()
                })
            ),
            Param::Block   => quote_stmt!(cx,
                link.$name.map_or((), |id| {
                    if out.blocks.len() <= id as usize {
                        unsafe { out.blocks.set_len(id as usize + 1) }
                    }
                    *out.blocks.get_mut(id as usize).unwrap() = {self.$name}
                })
            ),
            Param::Texture => quote_stmt!(cx,
                link.$name.map_or((), |id| {
                    if out.textures.len() <= id as usize {
                        unsafe { out.textures.set_len(id as usize + 1) }
                    }
                    *out.textures.get_mut(id as usize).unwrap() = {self.$name}
                })
            ),
            Param::Special => quote_stmt!(cx, ()),
        })
    }));
    cx.block_all(span, calls, None)
}

/// A helper function that translates variable type (`i32`, `TextureHandle`, etc)
/// into the corresponding shader var id type (`VarUniform`, `VarBlock`, or `VarTexture`)
fn node_to_var_type(cx: &mut ext::base::ExtCtxt,
                    span: codemap::Span, node: &ast::Ty_,
                    path_root: ast::Ident) -> P<ast::Ty> {
    let id = cx.ident_of(match classify(node) {
        Ok(Param::Uniform) => "VarUniform",
        Ok(Param::Block)   => "VarBlock",
        Ok(Param::Texture) => "VarTexture",
        Ok(Param::Special) => return quote_ty!(cx, Option<()>),
        Err(ParamError::DeprecatedTexture) => {
            cx.span_err(span, "Use gfx::shade::TextureParam for texture vars instead of gfx::shade::TextureHandle");
            ""
        },
    });
    quote_ty!(cx, Option<$path_root::gfx::shade::$id>)
}

fn impl_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span, name: &str, type_ident: ast::Ident) -> ast::ImplItem {
    ast::TypeImplItem(P(ast::Typedef {
        id: ast::DUMMY_NODE_ID,
        span: span,
        ident: cx.ident_of(name),
        vis: ast::Visibility::Inherited,
        attrs: Vec::new(),
        typ: cx.ty_ident(span, type_ident),
    }))
}

fn impl_method(cx: &mut ext::base::ExtCtxt, span: codemap::Span, name: &str,
               with_self: bool, declaration: P<ast::FnDecl>, body: P<ast::Block>)
               -> ast::ImplItem {
    ast::MethodImplItem(P(ast::Method {
        attrs: Vec::new(),
        id: ast::DUMMY_NODE_ID,
        span: span,
        node: ast::MethDecl(
            cx.ident_of(name),
            ast::Generics {
                lifetimes: Vec::new(),
                ty_params: OwnedSlice::empty(),
                where_clause: ast::WhereClause {
                    id: ast::DUMMY_NODE_ID,
                    predicates: Vec::new(),
                },
            },
            abi::Abi::Rust,
            codemap::Spanned {
                node: if with_self {
                        ast::SelfRegion(None, ast::MutImmutable, cx.ident_of("self"))
                    }else {
                        ast::SelfStatic
                },
                span: span,
            },
            ast::Unsafety::Normal,
            declaration,
            body,
            ast::Visibility::Inherited
        )
    }))
}

#[derive(Copy)]
pub struct ShaderParam;
impl ItemDecorator for ShaderParam {
    /// Decorator for `shader_param` attribute
    fn expand(&self, context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: &mut FnMut(P<ast::Item>)) {
        // Insert the `gfx` reexport module
        let extern_hack = context.ident_of(super::EXTERN_CRATE_HACK);
        let path_root = super::extern_crate_hack(context, span, |i| (*push)(i));

        // constructing the Link struct
        let (base_def, generics, link_def) = match item.node {
            ast::ItemStruct(ref definition, ref generics) => {
                (definition, generics.clone(), ast::StructDef {
                    fields: definition.fields.iter()
                        .map(|f| codemap::Spanned {
                            node: ast::StructField_ {
                                kind: f.node.kind,
                                id: f.node.id,
                                ty: node_to_var_type(context, f.span, &f.node.ty.node, path_root),
                                attrs: Vec::new(),
                            },
                            span: f.span,
                        }).collect(),
                    ctor_id: None,
                })
            },
            _ => {
                context.span_err(span, "Only free-standing named structs allowed to derive ShaderParam");
                return;
            }
        };

        // derive and push
        let link_name = format!("_{}Link", item.ident.as_str());
        let link_ident = context.ident_of(&link_name);
        let link_item = context.item_struct(span, link_ident, link_def)
                               .map(|mut item| {
            item.attrs.push(context.attribute(span,
                context.meta_list(span, token::InternedString::new("derive"), vec![
                        context.meta_word(span, token::InternedString::new("Copy")),
                        context.meta_word(span, token::InternedString::new("Debug")),
                ])
            ));
            item
        });
        (*push)(link_item);

        // process meta parameters (expecting none)
        match meta_item.node {
            ast::MetaWord(_) => (), //expected
            _ => {
                context.span_err(meta_item.span, "#[shader_param] needs no param");
            }
        }

        // find the generic `Resources` bound
        let resource_ident = match generics.ty_params.iter().find(|typ|
            typ.bounds.iter().find(|b| match **b {
                ast::TraitTyParamBound(ref poly_trait, _) =>
                    poly_trait.trait_ref.path.segments.last().unwrap().identifier.as_str() == "Resources",
                ast::RegionTyParamBound(_) => false,
            }).is_some()
        ){
            Some(typ) => typ.ident,
            None => {
                context.span_err(meta_item.span, "#[shader_param] unable to find generic `gfx::Resources` bound");
                context.ident_of("R")
            }
        };

        // construct `create_link()`
        let lifetimes = generics.lifetimes.iter().map(|ld| ld.lifetime).collect();
        let generic_parameters = generics.ty_params.iter().map(|ty|
            context.ty_ident(span, ty.ident)
        ).collect();
        let struct_ty = context.ty_path(context.path_all(
            span, false,
            vec![item.ident],
            lifetimes,
            generic_parameters,
            Vec::new(),
        ));
        let create_param = context.ident_of("params");
        let body_create = method_create(context, span, base_def, create_param, link_ident, path_root);
        let decl_create = context.fn_decl(
            vec![
                ast::Arg {
                    ty: quote_ty!(context, Option<&$struct_ty>),
                    pat: context.pat_wild(span),
                    id: ast::DUMMY_NODE_ID,
                },
                ast::Arg {
                    ty: quote_ty!(context, &$extern_hack::gfx::ProgramInfo),
                    pat: context.pat_ident(span, create_param),
                    id: ast::DUMMY_NODE_ID,
                },
            ],
            context.ty_path(context.path_all(
                span, false, vec![context.ident_of("Result")],
                Vec::new(), vec![
                    context.ty_ident(span, link_ident),
                    quote_ty!(context, $extern_hack::gfx::shade::ParameterError),
                ], Vec::new()
            )),
        );

        // construct `fill_params()`
        let body_fill = method_fill(context, span, base_def, path_root);
        let decl_fill = context.fn_decl(
             vec![
                ast::Arg::new_self(span, ast::MutImmutable, context.ident_of("self")),
                ast::Arg {
                    ty: quote_ty!(context, &$link_ident),
                    pat: context.pat_ident(span, context.ident_of("link")),
                    id: ast::DUMMY_NODE_ID,
                },
                ast::Arg {
                    ty: quote_ty!(context, $extern_hack::gfx::shade::ParamValues<$resource_ident>),
                    pat: context.pat_ident(span, context.ident_of("out")),
                    id: ast::DUMMY_NODE_ID,
                },
            ],
            quote_ty!(context, ())
        );

        // construct implementations for types and methods
        let impls = vec![
            impl_type(context, span, "Resources", resource_ident),
            impl_type(context, span, "Link", link_ident),
            impl_method(context, span, "create_link", false, decl_create, body_create),
            impl_method(context, span, "fill_params", true, decl_fill, body_fill),
        ];

        // final implementation item
        let item = context.item(span, item.ident, Vec::new(), ast::Item_::ItemImpl(
                ast::Unsafety::Normal,
                ast::ImplPolarity::Positive,
                generics,
                Some(context.trait_ref(context.path(span, vec![
                    extern_hack,
                    context.ident_of("gfx"),
                    context.ident_of("shade"),
                    context.ident_of("ShaderParam"),
                ]))),
                struct_ty,
                impls
        ));
        (*push)(super::fixup_extern_crate_paths(item, path_root));
    }
}
<|endoftext|>


<commit_before>use crate::Result;
use flume::{Receiver, Sender};
use std::task::Poll;
use tracing::trace;

pub(crate) struct SocketState {
    readable: bool,
    writable: bool,
    events: Receiver<SocketEvent>,
    handle: SocketStateHandle,
}

impl Default for SocketState {
    fn default() -> Self {
        let (sender, receiver) = flume::unbounded();
        Self {
            readable: true,
            writable: true,
            events: receiver,
            handle: SocketStateHandle { sender },
        }
    }
}

#[derive(Clone)]
pub struct SocketStateHandle {
    sender: Sender<SocketEvent>,
}

#[derive(Debug)]
pub enum SocketEvent {
    Readable,
    Writable,
    Wake,
}

impl SocketState {
    pub(crate) fn readable(&mut self) -> bool {
        self.readable
    }

    pub(crate) fn writable(&mut self) -> bool {
        self.writable
    }

    pub(crate) fn wait(&mut self) {
        self.handle_event(self.events.recv().expect("waiting for socket event failed"))
    }

    pub(crate) fn handle(&self) -> SocketStateHandle {
        self.handle.clone()
    }

    pub(crate) fn handle_read_poll(&mut self, poll: Poll<usize>) -> Option<usize> {
        match poll {
            Poll::Ready(sz) => Some(sz),
            Poll::Pending => {
                self.readable = false;
                None
            }
        }
    }

    pub(crate) fn handle_write_poll<T>(&mut self, poll: Poll<T>) -> Option<T> {
        match poll {
            Poll::Ready(sz) => Some(sz),
            Poll::Pending => {
                self.writable = false;
                None
            }
        }
    }

    pub(crate) fn handle_io_result(&self, result: Result<()>) -> Result<()> {
        if let Err(err) = result {
            if err.interrupted() {
                self.handle.wake();
            } else {
                return Err(err);
            }
        }
        Ok(())
    }

    pub(crate) fn poll_events(&mut self) {
        while let Ok(event) = self.events.try_recv() {
            self.handle_event(event);
        }
    }

    fn handle_event(&mut self, event: SocketEvent) {
        trace!(?event, "Got event for socket");
        match event {
            SocketEvent::Readable => self.readable = true,
            SocketEvent::Writable => self.writable = true,
            SocketEvent::Wake => {}
        }
    }
}

impl SocketStateHandle {
    pub fn send(&self, event: SocketEvent) {
        let _ = self.sender.send(event);
    }

    pub fn wake(&self) {
        self.send(SocketEvent::Wake);
    }
}
<commit_msg>socket_state: ignore wouldblock<commit_after>use crate::Result;
use flume::{Receiver, Sender};
use std::task::Poll;
use tracing::trace;

pub(crate) struct SocketState {
    readable: bool,
    writable: bool,
    events: Receiver<SocketEvent>,
    handle: SocketStateHandle,
}

impl Default for SocketState {
    fn default() -> Self {
        let (sender, receiver) = flume::unbounded();
        Self {
            readable: true,
            writable: true,
            events: receiver,
            handle: SocketStateHandle { sender },
        }
    }
}

#[derive(Clone)]
pub struct SocketStateHandle {
    sender: Sender<SocketEvent>,
}

#[derive(Debug)]
pub enum SocketEvent {
    Readable,
    Writable,
    Wake,
}

impl SocketState {
    pub(crate) fn readable(&mut self) -> bool {
        self.readable
    }

    pub(crate) fn writable(&mut self) -> bool {
        self.writable
    }

    pub(crate) fn wait(&mut self) {
        self.handle_event(self.events.recv().expect("waiting for socket event failed"))
    }

    pub(crate) fn handle(&self) -> SocketStateHandle {
        self.handle.clone()
    }

    pub(crate) fn handle_read_poll(&mut self, poll: Poll<usize>) -> Option<usize> {
        match poll {
            Poll::Ready(sz) => Some(sz),
            Poll::Pending => {
                self.readable = false;
                None
            }
        }
    }

    pub(crate) fn handle_write_poll<T>(&mut self, poll: Poll<T>) -> Option<T> {
        match poll {
            Poll::Ready(sz) => Some(sz),
            Poll::Pending => {
                self.writable = false;
                None
            }
        }
    }

    pub(crate) fn handle_io_result(&self, result: Result<()>) -> Result<()> {
        if let Err(err) = result {
            if err.interrupted() {
                self.handle.wake();
            } else if err.wouldblock() {
                // ignore, let the reactor handle that
            } else {
                return Err(err);
            }
        }
        Ok(())
    }

    pub(crate) fn poll_events(&mut self) {
        while let Ok(event) = self.events.try_recv() {
            self.handle_event(event);
        }
    }

    fn handle_event(&mut self, event: SocketEvent) {
        trace!(?event, "Got event for socket");
        match event {
            SocketEvent::Readable => self.readable = true,
            SocketEvent::Writable => self.writable = true,
            SocketEvent::Wake => {}
        }
    }
}

impl SocketStateHandle {
    pub fn send(&self, event: SocketEvent) {
        let _ = self.sender.send(event);
    }

    pub fn wake(&self) {
        self.send(SocketEvent::Wake);
    }
}
<|endoftext|>


<commit_before>//! Models pertaining to the gateway.

use parking_lot::RwLock;
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
use serde_json;
use std::sync::Arc;
use super::utils::*;
use super::prelude::*;

/// A representation of the data retrieved from the bot gateway endpoint.
///
/// This is different from the [`Gateway`], as this includes the number of
/// shards that Discord recommends to use for a bot user.
///
/// This is only applicable to bot users.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BotGateway {
    /// The number of shards that is recommended to be used by the current bot
    /// user.
    pub shards: u64,
    /// The gateway to connect to.
    pub url: String,
}

/// Representation of a game that a [`User`] is playing -- or streaming in the
/// case that a stream URL is provided.
#[derive(Clone, Debug, Serialize)]
pub struct Game {
    /// The type of game status.
    #[serde(default, rename = "type")]
    pub kind: GameType,
    /// The name of the game being played.
    pub name: String,
    /// The Stream URL if [`kind`] is [`GameType::Streaming`].
    ///
    /// [`GameType::Streaming`]: enum.GameType.html#variant.Streaming
    /// [`kind`]: #structfield.kind
    pub url: Option<String>,
}

#[cfg(feature = "model")]
impl Game {
    /// Creates a `Game` struct that appears as a `Playing <name>` status.
    ///
    /// **Note**: Maximum `name` length is 128.
    ///
    /// # Examples
    ///
    /// Create a command that sets the current game being played:
    ///
    /// ```rust,no_run
    /// # #[macro_use] extern crate serenity;
    /// #
    /// use serenity::framework::standard::Args;
    /// use serenity::model::gateway::Game;
    ///
    /// command!(game(ctx, _msg, args) {
    ///     let name = args.full();
    ///     ctx.set_game(Game::playing(&name));
    /// });
    /// #
    /// # fn main() {}
    /// ```
    pub fn playing(name: &str) -> Game {
        Game {
            kind: GameType::Playing,
            name: name.to_string(),
            url: None,
        }
    }

    /// Creates a `Game` struct that appears as a `Streaming <name>` status.
    ///
    /// **Note**: Maximum `name` length is 128.
    ///
    /// # Examples
    ///
    /// Create a command that sets the current game and stream:
    ///
    /// ```rust,no_run
    /// # #[macro_use] extern crate serenity;
    /// #
    /// use serenity::framework::standard::Args;
    /// use serenity::model::gateway::Game;
    ///
    /// // Assumes command has min_args set to 2.
    /// command!(stream(ctx, _msg, args) {
    ///     # let stream_url = String::from("");
    ///     let name = args.full();
    ///     ctx.set_game(Game::streaming(&name, &stream_url));
    /// });
    /// #
    /// # fn main() {}
    /// ```
    pub fn streaming(name: &str, url: &str) -> Game {
        Game {
            kind: GameType::Streaming,
            name: name.to_string(),
            url: Some(url.to_string()),
        }
    }

    /// Creates a `Game` struct that appears as a `Listening to <name>` status.
    ///
    /// **Note**: Maximum `name` length is 128.
    ///
    /// # Examples
    ///
    /// Create a command that sets the current game being played:
    ///
    /// ```rust,no_run
    /// # #[macro_use] extern crate serenity;
    /// #
    /// use serenity::framework::standard::Args;
    /// use serenity::model::gateway::Game;
    ///
    /// command!(listen(ctx, _msg, args) {
    ///     let name = args.full();
    ///     ctx.set_game(Game::listening(&name));
    /// });
    /// #
    /// # fn main() {}
    /// ```
    pub fn listening(name: &str) -> Game {
        Game {
            kind: GameType::Listening,
            name: name.to_string(),
            url: None,
        }
    }
}

impl<'a> From<&'a str> for Game {
    fn from(name: &'a str) -> Self {
        Game {
            kind: GameType::Playing,
            name: name.to_owned(),
            url: None,
        }
    }
}

impl From<String> for Game {
    fn from(name: String) -> Self {
        Game {
            kind: GameType::Playing,
            url: None,
            name,
        }
    }
}

impl<'a> From<(String, GameType)> for Game {
    fn from((name, kind): (String, GameType)) -> Self {
        Self {
            url: None,
            kind,
            name,
        }
    }
}

impl<'a> From<(&'a str, &'a str)> for Game {
    fn from((name, url): (&'a str, &'a str)) -> Self {
        Self {
            kind: GameType::Streaming,
            name: name.to_owned(),
            url: Some(url.to_owned()),
        }
    }
}

impl From<(String, String)> for Game {
    fn from((name, url): (String, String)) -> Self {
        Self {
            kind: GameType::Streaming,
            url: Some(url),
            name,
        }
    }
}

impl From<(String, GameType, String)> for Game {
    fn from((name, kind, url): (String, GameType, String)) -> Self {
        Self {
            url: Some(url),
            kind,
            name,
        }
    }
}

impl<'de> Deserialize<'de> for Game {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        let mut map = JsonMap::deserialize(deserializer)?;
        let kind = map.remove("type")
            .and_then(|v| GameType::deserialize(v).ok())
            .unwrap_or(GameType::Playing);
        let name = map.remove("name")
            .and_then(|v| String::deserialize(v).ok())
            .unwrap_or_else(String::new);
        let url = map.remove("url")
            .and_then(|v| serde_json::from_value::<String>(v).ok());

        Ok(Game {
            kind,
            name,
            url,
        })
    }
}

/// The type of activity that is being performed when playing a game.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum GameType {
    /// An indicator that the user is playing a game.
    Playing = 0,
    /// An indicator that the user is streaming to a service.
    Streaming = 1,
    /// An indicator that the user is listening to something.
    Listening = 2,
}

enum_number!(
    GameType {
        Playing,
        Streaming,
        Listening,
    }
);

impl GameType {
    pub fn num(&self) -> u64 {
        use self::GameType::*;

        match *self {
            Playing => 0,
            Streaming => 1,
            Listening => 2,
        }
    }
}

impl Default for GameType {
    fn default() -> Self { GameType::Playing }
}

/// A representation of the data retrieved from the gateway endpoint.
///
/// For the bot-specific gateway, refer to [`BotGateway`].
///
/// [`BotGateway`]: struct.BotGateway.html
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Gateway {
    /// The gateway to connect to.
    pub url: String,
}

/// Information detailing the current online status of a [`User`].
///
/// [`User`]: ../user/struct.User.html
#[derive(Clone, Debug)]
pub struct Presence {
    /// The game that a [`User`] is current playing.
    ///
    /// [`User`]: ../user/struct.User.html
    pub game: Option<Game>,
    /// The date of the last presence update.
    pub last_modified: Option<u64>,
    /// The nickname of the member, if applicable.
    pub nick: Option<String>,
    /// The user's online status.
    pub status: OnlineStatus,
    /// The Id of the [`User`](../user/struct.User.html). Can be used to calculate the user's creation
    /// date.
    pub user_id: UserId,
    /// The associated user instance.
    pub user: Option<Arc<RwLock<User>>>,
}

impl<'de> Deserialize<'de> for Presence {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Presence, D::Error> {
        let mut map = JsonMap::deserialize(deserializer)?;
        let mut user_map = map.remove("user")
            .ok_or_else(|| DeError::custom("expected presence user"))
            .and_then(JsonMap::deserialize)
            .map_err(DeError::custom)?;

        let (user_id, user) = if user_map.len() > 1 {
            let user = User::deserialize(Value::Object(user_map))
                .map_err(DeError::custom)?;

            (user.id, Some(Arc::new(RwLock::new(user))))
        } else {
            let user_id = user_map
                .remove("id")
                .ok_or_else(|| DeError::custom("Missing presence user id"))
                .and_then(UserId::deserialize)
                .map_err(DeError::custom)?;

            (user_id, None)
        };

        let game = match map.remove("game") {
            Some(v) => serde_json::from_value::<Option<Game>>(v)
                .map_err(DeError::custom)?,
            None => None,
        };
        let last_modified = match map.remove("last_modified") {
            Some(v) => Some(u64::deserialize(v).map_err(DeError::custom)?),
            None => None,
        };
        let nick = match map.remove("nick") {
            Some(v) => serde_json::from_value::<Option<String>>(v)
                .map_err(DeError::custom)?,
            None => None,
        };
        let status = map.remove("status")
            .ok_or_else(|| DeError::custom("expected presence status"))
            .and_then(OnlineStatus::deserialize)
            .map_err(DeError::custom)?;

        Ok(Presence {
            game,
            last_modified,
            nick,
            status,
            user,
            user_id,
        })
    }
}

impl Serialize for Presence {
    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
        where S: Serializer {
        #[derive(Serialize)]
        struct UserId {
            id: u64,
        }

        let mut state = serializer.serialize_struct("Presence", 5)?;
        state.serialize_field("game", &self.game)?;
        state.serialize_field("last_modified", &self.last_modified)?;
        state.serialize_field("nick", &self.nick)?;
        state.serialize_field("status", &self.status)?;

        if let Some(ref user) = self.user {
            state.serialize_field("user", &*user.read())?;
        } else {
            state.serialize_field("user", &UserId {
                id: self.user_id.0,
            })?;
        }

        state.end()
    }
}

/// An initial set of information given after IDENTIFYing to the gateway.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Ready {
    pub guilds: Vec<GuildStatus>,
    #[serde(default, deserialize_with = "deserialize_presences")]
    pub presences: HashMap<UserId, Presence>,
    #[serde(default, deserialize_with = "deserialize_private_channels")]
    pub private_channels: HashMap<ChannelId, Channel>,
    pub session_id: String,
    pub shard: Option<[u64; 2]>,
    #[serde(default, rename = "_trace")]
    pub trace: Vec<String>,
    pub user: CurrentUser,
    #[serde(rename = "v")]
    pub version: u64,
}
<commit_msg>Add support for session start info in BotGateway<commit_after>//! Models pertaining to the gateway.

use parking_lot::RwLock;
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
use serde_json;
use std::sync::Arc;
use super::utils::*;
use super::prelude::*;

/// A representation of the data retrieved from the bot gateway endpoint.
///
/// This is different from the [`Gateway`], as this includes the number of
/// shards that Discord recommends to use for a bot user.
///
/// This is only applicable to bot users.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BotGateway {
    /// Information describing how many gateway sessions you can initiate within
    /// a ratelimit period.
    pub session_start_limit: SessionStartLimit,
    /// The number of shards that is recommended to be used by the current bot
    /// user.
    pub shards: u64,
    /// The gateway to connect to.
    pub url: String,
}

/// Representation of a game that a [`User`] is playing -- or streaming in the
/// case that a stream URL is provided.
#[derive(Clone, Debug, Serialize)]
pub struct Game {
    /// The type of game status.
    #[serde(default, rename = "type")]
    pub kind: GameType,
    /// The name of the game being played.
    pub name: String,
    /// The Stream URL if [`kind`] is [`GameType::Streaming`].
    ///
    /// [`GameType::Streaming`]: enum.GameType.html#variant.Streaming
    /// [`kind`]: #structfield.kind
    pub url: Option<String>,
}

#[cfg(feature = "model")]
impl Game {
    /// Creates a `Game` struct that appears as a `Playing <name>` status.
    ///
    /// **Note**: Maximum `name` length is 128.
    ///
    /// # Examples
    ///
    /// Create a command that sets the current game being played:
    ///
    /// ```rust,no_run
    /// # #[macro_use] extern crate serenity;
    /// #
    /// use serenity::framework::standard::Args;
    /// use serenity::model::gateway::Game;
    ///
    /// command!(game(ctx, _msg, args) {
    ///     let name = args.full();
    ///     ctx.set_game(Game::playing(&name));
    /// });
    /// #
    /// # fn main() {}
    /// ```
    pub fn playing(name: &str) -> Game {
        Game {
            kind: GameType::Playing,
            name: name.to_string(),
            url: None,
        }
    }

    /// Creates a `Game` struct that appears as a `Streaming <name>` status.
    ///
    /// **Note**: Maximum `name` length is 128.
    ///
    /// # Examples
    ///
    /// Create a command that sets the current game and stream:
    ///
    /// ```rust,no_run
    /// # #[macro_use] extern crate serenity;
    /// #
    /// use serenity::framework::standard::Args;
    /// use serenity::model::gateway::Game;
    ///
    /// // Assumes command has min_args set to 2.
    /// command!(stream(ctx, _msg, args) {
    ///     # let stream_url = String::from("");
    ///     let name = args.full();
    ///     ctx.set_game(Game::streaming(&name, &stream_url));
    /// });
    /// #
    /// # fn main() {}
    /// ```
    pub fn streaming(name: &str, url: &str) -> Game {
        Game {
            kind: GameType::Streaming,
            name: name.to_string(),
            url: Some(url.to_string()),
        }
    }

    /// Creates a `Game` struct that appears as a `Listening to <name>` status.
    ///
    /// **Note**: Maximum `name` length is 128.
    ///
    /// # Examples
    ///
    /// Create a command that sets the current game being played:
    ///
    /// ```rust,no_run
    /// # #[macro_use] extern crate serenity;
    /// #
    /// use serenity::framework::standard::Args;
    /// use serenity::model::gateway::Game;
    ///
    /// command!(listen(ctx, _msg, args) {
    ///     let name = args.full();
    ///     ctx.set_game(Game::listening(&name));
    /// });
    /// #
    /// # fn main() {}
    /// ```
    pub fn listening(name: &str) -> Game {
        Game {
            kind: GameType::Listening,
            name: name.to_string(),
            url: None,
        }
    }
}

impl<'a> From<&'a str> for Game {
    fn from(name: &'a str) -> Self {
        Game {
            kind: GameType::Playing,
            name: name.to_owned(),
            url: None,
        }
    }
}

impl From<String> for Game {
    fn from(name: String) -> Self {
        Game {
            kind: GameType::Playing,
            url: None,
            name,
        }
    }
}

impl<'a> From<(String, GameType)> for Game {
    fn from((name, kind): (String, GameType)) -> Self {
        Self {
            url: None,
            kind,
            name,
        }
    }
}

impl<'a> From<(&'a str, &'a str)> for Game {
    fn from((name, url): (&'a str, &'a str)) -> Self {
        Self {
            kind: GameType::Streaming,
            name: name.to_owned(),
            url: Some(url.to_owned()),
        }
    }
}

impl From<(String, String)> for Game {
    fn from((name, url): (String, String)) -> Self {
        Self {
            kind: GameType::Streaming,
            url: Some(url),
            name,
        }
    }
}

impl From<(String, GameType, String)> for Game {
    fn from((name, kind, url): (String, GameType, String)) -> Self {
        Self {
            url: Some(url),
            kind,
            name,
        }
    }
}

impl<'de> Deserialize<'de> for Game {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        let mut map = JsonMap::deserialize(deserializer)?;
        let kind = map.remove("type")
            .and_then(|v| GameType::deserialize(v).ok())
            .unwrap_or(GameType::Playing);
        let name = map.remove("name")
            .and_then(|v| String::deserialize(v).ok())
            .unwrap_or_else(String::new);
        let url = map.remove("url")
            .and_then(|v| serde_json::from_value::<String>(v).ok());

        Ok(Game {
            kind,
            name,
            url,
        })
    }
}

/// The type of activity that is being performed when playing a game.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum GameType {
    /// An indicator that the user is playing a game.
    Playing = 0,
    /// An indicator that the user is streaming to a service.
    Streaming = 1,
    /// An indicator that the user is listening to something.
    Listening = 2,
}

enum_number!(
    GameType {
        Playing,
        Streaming,
        Listening,
    }
);

impl GameType {
    pub fn num(&self) -> u64 {
        use self::GameType::*;

        match *self {
            Playing => 0,
            Streaming => 1,
            Listening => 2,
        }
    }
}

impl Default for GameType {
    fn default() -> Self { GameType::Playing }
}

/// A representation of the data retrieved from the gateway endpoint.
///
/// For the bot-specific gateway, refer to [`BotGateway`].
///
/// [`BotGateway`]: struct.BotGateway.html
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Gateway {
    /// The gateway to connect to.
    pub url: String,
}

/// Information detailing the current online status of a [`User`].
///
/// [`User`]: ../user/struct.User.html
#[derive(Clone, Debug)]
pub struct Presence {
    /// The game that a [`User`] is current playing.
    ///
    /// [`User`]: ../user/struct.User.html
    pub game: Option<Game>,
    /// The date of the last presence update.
    pub last_modified: Option<u64>,
    /// The nickname of the member, if applicable.
    pub nick: Option<String>,
    /// The user's online status.
    pub status: OnlineStatus,
    /// The Id of the [`User`](../user/struct.User.html). Can be used to calculate the user's creation
    /// date.
    pub user_id: UserId,
    /// The associated user instance.
    pub user: Option<Arc<RwLock<User>>>,
}

impl<'de> Deserialize<'de> for Presence {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Presence, D::Error> {
        let mut map = JsonMap::deserialize(deserializer)?;
        let mut user_map = map.remove("user")
            .ok_or_else(|| DeError::custom("expected presence user"))
            .and_then(JsonMap::deserialize)
            .map_err(DeError::custom)?;

        let (user_id, user) = if user_map.len() > 1 {
            let user = User::deserialize(Value::Object(user_map))
                .map_err(DeError::custom)?;

            (user.id, Some(Arc::new(RwLock::new(user))))
        } else {
            let user_id = user_map
                .remove("id")
                .ok_or_else(|| DeError::custom("Missing presence user id"))
                .and_then(UserId::deserialize)
                .map_err(DeError::custom)?;

            (user_id, None)
        };

        let game = match map.remove("game") {
            Some(v) => serde_json::from_value::<Option<Game>>(v)
                .map_err(DeError::custom)?,
            None => None,
        };
        let last_modified = match map.remove("last_modified") {
            Some(v) => Some(u64::deserialize(v).map_err(DeError::custom)?),
            None => None,
        };
        let nick = match map.remove("nick") {
            Some(v) => serde_json::from_value::<Option<String>>(v)
                .map_err(DeError::custom)?,
            None => None,
        };
        let status = map.remove("status")
            .ok_or_else(|| DeError::custom("expected presence status"))
            .and_then(OnlineStatus::deserialize)
            .map_err(DeError::custom)?;

        Ok(Presence {
            game,
            last_modified,
            nick,
            status,
            user,
            user_id,
        })
    }
}

impl Serialize for Presence {
    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
        where S: Serializer {
        #[derive(Serialize)]
        struct UserId {
            id: u64,
        }

        let mut state = serializer.serialize_struct("Presence", 5)?;
        state.serialize_field("game", &self.game)?;
        state.serialize_field("last_modified", &self.last_modified)?;
        state.serialize_field("nick", &self.nick)?;
        state.serialize_field("status", &self.status)?;

        if let Some(ref user) = self.user {
            state.serialize_field("user", &*user.read())?;
        } else {
            state.serialize_field("user", &UserId {
                id: self.user_id.0,
            })?;
        }

        state.end()
    }
}

/// An initial set of information given after IDENTIFYing to the gateway.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Ready {
    pub guilds: Vec<GuildStatus>,
    #[serde(default, deserialize_with = "deserialize_presences")]
    pub presences: HashMap<UserId, Presence>,
    #[serde(default, deserialize_with = "deserialize_private_channels")]
    pub private_channels: HashMap<ChannelId, Channel>,
    pub session_id: String,
    pub shard: Option<[u64; 2]>,
    #[serde(default, rename = "_trace")]
    pub trace: Vec<String>,
    pub user: CurrentUser,
    #[serde(rename = "v")]
    pub version: u64,
}

/// Information describing how many gateway sessions you can initiate within a
/// ratelimit period.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SessionStartLimit {
    /// The number of sessions that you can still initiate within the current
    /// ratelimit period.
    pub remaining: u64,
    /// The number of milliseconds until the ratelimit period resets.
    pub reset_after: u64,
    /// The total number of session starts within the ratelimit period allowed.
    pub total: u64,
}<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) edef <edef@edef.eu>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
extern crate std;
extern crate libc;

use self::std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use self::std::ptr;
use self::std::io::Error as IoError;
use self::libc::{c_void, c_int, size_t};
use self::libc::{mmap, mprotect, munmap};
use self::libc::MAP_FAILED;

const GUARD_PROT:  c_int = libc::PROT_NONE;
const STACK_PROT:  c_int = libc::PROT_READ
                         | libc::PROT_WRITE;
#[cfg(not(any(target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple")))]
const STACK_FLAGS: c_int = libc::MAP_STACK
                         | libc::MAP_PRIVATE
                         | libc::MAP_ANON;
// workaround for http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html
// according to libgreen, DragonFlyBSD suffers from this too
#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple"))]
const STACK_FLAGS: c_int = libc::MAP_PRIVATE
                         | libc::MAP_ANON;

pub unsafe fn map_stack(len: usize) -> Result<*mut u8, IoError> {
  let ptr = mmap(ptr::null_mut(), len as size_t, STACK_PROT, STACK_FLAGS, -1, 0);
  if ptr == MAP_FAILED {
    Err(IoError::last_os_error())
  } else {
    Ok(ptr as *mut u8)
  }
}

pub unsafe fn protect_stack(ptr: *mut u8) -> Result<(), IoError> {
  if mprotect(ptr as *mut c_void, page_size() as size_t, GUARD_PROT) == 0 {
    Ok(())
  } else {
    Err(IoError::last_os_error())
  }
}

pub unsafe fn unmap_stack(ptr: *mut u8, len: usize) -> Result<(), IoError> {
  if munmap(ptr as *mut c_void, len as size_t) == 0 {
    Ok(())
  } else {
    Err(IoError::last_os_error())
  }
}

pub fn page_size() -> usize {
  #[cold]
  pub fn sys_page_size() -> usize {
    unsafe {
      libc::sysconf(libc::_SC_PAGESIZE) as usize
    }
  }

  static PAGE_SIZE_CACHE: AtomicUsize = ATOMIC_USIZE_INIT;
  match PAGE_SIZE_CACHE.load(Ordering::Relaxed) {
    0 => {
      let page_size = sys_page_size();
      PAGE_SIZE_CACHE.store(page_size, Ordering::Relaxed);
      page_size
    }
    page_size => page_size
  }
}
<commit_msg>Fix AtomicUsize deprecation warning.<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) edef <edef@edef.eu>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
extern crate std;
extern crate libc;

use self::std::sync::atomic::{AtomicUsize, Ordering};
use self::std::ptr;
use self::std::io::Error as IoError;
use self::libc::{c_void, c_int, size_t};
use self::libc::{mmap, mprotect, munmap};
use self::libc::MAP_FAILED;

const GUARD_PROT:  c_int = libc::PROT_NONE;
const STACK_PROT:  c_int = libc::PROT_READ
                         | libc::PROT_WRITE;
#[cfg(not(any(target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple")))]
const STACK_FLAGS: c_int = libc::MAP_STACK
                         | libc::MAP_PRIVATE
                         | libc::MAP_ANON;
// workaround for http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html
// according to libgreen, DragonFlyBSD suffers from this too
#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple"))]
const STACK_FLAGS: c_int = libc::MAP_PRIVATE
                         | libc::MAP_ANON;

pub unsafe fn map_stack(len: usize) -> Result<*mut u8, IoError> {
  let ptr = mmap(ptr::null_mut(), len as size_t, STACK_PROT, STACK_FLAGS, -1, 0);
  if ptr == MAP_FAILED {
    Err(IoError::last_os_error())
  } else {
    Ok(ptr as *mut u8)
  }
}

pub unsafe fn protect_stack(ptr: *mut u8) -> Result<(), IoError> {
  if mprotect(ptr as *mut c_void, page_size() as size_t, GUARD_PROT) == 0 {
    Ok(())
  } else {
    Err(IoError::last_os_error())
  }
}

pub unsafe fn unmap_stack(ptr: *mut u8, len: usize) -> Result<(), IoError> {
  if munmap(ptr as *mut c_void, len as size_t) == 0 {
    Ok(())
  } else {
    Err(IoError::last_os_error())
  }
}

pub fn page_size() -> usize {
  #[cold]
  pub fn sys_page_size() -> usize {
    unsafe {
      libc::sysconf(libc::_SC_PAGESIZE) as usize
    }
  }

  static PAGE_SIZE_CACHE: AtomicUsize = AtomicUsize::new(0);
  match PAGE_SIZE_CACHE.load(Ordering::Relaxed) {
    0 => {
      let page_size = sys_page_size();
      PAGE_SIZE_CACHE.store(page_size, Ordering::Relaxed);
      page_size
    }
    page_size => page_size
  }
}
<|endoftext|>