<commit_before>use fool::BoolExt;
use std::borrow::Borrow;
use std::collections::{HashSet, VecDeque};
use std::marker::PhantomData;

use crate::graph::borrow::Reborrow;
use crate::graph::geometry::GraphGeometry;
use crate::graph::mutation::Consistent;
use crate::graph::storage::key::{ArcKey, VertexKey};
use crate::graph::storage::payload::{Arc, Vertex};
use crate::graph::storage::{AsStorage, AsStorageMut};
use crate::graph::view::edge::ArcView;
use crate::graph::view::face::RingView;
use crate::graph::view::vertex::VertexView;
use crate::graph::view::{Binding, View};
use crate::graph::{GraphError, OptionExt as _, Selector};
use crate::IteratorExt as _;

/// View of a path in a graph.
///
/// Provides a representation of non-intersecting paths in a graph. A path
/// is conceptually an ordered set of vertices that are joined by arcs. A path
/// over vertices $A$, $B$, and $C$ is notated $\overrightarrow{\\{A,B,C\\}}$.
///
/// `PathView` represents paths of the form
/// $\overrightarrow{\\{A,\cdots,B\\}}$, where $A$ is the back of the path and
/// $B$ is the front of the path. By convention, $A$ and $B$ label the
/// endpoints of such a path.
///
/// Paths have no associated payload and do not directly expose geometry
/// (`PathView` does not implement `Deref` or expose a `geometry` field). See
/// the module documentation for more information about topological views.
#[derive(Clone)]
pub struct PathView<M, G>
where
    M: Reborrow,
    M::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent,
    G: GraphGeometry,
{
    keys: VecDeque<ArcKey>,
    storage: M,
    phantom: PhantomData<G>,
}

impl<M, G> PathView<M, G>
where
    M: Reborrow,
    M::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent,
    G: GraphGeometry,
{
    // Paths bind multiple keys to storage and so do not support `View`,
    // `Orphan`, nor `Binding`. This bespoke `bind` function ensures that the
    // path is not empty and that the topology forms a non-intersecting path.
    pub(in crate::graph) fn bind<I>(storage: M, keys: I) -> Result<Self, GraphError>
    where
        I: IntoIterator,
        I::Item: Borrow<VertexKey>,
    {
        let mut keys = keys.into_iter().map(|key| *key.borrow());
        let a = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let b = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let ab = (a, b).into();
        View::<_, Arc<G>>::bind(storage.reborrow(), ab)
            .ok_or_else(|| GraphError::TopologyNotFound)?;
        let mut path = PathView {
            keys: (&[ab]).iter().cloned().collect(),
            storage,
            phantom: PhantomData,
        };
        for key in keys {
            path.push_front(Selector::ByKey(key))?;
        }
        Ok(path)
    }

    /// Pushes a vertex onto the back of the path.
    ///
    /// The back of a path $\overrightarrow{\\{A,\cdots,B\\}}$ is the vertex
    /// $A$. This is the source vertex of the first arc that forms the path.
    ///
    /// The given vertex must be a source vertex of an arc formed with the the
    /// back of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{\\{X,A\\}}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{\\{X,A\\}}$ inserted into
    /// the path using the given source vertex $X$.
    pub fn push_back(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let back = self.back();
        let xa = match destination {
            Selector::ByKey(key) => back
                .incoming_arcs()
                .find(|arc| arc.into_source_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = back
                    .neighboring_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (x, back.key()).into()
            }
        };
        let (x, _) = xa.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the front of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_back(xa);
            Ok(xa)
        }
    }

    /// Pops a vertex from the back of the path.
    pub fn pop_back(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_back()
        }
        else {
            None
        }
    }

    /// Pushes a vertex onto the front of the path.
    ///
    /// The front of a path $\overrightarrow{\\{A,\cdots,B\\}}$ is the vertex
    /// $B$. This is the destination vertex of the last arc that forms the
    /// path.
    ///
    /// The given vertex must be a destination vertex of an arc formed with the
    /// the front of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{\\{B,X\\}}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{\\{B,X\\}}$ inserted into
    /// the path using the given source vertex $X$.
    pub fn push_front(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let front = self.front();
        let bx = match destination {
            Selector::ByKey(key) => front
                .outgoing_arcs()
                .find(|arc| arc.into_destination_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = front
                    .neighboring_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (front.key(), x).into()
            }
        };
        let (_, x) = bx.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the back of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_destination_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_front(bx);
            Ok(bx)
        }
    }

    /// Pops a vertex from the front of the path.
    pub fn pop_front(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_front()
        }
        else {
            None
        }
    }

    /// Gets the vertex at the back of the path.
    pub fn back(&self) -> VertexView<&M::Target, G> {
        let (key, _) = self.endpoints();
        View::bind_into(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets the vertex at the front of the path.
    pub fn front(&self) -> VertexView<&M::Target, G> {
        let (_, key) = self.endpoints();
        View::bind_into(self.storage.reborrow(), key).expect_consistent()
    }

    /// Converts the path into the ring it bisects, if any.
    ///
    /// A path bisects a ring if it is open, is not a boundary path, and its
    /// endpoint vertices participate in the ring.
    ///
    /// Returns the ring bisected by the path if such a ring exists, otherwise
    /// `None`.
    pub fn into_bisected_ring(self) -> Option<RingView<M, G>> {
        // The path may bisect a ring if it is open and is not a boundary path.
        // Note that open boundary paths cannot bisect a ring, so such paths
        // are ignored.
        if self.is_open() && !self.is_boundary_path() {
            let back = self.back();
            let front = self.front();
            // Get the ring of the first boundary arc of the vertex at the back
            // of the path.
            let ring = back
                .outgoing_arcs()
                .flat_map(|arc| arc.into_boundary_arc())
                .map(|arc| arc.into_ring())
                .nth(0);
            // If there is such a ring and it also includes the vertex at the
            // front of the path, then it is bisected. Rebind the path's
            // storage into a `RingView`.
            ring.filter(|ring| ring.vertices().keys().any(|key| key == front.key()))
                .map(|ring| ring.into_arc().key())
                .map(move |key| {
                    let PathView { storage, .. } = self;
                    ArcView::from(View::bind_unchecked(storage, key)).into_ring()
                })
        }
        else {
            None
        }
    }

    /// Gets the ring bisected by the path, if any.
    pub fn bisected_ring(&self) -> Option<RingView<&M::Target, G>> {
        self.interior_reborrow().into_bisected_ring()
    }

    /// Gets an iterator over the vertices in the path.
    pub fn vertices(&self) -> impl Iterator<Item = VertexView<&M::Target, G>> {
        let back = self.back();
        Some(back)
            .into_iter()
            .chain(self.arcs().map(|arc| arc.into_destination_vertex()))
    }

    /// Gets an iterator over the arcs in the path.
    pub fn arcs(&self) -> impl ExactSizeIterator<Item = ArcView<&M::Target, G>> {
        let storage = self.storage.reborrow();
        self.keys
            .iter()
            .rev()
            .cloned()
            .map(move |key| View::bind_into(storage, key).expect_consistent())
    }

    /// Returns `true` if the path is open.
    ///
    /// An _open path_ is a path that terminates and does **not** form a loop.
    pub fn is_open(&self) -> bool {
        !self.is_closed()
    }

    /// Returns `true` if the path is closed.
    ///
    /// A _closed path_ is a path that forms a loop by starting and ending at
    /// the same vertex.
    pub fn is_closed(&self) -> bool {
        let (a, b) = self.endpoints();
        a == b
    }

    /// Returns `true` if the path is a boundary path.
    ///
    /// A _boundary path_ is a path where all arcs forming the path are
    /// boundary arcs.
    pub fn is_boundary_path(&self) -> bool {
        !self.arcs().any(|arc| !arc.is_boundary_arc())
    }

    /// Returns `true` if the path is a bisecting path.
    ///
    /// A _bisecting path_ is a path that bisects a surface in a graph. A
    /// closed path is always a bisecting path, but open paths are not
    /// necessarily bisecting. See `into_bisected_ring`.
    pub fn is_bisecting_path(&self) -> bool {
        self.is_closed() || self.bisected_ring().is_some()
    }

    fn bind_unchecked<I>(storage: M, keys: I) -> Self
    where
        I: IntoIterator,
        I::Item: Borrow<ArcKey>,
    {
        let keys = keys.into_iter().map(|key| *key.borrow()).collect();
        PathView {
            storage,
            keys,
            phantom: PhantomData,
        }
    }

    fn endpoints(&self) -> (VertexKey, VertexKey) {
        let (a, _) = self.keys.back().cloned().expect("empty path").into();
        let (_, b) = self.keys.front().cloned().expect("empty pathy").into();
        (a, b)
    }

    fn interior_reborrow(&self) -> PathView<&M::Target, G> {
        let storage = self.storage.reborrow();
        let keys = self.keys.iter();
        PathView::bind_unchecked(storage, keys)
    }
}

impl<'a, M, G> PathView<&'a mut M, G>
where
    M: 'a + AsStorageMut<Arc<G>> + AsStorageMut<Vertex<G>> + Consistent,
    G: 'a + GraphGeometry,
{
    /// Converts a mutable view into an immutable view.
    ///
    /// This is useful when mutations are not (or no longer) needed and mutual
    /// access is desired.
    pub fn into_ref(self) -> PathView<&'a M, G> {
        let PathView { keys, storage, .. } = self;
        PathView {
            keys,
            storage: &*storage,
            phantom: PhantomData,
        }
    }
}

impl<M, G> PartialEq for PathView<M, G>
where
    M: Reborrow,
    M::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent,
    G: GraphGeometry,
{
    fn eq(&self, other: &Self) -> bool {
        let keys = |path: &Self| path.arcs().keys().collect::<HashSet<_>>();
        keys(self) == keys(other)
    }
}

#[cfg(test)]
mod tests {
    use nalgebra::Point2;

    use crate::graph::{Binding, MeshGraph, Selector};
    use crate::primitive::Trigon;
    use crate::{FromRawBuffers, IteratorExt};

    use Selector::ByKey;

    type E2 = Point2<f64>;

    #[test]
    fn open_close() {
        let graph = MeshGraph::<E2>::from_raw_buffers(
            vec![Trigon::from([0usize, 1, 2])],
            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)],
        )
        .unwrap();
        let keys = graph
            .faces()
            .nth(0)
            .unwrap()
            .interior_arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .collect::<Vec<_>>();

        let mut path = graph.path(keys.iter()).unwrap();
        assert!(path.is_open());
        // TODO: Move this assertion to a distinct test.
        assert_eq!(path.vertices().keys().collect::<Vec<_>>(), keys.to_vec());

        path.push_front(ByKey(keys[0])).unwrap();
        assert!(path.is_closed());
        assert_eq!(path.front().key(), path.back().key());
    }
}
<commit_msg>Use arc notation in path documentation.<commit_after>use fool::BoolExt;
use std::borrow::Borrow;
use std::collections::{HashSet, VecDeque};
use std::marker::PhantomData;

use crate::graph::borrow::Reborrow;
use crate::graph::geometry::GraphGeometry;
use crate::graph::mutation::Consistent;
use crate::graph::storage::key::{ArcKey, VertexKey};
use crate::graph::storage::payload::{Arc, Vertex};
use crate::graph::storage::{AsStorage, AsStorageMut};
use crate::graph::view::edge::ArcView;
use crate::graph::view::face::RingView;
use crate::graph::view::vertex::VertexView;
use crate::graph::view::{Binding, View};
use crate::graph::{GraphError, OptionExt as _, Selector};
use crate::IteratorExt as _;

/// View of a path in a graph.
///
/// Provides a representation of non-intersecting paths in a graph. A path
/// is conceptually an ordered set of vertices that are joined by arcs. A path
/// over vertices $A$, $B$, and $C$ is notated $\overrightarrow{\\{A,B,C\\}}$.
///
/// `PathView` represents paths of the form
/// $\overrightarrow{\\{A,\cdots,B\\}}$, where $A$ is the back of the path and
/// $B$ is the front of the path. By convention, $A$ and $B$ label the
/// endpoints of such a path.
///
/// Paths have no associated payload and do not directly expose geometry
/// (`PathView` does not implement `Deref` or expose a `geometry` field). See
/// the module documentation for more information about topological views.
#[derive(Clone)]
pub struct PathView<M, G>
where
    M: Reborrow,
    M::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent,
    G: GraphGeometry,
{
    keys: VecDeque<ArcKey>,
    storage: M,
    phantom: PhantomData<G>,
}

impl<M, G> PathView<M, G>
where
    M: Reborrow,
    M::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent,
    G: GraphGeometry,
{
    // Paths bind multiple keys to storage and so do not support `View`,
    // `Orphan`, nor `Binding`. This bespoke `bind` function ensures that the
    // path is not empty and that the topology forms a non-intersecting path.
    pub(in crate::graph) fn bind<I>(storage: M, keys: I) -> Result<Self, GraphError>
    where
        I: IntoIterator,
        I::Item: Borrow<VertexKey>,
    {
        let mut keys = keys.into_iter().map(|key| *key.borrow());
        let a = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let b = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let ab = (a, b).into();
        View::<_, Arc<G>>::bind(storage.reborrow(), ab)
            .ok_or_else(|| GraphError::TopologyNotFound)?;
        let mut path = PathView {
            keys: (&[ab]).iter().cloned().collect(),
            storage,
            phantom: PhantomData,
        };
        for key in keys {
            path.push_front(Selector::ByKey(key))?;
        }
        Ok(path)
    }

    /// Pushes a vertex onto the back of the path.
    ///
    /// The back of a path $\overrightarrow{\\{A,\cdots,B\\}}$ is the vertex
    /// $A$. This is the source vertex of the first arc that forms the path.
    ///
    /// The given vertex must be a source vertex of an arc formed with the the
    /// back of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{XA}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{XA}$ inserted into the path
    /// using the given source vertex $X$.
    pub fn push_back(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let back = self.back();
        let xa = match destination {
            Selector::ByKey(key) => back
                .incoming_arcs()
                .find(|arc| arc.into_source_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = back
                    .neighboring_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (x, back.key()).into()
            }
        };
        let (x, _) = xa.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the front of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_back(xa);
            Ok(xa)
        }
    }

    /// Pops a vertex from the back of the path.
    pub fn pop_back(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_back()
        }
        else {
            None
        }
    }

    /// Pushes a vertex onto the front of the path.
    ///
    /// The front of a path $\overrightarrow{\\{A,\cdots,B\\}}$ is the vertex
    /// $B$. This is the destination vertex of the last arc that forms the
    /// path.
    ///
    /// The given vertex must be a destination vertex of an arc formed with the
    /// the front of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{BX}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{BX}$ inserted into the path
    /// using the given source vertex $X$.
    pub fn push_front(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let front = self.front();
        let bx = match destination {
            Selector::ByKey(key) => front
                .outgoing_arcs()
                .find(|arc| arc.into_destination_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = front
                    .neighboring_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (front.key(), x).into()
            }
        };
        let (_, x) = bx.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the back of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_destination_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_front(bx);
            Ok(bx)
        }
    }

    /// Pops a vertex from the front of the path.
    pub fn pop_front(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_front()
        }
        else {
            None
        }
    }

    /// Gets the vertex at the back of the path.
    pub fn back(&self) -> VertexView<&M::Target, G> {
        let (key, _) = self.endpoints();
        View::bind_into(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets the vertex at the front of the path.
    pub fn front(&self) -> VertexView<&M::Target, G> {
        let (_, key) = self.endpoints();
        View::bind_into(self.storage.reborrow(), key).expect_consistent()
    }

    /// Converts the path into the ring it bisects, if any.
    ///
    /// A path bisects a ring if it is open, is not a boundary path, and its
    /// endpoint vertices participate in the ring.
    ///
    /// Returns the ring bisected by the path if such a ring exists, otherwise
    /// `None`.
    pub fn into_bisected_ring(self) -> Option<RingView<M, G>> {
        // The path may bisect a ring if it is open and is not a boundary path.
        // Note that open boundary paths cannot bisect a ring, so such paths
        // are ignored.
        if self.is_open() && !self.is_boundary_path() {
            let back = self.back();
            let front = self.front();
            // Get the ring of the first boundary arc of the vertex at the back
            // of the path.
            let ring = back
                .outgoing_arcs()
                .flat_map(|arc| arc.into_boundary_arc())
                .map(|arc| arc.into_ring())
                .nth(0);
            // If there is such a ring and it also includes the vertex at the
            // front of the path, then it is bisected. Rebind the path's
            // storage into a `RingView`.
            ring.filter(|ring| ring.vertices().keys().any(|key| key == front.key()))
                .map(|ring| ring.into_arc().key())
                .map(move |key| {
                    let PathView { storage, .. } = self;
                    ArcView::from(View::bind_unchecked(storage, key)).into_ring()
                })
        }
        else {
            None
        }
    }

    /// Gets the ring bisected by the path, if any.
    pub fn bisected_ring(&self) -> Option<RingView<&M::Target, G>> {
        self.interior_reborrow().into_bisected_ring()
    }

    /// Gets an iterator over the vertices in the path.
    pub fn vertices(&self) -> impl Iterator<Item = VertexView<&M::Target, G>> {
        let back = self.back();
        Some(back)
            .into_iter()
            .chain(self.arcs().map(|arc| arc.into_destination_vertex()))
    }

    /// Gets an iterator over the arcs in the path.
    pub fn arcs(&self) -> impl ExactSizeIterator<Item = ArcView<&M::Target, G>> {
        let storage = self.storage.reborrow();
        self.keys
            .iter()
            .rev()
            .cloned()
            .map(move |key| View::bind_into(storage, key).expect_consistent())
    }

    /// Returns `true` if the path is open.
    ///
    /// An _open path_ is a path that terminates and does **not** form a loop.
    pub fn is_open(&self) -> bool {
        !self.is_closed()
    }

    /// Returns `true` if the path is closed.
    ///
    /// A _closed path_ is a path that forms a loop by starting and ending at
    /// the same vertex.
    pub fn is_closed(&self) -> bool {
        let (a, b) = self.endpoints();
        a == b
    }

    /// Returns `true` if the path is a boundary path.
    ///
    /// A _boundary path_ is a path where all arcs forming the path are
    /// boundary arcs.
    pub fn is_boundary_path(&self) -> bool {
        !self.arcs().any(|arc| !arc.is_boundary_arc())
    }

    /// Returns `true` if the path is a bisecting path.
    ///
    /// A _bisecting path_ is a path that bisects a surface in a graph. A
    /// closed path is always a bisecting path, but open paths are not
    /// necessarily bisecting. See `into_bisected_ring`.
    pub fn is_bisecting_path(&self) -> bool {
        self.is_closed() || self.bisected_ring().is_some()
    }

    fn bind_unchecked<I>(storage: M, keys: I) -> Self
    where
        I: IntoIterator,
        I::Item: Borrow<ArcKey>,
    {
        let keys = keys.into_iter().map(|key| *key.borrow()).collect();
        PathView {
            storage,
            keys,
            phantom: PhantomData,
        }
    }

    fn endpoints(&self) -> (VertexKey, VertexKey) {
        let (a, _) = self.keys.back().cloned().expect("empty path").into();
        let (_, b) = self.keys.front().cloned().expect("empty pathy").into();
        (a, b)
    }

    fn interior_reborrow(&self) -> PathView<&M::Target, G> {
        let storage = self.storage.reborrow();
        let keys = self.keys.iter();
        PathView::bind_unchecked(storage, keys)
    }
}

impl<'a, M, G> PathView<&'a mut M, G>
where
    M: 'a + AsStorageMut<Arc<G>> + AsStorageMut<Vertex<G>> + Consistent,
    G: 'a + GraphGeometry,
{
    /// Converts a mutable view into an immutable view.
    ///
    /// This is useful when mutations are not (or no longer) needed and mutual
    /// access is desired.
    pub fn into_ref(self) -> PathView<&'a M, G> {
        let PathView { keys, storage, .. } = self;
        PathView {
            keys,
            storage: &*storage,
            phantom: PhantomData,
        }
    }
}

impl<M, G> PartialEq for PathView<M, G>
where
    M: Reborrow,
    M::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent,
    G: GraphGeometry,
{
    fn eq(&self, other: &Self) -> bool {
        let keys = |path: &Self| path.arcs().keys().collect::<HashSet<_>>();
        keys(self) == keys(other)
    }
}

#[cfg(test)]
mod tests {
    use nalgebra::Point2;

    use crate::graph::{Binding, MeshGraph, Selector};
    use crate::primitive::Trigon;
    use crate::{FromRawBuffers, IteratorExt};

    use Selector::ByKey;

    type E2 = Point2<f64>;

    #[test]
    fn open_close() {
        let graph = MeshGraph::<E2>::from_raw_buffers(
            vec![Trigon::from([0usize, 1, 2])],
            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)],
        )
        .unwrap();
        let keys = graph
            .faces()
            .nth(0)
            .unwrap()
            .interior_arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .collect::<Vec<_>>();

        let mut path = graph.path(keys.iter()).unwrap();
        assert!(path.is_open());
        // TODO: Move this assertion to a distinct test.
        assert_eq!(path.vertices().keys().collect::<Vec<_>>(), keys.to_vec());

        path.push_front(ByKey(keys[0])).unwrap();
        assert!(path.is_closed());
        assert_eq!(path.front().key(), path.back().key());
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

//! Implementation of a Micro Transport Protocol library,
//! as well as a small client and server.
//!
//! http://www.bittorrent.org/beps/bep_0029.html

extern crate utp;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

fn usage() {
    println!("Usage: utp [-s|-c] <address> <port>");
}

fn main() {
    use utp::UtpStream;
    use std::from_str::FromStr;

    // Defaults
    static BUF_SIZE: uint = 4096;
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

	if args.len() != 2 && args.len() != 4 {
		usage();
		return;
	}

    if args.len() == 4 {
        addr = SocketAddr {
            ip:   FromStr::from_str(args[2].as_slice()).unwrap(),
            port: FromStr::from_str(args[3].as_slice()).unwrap(),
        };
    }

    match args[1].as_slice() {
        "-s" => {
            let mut buf = [0, ..BUF_SIZE];
            let mut stream = UtpStream::bind(addr);

            println!("Serving on {}", addr);

            loop {
                match stream.read(buf) {
                    Ok(_read) => {}
                    Err(e) => fail!("{}", e),
                }
            }
        }
        "-c" => {
            let mut stream = UtpStream::connect(addr);

            let buf = [0xF, ..BUF_SIZE];
            match stream.write(buf) {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }

            match stream.close() {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }
            drop(stream);
        }
        _ => usage(),
    }
}
<commit_msg>Example program now reads user input in client mode.<commit_after>#![feature(macro_rules)]

//! Implementation of a Micro Transport Protocol library,
//! as well as a small client and server.
//!
//! http://www.bittorrent.org/beps/bep_0029.html

extern crate utp;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

fn usage() {
    println!("Usage: utp [-s|-c] <address> <port>");
}

fn main() {
    use utp::UtpStream;
    use std::from_str::FromStr;
    use std::io::{stdin, EndOfFile};

    // Defaults
    static BUF_SIZE: uint = 4096;
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

	if args.len() != 2 && args.len() != 4 {
		usage();
		return;
	}

    if args.len() == 4 {
        addr = SocketAddr {
            ip:   FromStr::from_str(args[2].as_slice()).unwrap(),
            port: FromStr::from_str(args[3].as_slice()).unwrap(),
        };
    }

    match args[1].as_slice() {
        "-s" => {
            let mut buf = [0, ..BUF_SIZE];
            let mut stream = UtpStream::bind(addr);

            println!("Serving on {}", addr);

            loop {
                match stream.read(buf) {
                    Ok(_read) => {}
                    Err(e) => fail!("{}", e),
                }
            }
        }
        "-c" => {
            let mut stream = UtpStream::connect(addr);
            let mut buf = [0, ..BUF_SIZE];
            let mut reader = stdin();

            loop {
                match reader.read(buf) {
                    Ok(nread) => stream.write(buf.slice(0, nread)),
                    Err(ref e) if e.kind == EndOfFile => break,
                    Err(e) => fail!("{}", e),
                };
            }

            match stream.close() {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }
            drop(stream);
        }
        _ => usage(),
    }
}
<|endoftext|>


<commit_before>use graph::Graph;
use maximum_flow::maximum_flow;

use std::u32;

pub fn edge_connectivity(g: &Graph) -> u32 {
    assert!(!g.directed, "This edge connectivity algorithm only supports undirected graphs");

    let mut connectivity = u32::MAX;

    for i in 1..g.vertex_count {
        let flow = maximum_flow(g, 0, i);
        if flow < connectivity {
            connectivity = flow;
        }
    }

    connectivity
}
<commit_msg>[edge_connectivity/rust] Replace for loop by map/min<commit_after>use graph::Graph;
use maximum_flow::maximum_flow;

pub fn edge_connectivity(g: &Graph) -> u32 {
    assert!(!g.directed, "This edge connectivity algorithm only supports undirected graphs");

    let maximum_flows = (1..g.vertex_count).map(|i| maximum_flow(g, 0, i));

    match maximum_flows.min() {
        Some(connectivity) => connectivity,
        None => 0,
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::DiagnosticsResult;
use errors::{validate, validate_map};

use crate::ir::*;
use crate::program::Program;

pub trait Validator {
    const NAME: &'static str;
    const VALIDATE_ARGUMENTS: bool;
    const VALIDATE_DIRECTIVES: bool;

    fn validate_program(&mut self, program: &Program) -> DiagnosticsResult<()> {
        self.default_validate_program(program)
    }

    fn default_validate_program(&mut self, program: &Program) -> DiagnosticsResult<()> {
        validate!(
            validate_map(program.operations(), |operation| {
                self.validate_operation(operation)
            }),
            validate_map(program.fragments(), |fragment| {
                self.validate_fragment(fragment)
            })
        )
    }

    // Fragment Definition
    fn validate_fragment(&mut self, fragment: &FragmentDefinition) -> DiagnosticsResult<()> {
        self.default_validate_fragment(fragment)
    }

    fn default_validate_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> DiagnosticsResult<()> {
        validate!(
            self.validate_selections(&fragment.selections),
            self.validate_directives(&fragment.directives)
        )
    }

    // Operation Definition
    fn validate_operation(&mut self, operation: &OperationDefinition) -> DiagnosticsResult<()> {
        self.default_validate_operation(operation)
    }

    fn default_validate_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> DiagnosticsResult<()> {
        validate!(
            self.validate_directives(&operation.directives),
            self.validate_selections(&operation.selections)
        )
    }

    // Selection
    fn validate_selections(&mut self, selections: &[Selection]) -> DiagnosticsResult<()> {
        self.validate_list(selections, Self::validate_selection)
    }

    fn validate_selection(&mut self, selection: &Selection) -> DiagnosticsResult<()> {
        self.default_validate_selection(selection)
    }

    fn default_validate_selection(&mut self, selection: &Selection) -> DiagnosticsResult<()> {
        match selection {
            Selection::FragmentSpread(selection) => self.validate_fragment_spread(selection),
            Selection::InlineFragment(selection) => self.validate_inline_fragment(selection),
            Selection::LinkedField(selection) => self.validate_linked_field(selection),
            Selection::ScalarField(selection) => self.validate_scalar_field(selection),
            Selection::Condition(selection) => self.validate_condition(selection),
        }
    }

    // Selection Kinds
    fn validate_scalar_field(&mut self, field: &ScalarField) -> DiagnosticsResult<()> {
        self.default_validate_scalar_field(field)
    }

    fn default_validate_scalar_field(&mut self, field: &ScalarField) -> DiagnosticsResult<()> {
        validate!(
            self.validate_arguments(&field.arguments),
            self.validate_directives(&field.directives)
        )
    }

    fn validate_linked_field(&mut self, field: &LinkedField) -> DiagnosticsResult<()> {
        self.default_validate_linked_field(field)
    }

    fn default_validate_linked_field(&mut self, field: &LinkedField) -> DiagnosticsResult<()> {
        validate!(
            self.validate_selections(&field.selections),
            self.validate_arguments(&field.arguments),
            self.validate_directives(&field.directives)
        )
    }

    fn validate_inline_fragment(&mut self, fragment: &InlineFragment) -> DiagnosticsResult<()> {
        self.default_validate_inline_fragment(fragment)
    }

    fn default_validate_inline_fragment(
        &mut self,
        fragment: &InlineFragment,
    ) -> DiagnosticsResult<()> {
        validate!(
            self.validate_selections(&fragment.selections),
            self.validate_directives(&fragment.directives)
        )
    }

    fn validate_fragment_spread(&mut self, spread: &FragmentSpread) -> DiagnosticsResult<()> {
        self.default_validate_fragment_spread(spread)
    }

    fn default_validate_fragment_spread(
        &mut self,
        spread: &FragmentSpread,
    ) -> DiagnosticsResult<()> {
        validate!(
            self.validate_arguments(&spread.arguments),
            self.validate_directives(&spread.directives)
        )
    }

    fn validate_condition(&mut self, condition: &Condition) -> DiagnosticsResult<()> {
        self.default_validate_condition(condition)
    }

    fn default_validate_condition(&mut self, condition: &Condition) -> DiagnosticsResult<()> {
        validate!(
            self.validate_condition_value(&condition.value),
            self.validate_selections(&condition.selections)
        )
    }

    fn validate_condition_value(
        &mut self,
        condition_value: &ConditionValue,
    ) -> DiagnosticsResult<()> {
        self.default_validate_condition_value(condition_value)
    }

    fn default_validate_condition_value(
        &mut self,
        condition_value: &ConditionValue,
    ) -> DiagnosticsResult<()> {
        if Self::VALIDATE_ARGUMENTS {
            match condition_value {
                ConditionValue::Variable(variable) => self.validate_variable(variable),
                ConditionValue::Constant(_) => Ok(()),
            }
        } else {
            Ok(())
        }
    }

    // Directives
    fn validate_directives(&mut self, directives: &[Directive]) -> DiagnosticsResult<()> {
        if Self::VALIDATE_DIRECTIVES {
            self.validate_list(directives, Self::validate_directive)
        } else {
            Ok(())
        }
    }

    fn validate_directive(&mut self, directive: &Directive) -> DiagnosticsResult<()> {
        self.default_validate_directive(directive)
    }

    fn default_validate_directive(&mut self, directive: &Directive) -> DiagnosticsResult<()> {
        self.validate_arguments(&directive.arguments)
    }

    // Arguments
    fn validate_arguments(&mut self, arguments: &[Argument]) -> DiagnosticsResult<()> {
        if Self::VALIDATE_ARGUMENTS {
            self.validate_list(arguments, Self::validate_argument)?;
        }
        Ok(())
    }

    fn validate_argument(&mut self, argument: &Argument) -> DiagnosticsResult<()> {
        self.default_validate_argument(argument)
    }

    fn default_validate_argument(&mut self, argument: &Argument) -> DiagnosticsResult<()> {
        self.validate_value(&argument.value.item)
    }

    // Values
    fn validate_value(&mut self, value: &Value) -> DiagnosticsResult<()> {
        self.default_validate_value(value)
    }

    fn default_validate_value(&mut self, value: &Value) -> DiagnosticsResult<()> {
        match value {
            Value::Variable(variable) => self.validate_variable(variable),
            Value::Constant(_) => Ok(()),
            Value::List(items) => self.validate_list(items, Self::validate_value),
            Value::Object(arguments) => self.validate_arguments(arguments),
        }
    }

    fn validate_variable(&mut self, value: &Variable) -> DiagnosticsResult<()> {
        let _ = value;
        Ok(())
    }

    // Helpers
    fn validate_list<F, T>(&mut self, list: &[T], f: F) -> DiagnosticsResult<()>
    where
        F: Fn(&mut Self, &T) -> DiagnosticsResult<()>,
        T: Clone,
    {
        validate_map(list, |item| f(self, item))
    }
}
<commit_msg>Remove T: Clone bound from validate_list<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::DiagnosticsResult;
use errors::{validate, validate_map};

use crate::ir::*;
use crate::program::Program;

pub trait Validator {
    const NAME: &'static str;
    const VALIDATE_ARGUMENTS: bool;
    const VALIDATE_DIRECTIVES: bool;

    fn validate_program(&mut self, program: &Program) -> DiagnosticsResult<()> {
        self.default_validate_program(program)
    }

    fn default_validate_program(&mut self, program: &Program) -> DiagnosticsResult<()> {
        validate!(
            validate_map(program.operations(), |operation| {
                self.validate_operation(operation)
            }),
            validate_map(program.fragments(), |fragment| {
                self.validate_fragment(fragment)
            })
        )
    }

    // Fragment Definition
    fn validate_fragment(&mut self, fragment: &FragmentDefinition) -> DiagnosticsResult<()> {
        self.default_validate_fragment(fragment)
    }

    fn default_validate_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> DiagnosticsResult<()> {
        validate!(
            self.validate_selections(&fragment.selections),
            self.validate_directives(&fragment.directives)
        )
    }

    // Operation Definition
    fn validate_operation(&mut self, operation: &OperationDefinition) -> DiagnosticsResult<()> {
        self.default_validate_operation(operation)
    }

    fn default_validate_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> DiagnosticsResult<()> {
        validate!(
            self.validate_directives(&operation.directives),
            self.validate_selections(&operation.selections)
        )
    }

    // Selection
    fn validate_selections(&mut self, selections: &[Selection]) -> DiagnosticsResult<()> {
        self.validate_list(selections, Self::validate_selection)
    }

    fn validate_selection(&mut self, selection: &Selection) -> DiagnosticsResult<()> {
        self.default_validate_selection(selection)
    }

    fn default_validate_selection(&mut self, selection: &Selection) -> DiagnosticsResult<()> {
        match selection {
            Selection::FragmentSpread(selection) => self.validate_fragment_spread(selection),
            Selection::InlineFragment(selection) => self.validate_inline_fragment(selection),
            Selection::LinkedField(selection) => self.validate_linked_field(selection),
            Selection::ScalarField(selection) => self.validate_scalar_field(selection),
            Selection::Condition(selection) => self.validate_condition(selection),
        }
    }

    // Selection Kinds
    fn validate_scalar_field(&mut self, field: &ScalarField) -> DiagnosticsResult<()> {
        self.default_validate_scalar_field(field)
    }

    fn default_validate_scalar_field(&mut self, field: &ScalarField) -> DiagnosticsResult<()> {
        validate!(
            self.validate_arguments(&field.arguments),
            self.validate_directives(&field.directives)
        )
    }

    fn validate_linked_field(&mut self, field: &LinkedField) -> DiagnosticsResult<()> {
        self.default_validate_linked_field(field)
    }

    fn default_validate_linked_field(&mut self, field: &LinkedField) -> DiagnosticsResult<()> {
        validate!(
            self.validate_selections(&field.selections),
            self.validate_arguments(&field.arguments),
            self.validate_directives(&field.directives)
        )
    }

    fn validate_inline_fragment(&mut self, fragment: &InlineFragment) -> DiagnosticsResult<()> {
        self.default_validate_inline_fragment(fragment)
    }

    fn default_validate_inline_fragment(
        &mut self,
        fragment: &InlineFragment,
    ) -> DiagnosticsResult<()> {
        validate!(
            self.validate_selections(&fragment.selections),
            self.validate_directives(&fragment.directives)
        )
    }

    fn validate_fragment_spread(&mut self, spread: &FragmentSpread) -> DiagnosticsResult<()> {
        self.default_validate_fragment_spread(spread)
    }

    fn default_validate_fragment_spread(
        &mut self,
        spread: &FragmentSpread,
    ) -> DiagnosticsResult<()> {
        validate!(
            self.validate_arguments(&spread.arguments),
            self.validate_directives(&spread.directives)
        )
    }

    fn validate_condition(&mut self, condition: &Condition) -> DiagnosticsResult<()> {
        self.default_validate_condition(condition)
    }

    fn default_validate_condition(&mut self, condition: &Condition) -> DiagnosticsResult<()> {
        validate!(
            self.validate_condition_value(&condition.value),
            self.validate_selections(&condition.selections)
        )
    }

    fn validate_condition_value(
        &mut self,
        condition_value: &ConditionValue,
    ) -> DiagnosticsResult<()> {
        self.default_validate_condition_value(condition_value)
    }

    fn default_validate_condition_value(
        &mut self,
        condition_value: &ConditionValue,
    ) -> DiagnosticsResult<()> {
        if Self::VALIDATE_ARGUMENTS {
            match condition_value {
                ConditionValue::Variable(variable) => self.validate_variable(variable),
                ConditionValue::Constant(_) => Ok(()),
            }
        } else {
            Ok(())
        }
    }

    // Directives
    fn validate_directives(&mut self, directives: &[Directive]) -> DiagnosticsResult<()> {
        if Self::VALIDATE_DIRECTIVES {
            self.validate_list(directives, Self::validate_directive)
        } else {
            Ok(())
        }
    }

    fn validate_directive(&mut self, directive: &Directive) -> DiagnosticsResult<()> {
        self.default_validate_directive(directive)
    }

    fn default_validate_directive(&mut self, directive: &Directive) -> DiagnosticsResult<()> {
        self.validate_arguments(&directive.arguments)
    }

    // Arguments
    fn validate_arguments(&mut self, arguments: &[Argument]) -> DiagnosticsResult<()> {
        if Self::VALIDATE_ARGUMENTS {
            self.validate_list(arguments, Self::validate_argument)?;
        }
        Ok(())
    }

    fn validate_argument(&mut self, argument: &Argument) -> DiagnosticsResult<()> {
        self.default_validate_argument(argument)
    }

    fn default_validate_argument(&mut self, argument: &Argument) -> DiagnosticsResult<()> {
        self.validate_value(&argument.value.item)
    }

    // Values
    fn validate_value(&mut self, value: &Value) -> DiagnosticsResult<()> {
        self.default_validate_value(value)
    }

    fn default_validate_value(&mut self, value: &Value) -> DiagnosticsResult<()> {
        match value {
            Value::Variable(variable) => self.validate_variable(variable),
            Value::Constant(_) => Ok(()),
            Value::List(items) => self.validate_list(items, Self::validate_value),
            Value::Object(arguments) => self.validate_arguments(arguments),
        }
    }

    fn validate_variable(&mut self, value: &Variable) -> DiagnosticsResult<()> {
        let _ = value;
        Ok(())
    }

    // Helpers
    fn validate_list<F, T>(&mut self, list: &[T], f: F) -> DiagnosticsResult<()>
    where
        F: Fn(&mut Self, &T) -> DiagnosticsResult<()>,
    {
        validate_map(list, |item| f(self, item))
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

// extern crate prost_build;
use std::io::Result;
use std::path::PathBuf;

const PROTOS: &'static [&'static str] = &[
    "fleetspeak/fleetspeak/src/common/proto/fleetspeak/common.proto",
    "fleetspeak/fleetspeak/src/client/channel/proto/fleetspeak_channel/channel.proto",
];

const INCLUDES: &'static [&'static str] = &[
    "fleetspeak/fleetspeak/src",
];

fn cargo_out_dir() -> PathBuf {
    let out_dir = std::env::var("OUT_DIR")
        .expect("output folder not specified");

    PathBuf::from(out_dir)
}

fn proto_out_dir() -> PathBuf {
    cargo_out_dir().join("proto")
}

fn main() -> Result<()> {
    let proto_out_dir = proto_out_dir();
    std::fs::create_dir_all(&proto_out_dir)?;

    protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
        out_dir: &proto_out_dir.to_str().unwrap(),
        includes: INCLUDES,
        input: PROTOS,
        customize: protobuf_codegen_pure::Customize {
            gen_mod_rs: Some(true),
            ..Default::default()
        },
    })?;

    prost_build::compile_protos(PROTOS, INCLUDES)
}
<commit_msg>Use non-deprecated code generator tools.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

// extern crate prost_build;
use std::io::Result;
use std::path::PathBuf;

const PROTOS: &'static [&'static str] = &[
    "fleetspeak/fleetspeak/src/common/proto/fleetspeak/common.proto",
    "fleetspeak/fleetspeak/src/client/channel/proto/fleetspeak_channel/channel.proto",
];

const INCLUDES: &'static [&'static str] = &[
    "fleetspeak/fleetspeak/src",
];

fn cargo_out_dir() -> PathBuf {
    let out_dir = std::env::var("OUT_DIR")
        .expect("output folder not specified");

    PathBuf::from(out_dir)
}

fn proto_out_dir() -> PathBuf {
    cargo_out_dir().join("proto")
}

fn main() -> Result<()> {
    let proto_out_dir = proto_out_dir();
    std::fs::create_dir_all(&proto_out_dir)?;

    protobuf_codegen_pure::Codegen::new()
        .out_dir(&proto_out_dir.to_str().unwrap())
        .includes(INCLUDES)
        .inputs(PROTOS)
        .customize(protobuf_codegen_pure::Customize {
            gen_mod_rs: Some(true),
            ..Default::default()
        })
        .run()?;

    prost_build::compile_protos(PROTOS, INCLUDES)
}
<|endoftext|>


<commit_before>/// A library for performing deterministic, pseudo-random shuffling on a vector.
///
/// This library is designed to confirm to the Ethereum 2.0 specification.
extern crate hashing;

mod rng;

use self::rng::ShuffleRng;

#[derive(Debug)]
pub enum ShuffleErr {
    ExceedsListLength,
}

/// Performs a deterministic, in-place shuffle of a vector.
///
/// The final order of the shuffle is determined by successive hashes
/// of the supplied `seed`.
///
/// This is a Fisher-Yates-Durtstenfeld shuffle.
pub fn shuffle<T>(seed: &[u8], mut list: Vec<T>) -> Result<Vec<T>, ShuffleErr> {
    let mut rng = ShuffleRng::new(seed);

    if list.len() > rng.rand_max as usize {
        return Err(ShuffleErr::ExceedsListLength);
    }

    if list.is_empty() {
        return Ok(list);
    }

    for i in 0..(list.len().saturating_sub(1)) {
        let n = list.len() - i;
        let j = rng.rand_range(n as u32) as usize + i;
        list.swap(i, j);
    }
    Ok(list)
}

#[cfg(test)]
mod tests {
    extern crate yaml_rust;

    use self::yaml_rust::yaml;
    use super::hashing::canonical_hash;
    use super::*;
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_shuffling() {
        let mut file = File::open("./src/specs/shuffle_test_vectors.yaml").unwrap();
        let mut yaml_str = String::new();

        file.read_to_string(&mut yaml_str).unwrap();

        let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
        let doc = &docs[0];
        let test_cases = doc["test_cases"].as_vec();

        for test_case in test_cases.unwrap() {
            let input = test_case["input"].clone().into_vec().unwrap();
            let output = test_case["output"].clone().into_vec().unwrap();
            let seed_bytes = test_case["seed"].as_str().unwrap().as_bytes();
            let mut seed;

            if seed_bytes.len() > 0 {
                seed = canonical_hash(seed_bytes);
            } else {
                seed = vec![];
            }

            let mut s = shuffle(&seed, input).unwrap();

            assert_eq!(s, output);
        }
    }
}
<commit_msg>removed unnecessary call to saturated_sub() in vec_shuffle<commit_after>/// A library for performing deterministic, pseudo-random shuffling on a vector.
///
/// This library is designed to confirm to the Ethereum 2.0 specification.
extern crate hashing;

mod rng;

use self::rng::ShuffleRng;

#[derive(Debug)]
pub enum ShuffleErr {
    ExceedsListLength,
}

/// Performs a deterministic, in-place shuffle of a vector.
///
/// The final order of the shuffle is determined by successive hashes
/// of the supplied `seed`.
///
/// This is a Fisher-Yates-Durtstenfeld shuffle.
pub fn shuffle<T>(seed: &[u8], mut list: Vec<T>) -> Result<Vec<T>, ShuffleErr> {
    let mut rng = ShuffleRng::new(seed);

    if list.len() > rng.rand_max as usize {
        return Err(ShuffleErr::ExceedsListLength);
    }

    if list.is_empty() {
        return Ok(list);
    }

    for i in 0..(list.len() - 1) {
        let n = list.len() - i;
        let j = rng.rand_range(n as u32) as usize + i;
        list.swap(i, j);
    }
    Ok(list)
}

#[cfg(test)]
mod tests {
    extern crate yaml_rust;

    use self::yaml_rust::yaml;
    use super::hashing::canonical_hash;
    use super::*;
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_shuffling() {
        let mut file = File::open("./src/specs/shuffle_test_vectors.yaml").unwrap();
        let mut yaml_str = String::new();

        file.read_to_string(&mut yaml_str).unwrap();

        let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
        let doc = &docs[0];
        let test_cases = doc["test_cases"].as_vec();

        for test_case in test_cases.unwrap() {
            let input = test_case["input"].clone().into_vec().unwrap();
            let output = test_case["output"].clone().into_vec().unwrap();
            let seed_bytes = test_case["seed"].as_str().unwrap().as_bytes();
            let mut seed;

            if seed_bytes.len() > 0 {
                seed = canonical_hash(seed_bytes);
            } else {
                seed = vec![];
            }

            let mut s = shuffle(&seed, input).unwrap();

            assert_eq!(s, output);
        }
    }
}
<|endoftext|>


<commit_before>use self::ItemType::*;
use std::io;
use std::io::Write;
use str::GopherStr;
use tokio_core::io::EasyBuf;

/// A client-to-server message.
#[derive(Clone, Debug)]
pub struct GopherRequest {
    /// Identifier of the resource to fetch. May be an empty string.
    pub selector: GopherStr,
    /// Search string for a full-text search transaction.
    pub query: Option<GopherStr>
}

impl GopherRequest {
    /// Read a Gopher request from a buffer containing a line *without* the trailing CRLF.
    pub fn decode(mut line: EasyBuf) -> Self {
        // Split on TAB if present.
        let query = match line.as_slice().iter().position(|b| *b == b'\t') {
            Some(i) => {
                let mut query = line.split_off(i);
                query.drain_to(1); // Consume the TAB.
                Some(GopherStr::new(query))
            }
            None => None
        };

        GopherRequest {
            selector: GopherStr::new(line),
            query: query,
        }
    }
}

/// A server-to-client message.
#[derive(Clone, Debug)]
pub enum GopherResponse {
    /// A list of resources.
    Menu(Vec<DirEntity>),
    /// A text document.
    TextFile(EasyBuf),
    /// A binary file download.
    BinaryFile(EasyBuf),
}

impl GopherResponse {
    /// Construct a menu with a single error line.
    pub fn error(text: GopherStr) -> Self {
        GopherResponse::Menu(vec![
            DirEntity {
                item_type: Error,
                name: text,
                selector: GopherStr::from_latin1(b"error"),
                host: GopherStr::from_latin1(b"error.host"),
                port: 0,
            }
        ])
    }

    /// Encode the response into bytes for sending over the wire.
    pub fn encode<W>(&self, mut buf: W) -> io::Result<()>
        where W: Write
    {
        match *self {
            GopherResponse::BinaryFile(ref file) => {
                buf.write_all(file.as_slice())?;
            }
            GopherResponse::TextFile(ref file) => {
                // TODO: Escape lines beginning with periods by adding an extra period.
                buf.write_all(file.as_slice())?;
                buf.write_all(b".\r\n")?;
            }
            GopherResponse::Menu(ref entities) => {
                for entity in entities {
                    buf.write_all(&[entity.item_type.encode()])?;
                    buf.write_all(&entity.name)?;
                    buf.write_all(b"\t")?;
                    buf.write_all(&entity.selector)?;
                    buf.write_all(b"\t")?;
                    buf.write_all(&entity.host)?;
                    write!(buf, "\t{}\r\n", entity.port)?;
                }
                buf.write_all(b".\r\n")?;
            }
        }
        Ok(())
    }
}

/// A list of Gopher resources.
pub struct Menu {
    pub entities: Vec<DirEntity>,
}

/// An menu item in a directory of Gopher resources.
#[derive(Clone, Debug)]
pub struct DirEntity {
    /// The type of the resource
    pub item_type: ItemType,
    /// String to display to the user.
    pub name: GopherStr,
    /// Path or identifier used for requesting this resource.
    pub selector: GopherStr,
    /// The hostname of the server hosting this resource.
    pub host: GopherStr,
    /// The TCP port of the server hosting this resource.
    pub port: u16,
}

/// The type of a resource in a Gopher directory.
///
/// For more details, see: https://tools.ietf.org/html/rfc1436
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
pub enum ItemType {
    /// Item is a file
    File,
    /// Item is a directory
    Dir,
    /// Item is a CSO phone-book server
    CsoServer,
    /// Error
    Error,
    /// Item is a BinHexed Macintosh file.
    BinHex,
    /// Item is DOS binary archive of some sort.
    ///
    /// Client must read until the TCP connection closes.  Beware.
    Dos,
    /// Item is a UNIX uuencoded file.
    Uuencoded,
    /// Item is an Index-Search server.
    IndexServer,
    /// Item points to a text-based telnet session.
    Telnet,
    /// Item is a binary file! Client must read until the TCP connection closes.  Beware
    Binary,
    /// Item is a redundant server
    RedundantServer,
    /// Item points to a text-based tn3270 session.
    Tn3270,
    /// Item is a GIF format graphics file.
    Gif,
    /// Item is some kind of image file.  Client decides how to display.
    Image,
    /// Item is a non-standard type
    Other(u8),
}

impl ItemType {
    pub fn decode(b: u8) -> Self {
        match b {
            b'0' => File,
            b'1' => Dir,
            b'2' => CsoServer,
            b'3' => Error,
            b'4' => BinHex,
            b'5' => Dos,
            b'6' => Uuencoded,
            b'7' => IndexServer,
            b'8' => Telnet,
            b'9' => Binary,
            b'+' => RedundantServer,
            b'T' => Tn3270,
            b'g' => Gif,
            b'I' => Image,
            byte => Other(byte)
        }
    }

    pub fn encode(self) -> u8 {
        match self {
            File            => b'0',
            Dir             => b'1',
            CsoServer       => b'2',
            Error           => b'3',
            BinHex          => b'4',
            Dos             => b'5',
            Uuencoded       => b'6',
            IndexServer     => b'7',
            Telnet          => b'8',
            Binary          => b'9',
            RedundantServer => b'+',
            Tn3270          => b'T',
            Gif             => b'g',
            Image           => b'I',
            Other(byte)     => byte,
        }
    }
}
<commit_msg>Fix LastLine pattern<commit_after>use self::ItemType::*;
use std::io;
use std::io::Write;
use str::GopherStr;
use tokio_core::io::EasyBuf;

/// A client-to-server message.
#[derive(Clone, Debug)]
pub struct GopherRequest {
    /// Identifier of the resource to fetch. May be an empty string.
    pub selector: GopherStr,
    /// Search string for a full-text search transaction.
    pub query: Option<GopherStr>
}

impl GopherRequest {
    /// Read a Gopher request from a buffer containing a line *without* the trailing CRLF.
    pub fn decode(mut line: EasyBuf) -> Self {
        // Split on TAB if present.
        let query = match line.as_slice().iter().position(|b| *b == b'\t') {
            Some(i) => {
                let mut query = line.split_off(i);
                query.drain_to(1); // Consume the TAB.
                Some(GopherStr::new(query))
            }
            None => None
        };

        GopherRequest {
            selector: GopherStr::new(line),
            query: query,
        }
    }
}

/// A server-to-client message.
#[derive(Clone, Debug)]
pub enum GopherResponse {
    /// A list of resources.
    Menu(Vec<DirEntity>),
    /// A text document.
    TextFile(EasyBuf),
    /// A binary file download.
    BinaryFile(EasyBuf),
}

impl GopherResponse {
    /// Construct a menu with a single error line.
    pub fn error(text: GopherStr) -> Self {
        GopherResponse::Menu(vec![
            DirEntity {
                item_type: Error,
                name: text,
                selector: GopherStr::from_latin1(b"error"),
                host: GopherStr::from_latin1(b"error.host"),
                port: 0,
            }
        ])
    }

    /// Encode the response into bytes for sending over the wire.
    pub fn encode<W>(&self, mut buf: W) -> io::Result<()>
        where W: Write
    {
        match *self {
            GopherResponse::BinaryFile(ref file) => {
                buf.write_all(file.as_slice())?;
            }
            GopherResponse::TextFile(ref file) => {
                // TODO: Escape lines beginning with periods by adding an extra period.
                buf.write_all(file.as_slice())?;
                buf.write_all(b"\r\n.\r\n")?;
            }
            GopherResponse::Menu(ref entities) => {
                for entity in entities {
                    buf.write_all(&[entity.item_type.encode()])?;
                    buf.write_all(&entity.name)?;
                    buf.write_all(b"\t")?;
                    buf.write_all(&entity.selector)?;
                    buf.write_all(b"\t")?;
                    buf.write_all(&entity.host)?;
                    write!(buf, "\t{}\r\n", entity.port)?;
                }
                buf.write_all(b".\r\n")?;
            }
        }
        Ok(())
    }
}

/// A list of Gopher resources.
pub struct Menu {
    pub entities: Vec<DirEntity>,
}

/// An menu item in a directory of Gopher resources.
#[derive(Clone, Debug)]
pub struct DirEntity {
    /// The type of the resource
    pub item_type: ItemType,
    /// String to display to the user.
    pub name: GopherStr,
    /// Path or identifier used for requesting this resource.
    pub selector: GopherStr,
    /// The hostname of the server hosting this resource.
    pub host: GopherStr,
    /// The TCP port of the server hosting this resource.
    pub port: u16,
}

/// The type of a resource in a Gopher directory.
///
/// For more details, see: https://tools.ietf.org/html/rfc1436
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
pub enum ItemType {
    /// Item is a file
    File,
    /// Item is a directory
    Dir,
    /// Item is a CSO phone-book server
    CsoServer,
    /// Error
    Error,
    /// Item is a BinHexed Macintosh file.
    BinHex,
    /// Item is DOS binary archive of some sort.
    ///
    /// Client must read until the TCP connection closes.  Beware.
    Dos,
    /// Item is a UNIX uuencoded file.
    Uuencoded,
    /// Item is an Index-Search server.
    IndexServer,
    /// Item points to a text-based telnet session.
    Telnet,
    /// Item is a binary file! Client must read until the TCP connection closes.  Beware
    Binary,
    /// Item is a redundant server
    RedundantServer,
    /// Item points to a text-based tn3270 session.
    Tn3270,
    /// Item is a GIF format graphics file.
    Gif,
    /// Item is some kind of image file.  Client decides how to display.
    Image,
    /// Item is a non-standard type
    Other(u8),
}

impl ItemType {
    pub fn decode(b: u8) -> Self {
        match b {
            b'0' => File,
            b'1' => Dir,
            b'2' => CsoServer,
            b'3' => Error,
            b'4' => BinHex,
            b'5' => Dos,
            b'6' => Uuencoded,
            b'7' => IndexServer,
            b'8' => Telnet,
            b'9' => Binary,
            b'+' => RedundantServer,
            b'T' => Tn3270,
            b'g' => Gif,
            b'I' => Image,
            byte => Other(byte)
        }
    }

    pub fn encode(self) -> u8 {
        match self {
            File            => b'0',
            Dir             => b'1',
            CsoServer       => b'2',
            Error           => b'3',
            BinHex          => b'4',
            Dos             => b'5',
            Uuencoded       => b'6',
            IndexServer     => b'7',
            Telnet          => b'8',
            Binary          => b'9',
            RedundantServer => b'+',
            Tn3270          => b'T',
            Gif             => b'g',
            Image           => b'I',
            Other(byte)     => byte,
        }
    }
}
<|endoftext|>


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

//! Specified types for CSS values related to borders.

use crate::parser::{Parse, ParserContext};
use crate::values::computed::{self, Context, ToComputedValue};
use crate::values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use crate::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use crate::values::generics::border::BorderImageSlice as GenericBorderImageSlice;
use crate::values::generics::border::BorderRadius as GenericBorderRadius;
use crate::values::generics::border::BorderSpacing as GenericBorderSpacing;
use crate::values::generics::rect::Rect;
use crate::values::generics::size::Size2D;
use crate::values::specified::length::{NonNegativeLength, NonNegativeLengthPercentage};
use crate::values::specified::{AllowQuirks, NonNegativeNumber, NonNegativeNumberOrPercentage};
use crate::Zero;
use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};

/// A specified value for a single side of a `border-style` property.
///
/// The order here corresponds to the integer values from the border conflict
/// resolution rules in CSS 2.1 § 17.6.2.1. Higher values override lower values.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    FromPrimitive,
    MallocSizeOf,
    Ord,
    Parse,
    PartialEq,
    PartialOrd,
    SpecifiedValueInfo,
    ToComputedValue,
    ToCss,
    ToResolvedValue,
    ToShmem,
)]
#[repr(u8)]
pub enum BorderStyle {
    Hidden,
    None,
    Inset,
    Groove,
    Outset,
    Ridge,
    Dotted,
    Dashed,
    Solid,
    Double,
}

impl BorderStyle {
    /// Whether this border style is either none or hidden.
    #[inline]
    pub fn none_or_hidden(&self) -> bool {
        matches!(*self, BorderStyle::None | BorderStyle::Hidden)
    }
}

/// A specified value for a single side of the `border-width` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
pub enum BorderSideWidth {
    /// `thin`
    Thin,
    /// `medium`
    Medium,
    /// `thick`
    Thick,
    /// `<length>`
    Length(NonNegativeLength),
}

/// A specified value for the `border-image-width` property.
pub type BorderImageWidth = Rect<BorderImageSideWidth>;

/// A specified value for a single side of a `border-image-width` property.
pub type BorderImageSideWidth =
    GenericBorderImageSideWidth<NonNegativeLengthPercentage, NonNegativeNumber>;

/// A specified value for the `border-image-slice` property.
pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>;

/// A specified value for the `border-radius` property.
pub type BorderRadius = GenericBorderRadius<NonNegativeLengthPercentage>;

/// A specified value for the `border-*-radius` longhand properties.
pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthPercentage>;

/// A specified value for the `border-spacing` longhand properties.
pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>;

impl BorderImageSlice {
    /// Returns the `100%` value.
    #[inline]
    pub fn hundred_percent() -> Self {
        GenericBorderImageSlice {
            offsets: Rect::all(NonNegativeNumberOrPercentage::hundred_percent()),
            fill: false,
        }
    }
}

impl BorderSideWidth {
    /// Returns the `0px` value.
    #[inline]
    pub fn zero() -> Self {
        BorderSideWidth::Length(NonNegativeLength::zero())
    }

    /// Parses, with quirks.
    pub fn parse_quirky<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
        allow_quirks: AllowQuirks,
    ) -> Result<Self, ParseError<'i>> {
        if let Ok(length) = input.try(|i| NonNegativeLength::parse_quirky(context, i, allow_quirks))
        {
            return Ok(BorderSideWidth::Length(length));
        }
        try_match_ident_ignore_ascii_case! { input,
            "thin" => Ok(BorderSideWidth::Thin),
            "medium" => Ok(BorderSideWidth::Medium),
            "thick" => Ok(BorderSideWidth::Thick),
        }
    }
}

impl Parse for BorderSideWidth {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Self::parse_quirky(context, input, AllowQuirks::No)
    }
}

impl ToComputedValue for BorderSideWidth {
    type ComputedValue = computed::NonNegativeLength;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        // We choose the pixel length of the keyword values the same as both spec and gecko.
        // Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width
        // Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0
        match *self {
            BorderSideWidth::Thin => NonNegativeLength::from_px(1.).to_computed_value(context),
            BorderSideWidth::Medium => NonNegativeLength::from_px(3.).to_computed_value(context),
            BorderSideWidth::Thick => NonNegativeLength::from_px(5.).to_computed_value(context),
            BorderSideWidth::Length(ref length) => length.to_computed_value(context),
        }
        .into()
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        BorderSideWidth::Length(ToComputedValue::from_computed_value(computed))
    }
}

impl BorderImageSideWidth {
    /// Returns `1`.
    #[inline]
    pub fn one() -> Self {
        GenericBorderImageSideWidth::Number(NonNegativeNumber::new(1.))
    }
}

impl Parse for BorderImageSideWidth {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
            return Ok(GenericBorderImageSideWidth::Auto);
        }

        if let Ok(len) = input.try(|i| NonNegativeLengthPercentage::parse(context, i)) {
            return Ok(GenericBorderImageSideWidth::LengthPercentage(len));
        }

        let num = NonNegativeNumber::parse(context, input)?;
        Ok(GenericBorderImageSideWidth::Number(num))
    }
}

impl Parse for BorderImageSlice {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
        let offsets = Rect::parse_with(context, input, NonNegativeNumberOrPercentage::parse)?;
        if !fill {
            fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
        }
        Ok(GenericBorderImageSlice { offsets, fill })
    }
}

impl Parse for BorderRadius {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        let widths = Rect::parse_with(context, input, NonNegativeLengthPercentage::parse)?;
        let heights = if input.try(|i| i.expect_delim('/')).is_ok() {
            Rect::parse_with(context, input, NonNegativeLengthPercentage::parse)?
        } else {
            widths.clone()
        };

        Ok(GenericBorderRadius {
            top_left: BorderCornerRadius::new(widths.0, heights.0),
            top_right: BorderCornerRadius::new(widths.1, heights.1),
            bottom_right: BorderCornerRadius::new(widths.2, heights.2),
            bottom_left: BorderCornerRadius::new(widths.3, heights.3),
        })
    }
}

impl Parse for BorderCornerRadius {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Size2D::parse_with(context, input, NonNegativeLengthPercentage::parse)
            .map(GenericBorderCornerRadius)
    }
}

impl Parse for BorderSpacing {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Size2D::parse_with(context, input, |context, input| {
            NonNegativeLength::parse_quirky(context, input, AllowQuirks::Yes).map(From::from)
        })
        .map(GenericBorderSpacing)
    }
}

/// A single border-image-repeat keyword.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
    Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
)]
pub enum BorderImageRepeatKeyword {
    Stretch,
    Repeat,
    Round,
    Space,
}

/// The specified value for the `border-image-repeat` property.
///
/// https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat
#[derive(
    Clone,
    Copy,
    Debug,
    MallocSizeOf,
    PartialEq,
    SpecifiedValueInfo,
    ToComputedValue,
    ToResolvedValue,
    ToShmem,
)]
pub struct BorderImageRepeat(pub BorderImageRepeatKeyword, pub BorderImageRepeatKeyword);

impl ToCss for BorderImageRepeat {
    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    where
        W: Write,
    {
        self.0.to_css(dest)?;
        if self.0 != self.1 {
            dest.write_str(" ")?;
            self.1.to_css(dest)?;
        }
        Ok(())
    }
}

impl BorderImageRepeat {
    /// Returns the `stretch` value.
    #[inline]
    pub fn stretch() -> Self {
        BorderImageRepeat(
            BorderImageRepeatKeyword::Stretch,
            BorderImageRepeatKeyword::Stretch,
        )
    }
}

impl Parse for BorderImageRepeat {
    fn parse<'i, 't>(
        _context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        let horizontal = BorderImageRepeatKeyword::parse(input)?;
        let vertical = input.try(BorderImageRepeatKeyword::parse).ok();
        Ok(BorderImageRepeat(
            horizontal,
            vertical.unwrap_or(horizontal),
        ))
    }
}
<commit_msg>style: Remove a map(From::from) statement that does literally nothing.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Specified types for CSS values related to borders.

use crate::parser::{Parse, ParserContext};
use crate::values::computed::{self, Context, ToComputedValue};
use crate::values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use crate::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use crate::values::generics::border::BorderImageSlice as GenericBorderImageSlice;
use crate::values::generics::border::BorderRadius as GenericBorderRadius;
use crate::values::generics::border::BorderSpacing as GenericBorderSpacing;
use crate::values::generics::rect::Rect;
use crate::values::generics::size::Size2D;
use crate::values::specified::length::{NonNegativeLength, NonNegativeLengthPercentage};
use crate::values::specified::{AllowQuirks, NonNegativeNumber, NonNegativeNumberOrPercentage};
use crate::Zero;
use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};

/// A specified value for a single side of a `border-style` property.
///
/// The order here corresponds to the integer values from the border conflict
/// resolution rules in CSS 2.1 § 17.6.2.1. Higher values override lower values.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    FromPrimitive,
    MallocSizeOf,
    Ord,
    Parse,
    PartialEq,
    PartialOrd,
    SpecifiedValueInfo,
    ToComputedValue,
    ToCss,
    ToResolvedValue,
    ToShmem,
)]
#[repr(u8)]
pub enum BorderStyle {
    Hidden,
    None,
    Inset,
    Groove,
    Outset,
    Ridge,
    Dotted,
    Dashed,
    Solid,
    Double,
}

impl BorderStyle {
    /// Whether this border style is either none or hidden.
    #[inline]
    pub fn none_or_hidden(&self) -> bool {
        matches!(*self, BorderStyle::None | BorderStyle::Hidden)
    }
}

/// A specified value for a single side of the `border-width` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
pub enum BorderSideWidth {
    /// `thin`
    Thin,
    /// `medium`
    Medium,
    /// `thick`
    Thick,
    /// `<length>`
    Length(NonNegativeLength),
}

/// A specified value for the `border-image-width` property.
pub type BorderImageWidth = Rect<BorderImageSideWidth>;

/// A specified value for a single side of a `border-image-width` property.
pub type BorderImageSideWidth =
    GenericBorderImageSideWidth<NonNegativeLengthPercentage, NonNegativeNumber>;

/// A specified value for the `border-image-slice` property.
pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>;

/// A specified value for the `border-radius` property.
pub type BorderRadius = GenericBorderRadius<NonNegativeLengthPercentage>;

/// A specified value for the `border-*-radius` longhand properties.
pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthPercentage>;

/// A specified value for the `border-spacing` longhand properties.
pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>;

impl BorderImageSlice {
    /// Returns the `100%` value.
    #[inline]
    pub fn hundred_percent() -> Self {
        GenericBorderImageSlice {
            offsets: Rect::all(NonNegativeNumberOrPercentage::hundred_percent()),
            fill: false,
        }
    }
}

impl BorderSideWidth {
    /// Returns the `0px` value.
    #[inline]
    pub fn zero() -> Self {
        BorderSideWidth::Length(NonNegativeLength::zero())
    }

    /// Parses, with quirks.
    pub fn parse_quirky<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
        allow_quirks: AllowQuirks,
    ) -> Result<Self, ParseError<'i>> {
        if let Ok(length) = input.try(|i| NonNegativeLength::parse_quirky(context, i, allow_quirks))
        {
            return Ok(BorderSideWidth::Length(length));
        }
        try_match_ident_ignore_ascii_case! { input,
            "thin" => Ok(BorderSideWidth::Thin),
            "medium" => Ok(BorderSideWidth::Medium),
            "thick" => Ok(BorderSideWidth::Thick),
        }
    }
}

impl Parse for BorderSideWidth {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Self::parse_quirky(context, input, AllowQuirks::No)
    }
}

impl ToComputedValue for BorderSideWidth {
    type ComputedValue = computed::NonNegativeLength;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        // We choose the pixel length of the keyword values the same as both spec and gecko.
        // Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width
        // Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0
        match *self {
            BorderSideWidth::Thin => NonNegativeLength::from_px(1.).to_computed_value(context),
            BorderSideWidth::Medium => NonNegativeLength::from_px(3.).to_computed_value(context),
            BorderSideWidth::Thick => NonNegativeLength::from_px(5.).to_computed_value(context),
            BorderSideWidth::Length(ref length) => length.to_computed_value(context),
        }
        .into()
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        BorderSideWidth::Length(ToComputedValue::from_computed_value(computed))
    }
}

impl BorderImageSideWidth {
    /// Returns `1`.
    #[inline]
    pub fn one() -> Self {
        GenericBorderImageSideWidth::Number(NonNegativeNumber::new(1.))
    }
}

impl Parse for BorderImageSideWidth {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
            return Ok(GenericBorderImageSideWidth::Auto);
        }

        if let Ok(len) = input.try(|i| NonNegativeLengthPercentage::parse(context, i)) {
            return Ok(GenericBorderImageSideWidth::LengthPercentage(len));
        }

        let num = NonNegativeNumber::parse(context, input)?;
        Ok(GenericBorderImageSideWidth::Number(num))
    }
}

impl Parse for BorderImageSlice {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
        let offsets = Rect::parse_with(context, input, NonNegativeNumberOrPercentage::parse)?;
        if !fill {
            fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
        }
        Ok(GenericBorderImageSlice { offsets, fill })
    }
}

impl Parse for BorderRadius {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        let widths = Rect::parse_with(context, input, NonNegativeLengthPercentage::parse)?;
        let heights = if input.try(|i| i.expect_delim('/')).is_ok() {
            Rect::parse_with(context, input, NonNegativeLengthPercentage::parse)?
        } else {
            widths.clone()
        };

        Ok(GenericBorderRadius {
            top_left: BorderCornerRadius::new(widths.0, heights.0),
            top_right: BorderCornerRadius::new(widths.1, heights.1),
            bottom_right: BorderCornerRadius::new(widths.2, heights.2),
            bottom_left: BorderCornerRadius::new(widths.3, heights.3),
        })
    }
}

impl Parse for BorderCornerRadius {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Size2D::parse_with(context, input, NonNegativeLengthPercentage::parse)
            .map(GenericBorderCornerRadius)
    }
}

impl Parse for BorderSpacing {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Size2D::parse_with(context, input, |context, input| {
            NonNegativeLength::parse_quirky(context, input, AllowQuirks::Yes)
        })
        .map(GenericBorderSpacing)
    }
}

/// A single border-image-repeat keyword.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
    Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
)]
pub enum BorderImageRepeatKeyword {
    Stretch,
    Repeat,
    Round,
    Space,
}

/// The specified value for the `border-image-repeat` property.
///
/// https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat
#[derive(
    Clone,
    Copy,
    Debug,
    MallocSizeOf,
    PartialEq,
    SpecifiedValueInfo,
    ToComputedValue,
    ToResolvedValue,
    ToShmem,
)]
pub struct BorderImageRepeat(pub BorderImageRepeatKeyword, pub BorderImageRepeatKeyword);

impl ToCss for BorderImageRepeat {
    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    where
        W: Write,
    {
        self.0.to_css(dest)?;
        if self.0 != self.1 {
            dest.write_str(" ")?;
            self.1.to_css(dest)?;
        }
        Ok(())
    }
}

impl BorderImageRepeat {
    /// Returns the `stretch` value.
    #[inline]
    pub fn stretch() -> Self {
        BorderImageRepeat(
            BorderImageRepeatKeyword::Stretch,
            BorderImageRepeatKeyword::Stretch,
        )
    }
}

impl Parse for BorderImageRepeat {
    fn parse<'i, 't>(
        _context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        let horizontal = BorderImageRepeatKeyword::parse(input)?;
        let vertical = input.try(BorderImageRepeatKeyword::parse).ok();
        Ok(BorderImageRepeat(
            horizontal,
            vertical.unwrap_or(horizontal),
        ))
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::collections::HashMap;
use std::io::{Read, Write};
use std::path::PathBuf;

use serde_json;
use toml;

use error::StoreErrorKind as SEK;
use error::MapErrInto;
use super::Mapper;
use store::Result;
use store::Entry;
use storeid::StoreId;

use libimagerror::into::IntoError;

#[derive(Deserialize, Serialize)]
struct BackendEntry {
    header: serde_json::Value,
    content: String,
}

impl BackendEntry {

    fn to_string(self) -> Result<String> {
        toml::to_string(&self.header)
            .map_err_into(SEK::IoError)
            .map(|hdr| {
                format!("---\n{header}---\n{content}",
                        header  = hdr,
                        content = self.content)
            })
    }

}

#[derive(Deserialize, Serialize)]
struct Document {
    version: String,
    store: HashMap<PathBuf, BackendEntry>,
}

pub struct JsonMapper;

impl JsonMapper {

    pub fn new() -> JsonMapper {
        JsonMapper
    }

}

impl Mapper for JsonMapper {
    fn read_to_fs<R: Read>(&self, r: &mut R, hm: &mut HashMap<PathBuf, Entry>)   -> Result<()> {
        let mut document = {
            let mut s = String::new();
            try!(r.read_to_string(&mut s).map_err_into(SEK::IoError));
            let doc : Document = try!(serde_json::from_str(&s).map_err_into(SEK::IoError));
            doc
        };

        let _ = try!(::semver::Version::parse(&document.version)
            .map_err_into(SEK::VersionError)
            .and_then(|doc_vers| {
                // safe because cargo does not compile if crate version is not valid
                let crate_version = ::semver::Version::parse(version!()).unwrap();

                if doc_vers > crate_version {
                    Err(SEK::VersionError.into_error())
                } else {
                    Ok(())
                }
            }));

        for (key, val) in document.store.drain() {
            let res = val
                .to_string()
                .and_then(|vals| {
                    StoreId::new_baseless(key.clone())
                        .and_then(|id| Entry::from_str(id, &vals))
                        .map(|entry| hm.insert(key, entry))
                })
                .map(|_| ());

            let _ = try!(res);
        }

        Ok(())
    }

    fn fs_to_write<W: Write>(&self, hm: &mut HashMap<PathBuf, Entry>, out: &mut W) -> Result<()> {
        #[derive(Serialize)]
        struct BackendEntry {
            header: ::toml::Value,
            content: String,
        }

        impl BackendEntry {
            fn construct_from(e: Entry) -> BackendEntry {
                BackendEntry {
                    header:  e.get_header().clone(),
                    content: e.get_content().clone(),
                }
            }
        }

        #[derive(Serialize)]
        struct OutDocument {
            version: String,
            store: HashMap<PathBuf, BackendEntry>,
        }

        let mut store = HashMap::new();
        for (key, value) in hm.drain() {
            store.insert(key, BackendEntry::construct_from(value));
        }

        let doc = OutDocument {
            version: String::from(version!()),
            store:   store,
        };

        serde_json::to_string(&doc)
            .map_err_into(SEK::IoError)
            .and_then(|json| out.write(&json.into_bytes()).map_err_into(SEK::IoError))
            .and_then(|_| out.flush().map_err_into(SEK::IoError))
            .map(|_| ())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    #[test]
    fn test_empty_json_to_fs() {
        let json = r#"{"version":"0.3.0","store":{}}"#;
        let mut json = Cursor::new(String::from(json).into_bytes());
        let mapper   = JsonMapper::new();
        let mut hm   = HashMap::new();

        let io_res  = mapper.read_to_fs(&mut json, &mut hm);
        assert!(io_res.is_ok());
        assert!(hm.is_empty());
    }

    #[test]
    fn test_json_to_fs() {
        let json = r#"
        { "version": "0.3.0",
          "store": {
            "example": {
                "header": {
                    "imag": {
                        "version": "0.3.0"
                    }
                },
                "content": "test"
            }
          }
        }
        "#;
        let mut json = Cursor::new(String::from(json).into_bytes());
        let mapper   = JsonMapper::new();
        let mut hm   = HashMap::new();

        let io_res  = mapper.read_to_fs(&mut json, &mut hm);
        assert!(io_res.is_ok());

        assert_eq!(1, hm.len()); // we should have exactly one entry
    }

    #[test]
    fn test_fs_to_json() {
        let mapper                    = JsonMapper::new();
        let mut out : Cursor<Vec<u8>> = Cursor::new(vec![]);

        let mut hm = {
            let mut hm = HashMap::new();
            let content = r#"---
[imag]
version = "0.3.0"
---
hi there!"#;

            let id = PathBuf::from("example");
            let entry = Entry::from_str(id.clone(), content).unwrap();
            hm.insert(id, entry);
            hm
        };

        let io_res = mapper.fs_to_write(&mut hm, &mut out);
        assert!(io_res.is_ok());

        let example = r#"
        {
            "version": "0.3.0",
            "store": {
                "example": {
                    "header": {
                        "imag": {
                            "version": "0.3.0"
                        }
                    },
                    "content": "hi there!"
                }
            }
        }
        "#;

        let example_json : ::serde_json::Value = ::serde_json::from_str(example).unwrap();

        let output_json = String::from_utf8(out.into_inner()).unwrap();
        let output_json : ::serde_json::Value = ::serde_json::from_str(&output_json).unwrap();

        assert_eq!(example_json, output_json);
    }
}

<commit_msg>Add some debug output to JSON mapper<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::collections::HashMap;
use std::io::{Read, Write};
use std::path::PathBuf;

use serde_json;
use toml;

use error::StoreErrorKind as SEK;
use error::MapErrInto;
use super::Mapper;
use store::Result;
use store::Entry;
use storeid::StoreId;

use libimagerror::into::IntoError;

#[derive(Debug, Deserialize, Serialize)]
struct BackendEntry {
    header: serde_json::Value,
    content: String,
}

impl BackendEntry {

    fn to_string(self) -> Result<String> {
        toml::to_string(&self.header)
            .map_err_into(SEK::IoError)
            .map(|hdr| {
                format!("---\n{header}---\n{content}",
                        header  = hdr,
                        content = self.content)
            })
    }

}

#[derive(Debug, Deserialize, Serialize)]
struct Document {
    version: String,
    store: HashMap<PathBuf, BackendEntry>,
}

pub struct JsonMapper;

impl JsonMapper {

    pub fn new() -> JsonMapper {
        JsonMapper
    }

}

impl Mapper for JsonMapper {
    fn read_to_fs<R: Read>(&self, r: &mut R, hm: &mut HashMap<PathBuf, Entry>)   -> Result<()> {
        let mut document = {
            debug!("Reading Document");
            let mut s = String::new();
            try!(r.read_to_string(&mut s).map_err_into(SEK::IoError));
            debug!("Document = {:?}", s);
            debug!("Parsing Document");
            let doc : Document = try!(serde_json::from_str(&s).map_err_into(SEK::IoError));
            debug!("Document = {:?}", doc);
            doc
        };

        let _ = try!(::semver::Version::parse(&document.version)
            .map_err_into(SEK::VersionError)
            .and_then(|doc_vers| {
                // safe because cargo does not compile if crate version is not valid
                let crate_version = ::semver::Version::parse(version!()).unwrap();

                debug!("Document version vs. own version: {doc_vers} > {crate_vers}",
                       doc_vers = doc_vers,
                       crate_vers = crate_version);

                if doc_vers > crate_version {
                    Err(SEK::VersionError.into_error())
                } else {
                    Ok(())
                }
            }));

        for (key, val) in document.store.drain() {
            debug!("(key, value) ({:?}, {:?})", key, val);
            let res = val
                .to_string()
                .and_then(|vals| {
                    debug!("value string = {:?}", vals);
                    StoreId::new_baseless(key.clone())
                        .and_then(|id| Entry::from_str(id, &vals))
                        .map(|entry| hm.insert(key, entry))
                })
                .map(|_| ());

            let _ = try!(res);
        }

        Ok(())
    }

    fn fs_to_write<W: Write>(&self, hm: &mut HashMap<PathBuf, Entry>, out: &mut W) -> Result<()> {
        #[derive(Serialize)]
        struct BackendEntry {
            header: ::toml::Value,
            content: String,
        }

        impl BackendEntry {
            fn construct_from(e: Entry) -> BackendEntry {
                BackendEntry {
                    header:  e.get_header().clone(),
                    content: e.get_content().clone(),
                }
            }
        }

        #[derive(Serialize)]
        struct OutDocument {
            version: String,
            store: HashMap<PathBuf, BackendEntry>,
        }

        let mut store = HashMap::new();
        for (key, value) in hm.drain() {
            store.insert(key, BackendEntry::construct_from(value));
        }

        let doc = OutDocument {
            version: String::from(version!()),
            store:   store,
        };

        serde_json::to_string(&doc)
            .map_err_into(SEK::IoError)
            .and_then(|json| out.write(&json.into_bytes()).map_err_into(SEK::IoError))
            .and_then(|_| out.flush().map_err_into(SEK::IoError))
            .map(|_| ())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    #[test]
    fn test_empty_json_to_fs() {
        let json = r#"{"version":"0.3.0","store":{}}"#;
        let mut json = Cursor::new(String::from(json).into_bytes());
        let mapper   = JsonMapper::new();
        let mut hm   = HashMap::new();

        let io_res  = mapper.read_to_fs(&mut json, &mut hm);
        assert!(io_res.is_ok());
        assert!(hm.is_empty());
    }

    #[test]
    fn test_json_to_fs() {
        let json = r#"
        { "version": "0.3.0",
          "store": {
            "example": {
                "header": {
                    "imag": {
                        "version": "0.3.0"
                    }
                },
                "content": "test"
            }
          }
        }
        "#;
        let mut json = Cursor::new(String::from(json).into_bytes());
        let mapper   = JsonMapper::new();
        let mut hm   = HashMap::new();

        let io_res  = mapper.read_to_fs(&mut json, &mut hm);
        assert!(io_res.is_ok());

        assert_eq!(1, hm.len()); // we should have exactly one entry
    }

    #[test]
    fn test_fs_to_json() {
        let mapper                    = JsonMapper::new();
        let mut out : Cursor<Vec<u8>> = Cursor::new(vec![]);

        let mut hm = {
            let mut hm = HashMap::new();
            let content = r#"---
[imag]
version = "0.3.0"
---
hi there!"#;

            let id = PathBuf::from("example");
            let entry = Entry::from_str(id.clone(), content).unwrap();
            hm.insert(id, entry);
            hm
        };

        let io_res = mapper.fs_to_write(&mut hm, &mut out);
        assert!(io_res.is_ok());

        let example = r#"
        {
            "version": "0.3.0",
            "store": {
                "example": {
                    "header": {
                        "imag": {
                            "version": "0.3.0"
                        }
                    },
                    "content": "hi there!"
                }
            }
        }
        "#;

        let example_json : ::serde_json::Value = ::serde_json::from_str(example).unwrap();

        let output_json = String::from_utf8(out.into_inner()).unwrap();
        let output_json : ::serde_json::Value = ::serde_json::from_str(&output_json).unwrap();

        assert_eq!(example_json, output_json);
    }
}

<|endoftext|>