<commit_before>//! Fractional Brownian motion and fractional Gaussian noise.

use complex::Complex;
use probability::distribution::{Distribution, Gaussian};
use probability::generator::Generator;

use {Process, Stationary};
use gaussian::circulant_embedding;

macro_rules! hurst(
    ($value:expr) => ({
        let value = $value;
        debug_assert!(value > 0.0 && value < 1.0);
        value
    });
);

macro_rules! step(
    ($value:expr) => ({
        let value = $value;
        debug_assert!(value > 0.0);
        value
    });
);

/// A fractional Brownian motion.
pub struct Motion {
    hurst: f64,
}

/// A fractional Gaussian noise.
pub struct Noise {
    hurst: f64,
    step: f64,
}

impl Motion {
    /// Create a fractional Brownian motion.
    #[inline]
    pub fn new(hurst: f64) -> Motion {
        Motion { hurst: hurst!(hurst) }
    }

    /// Generate a sample path.
    pub fn sample<G>(&self, points: usize, step: f64, generator: &mut G) -> Vec<f64>
        where G: Generator
    {
        match points {
            0 => vec![],
            1 => vec![0.0],
            _ => {
                let mut data = vec![0.0];
                data.extend(Noise::new(self.hurst, step).sample(points - 1, generator));
                for i in 2..points {
                    data[i] += data[i - 1];
                }
                data
            },
        }
    }
}

impl Noise {
    /// Create a fractional Gaussian noise.
    #[inline]
    pub fn new(hurst: f64, step: f64) -> Noise {
        Noise { hurst: hurst!(hurst), step: step!(step) }
    }

    /// Generate a sample path.
    pub fn sample<G>(&self, points: usize, generator: &mut G) -> Vec<f64>
        where G: Generator
    {
        match points {
            0 => vec![],
            1 => vec![Gaussian::new(0.0, 1.0).sample(generator)],
            _ => {
                let n = points - 1;
                let gaussian = Gaussian::new(0.0, 1.0);
                let scale = (1.0 / n as f64).powf(self.hurst);
                let data = circulant_embedding(self, n, || gaussian.sample(generator));
                data.iter().take(points).map(|point| scale * point.re()).collect()
            },
        }
    }
}

impl Process for Motion {
    type Index = f64;
    type State = f64;

    fn cov(&self, t: f64, s: f64) -> f64 {
        debug_assert!(t >= 0.0 && s >= 0.0);
        let power = 2.0 * self.hurst;
        0.5 * (t.powf(power) + s.powf(power) - (t - s).abs().powf(power))
    }
}

impl Process for Noise {
    type Index = usize;
    type State = f64;

    #[inline]
    fn cov(&self, t: usize, s: usize) -> f64 {
        Stationary::cov(self, if t < s { s - t } else { t - s })
    }
}

impl Stationary for Noise {
    type Distance = usize;

    fn cov(&self, delta: usize) -> f64 {
        let delta = delta as f64;
        let power = 2.0 * self.hurst;
        let var = self.step.powf(power);
        0.5 * var * ((delta + 1.0).powf(power) - 2.0 * delta.powf(power) +
                     (delta - 1.0).abs().powf(power))
    }
}

#[cfg(test)]
mod tests {
    use super::{Motion, Noise};

    #[test]
    fn motion_var() {
        use Process;
        let process = Motion::new(0.25);
        let variances = (0..3).map(|i| process.var(i as f64)).collect::<Vec<_>>();
        assert_eq!(&variances, &[0.0, 1.0, 2f64.sqrt()]);
    }

    #[test]
    fn noise_var() {
        let process = Noise::new(0.42, 1.0);
        {
            use Process;
            let variances = (0..3).map(|i| process.var(i)).collect::<Vec<_>>();
            assert_eq!(&variances, &[1.0, 1.0, 1.0]);
        }
        {
            use Stationary;
            assert_eq!(process.var(), 1.0);
        }
        let process = Noise::new(0.25, 0.01);
        {
            use Process;
            let variances = (0..3).map(|i| process.var(i)).collect::<Vec<_>>();
            assert_eq!(&variances, &[0.1, 0.1, 0.1]);
        }
        {
            use Stationary;
            assert_eq!(process.var(), 0.1);
        }
    }
}
<commit_msg>Do not scale fGn to [0, 1]<commit_after>//! Fractional Brownian motion and fractional Gaussian noise.

use complex::Complex;
use probability::distribution::{Distribution, Gaussian};
use probability::generator::Generator;

use {Process, Stationary};
use gaussian::circulant_embedding;

macro_rules! hurst(
    ($value:expr) => ({
        let value = $value;
        debug_assert!(value > 0.0 && value < 1.0);
        value
    });
);

macro_rules! step(
    ($value:expr) => ({
        let value = $value;
        debug_assert!(value > 0.0);
        value
    });
);

/// A fractional Brownian motion.
pub struct Motion {
    hurst: f64,
}

/// A fractional Gaussian noise.
pub struct Noise {
    hurst: f64,
    step: f64,
}

impl Motion {
    /// Create a fractional Brownian motion.
    #[inline]
    pub fn new(hurst: f64) -> Motion {
        Motion { hurst: hurst!(hurst) }
    }

    /// Generate a sample path.
    pub fn sample<G>(&self, points: usize, step: f64, generator: &mut G) -> Vec<f64>
        where G: Generator
    {
        match points {
            0 => vec![],
            1 => vec![0.0],
            _ => {
                let mut data = vec![0.0];
                data.extend(Noise::new(self.hurst, step).sample(points - 1, generator));
                for i in 2..points {
                    data[i] += data[i - 1];
                }
                data
            },
        }
    }
}

impl Noise {
    /// Create a fractional Gaussian noise.
    #[inline]
    pub fn new(hurst: f64, step: f64) -> Noise {
        Noise { hurst: hurst!(hurst), step: step!(step) }
    }

    /// Generate a sample path.
    pub fn sample<G>(&self, points: usize, generator: &mut G) -> Vec<f64>
        where G: Generator
    {
        match points {
            0 => vec![],
            1 => vec![Gaussian::new(0.0, 1.0).sample(generator)],
            _ => {
                let n = points - 1;
                let gaussian = Gaussian::new(0.0, 1.0);
                let data = circulant_embedding(self, n, || gaussian.sample(generator));
                data.iter().take(points).map(|point| point.re()).collect()
            },
        }
    }
}

impl Process for Motion {
    type Index = f64;
    type State = f64;

    fn cov(&self, t: f64, s: f64) -> f64 {
        debug_assert!(t >= 0.0 && s >= 0.0);
        let power = 2.0 * self.hurst;
        0.5 * (t.powf(power) + s.powf(power) - (t - s).abs().powf(power))
    }
}

impl Process for Noise {
    type Index = usize;
    type State = f64;

    #[inline]
    fn cov(&self, t: usize, s: usize) -> f64 {
        Stationary::cov(self, if t < s { s - t } else { t - s })
    }
}

impl Stationary for Noise {
    type Distance = usize;

    fn cov(&self, delta: usize) -> f64 {
        let delta = delta as f64;
        let power = 2.0 * self.hurst;
        let var = self.step.powf(power);
        0.5 * var * ((delta + 1.0).powf(power) - 2.0 * delta.powf(power) +
                     (delta - 1.0).abs().powf(power))
    }
}

#[cfg(test)]
mod tests {
    use super::{Motion, Noise};

    #[test]
    fn motion_var() {
        use Process;
        let process = Motion::new(0.25);
        let variances = (0..3).map(|i| process.var(i as f64)).collect::<Vec<_>>();
        assert_eq!(&variances, &[0.0, 1.0, 2f64.sqrt()]);
    }

    #[test]
    fn noise_var() {
        let process = Noise::new(0.42, 1.0);
        {
            use Process;
            let variances = (0..3).map(|i| process.var(i)).collect::<Vec<_>>();
            assert_eq!(&variances, &[1.0, 1.0, 1.0]);
        }
        {
            use Stationary;
            assert_eq!(process.var(), 1.0);
        }
        let process = Noise::new(0.25, 0.01);
        {
            use Process;
            let variances = (0..3).map(|i| process.var(i)).collect::<Vec<_>>();
            assert_eq!(&variances, &[0.1, 0.1, 0.1]);
        }
        {
            use Stationary;
            assert_eq!(process.var(), 0.1);
        }
    }
}
<|endoftext|>


<commit_before>use failure::Error;
use std::ops::{Add, Deref, DerefMut, Mul};

use geometry::convert::AsPosition;
use geometry::Geometry;
use graph::geometry::alias::{ScaledEdgeLateral, VertexPosition};
use graph::geometry::{EdgeLateral, EdgeMidpoint};
use graph::mesh::Mesh;
use graph::mutation::vertex::VertexMutation;
use graph::mutation::{Commit, Mode, Mutate, Mutation};
use graph::storage::convert::AsStorage;
use graph::storage::{Bind, Core, EdgeKey, FaceKey, Storage, VertexKey};
use graph::topology::{Edge, Face, Vertex};
use graph::view::convert::IntoView;
use graph::view::{EdgeView, Inconsistent};
use graph::{GraphError, Perimeter, ResultExt};

pub struct EdgeMutation<G>
where
    G: Geometry,
{
    mutation: VertexMutation<G>,
    storage: Storage<Edge<G>>,
}

impl<G> EdgeMutation<G>
where
    G: Geometry,
{
    pub fn insert_edge(
        &mut self,
        vertices: (VertexKey, VertexKey),
        geometry: G::Edge,
    ) -> Result<EdgeKey, Error> {
        let (a, b) = vertices;
        let ab = (a, b).into();
        let ba = (b, a).into();
        // If the edge already exists, then fail. This ensures an important
        // invariant: edges may only have two adjacent faces. That is, a
        // half-edge may only have one associated face, at most one preceding
        // half-edge, at most one following half-edge, and may form at most one
        // closed loop.
        if self.storage.contains_key(&ab) {
            return Err(GraphError::TopologyConflict.into());
        }
        if !self.mutation.as_storage().contains_key(&b) {
            return Err(GraphError::TopologyNotFound.into());
        }
        let mut edge = Edge::new(b, geometry);
        if let Some(opposite) = self.storage.get_mut(&ba) {
            edge.opposite = Some(ba);
            opposite.opposite = Some(ab);
        }
        self.storage.insert_with_key(&ab, edge);
        self.connect_outgoing_edge(a, ab)?;
        Ok(ab)
    }

    pub fn get_or_insert_edge(
        &mut self,
        vertices: (VertexKey, VertexKey),
        geometry: G::Edge,
    ) -> Result<EdgeKey, Error> {
        self.insert_edge(vertices, geometry)
            .or_if_conflict(|| Ok(vertices.into()))
    }

    pub fn get_or_insert_composite_edge(
        &mut self,
        vertices: (VertexKey, VertexKey),
        geometry: G::Edge,
    ) -> Result<(EdgeKey, EdgeKey), Error> {
        let (a, b) = vertices;
        let ab = self.get_or_insert_edge((a, b), geometry.clone())?;
        let ba = self.get_or_insert_edge((b, a), geometry)?;
        Ok((ab, ba))
    }

    pub fn remove_edge(&mut self, ab: EdgeKey) -> Result<Edge<G>, Error> {
        let (a, _) = ab.to_vertex_keys();
        self.disconnect_next_edge(ab)?;
        self.disconnect_previous_edge(ab)?;
        self.disconnect_outgoing_edge(a)?;
        Ok(self.storage.remove(&ab).unwrap())
    }

    pub fn remove_composite_edge(&mut self, ab: EdgeKey) -> Result<(Edge<G>, Edge<G>), Error> {
        let (a, b) = ab.to_vertex_keys();
        let edge = self.remove_edge((a, b).into())?;
        let opposite = self.remove_edge((b, a).into())?;
        Ok((edge, opposite))
    }

    pub fn connect_neighboring_edges(&mut self, ab: EdgeKey, bc: EdgeKey) -> Result<(), Error> {
        if ab.to_vertex_keys().1 == bc.to_vertex_keys().0 {
            let previous = match self.storage.get_mut(&ab) {
                Some(previous) => {
                    previous.next = Some(bc);
                    Ok(())
                }
                _ => Err(Error::from(GraphError::TopologyNotFound)),
            };
            let next = match self.storage.get_mut(&bc) {
                Some(next) => {
                    next.previous = Some(ab);
                    Ok(())
                }
                _ => Err(Error::from(GraphError::TopologyNotFound)),
            };
            previous.and(next)
        }
        else {
            Err(Error::from(GraphError::TopologyMalformed))
        }
    }

    pub fn disconnect_next_edge(&mut self, ab: EdgeKey) -> Result<Option<EdgeKey>, Error> {
        let bx = {
            self.storage
                .get_mut(&ab)
                .ok_or_else(|| Error::from(GraphError::TopologyNotFound))?
                .next
                .take()
        };
        if let Some(bx) = bx.as_ref() {
            self.storage.get_mut(bx).unwrap().previous = None;
        }
        Ok(bx)
    }

    pub fn disconnect_previous_edge(&mut self, ab: EdgeKey) -> Result<Option<EdgeKey>, Error> {
        let xa = {
            self.storage
                .get_mut(&ab)
                .ok_or_else(|| Error::from(GraphError::TopologyNotFound))?
                .previous
                .take()
        };
        if let Some(xa) = xa.as_ref() {
            self.storage.get_mut(xa).unwrap().previous = None;
        }
        Ok(xa)
    }

    pub fn connect_edge_to_face(&mut self, ab: EdgeKey, abc: FaceKey) -> Result<(), Error> {
        let edge = self
            .storage
            .get_mut(&ab)
            .ok_or_else(|| Error::from(GraphError::TopologyNotFound))?;
        edge.face = Some(abc);
        Ok(())
    }

    pub fn disconnect_edge_from_face(&mut self, ab: EdgeKey) -> Result<Option<FaceKey>, Error> {
        let face = self
            .storage
            .get_mut(&ab)
            .ok_or_else(|| Error::from(GraphError::TopologyNotFound))?
            .face
            .take();
        Ok(face)
    }
}

impl<G> AsStorage<Edge<G>> for EdgeMutation<G>
where
    G: Geometry,
{
    fn as_storage(&self) -> &Storage<Edge<G>> {
        &self.storage
    }
}

impl<G> Commit<G> for EdgeMutation<G>
where
    G: Geometry,
{
    type Error = Error;

    fn commit(self) -> Result<Self::Mutant, Self::Error> {
        let EdgeMutation {
            mutation,
            storage: edges,
            ..
        } = self;
        mutation
            .commit()
            .and_then(move |vertices| Ok((vertices, edges)))
    }
}

impl<G> Deref for EdgeMutation<G>
where
    G: Geometry,
{
    type Target = VertexMutation<G>;

    fn deref(&self) -> &Self::Target {
        &self.mutation
    }
}

impl<G> DerefMut for EdgeMutation<G>
where
    G: Geometry,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.mutation
    }
}

impl<G> Mode<G> for EdgeMutation<G>
where
    G: Geometry,
{
    type Mutant = (Storage<Vertex<G>>, Storage<Edge<G>>);
}

impl<G> Mutate<G> for EdgeMutation<G>
where
    G: Geometry,
{
    fn mutate(mutant: Self::Mutant) -> Self {
        let (vertices, edges) = mutant;
        EdgeMutation {
            mutation: VertexMutation::mutate(vertices),
            storage: edges,
        }
    }
}

pub struct EdgeSplitCache<G>
where
    G: Geometry,
{
    ab: EdgeKey,
    ba: EdgeKey,
    midpoint: G::Vertex,
}

impl<G> EdgeSplitCache<G>
where
    G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
    G::Vertex: AsPosition,
{
    pub fn snapshot<M>(storage: M, ab: EdgeKey) -> Result<Self, Error>
    where
        M: AsStorage<Edge<G>> + AsStorage<Vertex<G>>,
    {
        let (a, b) = ab.to_vertex_keys();
        let edge: EdgeView<M, G, _> = match (ab, storage).into_view() {
            Some(edge) => edge,
            _ => return Err(GraphError::TopologyNotFound.into()),
        };
        let mut midpoint = edge.source_vertex().geometry.clone();
        *midpoint.as_position_mut() = EdgeMidpoint::midpoint(&edge)?;
        Ok(EdgeSplitCache {
            ab,
            ba: (b, a).into(),
            midpoint,
        })
    }
}

pub struct EdgeJoinCache<G>
where
    G: Geometry,
{
    source: EdgeKey,
    destination: EdgeKey,
    edge: G::Edge,
    face: G::Face,
}

impl<G> EdgeJoinCache<G>
where
    G: Geometry,
{
    pub fn snapshot<M>(storage: M, source: EdgeKey, destination: EdgeKey) -> Result<Self, Error>
    where
        M: AsStorage<Edge<G>> + AsStorage<Face<G>> + AsStorage<Vertex<G>>,
    {
        let (a, b) = source.to_vertex_keys();
        let (c, d) = destination.to_vertex_keys();
        let source = match (
            EdgeView::<_, _, Inconsistent>::from_keyed_storage(source, &storage),
            EdgeView::<_, _, Inconsistent>::from_keyed_storage(destination, &storage),
        ) {
            (Some(source), Some(_)) => source,
            _ => return Err(GraphError::TopologyNotFound.into()),
        };
        // At this point, we can assume the points a, b, c, and d exist in the
        // mesh. Before mutating the mesh, ensure that existing interior edges
        // are boundaries.
        for edge in [a, b, c, d]
            .perimeter()
            .flat_map(|ab| EdgeView::<_, _, Inconsistent>::from_keyed_storage(ab.into(), &storage))
        {
            if !edge.is_boundary_edge() {
                return Err(GraphError::TopologyConflict.into());
            }
        }
        Ok(EdgeJoinCache {
            source: source.key(),
            destination,
            edge: source.geometry.clone(),
            face: source
                .reachable_opposite_edge()
                .and_then(|opposite| opposite.into_reachable_face())
                .map(|face| face.geometry.clone())
                .unwrap_or_else(Default::default),
        })
    }
}

pub struct EdgeExtrudeCache<G>
where
    G: Geometry,
{
    ab: EdgeKey,
    vertices: (G::Vertex, G::Vertex),
    edge: G::Edge,
}

impl<G> EdgeExtrudeCache<G>
where
    G: Geometry,
{
    pub fn snapshot<T>(storage: &Mesh<G>, ab: EdgeKey, distance: T) -> Result<Self, Error>
    where
        G: Geometry + EdgeLateral,
        G::Lateral: Mul<T>,
        G::Vertex: AsPosition,
        ScaledEdgeLateral<G, T>: Clone,
        VertexPosition<G>: Add<ScaledEdgeLateral<G, T>, Output = VertexPosition<G>> + Clone,
    {
        // Get the extruded geometry.
        let (vertices, edge) = {
            let edge = match storage.edge(ab) {
                Some(edge) => edge,
                _ => return Err(GraphError::TopologyNotFound.into()),
            };
            if !edge.is_boundary_edge() {
                return Err(GraphError::TopologyConflict.into());
            }
            let mut vertices = (
                edge.destination_vertex().geometry.clone(),
                edge.source_vertex().geometry.clone(),
            );
            let translation = edge.lateral()? * distance;
            *vertices.0.as_position_mut() = vertices.0.as_position().clone() + translation.clone();
            *vertices.1.as_position_mut() = vertices.1.as_position().clone() + translation;
            (vertices, edge.geometry.clone())
        };
        Ok(EdgeExtrudeCache { ab, vertices, edge })
    }
}

pub fn split_with_cache<G>(
    mutation: &mut Mutation<G>,
    cache: EdgeSplitCache<G>,
) -> Result<VertexKey, Error>
where
    G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
    G::Vertex: AsPosition,
{
    fn split_at_vertex<G>(
        mutation: &mut Mutation<G>,
        ab: EdgeKey,
        m: VertexKey,
    ) -> Result<(EdgeKey, EdgeKey), Error>
    where
        G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
        G::Vertex: AsPosition,
    {
        // Remove the edge and insert two truncated edges in its place.
        let (a, b) = ab.to_vertex_keys();
        let span = mutation.remove_edge(ab)?;
        let am = mutation.insert_edge((a, m), span.geometry.clone())?;
        let mb = mutation.insert_edge((m, b), span.geometry.clone())?;
        // Connect the new edges to each other and their leading edges.
        mutation.connect_neighboring_edges(am, mb)?;
        if let Some(xa) = span.previous {
            mutation.connect_neighboring_edges(xa, am)?;
        }
        if let Some(bx) = span.next {
            mutation.connect_neighboring_edges(mb, bx)?;
        }
        // Update the associated face, if any, because it may refer to the
        // removed edge.
        if let Some(abc) = span.face {
            mutation.connect_face_to_edge(am, abc)?;
            mutation.connect_edge_to_face(am, abc)?;
            mutation.connect_edge_to_face(mb, abc)?;
        }
        Ok((am, mb))
    }

    let EdgeSplitCache { ab, ba, midpoint } = cache;
    let m = mutation.insert_vertex(midpoint);
    // Split the half-edges.
    split_at_vertex(mutation, ab, m)?;
    split_at_vertex(mutation, ba, m)?;
    Ok(m)
}

pub fn join_with_cache<G>(
    mutation: &mut Mutation<G>,
    cache: EdgeJoinCache<G>,
) -> Result<EdgeKey, Error>
where
    G: Geometry,
{
    let EdgeJoinCache {
        source,
        destination,
        edge,
        face,
    } = cache;
    let (a, b) = source.to_vertex_keys();
    let (c, d) = destination.to_vertex_keys();
    // TODO: Split the face to form triangles.
    mutation.insert_face(&[a, b, c, d], (edge, face))?;
    Ok(source)
}

pub fn extrude_with_cache<G, T>(
    mutation: &mut Mutation<G>,
    cache: EdgeExtrudeCache<G>,
) -> Result<EdgeKey, Error>
where
    G: Geometry + EdgeLateral,
    G::Lateral: Mul<T>,
    G::Vertex: AsPosition,
    ScaledEdgeLateral<G, T>: Clone,
    VertexPosition<G>: Add<ScaledEdgeLateral<G, T>, Output = VertexPosition<G>> + Clone,
{
    let EdgeExtrudeCache { ab, vertices, edge } = cache;
    let c = mutation.insert_vertex(vertices.0);
    let d = mutation.insert_vertex(vertices.1);
    let cd = mutation.insert_edge((c, d), edge)?;
    let cache = EdgeJoinCache::snapshot(
        Core::empty()
            .bind(AsStorage::<Vertex<G>>::as_storage(mutation))
            .bind(AsStorage::<Edge<G>>::as_storage(mutation))
            .bind(AsStorage::<Face<G>>::as_storage(mutation)),
        ab,
        cd,
    )?;
    join_with_cache(mutation, cache)
}
<commit_msg>Do not mutate target `Edge` upon removal and return.<commit_after>use failure::Error;
use std::ops::{Add, Deref, DerefMut, Mul};

use geometry::convert::AsPosition;
use geometry::Geometry;
use graph::geometry::alias::{ScaledEdgeLateral, VertexPosition};
use graph::geometry::{EdgeLateral, EdgeMidpoint};
use graph::mesh::Mesh;
use graph::mutation::vertex::VertexMutation;
use graph::mutation::{Commit, Mode, Mutate, Mutation};
use graph::storage::convert::AsStorage;
use graph::storage::{Bind, Core, EdgeKey, FaceKey, Storage, VertexKey};
use graph::topology::{Edge, Face, Vertex};
use graph::view::convert::IntoView;
use graph::view::{EdgeView, Inconsistent};
use graph::{GraphError, Perimeter, ResultExt};

pub struct EdgeMutation<G>
where
    G: Geometry,
{
    mutation: VertexMutation<G>,
    storage: Storage<Edge<G>>,
}

impl<G> EdgeMutation<G>
where
    G: Geometry,
{
    pub fn insert_edge(
        &mut self,
        vertices: (VertexKey, VertexKey),
        geometry: G::Edge,
    ) -> Result<EdgeKey, Error> {
        let (a, b) = vertices;
        let ab = (a, b).into();
        let ba = (b, a).into();
        // If the edge already exists, then fail. This ensures an important
        // invariant: edges may only have two adjacent faces. That is, a
        // half-edge may only have one associated face, at most one preceding
        // half-edge, at most one following half-edge, and may form at most one
        // closed loop.
        if self.storage.contains_key(&ab) {
            return Err(GraphError::TopologyConflict.into());
        }
        if !self.mutation.as_storage().contains_key(&b) {
            return Err(GraphError::TopologyNotFound.into());
        }
        let mut edge = Edge::new(b, geometry);
        if let Some(opposite) = self.storage.get_mut(&ba) {
            edge.opposite = Some(ba);
            opposite.opposite = Some(ab);
        }
        self.storage.insert_with_key(&ab, edge);
        self.connect_outgoing_edge(a, ab)?;
        Ok(ab)
    }

    pub fn get_or_insert_edge(
        &mut self,
        vertices: (VertexKey, VertexKey),
        geometry: G::Edge,
    ) -> Result<EdgeKey, Error> {
        self.insert_edge(vertices, geometry)
            .or_if_conflict(|| Ok(vertices.into()))
    }

    pub fn get_or_insert_composite_edge(
        &mut self,
        vertices: (VertexKey, VertexKey),
        geometry: G::Edge,
    ) -> Result<(EdgeKey, EdgeKey), Error> {
        let (a, b) = vertices;
        let ab = self.get_or_insert_edge((a, b), geometry.clone())?;
        let ba = self.get_or_insert_edge((b, a), geometry)?;
        Ok((ab, ba))
    }

    pub fn remove_edge(&mut self, ab: EdgeKey) -> Result<Edge<G>, Error> {
        let (a, _) = ab.to_vertex_keys();
        let (xa, bx) = {
            self.storage
                .get(&ab)
                .ok_or_else(|| Error::from(GraphError::TopologyNotFound))
                .map(|edge| (edge.previous, edge.next))
        }?;
        if let Some(xa) = xa {
            self.disconnect_next_edge(xa)?;
        }
        if let Some(bx) = bx {
            self.disconnect_previous_edge(bx)?;
        }
        self.disconnect_outgoing_edge(a)?;
        Ok(self.storage.remove(&ab).unwrap())
    }

    pub fn remove_composite_edge(&mut self, ab: EdgeKey) -> Result<(Edge<G>, Edge<G>), Error> {
        let (a, b) = ab.to_vertex_keys();
        let edge = self.remove_edge((a, b).into())?;
        let opposite = self.remove_edge((b, a).into())?;
        Ok((edge, opposite))
    }

    pub fn connect_neighboring_edges(&mut self, ab: EdgeKey, bc: EdgeKey) -> Result<(), Error> {
        if ab.to_vertex_keys().1 == bc.to_vertex_keys().0 {
            let previous = match self.storage.get_mut(&ab) {
                Some(previous) => {
                    previous.next = Some(bc);
                    Ok(())
                }
                _ => Err(Error::from(GraphError::TopologyNotFound)),
            };
            let next = match self.storage.get_mut(&bc) {
                Some(next) => {
                    next.previous = Some(ab);
                    Ok(())
                }
                _ => Err(Error::from(GraphError::TopologyNotFound)),
            };
            previous.and(next)
        }
        else {
            Err(Error::from(GraphError::TopologyMalformed))
        }
    }

    pub fn disconnect_next_edge(&mut self, ab: EdgeKey) -> Result<Option<EdgeKey>, Error> {
        let bx = {
            self.storage
                .get_mut(&ab)
                .ok_or_else(|| Error::from(GraphError::TopologyNotFound))?
                .next
                .take()
        };
        if let Some(bx) = bx.as_ref() {
            self.storage.get_mut(bx).unwrap().previous = None;
        }
        Ok(bx)
    }

    pub fn disconnect_previous_edge(&mut self, ab: EdgeKey) -> Result<Option<EdgeKey>, Error> {
        let xa = {
            self.storage
                .get_mut(&ab)
                .ok_or_else(|| Error::from(GraphError::TopologyNotFound))?
                .previous
                .take()
        };
        if let Some(xa) = xa.as_ref() {
            self.storage.get_mut(xa).unwrap().previous = None;
        }
        Ok(xa)
    }

    pub fn connect_edge_to_face(&mut self, ab: EdgeKey, abc: FaceKey) -> Result<(), Error> {
        let edge = self
            .storage
            .get_mut(&ab)
            .ok_or_else(|| Error::from(GraphError::TopologyNotFound))?;
        edge.face = Some(abc);
        Ok(())
    }

    pub fn disconnect_edge_from_face(&mut self, ab: EdgeKey) -> Result<Option<FaceKey>, Error> {
        let face = self
            .storage
            .get_mut(&ab)
            .ok_or_else(|| Error::from(GraphError::TopologyNotFound))?
            .face
            .take();
        Ok(face)
    }
}

impl<G> AsStorage<Edge<G>> for EdgeMutation<G>
where
    G: Geometry,
{
    fn as_storage(&self) -> &Storage<Edge<G>> {
        &self.storage
    }
}

impl<G> Commit<G> for EdgeMutation<G>
where
    G: Geometry,
{
    type Error = Error;

    fn commit(self) -> Result<Self::Mutant, Self::Error> {
        let EdgeMutation {
            mutation,
            storage: edges,
            ..
        } = self;
        mutation
            .commit()
            .and_then(move |vertices| Ok((vertices, edges)))
    }
}

impl<G> Deref for EdgeMutation<G>
where
    G: Geometry,
{
    type Target = VertexMutation<G>;

    fn deref(&self) -> &Self::Target {
        &self.mutation
    }
}

impl<G> DerefMut for EdgeMutation<G>
where
    G: Geometry,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.mutation
    }
}

impl<G> Mode<G> for EdgeMutation<G>
where
    G: Geometry,
{
    type Mutant = (Storage<Vertex<G>>, Storage<Edge<G>>);
}

impl<G> Mutate<G> for EdgeMutation<G>
where
    G: Geometry,
{
    fn mutate(mutant: Self::Mutant) -> Self {
        let (vertices, edges) = mutant;
        EdgeMutation {
            mutation: VertexMutation::mutate(vertices),
            storage: edges,
        }
    }
}

pub struct EdgeSplitCache<G>
where
    G: Geometry,
{
    ab: EdgeKey,
    ba: EdgeKey,
    midpoint: G::Vertex,
}

impl<G> EdgeSplitCache<G>
where
    G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
    G::Vertex: AsPosition,
{
    pub fn snapshot<M>(storage: M, ab: EdgeKey) -> Result<Self, Error>
    where
        M: AsStorage<Edge<G>> + AsStorage<Vertex<G>>,
    {
        let (a, b) = ab.to_vertex_keys();
        let edge: EdgeView<M, G, _> = match (ab, storage).into_view() {
            Some(edge) => edge,
            _ => return Err(GraphError::TopologyNotFound.into()),
        };
        let mut midpoint = edge.source_vertex().geometry.clone();
        *midpoint.as_position_mut() = EdgeMidpoint::midpoint(&edge)?;
        Ok(EdgeSplitCache {
            ab,
            ba: (b, a).into(),
            midpoint,
        })
    }
}

pub struct EdgeJoinCache<G>
where
    G: Geometry,
{
    source: EdgeKey,
    destination: EdgeKey,
    edge: G::Edge,
    face: G::Face,
}

impl<G> EdgeJoinCache<G>
where
    G: Geometry,
{
    pub fn snapshot<M>(storage: M, source: EdgeKey, destination: EdgeKey) -> Result<Self, Error>
    where
        M: AsStorage<Edge<G>> + AsStorage<Face<G>> + AsStorage<Vertex<G>>,
    {
        let (a, b) = source.to_vertex_keys();
        let (c, d) = destination.to_vertex_keys();
        let source = match (
            EdgeView::<_, _, Inconsistent>::from_keyed_storage(source, &storage),
            EdgeView::<_, _, Inconsistent>::from_keyed_storage(destination, &storage),
        ) {
            (Some(source), Some(_)) => source,
            _ => return Err(GraphError::TopologyNotFound.into()),
        };
        // At this point, we can assume the points a, b, c, and d exist in the
        // mesh. Before mutating the mesh, ensure that existing interior edges
        // are boundaries.
        for edge in [a, b, c, d]
            .perimeter()
            .flat_map(|ab| EdgeView::<_, _, Inconsistent>::from_keyed_storage(ab.into(), &storage))
        {
            if !edge.is_boundary_edge() {
                return Err(GraphError::TopologyConflict.into());
            }
        }
        Ok(EdgeJoinCache {
            source: source.key(),
            destination,
            edge: source.geometry.clone(),
            face: source
                .reachable_opposite_edge()
                .and_then(|opposite| opposite.into_reachable_face())
                .map(|face| face.geometry.clone())
                .unwrap_or_else(Default::default),
        })
    }
}

pub struct EdgeExtrudeCache<G>
where
    G: Geometry,
{
    ab: EdgeKey,
    vertices: (G::Vertex, G::Vertex),
    edge: G::Edge,
}

impl<G> EdgeExtrudeCache<G>
where
    G: Geometry,
{
    pub fn snapshot<T>(storage: &Mesh<G>, ab: EdgeKey, distance: T) -> Result<Self, Error>
    where
        G: Geometry + EdgeLateral,
        G::Lateral: Mul<T>,
        G::Vertex: AsPosition,
        ScaledEdgeLateral<G, T>: Clone,
        VertexPosition<G>: Add<ScaledEdgeLateral<G, T>, Output = VertexPosition<G>> + Clone,
    {
        // Get the extruded geometry.
        let (vertices, edge) = {
            let edge = match storage.edge(ab) {
                Some(edge) => edge,
                _ => return Err(GraphError::TopologyNotFound.into()),
            };
            if !edge.is_boundary_edge() {
                return Err(GraphError::TopologyConflict.into());
            }
            let mut vertices = (
                edge.destination_vertex().geometry.clone(),
                edge.source_vertex().geometry.clone(),
            );
            let translation = edge.lateral()? * distance;
            *vertices.0.as_position_mut() = vertices.0.as_position().clone() + translation.clone();
            *vertices.1.as_position_mut() = vertices.1.as_position().clone() + translation;
            (vertices, edge.geometry.clone())
        };
        Ok(EdgeExtrudeCache { ab, vertices, edge })
    }
}

pub fn split_with_cache<G>(
    mutation: &mut Mutation<G>,
    cache: EdgeSplitCache<G>,
) -> Result<VertexKey, Error>
where
    G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
    G::Vertex: AsPosition,
{
    fn split_at_vertex<G>(
        mutation: &mut Mutation<G>,
        ab: EdgeKey,
        m: VertexKey,
    ) -> Result<(EdgeKey, EdgeKey), Error>
    where
        G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
        G::Vertex: AsPosition,
    {
        // Remove the edge and insert two truncated edges in its place.
        let (a, b) = ab.to_vertex_keys();
        let span = mutation.remove_edge(ab)?;
        let am = mutation.insert_edge((a, m), span.geometry.clone())?;
        let mb = mutation.insert_edge((m, b), span.geometry.clone())?;
        // Connect the new edges to each other and their leading edges.
        mutation.connect_neighboring_edges(am, mb)?;
        if let Some(xa) = span.previous {
            mutation.connect_neighboring_edges(xa, am)?;
        }
        if let Some(bx) = span.next {
            mutation.connect_neighboring_edges(mb, bx)?;
        }
        // Update the associated face, if any, because it may refer to the
        // removed edge.
        if let Some(abc) = span.face {
            mutation.connect_face_to_edge(am, abc)?;
            mutation.connect_edge_to_face(am, abc)?;
            mutation.connect_edge_to_face(mb, abc)?;
        }
        Ok((am, mb))
    }

    let EdgeSplitCache { ab, ba, midpoint } = cache;
    let m = mutation.insert_vertex(midpoint);
    // Split the half-edges.
    split_at_vertex(mutation, ab, m)?;
    split_at_vertex(mutation, ba, m)?;
    Ok(m)
}

pub fn join_with_cache<G>(
    mutation: &mut Mutation<G>,
    cache: EdgeJoinCache<G>,
) -> Result<EdgeKey, Error>
where
    G: Geometry,
{
    let EdgeJoinCache {
        source,
        destination,
        edge,
        face,
    } = cache;
    let (a, b) = source.to_vertex_keys();
    let (c, d) = destination.to_vertex_keys();
    // TODO: Split the face to form triangles.
    mutation.insert_face(&[a, b, c, d], (edge, face))?;
    Ok(source)
}

pub fn extrude_with_cache<G, T>(
    mutation: &mut Mutation<G>,
    cache: EdgeExtrudeCache<G>,
) -> Result<EdgeKey, Error>
where
    G: Geometry + EdgeLateral,
    G::Lateral: Mul<T>,
    G::Vertex: AsPosition,
    ScaledEdgeLateral<G, T>: Clone,
    VertexPosition<G>: Add<ScaledEdgeLateral<G, T>, Output = VertexPosition<G>> + Clone,
{
    let EdgeExtrudeCache { ab, vertices, edge } = cache;
    let c = mutation.insert_vertex(vertices.0);
    let d = mutation.insert_vertex(vertices.1);
    let cd = mutation.insert_edge((c, d), edge)?;
    let cache = EdgeJoinCache::snapshot(
        Core::empty()
            .bind(AsStorage::<Vertex<G>>::as_storage(mutation))
            .bind(AsStorage::<Edge<G>>::as_storage(mutation))
            .bind(AsStorage::<Face<G>>::as_storage(mutation)),
        ab,
        cd,
    )?;
    join_with_cache(mutation, cache)
}
<|endoftext|>


<commit_before>#![feature(str_match_indices, test)]

extern crate quickcheck;
extern crate suffix;
extern crate test;

use quickcheck::{QuickCheck, TestResult, Testable};
use suffix::SuffixTable;

// A trivial logging macro. No reason to pull in `log`, which has become
// difficult to use in tests.
macro_rules! lg {
    ($($arg:tt)*) => ({
        let _ = writeln!(&mut ::std::old_io::stderr(), $($arg)*);
    });
}

fn sais(text: &str) -> SuffixTable { SuffixTable::new(text) }
fn naive(text: &str) -> SuffixTable { SuffixTable::new_naive(text) }

fn qc<T: Testable>(f: T) {
    QuickCheck::new().tests(1000).max_tests(10000).quickcheck(f);
}

// These tests assume the correctness of the `naive` method of computing a
// suffix array. (It's only a couple lines of code and probably difficult to
// get wrong.)

#[test]
fn basic1() {
    assert_eq!(naive("apple"), sais("apple"));
}

#[test]
fn basic2() {
    assert_eq!(naive("banana"), sais("banana"));
}

#[test]
fn basic3() {
    assert_eq!(naive("mississippi"), sais("mississippi"));
}

#[test]
fn basic4() {
    assert_eq!(naive("tgtgtgtgcaccg"), sais("tgtgtgtgcaccg"));
}

#[test]
fn empty_is_ok() {
    assert_eq!(naive(""), sais(""));
}

#[test]
fn one_is_ok() {
    assert_eq!(naive("a"), sais("a"));
}

#[test]
fn two_diff_is_ok() {
    assert_eq!(naive("ab"), sais("ab"));
}

#[test]
fn two_same_is_ok() {
    assert_eq!(naive("aa"), sais("aa"));
}

#[test]
fn nul_is_ok() {
    assert_eq!(naive("\x00"), sais("\x00"));
}

#[test]
fn snowman_is_ok() {
    assert_eq!(naive("☃abc☃"), sais("☃abc☃"));
}

// See if we can catch any corner cases we forgot about.
#[test]
fn prop_naive_equals_sais() {
    fn prop(s: String) -> TestResult {
        if s.is_empty() { return TestResult::discard(); }
        let expected = naive(&*s);
        let got = sais(&*s);
        TestResult::from_bool(expected == got)
    }
    qc(prop as fn(String) -> TestResult);
}

// Do some testing on substring search.

#[test]
fn empty_find_empty() {
    let sa = sais("");
    assert_eq!(sa.positions(""), &[]);
    assert!(!sa.contains(""));
}

#[test]
fn empty_find_one() {
    let sa = sais("");
    assert_eq!(sa.positions("a"), &[]);
    assert!(!sa.contains("a"));
}

#[test]
fn empty_find_two() {
    let sa = sais("");
    assert_eq!(sa.positions("ab"), &[]);
    assert!(!sa.contains("ab"));
}

#[test]
fn one_find_empty() {
    let sa = sais("a");
    assert_eq!(sa.positions(""), &[]);
    assert!(!sa.contains(""));
}

#[test]
fn one_find_one_notexists() {
    let sa = sais("a");
    assert_eq!(sa.positions("b"), &[]);
    assert!(!sa.contains("b"));
}

#[test]
fn one_find_one_exists() {
    let sa = sais("a");
    assert_eq!(sa.positions("a"), &[0]);
    assert!(sa.contains("a"));
}

#[test]
fn two_find_one_exists() {
    let sa = sais("ab");
    assert_eq!(sa.positions("b"), &[1]);
    assert!(sa.contains("b"));
}

#[test]
fn two_find_two_exists() {
    let sa = sais("aa");
    assert_eq!(vec![1, 0], sa.positions("a"));
    assert!(sa.contains("a"));
}

#[test]
fn many_exists() {
    let sa = sais("zzzzzaazzzzz");
    assert_eq!(vec![5, 6], sa.positions("a"));
    assert!(sa.contains("a"));
}

#[test]
fn many_exists_long() {
    let sa = sais("zzzzabczzzzzabczzzzzz");
    assert_eq!(sa.positions("abc"), &[4, 12]);
    assert!(sa.contains("abc"));
}

#[test]
fn parts() {
    let sa = sais("poëzie");
    let sa2 = sa.clone();

    let (data, table) = sa2.into_parts();
    let sa3 = SuffixTable::from_parts(data, table);

    assert_eq!(sa, sa3);
}

#[test]
fn query_longer() {
    let sa = sais("az");
    assert_eq!(sa.positions("mnomnomnomnomnomnomno"), &[]);
    assert!(!sa.contains("mnomnomnomnomnomnomno"));
}

#[test]
fn query_longer_less() {
    let sa = sais("zz");
    assert_eq!(sa.positions("mnomnomnomnomnomnomno"), &[]);
    assert!(!sa.contains("mnomnomnomnomnomnomno"));
}

#[test]
fn query_longer_greater() {
    let sa = sais("aa");
    assert_eq!(sa.positions("mnomnomnomnomnomnomno"), &[]);
    assert!(!sa.contains("mnomnomnomnomnomnomno"));
}

#[test]
fn query_spaces() {
    let sa = sais("The quick brown fox was very quick.");
    assert_eq!(sa.positions("quick"), &[4, 29]);
}

#[test]
fn unicode_snowman() {
    let sa = sais("☃abc☃");
    assert!(sa.contains("☃"));
    assert_eq!(sa.positions("☃"), &[6, 0]);
}

#[test]
fn prop_contains() {
    fn prop(s: String, c: u8) -> bool {
        let c = (c as char).to_string();
        s.contains(&c) == sais(&s).contains(&c)
    }
    qc(prop as fn(String, u8) -> bool);
}

#[test]
fn prop_positions() {
    fn prop(s: String, c: u8) -> bool {
        let c = (c as char).to_string();
        let expected: Vec<_> =
            s.match_indices(&c).map(|(s, _)| s as u32).collect();
        let mut got = sais(&s).positions(&c).to_vec();
        got.sort();
        expected == got
    }
    qc(prop as fn(String, u8) -> bool);
}
<commit_msg>Add a couple quickcheck properties.<commit_after>#![feature(test)]

extern crate quickcheck;
extern crate suffix;
extern crate test;

use quickcheck::{QuickCheck, TestResult, Testable};
use suffix::SuffixTable;

// A trivial logging macro. No reason to pull in `log`, which has become
// difficult to use in tests.
macro_rules! lg {
    ($($arg:tt)*) => ({
        let _ = writeln!(&mut ::std::old_io::stderr(), $($arg)*);
    });
}

fn sais(text: &str) -> SuffixTable { SuffixTable::new(text) }
fn naive(text: &str) -> SuffixTable { SuffixTable::new_naive(text) }

fn qc<T: Testable>(f: T) {
    QuickCheck::new().tests(1000).max_tests(10000).quickcheck(f);
}

// These tests assume the correctness of the `naive` method of computing a
// suffix array. (It's only a couple lines of code and probably difficult to
// get wrong.)

#[test]
fn basic1() {
    assert_eq!(naive("apple"), sais("apple"));
}

#[test]
fn basic2() {
    assert_eq!(naive("banana"), sais("banana"));
}

#[test]
fn basic3() {
    assert_eq!(naive("mississippi"), sais("mississippi"));
}

#[test]
fn basic4() {
    assert_eq!(naive("tgtgtgtgcaccg"), sais("tgtgtgtgcaccg"));
}

#[test]
fn empty_is_ok() {
    assert_eq!(naive(""), sais(""));
}

#[test]
fn one_is_ok() {
    assert_eq!(naive("a"), sais("a"));
}

#[test]
fn two_diff_is_ok() {
    assert_eq!(naive("ab"), sais("ab"));
}

#[test]
fn two_same_is_ok() {
    assert_eq!(naive("aa"), sais("aa"));
}

#[test]
fn nul_is_ok() {
    assert_eq!(naive("\x00"), sais("\x00"));
}

#[test]
fn snowman_is_ok() {
    assert_eq!(naive("☃abc☃"), sais("☃abc☃"));
}

// See if we can catch any corner cases we forgot about.
#[test]
fn prop_naive_equals_sais() {
    fn prop(s: String) -> TestResult {
        if s.is_empty() { return TestResult::discard(); }
        let expected = naive(&*s);
        let got = sais(&*s);
        TestResult::from_bool(expected == got)
    }
    qc(prop as fn(String) -> TestResult);
}

#[test]
fn prop_matches_naive() {
    fn prop(s: String) -> bool {
        let expected_table = SuffixTable::new_naive(&*s);
        let expected = expected_table.table();
        let got_table = SuffixTable::new(&*s);
        let got = got_table.table();
        expected == got
    }
    qc(prop as fn(String) -> bool);
}

// Do some testing on substring search.

#[test]
fn empty_find_empty() {
    let sa = sais("");
    assert_eq!(sa.positions(""), &[]);
    assert!(!sa.contains(""));
}

#[test]
fn empty_find_one() {
    let sa = sais("");
    assert_eq!(sa.positions("a"), &[]);
    assert!(!sa.contains("a"));
}

#[test]
fn empty_find_two() {
    let sa = sais("");
    assert_eq!(sa.positions("ab"), &[]);
    assert!(!sa.contains("ab"));
}

#[test]
fn one_find_empty() {
    let sa = sais("a");
    assert_eq!(sa.positions(""), &[]);
    assert!(!sa.contains(""));
}

#[test]
fn one_find_one_notexists() {
    let sa = sais("a");
    assert_eq!(sa.positions("b"), &[]);
    assert!(!sa.contains("b"));
}

#[test]
fn one_find_one_exists() {
    let sa = sais("a");
    assert_eq!(sa.positions("a"), &[0]);
    assert!(sa.contains("a"));
}

#[test]
fn two_find_one_exists() {
    let sa = sais("ab");
    assert_eq!(sa.positions("b"), &[1]);
    assert!(sa.contains("b"));
}

#[test]
fn two_find_two_exists() {
    let sa = sais("aa");
    assert_eq!(vec![1, 0], sa.positions("a"));
    assert!(sa.contains("a"));
}

#[test]
fn many_exists() {
    let sa = sais("zzzzzaazzzzz");
    assert_eq!(vec![5, 6], sa.positions("a"));
    assert!(sa.contains("a"));
}

#[test]
fn many_exists_long() {
    let sa = sais("zzzzabczzzzzabczzzzzz");
    assert_eq!(sa.positions("abc"), &[4, 12]);
    assert!(sa.contains("abc"));
}

#[test]
fn parts() {
    let sa = sais("poëzie");
    let sa2 = sa.clone();

    let (data, table) = sa2.into_parts();
    let sa3 = SuffixTable::from_parts(data, table);

    assert_eq!(sa, sa3);
}

#[test]
fn query_longer() {
    let sa = sais("az");
    assert_eq!(sa.positions("mnomnomnomnomnomnomno"), &[]);
    assert!(!sa.contains("mnomnomnomnomnomnomno"));
}

#[test]
fn query_longer_less() {
    let sa = sais("zz");
    assert_eq!(sa.positions("mnomnomnomnomnomnomno"), &[]);
    assert!(!sa.contains("mnomnomnomnomnomnomno"));
}

#[test]
fn query_longer_greater() {
    let sa = sais("aa");
    assert_eq!(sa.positions("mnomnomnomnomnomnomno"), &[]);
    assert!(!sa.contains("mnomnomnomnomnomnomno"));
}

#[test]
fn query_spaces() {
    let sa = sais("The quick brown fox was very quick.");
    assert_eq!(sa.positions("quick"), &[4, 29]);
}

#[test]
fn unicode_snowman() {
    let sa = sais("☃abc☃");
    assert!(sa.contains("☃"));
    assert_eq!(sa.positions("☃"), &[6, 0]);
}

#[test]
fn prop_length() {
    fn prop(s: String) -> bool {
        s.len() == sais(&s).len()
    }
    qc(prop as fn(String) -> bool);
}

#[test]
fn prop_contains() {
    fn prop(s: String, c: u8) -> bool {
        let c = (c as char).to_string();
        s.contains(&c) == sais(&s).contains(&c)
    }
    qc(prop as fn(String, u8) -> bool);
}

#[test]
fn prop_positions() {
    fn prop(s: String, c: u8) -> bool {
        let c = (c as char).to_string();
        let expected: Vec<_> =
            s.match_indices(&c).map(|(s, _)| s as u32).collect();
        let mut got = sais(&s).positions(&c).to_vec();
        got.sort();
        expected == got
    }
    qc(prop as fn(String, u8) -> bool);
}
<|endoftext|>


<commit_before>// `cargo test --benches` and `#[feature(test)]` work only in nightly
#![cfg(rustc_nightly)]
#![cfg(feature = "bytes")]
#![feature(test)]

extern crate bytes;
extern crate test;

extern crate protobuf;

extern crate perftest_bytes;

use std::fmt::Write;

use bytes::Bytes;

use perftest_bytes::messages;
use protobuf::Message;

fn make_string_of_len(len: usize) -> String {
    let mut s = String::new();
    for i in 0..len {
        write!(s, "{}", i % 10).expect("unreachable");
    }
    s
}

fn make_repeated(len: usize) -> Vec<u8> {
    let mut m = messages::TestMessage::new();

    for i in 0..100 {
        m.sr.push(make_string_of_len(i % len));
        m.br.push(make_string_of_len((i + len / 2) % len).into_bytes());
    }

    m.write_to_bytes().expect("write")
}

#[bench]
fn parse_repeated_small_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30);
    b.iter(|| protobuf::parse_from_bytes::<messages::TestMessage>(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_small_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30));
    b.iter(|| {
        protobuf::parse_from_carllerche_bytes::<messages::TestMessageWithBytes>(&bs).expect("parse")
    })
}

#[bench]
fn parse_repeated_medium_regular(b: &mut test::Bencher) {
    let bs = make_repeated(300);
    b.iter(|| protobuf::parse_from_bytes::<messages::TestMessage>(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(300));
    b.iter(|| {
        protobuf::parse_from_carllerche_bytes::<messages::TestMessageWithBytes>(&bs).expect("parse")
    })
}

#[bench]
fn parse_repeated_large_regular(b: &mut test::Bencher) {
    let bs = make_repeated(3000);
    b.iter(|| protobuf::parse_from_bytes::<messages::TestMessage>(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(3000));
    b.iter(|| {
        protobuf::parse_from_carllerche_bytes::<messages::TestMessageWithBytes>(&bs).expect("parse")
    })
}

#[bench]
fn parse_repeated_huge_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30000);
    b.iter(|| protobuf::parse_from_bytes::<messages::TestMessage>(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30000));
    b.iter(|| {
        protobuf::parse_from_carllerche_bytes::<messages::TestMessageWithBytes>(&bs).expect("parse")
    })
}
<commit_msg>Fix benches compilation<commit_after>// `cargo test --benches` and `#[feature(test)]` work only in nightly
#![cfg(rustc_nightly)]
#![cfg(feature = "bytes")]
#![feature(test)]

extern crate bytes;
extern crate test;

extern crate protobuf;

extern crate perftest_bytes;

use std::fmt::Write;

use bytes::Bytes;

use perftest_bytes::messages;
use protobuf::Message;

fn make_string_of_len(len: usize) -> String {
    let mut s = String::new();
    for i in 0..len {
        write!(s, "{}", i % 10).expect("unreachable");
    }
    s
}

fn make_repeated(len: usize) -> Vec<u8> {
    let mut m = messages::TestMessage::new();

    for i in 0..100 {
        m.sr.push(make_string_of_len(i % len));
        m.br.push(make_string_of_len((i + len / 2) % len).into_bytes());
    }

    m.write_to_bytes().expect("write")
}

#[bench]
fn parse_repeated_small_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_small_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30));
    b.iter(|| messages::TestMessageWithBytes::parse_from_carllerche_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_regular(b: &mut test::Bencher) {
    let bs = make_repeated(300);
    b.iter(|| protobuf::parse_from_bytes::<messages::TestMessage>(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(300));
    b.iter(|| messages::TestMessageWithBytes::parse_from_carllerche_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_regular(b: &mut test::Bencher) {
    let bs = make_repeated(3000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(3000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_carllerche_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_carllerche_bytes(&bs).expect("parse"))
}
<|endoftext|>


<commit_before>use crate::alloc::Layout;
use crate::cmp;
use crate::ptr;

/// A memory allocator that can be registered as the standard library’s default
/// through the `#[global_allocator]` attribute.
///
/// Some of the methods require that a memory block be *currently
/// allocated* via an allocator. This means that:
///
/// * the starting address for that memory block was previously
///   returned by a previous call to an allocation method
///   such as `alloc`, and
///
/// * the memory block has not been subsequently deallocated, where
///   blocks are deallocated either by being passed to a deallocation
///   method such as `dealloc` or by being
///   passed to a reallocation method that returns a non-null pointer.
///
///
/// # Example
///
/// ```no_run
/// use std::alloc::{GlobalAlloc, Layout, alloc};
/// use std::ptr::null_mut;
///
/// struct MyAllocator;
///
/// unsafe impl GlobalAlloc for MyAllocator {
///     unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
///     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
/// }
///
/// #[global_allocator]
/// static A: MyAllocator = MyAllocator;
///
/// fn main() {
///     unsafe {
///         assert!(alloc(Layout::new::<u32>()).is_null())
///     }
/// }
/// ```
///
/// # Safety
///
/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
/// implementors must ensure that they adhere to these contracts:
///
/// * It's undefined behavior if global allocators unwind. This restriction may
///   be lifted in the future, but currently a panic from any of these
///   functions may lead to memory unsafety.
///
/// * `Layout` queries and calculations in general must be correct. Callers of
///   this trait are allowed to rely on the contracts defined on each method,
///   and implementors must ensure such contracts remain true.
///
/// * You may not rely on allocations actually happening, even if there are explicit
///   heap allocations in the source. The optimizer may detect unused allocations that it can either
///   eliminate entirely or move to the stack and thus never invoke the allocator. The
///   optimizer may further assume that allocation is infallible, so code that used to fail due
///   to allocator failures may now suddenly work because the optimizer worked around the
///   need for an allocation. More concretely, the following code example is unsound, irrespective
///   of whether your custom allocator allows counting how many allocations have happened.
///
///   ```rust,ignore (unsound and has placeholders)
///   drop(Box::new(42));
///   let number_of_heap_allocs = /* call private allocator API */;
///   unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); }
///   ```
///
///   Note that the optimizations mentioned above are not the only
///   optimization that can be applied. You may generally not rely on heap allocations
///   happening if they can be removed without changing program behavior.
///   Whether allocations happen or not is not part of the program behavior, even if it
///   could be detected via an allocator that tracks allocations by printing or otherwise
///   having side effects.
#[stable(feature = "global_alloc", since = "1.28.0")]
pub unsafe trait GlobalAlloc {
    /// Allocate memory as described by the given `layout`.
    ///
    /// Returns a pointer to newly-allocated memory,
    /// or null to indicate allocation failure.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure that `layout` has non-zero size.
    ///
    /// (Extension subtraits might provide more specific bounds on
    /// behavior, e.g., guarantee a sentinel address or a null pointer
    /// in response to a zero-size allocation request.)
    ///
    /// The allocated block of memory may or may not be initialized.
    ///
    /// # Errors
    ///
    /// Returning a null pointer indicates that either memory is exhausted
    /// or `layout` does not meet this allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return null on memory
    /// exhaustion rather than aborting, but this is not
    /// a strict requirement. (Specifically: it is *legal* to
    /// implement this trait atop an underlying native allocation
    /// library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an
    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn alloc(&self, layout: Layout) -> *mut u8;

    /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure all of the following:
    ///
    /// * `ptr` must denote a block of memory currently allocated via
    ///   this allocator,
    ///
    /// * `layout` must be the same layout that was used
    ///   to allocate that block of memory.
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);

    /// Behaves like `alloc`, but also ensures that the contents
    /// are set to zero before being returned.
    ///
    /// # Safety
    ///
    /// This function is unsafe for the same reasons that `alloc` is.
    /// However the allocated block of memory is guaranteed to be initialized.
    ///
    /// # Errors
    ///
    /// Returning a null pointer indicates that either memory is exhausted
    /// or `layout` does not meet allocator's size or alignment constraints,
    /// just as in `alloc`.
    ///
    /// Clients wishing to abort computation in response to an
    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        let size = layout.size();
        // SAFETY: the safety contract for `alloc` must be upheld by the caller.
        let ptr = unsafe { self.alloc(layout) };
        if !ptr.is_null() {
            // SAFETY: as allocation succeeded, the region from `ptr`
            // of size `size` is guaranteed to be valid for writes.
            unsafe { ptr::write_bytes(ptr, 0, size) };
        }
        ptr
    }

    /// Shrink or grow a block of memory to the given `new_size`.
    /// The block is described by the given `ptr` pointer and `layout`.
    ///
    /// If this returns a non-null pointer, then ownership of the memory block
    /// referenced by `ptr` has been transferred to this allocator.
    /// The memory may or may not have been deallocated,
    /// and should be considered unusable (unless of course it was
    /// transferred back to the caller again via the return value of
    /// this method). The new memory block is allocated with `layout`, but
    /// with the `size` updated to `new_size`. This new layout should be
    /// used when deallocating the new memory block with `dealloc`. The range
    /// `0..min(layout.size(), new_size)` of the new memory block is
    /// guaranteed to have the same values as the original block.
    ///
    /// If this method returns null, then ownership of the memory
    /// block has not been transferred to this allocator, and the
    /// contents of the memory block are unaltered.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure all of the following:
    ///
    /// * `ptr` must be currently allocated via this allocator,
    ///
    /// * `layout` must be the same layout that was used
    ///   to allocate that block of memory,
    ///
    /// * `new_size` must be greater than zero.
    ///
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
    ///   must not overflow (i.e., the rounded value must be less than `usize::MAX`).
    ///
    /// (Extension subtraits might provide more specific bounds on
    /// behavior, e.g., guarantee a sentinel address or a null pointer
    /// in response to a zero-size allocation request.)
    ///
    /// # Errors
    ///
    /// Returns null if the new layout does not meet the size
    /// and alignment constraints of the allocator, or if reallocation
    /// otherwise fails.
    ///
    /// Implementations are encouraged to return null on memory
    /// exhaustion rather than panicking or aborting, but this is not
    /// a strict requirement. (Specifically: it is *legal* to
    /// implement this trait atop an underlying native allocation
    /// library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to a
    /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        // SAFETY: the caller must ensure that the `new_size` does not overflow.
        // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
        let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
        // SAFETY: the caller must ensure that `new_layout` is greater than zero.
        let new_ptr = unsafe { self.alloc(new_layout) };
        if !new_ptr.is_null() {
            // SAFETY: the previously allocated block cannot overlap the newly allocated block.
            // The safety contract for `dealloc` must be upheld by the caller.
            unsafe {
                ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
                self.dealloc(ptr, layout);
            }
        }
        new_ptr
    }
}
<commit_msg>Rollup merge of #81864 - ijackson:globalalloc-example, r=Amanieu<commit_after>use crate::alloc::Layout;
use crate::cmp;
use crate::ptr;

/// A memory allocator that can be registered as the standard library’s default
/// through the `#[global_allocator]` attribute.
///
/// Some of the methods require that a memory block be *currently
/// allocated* via an allocator. This means that:
///
/// * the starting address for that memory block was previously
///   returned by a previous call to an allocation method
///   such as `alloc`, and
///
/// * the memory block has not been subsequently deallocated, where
///   blocks are deallocated either by being passed to a deallocation
///   method such as `dealloc` or by being
///   passed to a reallocation method that returns a non-null pointer.
///
///
/// # Example
///
/// ```
/// use std::alloc::{GlobalAlloc, Layout};
/// use std::cell::UnsafeCell;
/// use std::ptr::null_mut;
/// use std::sync::atomic::{
///     AtomicUsize,
///     Ordering::{Acquire, SeqCst},
/// };
///
/// const ARENA_SIZE: usize = 128 * 1024;
/// const MAX_SUPPORTED_ALIGN: usize = 4096;
/// #[repr(C, align(4096))] // 4096 == MAX_SUPPORTED_ALIGN
/// struct SimpleAllocator {
///     arena: UnsafeCell<[u8; ARENA_SIZE]>,
///     remaining: AtomicUsize, // we allocate from the top, counting down
/// }
///
/// #[global_allocator]
/// static ALLOCATOR: SimpleAllocator = SimpleAllocator {
///     arena: UnsafeCell::new([0x55; ARENA_SIZE]),
///     remaining: AtomicUsize::new(ARENA_SIZE),
/// };
///
/// unsafe impl Sync for SimpleAllocator {}
///
/// unsafe impl GlobalAlloc for SimpleAllocator {
///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
///         let size = layout.size();
///         let align = layout.align();
///
///         // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2.
///         // So we can safely use a mask to ensure alignment without worrying about UB.
///         let align_mask_to_round_down = !(align - 1);
///
///         if align > MAX_SUPPORTED_ALIGN {
///             return null_mut();
///         }
///
///         let mut allocated = 0;
///         if self
///             .remaining
///             .fetch_update(SeqCst, SeqCst, |mut remaining| {
///                 if size > remaining {
///                     return None;
///                 }
///                 remaining -= size;
///                 remaining &= align_mask_to_round_down;
///                 allocated = remaining;
///                 Some(remaining)
///             })
///             .is_err()
///         {
///             return null_mut();
///         };
///         (self.arena.get() as *mut u8).add(allocated)
///     }
///     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
/// }
///
/// fn main() {
///     let _s = format!("allocating a string!");
///     let currently = ALLOCATOR.remaining.load(Acquire);
///     println!("allocated so far: {}", ARENA_SIZE - currently);
/// }
/// ```
///
/// # Safety
///
/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
/// implementors must ensure that they adhere to these contracts:
///
/// * It's undefined behavior if global allocators unwind. This restriction may
///   be lifted in the future, but currently a panic from any of these
///   functions may lead to memory unsafety.
///
/// * `Layout` queries and calculations in general must be correct. Callers of
///   this trait are allowed to rely on the contracts defined on each method,
///   and implementors must ensure such contracts remain true.
///
/// * You may not rely on allocations actually happening, even if there are explicit
///   heap allocations in the source. The optimizer may detect unused allocations that it can either
///   eliminate entirely or move to the stack and thus never invoke the allocator. The
///   optimizer may further assume that allocation is infallible, so code that used to fail due
///   to allocator failures may now suddenly work because the optimizer worked around the
///   need for an allocation. More concretely, the following code example is unsound, irrespective
///   of whether your custom allocator allows counting how many allocations have happened.
///
///   ```rust,ignore (unsound and has placeholders)
///   drop(Box::new(42));
///   let number_of_heap_allocs = /* call private allocator API */;
///   unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); }
///   ```
///
///   Note that the optimizations mentioned above are not the only
///   optimization that can be applied. You may generally not rely on heap allocations
///   happening if they can be removed without changing program behavior.
///   Whether allocations happen or not is not part of the program behavior, even if it
///   could be detected via an allocator that tracks allocations by printing or otherwise
///   having side effects.
#[stable(feature = "global_alloc", since = "1.28.0")]
pub unsafe trait GlobalAlloc {
    /// Allocate memory as described by the given `layout`.
    ///
    /// Returns a pointer to newly-allocated memory,
    /// or null to indicate allocation failure.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure that `layout` has non-zero size.
    ///
    /// (Extension subtraits might provide more specific bounds on
    /// behavior, e.g., guarantee a sentinel address or a null pointer
    /// in response to a zero-size allocation request.)
    ///
    /// The allocated block of memory may or may not be initialized.
    ///
    /// # Errors
    ///
    /// Returning a null pointer indicates that either memory is exhausted
    /// or `layout` does not meet this allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return null on memory
    /// exhaustion rather than aborting, but this is not
    /// a strict requirement. (Specifically: it is *legal* to
    /// implement this trait atop an underlying native allocation
    /// library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an
    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn alloc(&self, layout: Layout) -> *mut u8;

    /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure all of the following:
    ///
    /// * `ptr` must denote a block of memory currently allocated via
    ///   this allocator,
    ///
    /// * `layout` must be the same layout that was used
    ///   to allocate that block of memory.
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);

    /// Behaves like `alloc`, but also ensures that the contents
    /// are set to zero before being returned.
    ///
    /// # Safety
    ///
    /// This function is unsafe for the same reasons that `alloc` is.
    /// However the allocated block of memory is guaranteed to be initialized.
    ///
    /// # Errors
    ///
    /// Returning a null pointer indicates that either memory is exhausted
    /// or `layout` does not meet allocator's size or alignment constraints,
    /// just as in `alloc`.
    ///
    /// Clients wishing to abort computation in response to an
    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        let size = layout.size();
        // SAFETY: the safety contract for `alloc` must be upheld by the caller.
        let ptr = unsafe { self.alloc(layout) };
        if !ptr.is_null() {
            // SAFETY: as allocation succeeded, the region from `ptr`
            // of size `size` is guaranteed to be valid for writes.
            unsafe { ptr::write_bytes(ptr, 0, size) };
        }
        ptr
    }

    /// Shrink or grow a block of memory to the given `new_size`.
    /// The block is described by the given `ptr` pointer and `layout`.
    ///
    /// If this returns a non-null pointer, then ownership of the memory block
    /// referenced by `ptr` has been transferred to this allocator.
    /// The memory may or may not have been deallocated,
    /// and should be considered unusable (unless of course it was
    /// transferred back to the caller again via the return value of
    /// this method). The new memory block is allocated with `layout`, but
    /// with the `size` updated to `new_size`. This new layout should be
    /// used when deallocating the new memory block with `dealloc`. The range
    /// `0..min(layout.size(), new_size)` of the new memory block is
    /// guaranteed to have the same values as the original block.
    ///
    /// If this method returns null, then ownership of the memory
    /// block has not been transferred to this allocator, and the
    /// contents of the memory block are unaltered.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure all of the following:
    ///
    /// * `ptr` must be currently allocated via this allocator,
    ///
    /// * `layout` must be the same layout that was used
    ///   to allocate that block of memory,
    ///
    /// * `new_size` must be greater than zero.
    ///
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
    ///   must not overflow (i.e., the rounded value must be less than `usize::MAX`).
    ///
    /// (Extension subtraits might provide more specific bounds on
    /// behavior, e.g., guarantee a sentinel address or a null pointer
    /// in response to a zero-size allocation request.)
    ///
    /// # Errors
    ///
    /// Returns null if the new layout does not meet the size
    /// and alignment constraints of the allocator, or if reallocation
    /// otherwise fails.
    ///
    /// Implementations are encouraged to return null on memory
    /// exhaustion rather than panicking or aborting, but this is not
    /// a strict requirement. (Specifically: it is *legal* to
    /// implement this trait atop an underlying native allocation
    /// library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to a
    /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        // SAFETY: the caller must ensure that the `new_size` does not overflow.
        // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
        let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
        // SAFETY: the caller must ensure that `new_layout` is greater than zero.
        let new_ptr = unsafe { self.alloc(new_layout) };
        if !new_ptr.is_null() {
            // SAFETY: the previously allocated block cannot overlap the newly allocated block.
            // The safety contract for `dealloc` must be upheld by the caller.
            unsafe {
                ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
                self.dealloc(ptr, layout);
            }
        }
        new_ptr
    }
}
<|endoftext|>


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

use std::sync::{Arc, Mutex};
use std::thread::sleep;
use std::time::Duration;

use futures::{Future, Sink, Stream};
use grpcio;
use protobuf::Message;

use errors::*;
use grpc::sdk;
use grpc::sdk_grpc;
use types::*;

const PORT: i32 = 59357;

/// SDK is an instance of the Agones SDK
pub struct Sdk {
    client: Arc<sdk_grpc::SdkClient>,
    health: Arc<Mutex<Option<grpcio::ClientCStreamSender<sdk::Empty>>>>,
}

impl Sdk {
    /// Starts a new SDK instance, and connects to localhost on port 59357.
    /// Blocks until connection and handshake are made.
    /// Times out after ~30 seconds.
    pub fn new() -> Result<Sdk> {
        let addr = format!("localhost:{}", PORT);
        let env = Arc::new(grpcio::EnvBuilder::new().build());
        let ch = grpcio::ChannelBuilder::new(env)
            .keepalive_timeout(Duration::new(30, 0))
            .connect(&addr);
        let cli = sdk_grpc::SdkClient::new(ch);
        let req = sdk::Empty::new();

        // Unfortunately there isn't a native way to block until connected
        // so we had to roll our own.
        let mut counter = 0;
        loop {
            counter += 1;
            match cli.get_game_server(&req) {
                Ok(_) => break,
                Err(e) => {
                    if counter > 30 {
                        return Err(ErrorKind::Grpc(e).into());
                    }
                    sleep(Duration::from_secs(1));
                    continue;
                }
            }
        }

        let (sender, _) = cli.health()?;
        Ok(Sdk {
            client: Arc::new(cli),
            health: Arc::new(Mutex::new(Some(sender))),
        })
    }

    /// Marks the Game Server as ready to receive connections
    pub fn ready(&self) -> Result<()> {
        let req = sdk::Empty::default_instance();
        let res = self.client.ready(req).map(|_| ())?;
        Ok(res)
    }

    /// Allocate the Game Server
    pub fn allocate(&self) -> Result<()> {
        let req = sdk::Empty::default_instance();
        let res = self.client.allocate(req).map(|_| ())?;
        Ok(res)
    }

    /// Marks the Game Server as ready to shutdown
    pub fn shutdown(&self) -> Result<()> {
        let req = sdk::Empty::default_instance();
        let res = self.client.shutdown(req).map(|_| ())?;
        Ok(res)
    }

    /// Sends a ping to the health check to indicate that this server is healthy
    pub fn health(mut self) -> (Self, Result<()>) {
        // Avoid `cannot move out of borrowed content` compile error for self.health
        let h = self.health.lock().unwrap().take();
        if h.is_none() {
            return (
                self,
                Err(ErrorKind::HealthPingConnectionFailure(
                    "failed to hold client stream for health ping".to_string(),
                )
                .into()),
            );
        }
        let h: grpcio::ClientCStreamSender<sdk::Empty> = h.unwrap().into();

        let req = sdk::Empty::new();
        match h.send((req, grpcio::WriteFlags::default())).wait() {
            Ok(h) => {
                self.health = Arc::new(Mutex::new(Some(h)));
                (self, Ok(()))
            }
            Err(e) => (self, Err(ErrorKind::Grpc(e).into())),
        }
    }

    /// Set a Label value on the backing GameServer record that is stored in Kubernetes
    pub fn set_label<S>(&self, key: S, value: S) -> Result<()>
    where
        S: Into<String>,
    {
        let mut kv = sdk::KeyValue::new();
        kv.set_key(key.into());
        kv.set_value(value.into());
        let res = self.client.set_label(&kv).map(|_| ())?;
        Ok(res)
    }

    /// Set a Annotation value on the backing Gameserver record that is stored in Kubernetes
    pub fn set_annotation<S>(&self, key: S, value: S) -> Result<()>
    where
        S: Into<String>,
    {
        let mut kv = sdk::KeyValue::new();
        kv.set_key(key.into());
        kv.set_value(value.into());
        let res = self.client.set_annotation(&kv).map(|_| ())?;
        Ok(res)
    }

    /// Returns most of the backing GameServer configuration and Status
    pub fn get_gameserver(&self) -> Result<GameServer> {
        let req = sdk::Empty::new();
        let res = self
            .client
            .get_game_server(&req)
            .map(|e| GameServer::from_message(e))?;
        Ok(res)
    }

    /// Reserve marks the Game Server as Reserved for a given duration, at which point
    /// it will return the GameServer to a Ready state.
    /// Do note, the smallest unit available in the time.Duration argument is a second.
    pub fn reserve(&self, duration: Duration) -> Result<()> {
        let mut d = sdk::Duration::new();
        d.set_seconds(duration.as_secs() as i64);

        let res = self.client.reserve(&d).map(|_| ())?;
        Ok(res)
    }

    /// Watch the backing GameServer configuration on updated
    pub fn watch_gameserver<F>(&self, mut watcher: F) -> Result<()>
    where
        F: FnMut(GameServer) -> (),
    {
        let req = sdk::Empty::new();
        let mut receiver = self
            .client
            .watch_game_server(&req)?
            .map(|e| GameServer::from_message(e));
        loop {
            match receiver.into_future().wait() {
                Ok((Some(game_server), r)) => {
                    watcher(game_server);
                    receiver = r;
                }
                Ok((None, _)) => break,
                Err((e, _)) => return Err(e.into()),
            }
        }
        Ok(())
    }
}

impl Clone for Sdk {
    fn clone(&self) -> Self {
        Self {
            client: Arc::clone(&self.client),
            health: self.health.clone(),
        }
    }
}
<commit_msg>Added dynamic configuration of http port in the rust sdk (#1125)<commit_after>// Copyright 2018 Google LLC All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::sync::{Arc, Mutex};
use std::thread::sleep;
use std::time::Duration;

use futures::{Future, Sink, Stream};
use grpcio;
use protobuf::Message;

use errors::*;
use grpc::sdk;
use grpc::sdk_grpc;
use types::*;

/// SDK is an instance of the Agones SDK
pub struct Sdk {
    client: Arc<sdk_grpc::SdkClient>,
    health: Arc<Mutex<Option<grpcio::ClientCStreamSender<sdk::Empty>>>>,
}

impl Sdk {
    /// Starts a new SDK instance, and connects to localhost on port 59357.
    /// Blocks until connection and handshake are made.
    /// Times out after ~30 seconds.
    pub fn new() -> Result<Sdk> {
        let port = env::var("AGONES_SDK_GRPC_PORT").unwrap_or("59357".to_string());
        let addr = format!("localhost:{}", port);
        let env = Arc::new(grpcio::EnvBuilder::new().build());
        let ch = grpcio::ChannelBuilder::new(env)
            .keepalive_timeout(Duration::new(30, 0))
            .connect(&addr);
        let cli = sdk_grpc::SdkClient::new(ch);
        let req = sdk::Empty::new();

        // Unfortunately there isn't a native way to block until connected
        // so we had to roll our own.
        let mut counter = 0;
        loop {
            counter += 1;
            match cli.get_game_server(&req) {
                Ok(_) => break,
                Err(e) => {
                    if counter > 30 {
                        return Err(ErrorKind::Grpc(e).into());
                    }
                    sleep(Duration::from_secs(1));
                    continue;
                }
            }
        }

        let (sender, _) = cli.health()?;
        Ok(Sdk {
            client: Arc::new(cli),
            health: Arc::new(Mutex::new(Some(sender))),
        })
    }

    /// Marks the Game Server as ready to receive connections
    pub fn ready(&self) -> Result<()> {
        let req = sdk::Empty::default_instance();
        let res = self.client.ready(req).map(|_| ())?;
        Ok(res)
    }

    /// Allocate the Game Server
    pub fn allocate(&self) -> Result<()> {
        let req = sdk::Empty::default_instance();
        let res = self.client.allocate(req).map(|_| ())?;
        Ok(res)
    }

    /// Marks the Game Server as ready to shutdown
    pub fn shutdown(&self) -> Result<()> {
        let req = sdk::Empty::default_instance();
        let res = self.client.shutdown(req).map(|_| ())?;
        Ok(res)
    }

    /// Sends a ping to the health check to indicate that this server is healthy
    pub fn health(mut self) -> (Self, Result<()>) {
        // Avoid `cannot move out of borrowed content` compile error for self.health
        let h = self.health.lock().unwrap().take();
        if h.is_none() {
            return (
                self,
                Err(ErrorKind::HealthPingConnectionFailure(
                    "failed to hold client stream for health ping".to_string(),
                )
                .into()),
            );
        }
        let h: grpcio::ClientCStreamSender<sdk::Empty> = h.unwrap().into();

        let req = sdk::Empty::new();
        match h.send((req, grpcio::WriteFlags::default())).wait() {
            Ok(h) => {
                self.health = Arc::new(Mutex::new(Some(h)));
                (self, Ok(()))
            }
            Err(e) => (self, Err(ErrorKind::Grpc(e).into())),
        }
    }

    /// Set a Label value on the backing GameServer record that is stored in Kubernetes
    pub fn set_label<S>(&self, key: S, value: S) -> Result<()>
    where
        S: Into<String>,
    {
        let mut kv = sdk::KeyValue::new();
        kv.set_key(key.into());
        kv.set_value(value.into());
        let res = self.client.set_label(&kv).map(|_| ())?;
        Ok(res)
    }

    /// Set a Annotation value on the backing Gameserver record that is stored in Kubernetes
    pub fn set_annotation<S>(&self, key: S, value: S) -> Result<()>
    where
        S: Into<String>,
    {
        let mut kv = sdk::KeyValue::new();
        kv.set_key(key.into());
        kv.set_value(value.into());
        let res = self.client.set_annotation(&kv).map(|_| ())?;
        Ok(res)
    }

    /// Returns most of the backing GameServer configuration and Status
    pub fn get_gameserver(&self) -> Result<GameServer> {
        let req = sdk::Empty::new();
        let res = self
            .client
            .get_game_server(&req)
            .map(|e| GameServer::from_message(e))?;
        Ok(res)
    }

    /// Reserve marks the Game Server as Reserved for a given duration, at which point
    /// it will return the GameServer to a Ready state.
    /// Do note, the smallest unit available in the time.Duration argument is a second.
    pub fn reserve(&self, duration: Duration) -> Result<()> {
        let mut d = sdk::Duration::new();
        d.set_seconds(duration.as_secs() as i64);

        let res = self.client.reserve(&d).map(|_| ())?;
        Ok(res)
    }

    /// Watch the backing GameServer configuration on updated
    pub fn watch_gameserver<F>(&self, mut watcher: F) -> Result<()>
    where
        F: FnMut(GameServer) -> (),
    {
        let req = sdk::Empty::new();
        let mut receiver = self
            .client
            .watch_game_server(&req)?
            .map(|e| GameServer::from_message(e));
        loop {
            match receiver.into_future().wait() {
                Ok((Some(game_server), r)) => {
                    watcher(game_server);
                    receiver = r;
                }
                Ok((None, _)) => break,
                Err((e, _)) => return Err(e.into()),
            }
        }
        Ok(())
    }
}

impl Clone for Sdk {
    fn clone(&self) -> Self {
        Self {
            client: Arc::clone(&self.client),
            health: self.health.clone(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(reason = "not public", issue = "0", feature = "fd")]

use io::{self, Read};
use libc;
use mem;
use sys::cvt;
use sys_common::AsInner;
use sys_common::io::read_to_end_uninitialized;

pub struct FileDesc {
    fd: usize,
}

impl FileDesc {
    pub fn new(fd: usize) -> FileDesc {
        FileDesc { fd: fd }
    }

    pub fn raw(&self) -> usize { self.fd }

    /// Extracts the actual filedescriptor without closing it.
    pub fn into_raw(self) -> usize {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        cvt(libc::read(self.fd, buf))
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        cvt(libc::write(self.fd, buf))
    }

    pub fn set_cloexec(&self) -> io::Result<()> {
        ::sys_common::util::dumb_print(format_args!("{}: set cloexec\n", self.fd));
        unimplemented!();
    }

    pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> {
        ::sys_common::util::dumb_print(format_args!("{}: set nonblocking\n", self.fd));
        unimplemented!();
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        let new_fd = cvt(libc::dup(self.fd, &[]))?;
        Ok(FileDesc::new(new_fd))
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        unsafe { read_to_end_uninitialized(self, buf) }
    }
}

impl AsInner<usize> for FileDesc {
    fn as_inner(&self) -> &usize { &self.fd }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // (opened after we closed ours.
        let _ = libc::close(self.fd);
    }
}
<commit_msg>Add fcntl<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(reason = "not public", issue = "0", feature = "fd")]

use io::{self, Read};
use libc;
use mem;
use sys::cvt;
use sys_common::AsInner;
use sys_common::io::read_to_end_uninitialized;

pub struct FileDesc {
    fd: usize,
}

impl FileDesc {
    pub fn new(fd: usize) -> FileDesc {
        FileDesc { fd: fd }
    }

    pub fn raw(&self) -> usize { self.fd }

    /// Extracts the actual filedescriptor without closing it.
    pub fn into_raw(self) -> usize {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        cvt(libc::read(self.fd, buf))
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        cvt(libc::write(self.fd, buf))
    }

    pub fn set_cloexec(&self) -> io::Result<()> {
        let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?;
        flags |= libc::O_CLOEXEC;
        cvt(libc::fcntl(self.fd, libc::F_SETFL, flags)).and(Ok(()))
    }

    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?;
        if nonblocking {
            flags |= libc::O_NONBLOCK;
        } else {
            flags &= !libc::O_NONBLOCK;
        }
        cvt(libc::fcntl(self.fd, libc::F_SETFL, flags)).and(Ok(()))
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        let new_fd = cvt(libc::dup(self.fd, &[]))?;
        Ok(FileDesc::new(new_fd))
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        unsafe { read_to_end_uninitialized(self, buf) }
    }
}

impl AsInner<usize> for FileDesc {
    fn as_inner(&self) -> &usize { &self.fd }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // (opened after we closed ours.
        let _ = libc::close(self.fd);
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    // Tell cargo to tell rustc to link the system pam
    // shared library.
    println!("cargo:rustc-link-lib=pam");
    // pam_misc is only supported on Linux afaik
    if cfg!(target_os = "linux") {
        println!("cargo:rustc-link-lib=pam_misc");
    }

    // Tell cargo to invalidate the built crate whenever the wrapper changes
    println!("cargo:rerun-if-changed=wrapper.h");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        // TODO: find out what is broken here
        //.parse_callbacks(Box::new(bindgen::CargoCallbacks))
        //
        // Import std::os::raw so our signatures a slightly nicer
        .raw_line("use libc::{uid_t, gid_t, group, passwd, spwd};")
        // And use just `raw` as type prefix
        .ctypes_prefix("libc")
        // Whitelist all PAM constants
        .whitelist_var("PAM_.*")
        // Whitelist all PAM functions
        .whitelist_function("pam_.*")
        // Blacklist types we use from libc
        .blacklist_type(".*gid_t")
        .blacklist_type(".*uid_t")
        .blacklist_type("group")
        .blacklist_type("passwd")
        .blacklist_type("spwd")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>[FIX] Blacklist var-args functions and related types for now<commit_after>extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    // Tell cargo to tell rustc to link the system pam
    // shared library.
    println!("cargo:rustc-link-lib=pam");
    // pam_misc is only supported on Linux afaik
    if cfg!(target_os = "linux") {
        println!("cargo:rustc-link-lib=pam_misc");
    }

    // Tell cargo to invalidate the built crate whenever the wrapper changes
    println!("cargo:rerun-if-changed=wrapper.h");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        // TODO: find out what is broken here
        //.parse_callbacks(Box::new(bindgen::CargoCallbacks))
        //
        // Import std::os::raw so our signatures a slightly nicer
        .raw_line("use libc::{uid_t, gid_t, group, passwd, spwd};")
        // And use just `raw` as type prefix
        .ctypes_prefix("libc")
        // Blacklist varargs functions and related types for now
        // TODO: find a nice solution for this
        .blacklist_type("va_list")
        .blacklist_type("__builtin_va_list")
        .blacklist_type("__va_list_tag")
        .blacklist_function("pam_v.*")
        // Blacklist types we use from libc
        .blacklist_type(".*gid_t")
        .blacklist_type(".*uid_t")
        .blacklist_type("group")
        .blacklist_type("passwd")
        .blacklist_type("spwd")
        // Whitelist all PAM constants
        .whitelist_var("PAM_.*")
        // Whitelist all PAM functions
        .whitelist_function("pam_.*")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>
use crowbook_intl::{Localizer, Extractor};

use std::path::Path;
use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=lang/fr.po");
    // Extract and localize src/lib
    let mut extractor = Extractor::new();
    extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src/lib")).unwrap();
    // Uncomment to update crowbook.pot
     extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/lib/crowbook.pot")).unwrap();

    let mut localizer = Localizer::new(&extractor);
    localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/lib/fr.po"))).unwrap();
    let dest_path = Path::new(&env::var("OUT_DIR").unwrap())
        .join("localize_macros.rs");
    localizer.write_macro_file(dest_path).unwrap();

    // Extract and localize src/bin
    let mut extractor = Extractor::new();
    extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src/bin")).unwrap();
    // Uncomment to update crowbook.pot
    extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/bin/crowbook.pot")).unwrap();

    let mut localizer = Localizer::new(&extractor);
    localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/bin/fr.po"))).unwrap();
    let dest_path = Path::new(&env::var("OUT_DIR").unwrap())
        .join("localize_macros_bin.rs");
    localizer.write_macro_file(dest_path).unwrap();
}
<commit_msg>Fix build.rs for crates.io<commit_after>
use crowbook_intl::{Localizer, Extractor};

use std::path::Path;
use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=lang/fr.po");
    // Extract and localize src/lib
    let mut extractor = Extractor::new();
    extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src/lib")).unwrap();
    // Uncomment to update crowbook.pot
    //extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/lib/crowbook.pot")).unwrap();

    let mut localizer = Localizer::new(&extractor);
    localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/lib/fr.po"))).unwrap();
    let dest_path = Path::new(&env::var("OUT_DIR").unwrap())
        .join("localize_macros.rs");
    localizer.write_macro_file(dest_path).unwrap();

    // Extract and localize src/bin
    let mut extractor = Extractor::new();
    extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src/bin")).unwrap();
    // Uncomment to update crowbook.pot
    //extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/bin/crowbook.pot")).unwrap();

    let mut localizer = Localizer::new(&extractor);
    localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/bin/fr.po"))).unwrap();
    let dest_path = Path::new(&env::var("OUT_DIR").unwrap())
        .join("localize_macros_bin.rs");
    localizer.write_macro_file(dest_path).unwrap();
}
<|endoftext|>


<commit_before>extern crate cc;

fn main() {
    let sources = ["sss/sss.c", "sss/hazmat.c", "sss/randombytes.c", "sss/tweetnacl.c"];
    cc::Build::new()
        .files(sources.iter())
        .compile("libsss.a");
}
<commit_msg>Add -Wno-sign-compare to build script<commit_after>extern crate cc;

fn main() {
    let sources = ["sss/sss.c", "sss/hazmat.c", "sss/randombytes.c", "sss/tweetnacl.c"];
    cc::Build::new()
        .files(sources.iter())
        .flag("-Wno-sign-compare") // Suppress sign warnings in tweetnacl.c
        .compile("libsss.a");
}
<|endoftext|>