<commit_before>//! Utilities for graph transformations.

use std::cell::{Ref, RefCell, RefMut};
use std::default::Default;
use super::interface::{Graph, ConcreteGraph, Id};
use util::splitvec::SplitVec;

// ----------------------------------------------------------------

/// Target-node specifier for use with `Builder::append_edge`.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Target<I> where I: Id {
    /// Use the specified target node, and ensure that it is in the outputs
    /// list
    Output(I),

    /// Use all current output nodes, creating one if none exist
    AllOutputs,

    /// Use the first available output node if one exists, or create one and
    /// add it to the outputs list
    AutoOutput,

    /// Unconditionally create a new node, and add it to the outputs list
    NewOutput,

    /// Use the specified target node, but do not add it to the outputs list
    Intermediate(I),

    /// Create a new target node, but do not add it to the outputs list
    AutoIntermediate,

    /// Use each input node as the output.
    InputOutput
}

impl<I> Target<I> where I: Id {
    /// Check if the target specifies a node that should be added to the
    /// Builder's outputs list.
    pub fn is_output(&self) -> bool {
        match self {
            &Target::Output(_) |
            &Target::AutoOutput |
            &Target::NewOutput |
            &Target::InputOutput |
            &Target::AllOutputs
                => true,
            &Target::Intermediate(_) |
            &Target::AutoIntermediate
                => false
        }
    }

    /// Resolve the target into a node id, potentially creating a new node
    ///
    /// `auto_output_candidate` is the calling Builder's first output (or None if
    /// no outputs currently exist).
    ///
    /// `f` is called when a new node should be created, and must return that
    /// node's ID.
    pub fn node_id<'a, F>(&self, auto_output_candidate: Option<I>, mut f: F) -> I
        where F: FnMut() -> I
    {
        match self {
            &Target::AutoOutput
                => auto_output_candidate.unwrap_or_else(|| f()),
            &Target::Output(id) |
            &Target::Intermediate(id)
                => id,
            &Target::NewOutput |
            &Target::AutoIntermediate
                => f(),
            &Target::AllOutputs
                => panic!("cannot handle `Target::AllOutputs` variant from `node_id`"),
            &Target::InputOutput
                => panic!("cannot handle `Target::InputOutput` variant from `node_id`")
        }
    }

    /// Fetch the ID contained in an `Output` or `Intermediate` variant.
    pub fn unwrap_id(&self) -> I {
        match self {
            &Target::Output(id) | &Target::Intermediate(id) => id,
            _ => panic!("Attempted to unwrap Target instance without a specific id")
        }
    }
}

// ----------------------------------------------------------------

/// Trait describing bounds on graph-construction functions and closures passed
/// to `Builder`'s methods.
pub trait BuildFn<G, I>: for<'a> Fn(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId
    where G: Graph
{}

impl<G, I, F> BuildFn<G, I> for F
    where F: for<'a> Fn(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId,
          G: Graph
{}

/// Closure type used when a new node must be created on a graph
pub trait NodeFn<G, E>: Fn(&mut G, &E) -> G::NodeId
    where G: Graph
{}

impl<G, E, F> NodeFn<G, E> for F
    where F: Fn(&mut G, &E) -> G::NodeId,
          G: Graph
{}

// ----------------------------------------------------------------

/// Handles node and edge addition for each stage of a graph
/// under construction.
#[derive(Clone, Debug)]
pub struct Builder<G>
    where G: ConcreteGraph
{
    graph: RefCell<G>,

    /// "out" nodes from the previous stage
    pub inputs: SplitVec<G::NodeId>,

    /// "out" nodes  for the stage under construction
    pub outputs: SplitVec<G::NodeId>,
}

impl<G> Builder<G> where G: ConcreteGraph
{
    /// Create an empty `Builder` instance for the given entry node
    pub fn new(g: G, entry: G::NodeId) -> Self {
        Builder{graph: RefCell::new(g),
                inputs: vec![entry].into(),
                outputs: SplitVec::new()}
    }

    /// Consume the Builder object, returning the built graph.
    pub fn finish(self) -> G {
        self.graph.into_inner()
    }

    /// Get a reference to the builder's graph
    pub fn graph(&self) -> Ref<G> {
        self.graph.borrow()
    }

    /// Get a reference to the builder's graph
    pub fn graph_mut(&mut self) -> &mut G {
        self.graph.get_mut()
    }

    /// Fetch a slice over the IDs of nodes that act as inputs for this stage
    pub fn stage_inputs(&self) -> &[G::NodeId] {
        &self.inputs[..]
    }

    /// Fetch a slice over the IDs of nodes that act as outputs for this stage
    pub fn stage_outputs(&self) -> &[G::NodeId] {
        &self.outputs[..]
    }

    /// Run the given function or closure, providing mutable access to the
    /// underlying graph.
    pub fn with_graph_mut<F>(&mut self, f: F)
        where F: FnOnce(&Self, RefMut<G>) {
        f(self, self.graph.borrow_mut());
    }

    /// Append an edge between all inputs for the stage and some target node.
    ///
    ///
    pub fn append_edge<E, F>(&mut self, tgt: Target<G::NodeId>, e: E, f: F) -> G::NodeId
        where F: NodeFn<G, E>,
              (G::NodeId, G::NodeId, E): Into<G::Edge>,
              E: Clone
    {
        match tgt {
            Target::InputOutput
                => {
                    for prev in self.inputs.iter() {
                        self.graph.get_mut().add_edge((*prev, *prev, e.clone()));
                    }
                    *self.inputs.first().unwrap()
                },
            Target::AllOutputs
                => {
                    // If the stage has no outputs, create one.
                    if self.outputs.is_empty() {
                        self.outputs.push(f(self.graph.get_mut(), &e));
                    }

                    for next in self.outputs.iter() {
                        for prev in self.inputs.iter() {
                            self.graph.get_mut().add_edge((*prev, *next, e.clone()));
                        }
                    }
                    *self.outputs.first().unwrap()
                },
            _ => {
                let next = tgt.node_id(self.outputs.first().cloned(), || f(self.graph.get_mut(), &e));
                if tgt.is_output() {
                    self.mark_output(next);
                }

                // For ALL inputs from the previous stage, add an edge from that input
                // to the specified output.
                for prev in self.inputs.iter() {
                    self.graph.get_mut().add_edge((*prev, next, e.clone()));
                }
                next
            }
        }
    }

    /// Add an edge from a *specific* source node to some target node
    pub fn append_edge_from<E, F>(&mut self,
                                  source: G::NodeId,
                                  target: Target<G::NodeId>,
                                  e: E,
                                  f: F) -> G::NodeId
        where F: NodeFn<G, E>,
              (G::NodeId, G::NodeId, E): Into<G::Edge>,
              E: Clone
    {
        let next = target.node_id(self.outputs.first().cloned(), || f(self.graph.get_mut(), &e));
        if target.is_output() {
            self.mark_output(next);
        }
        self.graph.get_mut().add_edge((source, next, e));
        next
    }

    /// Ensure that a particular node id is included in the current
    /// stage's outputs.
    pub fn mark_output(&mut self, id: G::NodeId) -> G::NodeId {
        if ! self.outputs.contains(&id) {
            self.outputs.push(id);
        }
        id
    }

    /// Mark all stage inputs as outputs.
    pub fn mark_inputs_as_outputs(&mut self) {
        for id in self.inputs.iter_mut() {
            self.outputs.push(*id)
        }
    }

    /// Build _within_ the current stage, preserving the list of stage inputs.
    pub fn recurse<F, I>(&mut self, next: Target<G::NodeId>, input: I, build: F) -> G::NodeId
        where F: for<'a> FnOnce(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId
    {
        self.inputs.dedup();

        self.inputs.push_and_copy_state();

        let o = build(self, next, input);

        self.inputs.pop_state();

        o
    }

    /// Chain together the subgraphs built from the elements produced by
    /// an iterator.
    ///
    /// If the given target specifies a node, that node will be used as the
    /// terminal end of the subgraph chain in addition to being marked as
    /// a stage output.
    ///
    /// This method will **panic** if called with an empty iterator.
    pub fn chain<F, I, R>(&mut self, target: Target<G::NodeId>, input: R, build: F) -> G::NodeId
        where R: IntoIterator<Item=I>,
              F: for<'a> Fn(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId
    {
        let mut o = None;
        let mut iter = input.into_iter().peekable();
        let build = &build;

        self.inputs.push_and_copy_state();
        self.outputs.push_state();
        while let Some(elt) = iter.next() {
            if iter.peek().is_some() {
                // If there's another element after this one, create a pristine
                // node to connect it to the one we're about to build
                o = Some(build(self, Target::NewOutput, elt));
                self.advance();
            } else {
                // Last element; connect to the specified target.
                match target {
                    Target::InputOutput
                        => {
                            // When `InputOutput` was specified, we need to
                            // copy the *chain* inputs -- i.e., the inputs to
                            // the _first_ stage in the chain -- to the current
                            // outputs list.
                            self.outputs.truncate(0);
                            self.outputs.extend_from_slice(self.inputs.prev_state().unwrap());
                            o = Some(build(self, Target::AllOutputs, elt));
                            self.outputs.pop_state();
                            self.outputs.extend_from_slice(self.inputs.prev_state().unwrap());
                        },
                    _ => {
                        self.outputs.pop_state();
                        o = Some(build(self, target, elt));
                    }
                }
            }
        }
        self.inputs.pop_state();
        o.unwrap()
    }

    /// Build subgraphs from the elements of an iterator between the current
    /// stage's inputs and some specified output.
    pub fn branch<F, I, R>(&mut self, target: Target<G::NodeId>, input: R, build: F) -> G::NodeId
        where R: IntoIterator<Item=I>,
              F: for<'a> Fn(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId//BuildFn<G, I>
    {
        let build = &build;
        let mut target = target;
        for elt in input {
            target = Target::Output(self.recurse(target, elt.into(), build));
        }
        target.unwrap_id()
    }

    /// Finalize the current stage.
    ///
    /// This overwrites the current list of input nodes with the list of output
    /// nodes, and truncates the output-node list.
    pub fn advance(&mut self) {
        if self.outputs.len() > 0 {
            self.inputs.truncate(0);
            self.inputs.extend_from_slice(&self.outputs[..]);
            self.outputs.truncate(0);
        }
    }
}

// ----------------------------------------------------------------

/// Graph-building interface.
pub trait Build<G: ConcreteGraph> {
    /// Type from which the graph is built.
    type Input;

    /// Create the entry node for the given input, returning its ID.
    fn entry_node(g: &mut G, input: &Self::Input) -> G::NodeId;

    /// Create the target node for the given edge data, returning the ID of the
    /// new node.
    fn target_node<E>(g: &mut G, e: &E) -> G::NodeId
        where (G::NodeId, G::NodeId, E): Into<G::Edge>;

    /// Perform any finalization on the builder or the built graph.
    #[inline]
    fn finish(_: &mut Builder<G>) {
    }

    /// Recursively build the graph for the given input data.
    ///
    /// @param b Builder instance to use for building the graph
    ///
    /// @param next Output to which the stage built from this input data should
    /// connect
    ///
    /// @param input
    fn build_recursive(b: &mut Builder<G>,
                       next: Target<G::NodeId>,
                       input: Self::Input) -> G::NodeId;

    // /// Create a subgraph describing the given input, and return its
    // /// entry and exit node IDs.
    // ///
    // /// @return Tuple containing the stand-alone graph's entry- and
    // /// exit-node IDs.
    // fn build_subgraph<'g>(ep: &mut Builder<'g, G>,
    //                       input: Self::Input) -> (G::NodeId,
    //                                               G::NodeId) {
    //     Self::build_recursive(ep, input);
    // }

    /// Convert the given input into a graph.
    ///
    /// Returns the resulting graph and the entry node.
    fn build(input: Self::Input) -> (G, G::NodeId)
        where G: Default {
        let mut g = G::new();
        let entry = Self::entry_node(&mut g, &input);

        let mut builder = Builder::new(g, entry);
        Self::build_recursive(&mut builder, Target::AutoOutput, input);
        Self::finish(&mut builder);
        (builder.finish(), entry)
    }
}

/*enum Placement {
    Before,
    After
}
struct Insertion<'a,G: Graph> {
    placement: Placement,
    node: <G as Graph>::Node
}*/

/// Graph-rewriting helper.
///
/// Rewriter provides an implementation of Graph in which all `mut` methods act
/// on the output graph, while all non-`mut` methods act on the input.
pub struct Rewriter<'a,G>
    where G: Graph + Default + 'a {
    input: &'a G,
    output: G
}

impl<'a,G> Rewriter<'a,G>
    where G: Graph + Default + 'a {
    /// Create a rewriter for the given input graph.
    pub fn new(g: &'a G) -> Self {
        Rewriter{input: g, output: G::new()}
    }

    /// Finish the
    pub fn finish(self) -> G {
        self.output
    }
}

impl<'a,G> Graph for Rewriter<'a,G>
    where G: Graph + Default + 'a {
    type NodeId = <G as Graph>::NodeId;
    type EdgeId = <G as Graph>::EdgeId;
    type Node = <G as Graph>::Node;
    type Edge = <G as Graph>::Edge;
    type NodeIdIterator = <G as Graph>::NodeIdIterator;
    type EdgeIdIterator = <G as Graph>::EdgeIdIterator;

    fn add_node<T: Into<Self::Node>>(&mut self, n: T) -> Self::NodeId {
        self.output.add_node(n)
    }

    #[inline(always)]
    fn contains_node(&self, n: Self::NodeId) -> bool {
        self.input.contains_node(n)
    }

    #[inline(always)]
    fn node(&self, n: Self::NodeId) -> &Self::Node {
        self.input.node(n)
    }

    #[inline(always)]
    fn node_mut(&mut self, n: Self::NodeId) -> &mut Self::Node {
        self.output.node_mut(n)
    }

    #[inline(always)]
    fn node_ids(&self) -> Self::NodeIdIterator {
        self.input.node_ids()
    }

    #[inline(always)]
    fn node_count(&self) -> usize {
        self.input.node_count()
    }

    #[inline(always)]
    fn add_edge<T: Into<Self::Edge>>(&mut self, e: T) -> Self::EdgeId {
        self.output.add_edge(e)
    }

    #[inline(always)]
    fn edge(&self, e: Self::EdgeId) -> &Self::Edge {
        self.input.edge(e)
    }

    #[inline(always)]
    fn contains_edge(&self, e: Self::EdgeId) -> bool {
        self.input.contains_edge(e)
    }

    #[inline(always)]
    fn edge_ids(&self) -> Self::EdgeIdIterator {
        self.input.edge_ids()
    }

    #[inline(always)]
    fn edge_count(&self) -> usize {
        self.input.edge_count()
    }
}

<commit_msg>util/graph/transform: remove unused (and broken) graph-rewrite code<commit_after>//! Utilities for graph transformations.

use std::cell::{Ref, RefCell, RefMut};
use std::default::Default;
use super::interface::{Graph, ConcreteGraph, Id};
use util::splitvec::SplitVec;

// ----------------------------------------------------------------

/// Target-node specifier for use with `Builder::append_edge`.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Target<I> where I: Id {
    /// Use the specified target node, and ensure that it is in the outputs
    /// list
    Output(I),

    /// Use all current output nodes, creating one if none exist
    AllOutputs,

    /// Use the first available output node if one exists, or create one and
    /// add it to the outputs list
    AutoOutput,

    /// Unconditionally create a new node, and add it to the outputs list
    NewOutput,

    /// Use the specified target node, but do not add it to the outputs list
    Intermediate(I),

    /// Create a new target node, but do not add it to the outputs list
    AutoIntermediate,

    /// Use each input node as the output.
    InputOutput
}

impl<I> Target<I> where I: Id {
    /// Check if the target specifies a node that should be added to the
    /// Builder's outputs list.
    pub fn is_output(&self) -> bool {
        match self {
            &Target::Output(_) |
            &Target::AutoOutput |
            &Target::NewOutput |
            &Target::InputOutput |
            &Target::AllOutputs
                => true,
            &Target::Intermediate(_) |
            &Target::AutoIntermediate
                => false
        }
    }

    /// Resolve the target into a node id, potentially creating a new node
    ///
    /// `auto_output_candidate` is the calling Builder's first output (or None if
    /// no outputs currently exist).
    ///
    /// `f` is called when a new node should be created, and must return that
    /// node's ID.
    pub fn node_id<'a, F>(&self, auto_output_candidate: Option<I>, mut f: F) -> I
        where F: FnMut() -> I
    {
        match self {
            &Target::AutoOutput
                => auto_output_candidate.unwrap_or_else(|| f()),
            &Target::Output(id) |
            &Target::Intermediate(id)
                => id,
            &Target::NewOutput |
            &Target::AutoIntermediate
                => f(),
            &Target::AllOutputs
                => panic!("cannot handle `Target::AllOutputs` variant from `node_id`"),
            &Target::InputOutput
                => panic!("cannot handle `Target::InputOutput` variant from `node_id`")
        }
    }

    /// Fetch the ID contained in an `Output` or `Intermediate` variant.
    pub fn unwrap_id(&self) -> I {
        match self {
            &Target::Output(id) | &Target::Intermediate(id) => id,
            _ => panic!("Attempted to unwrap Target instance without a specific id")
        }
    }
}

// ----------------------------------------------------------------

/// Trait describing bounds on graph-construction functions and closures passed
/// to `Builder`'s methods.
pub trait BuildFn<G, I>: for<'a> Fn(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId
    where G: Graph
{}

impl<G, I, F> BuildFn<G, I> for F
    where F: for<'a> Fn(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId,
          G: Graph
{}

/// Closure type used when a new node must be created on a graph
pub trait NodeFn<G, E>: Fn(&mut G, &E) -> G::NodeId
    where G: Graph
{}

impl<G, E, F> NodeFn<G, E> for F
    where F: Fn(&mut G, &E) -> G::NodeId,
          G: Graph
{}

// ----------------------------------------------------------------

/// Handles node and edge addition for each stage of a graph
/// under construction.
#[derive(Clone, Debug)]
pub struct Builder<G>
    where G: ConcreteGraph
{
    graph: RefCell<G>,

    /// "out" nodes from the previous stage
    pub inputs: SplitVec<G::NodeId>,

    /// "out" nodes  for the stage under construction
    pub outputs: SplitVec<G::NodeId>,
}

impl<G> Builder<G> where G: ConcreteGraph
{
    /// Create an empty `Builder` instance for the given entry node
    pub fn new(g: G, entry: G::NodeId) -> Self {
        Builder{graph: RefCell::new(g),
                inputs: vec![entry].into(),
                outputs: SplitVec::new()}
    }

    /// Consume the Builder object, returning the built graph.
    pub fn finish(self) -> G {
        self.graph.into_inner()
    }

    /// Get a reference to the builder's graph
    pub fn graph(&self) -> Ref<G> {
        self.graph.borrow()
    }

    /// Get a reference to the builder's graph
    pub fn graph_mut(&mut self) -> &mut G {
        self.graph.get_mut()
    }

    /// Fetch a slice over the IDs of nodes that act as inputs for this stage
    pub fn stage_inputs(&self) -> &[G::NodeId] {
        &self.inputs[..]
    }

    /// Fetch a slice over the IDs of nodes that act as outputs for this stage
    pub fn stage_outputs(&self) -> &[G::NodeId] {
        &self.outputs[..]
    }

    /// Run the given function or closure, providing mutable access to the
    /// underlying graph.
    pub fn with_graph_mut<F>(&mut self, f: F)
        where F: FnOnce(&Self, RefMut<G>) {
        f(self, self.graph.borrow_mut());
    }

    /// Append an edge between all inputs for the stage and some target node.
    ///
    ///
    pub fn append_edge<E, F>(&mut self, tgt: Target<G::NodeId>, e: E, f: F) -> G::NodeId
        where F: NodeFn<G, E>,
              (G::NodeId, G::NodeId, E): Into<G::Edge>,
              E: Clone
    {
        match tgt {
            Target::InputOutput
                => {
                    for prev in self.inputs.iter() {
                        self.graph.get_mut().add_edge((*prev, *prev, e.clone()));
                    }
                    *self.inputs.first().unwrap()
                },
            Target::AllOutputs
                => {
                    // If the stage has no outputs, create one.
                    if self.outputs.is_empty() {
                        self.outputs.push(f(self.graph.get_mut(), &e));
                    }

                    for next in self.outputs.iter() {
                        for prev in self.inputs.iter() {
                            self.graph.get_mut().add_edge((*prev, *next, e.clone()));
                        }
                    }
                    *self.outputs.first().unwrap()
                },
            _ => {
                let next = tgt.node_id(self.outputs.first().cloned(), || f(self.graph.get_mut(), &e));
                if tgt.is_output() {
                    self.mark_output(next);
                }

                // For ALL inputs from the previous stage, add an edge from that input
                // to the specified output.
                for prev in self.inputs.iter() {
                    self.graph.get_mut().add_edge((*prev, next, e.clone()));
                }
                next
            }
        }
    }

    /// Add an edge from a *specific* source node to some target node
    pub fn append_edge_from<E, F>(&mut self,
                                  source: G::NodeId,
                                  target: Target<G::NodeId>,
                                  e: E,
                                  f: F) -> G::NodeId
        where F: NodeFn<G, E>,
              (G::NodeId, G::NodeId, E): Into<G::Edge>,
              E: Clone
    {
        let next = target.node_id(self.outputs.first().cloned(), || f(self.graph.get_mut(), &e));
        if target.is_output() {
            self.mark_output(next);
        }
        self.graph.get_mut().add_edge((source, next, e));
        next
    }

    /// Ensure that a particular node id is included in the current
    /// stage's outputs.
    pub fn mark_output(&mut self, id: G::NodeId) -> G::NodeId {
        if ! self.outputs.contains(&id) {
            self.outputs.push(id);
        }
        id
    }

    /// Mark all stage inputs as outputs.
    pub fn mark_inputs_as_outputs(&mut self) {
        for id in self.inputs.iter_mut() {
            self.outputs.push(*id)
        }
    }

    /// Build _within_ the current stage, preserving the list of stage inputs.
    pub fn recurse<F, I>(&mut self, next: Target<G::NodeId>, input: I, build: F) -> G::NodeId
        where F: for<'a> FnOnce(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId
    {
        self.inputs.dedup();

        self.inputs.push_and_copy_state();

        let o = build(self, next, input);

        self.inputs.pop_state();

        o
    }

    /// Chain together the subgraphs built from the elements produced by
    /// an iterator.
    ///
    /// If the given target specifies a node, that node will be used as the
    /// terminal end of the subgraph chain in addition to being marked as
    /// a stage output.
    ///
    /// This method will **panic** if called with an empty iterator.
    pub fn chain<F, I, R>(&mut self, target: Target<G::NodeId>, input: R, build: F) -> G::NodeId
        where R: IntoIterator<Item=I>,
              F: for<'a> Fn(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId
    {
        let mut o = None;
        let mut iter = input.into_iter().peekable();
        let build = &build;

        self.inputs.push_and_copy_state();
        self.outputs.push_state();
        while let Some(elt) = iter.next() {
            if iter.peek().is_some() {
                // If there's another element after this one, create a pristine
                // node to connect it to the one we're about to build
                o = Some(build(self, Target::NewOutput, elt));
                self.advance();
            } else {
                // Last element; connect to the specified target.
                match target {
                    Target::InputOutput
                        => {
                            // When `InputOutput` was specified, we need to
                            // copy the *chain* inputs -- i.e., the inputs to
                            // the _first_ stage in the chain -- to the current
                            // outputs list.
                            self.outputs.truncate(0);
                            self.outputs.extend_from_slice(self.inputs.prev_state().unwrap());
                            o = Some(build(self, Target::AllOutputs, elt));
                            self.outputs.pop_state();
                            self.outputs.extend_from_slice(self.inputs.prev_state().unwrap());
                        },
                    _ => {
                        self.outputs.pop_state();
                        o = Some(build(self, target, elt));
                    }
                }
            }
        }
        self.inputs.pop_state();
        o.unwrap()
    }

    /// Build subgraphs from the elements of an iterator between the current
    /// stage's inputs and some specified output.
    pub fn branch<F, I, R>(&mut self, target: Target<G::NodeId>, input: R, build: F) -> G::NodeId
        where R: IntoIterator<Item=I>,
              F: for<'a> Fn(&'a mut Builder<G>, Target<G::NodeId>, I) -> G::NodeId//BuildFn<G, I>
    {
        let build = &build;
        let mut target = target;
        for elt in input {
            target = Target::Output(self.recurse(target, elt.into(), build));
        }
        target.unwrap_id()
    }

    /// Finalize the current stage.
    ///
    /// This overwrites the current list of input nodes with the list of output
    /// nodes, and truncates the output-node list.
    pub fn advance(&mut self) {
        if self.outputs.len() > 0 {
            self.inputs.truncate(0);
            self.inputs.extend_from_slice(&self.outputs[..]);
            self.outputs.truncate(0);
        }
    }
}

// ----------------------------------------------------------------

/// Graph-building interface.
pub trait Build<G: ConcreteGraph> {
    /// Type from which the graph is built.
    type Input;

    /// Create the entry node for the given input, returning its ID.
    fn entry_node(g: &mut G, input: &Self::Input) -> G::NodeId;

    /// Create the target node for the given edge data, returning the ID of the
    /// new node.
    fn target_node<E>(g: &mut G, e: &E) -> G::NodeId
        where (G::NodeId, G::NodeId, E): Into<G::Edge>;

    /// Perform any finalization on the builder or the built graph.
    #[inline]
    fn finish(_: &mut Builder<G>) {
    }

    /// Recursively build the graph for the given input data.
    ///
    /// @param b Builder instance to use for building the graph
    ///
    /// @param next Output to which the stage built from this input data should
    /// connect
    ///
    /// @param input
    fn build_recursive(b: &mut Builder<G>,
                       next: Target<G::NodeId>,
                       input: Self::Input) -> G::NodeId;

    // /// Create a subgraph describing the given input, and return its
    // /// entry and exit node IDs.
    // ///
    // /// @return Tuple containing the stand-alone graph's entry- and
    // /// exit-node IDs.
    // fn build_subgraph<'g>(ep: &mut Builder<'g, G>,
    //                       input: Self::Input) -> (G::NodeId,
    //                                               G::NodeId) {
    //     Self::build_recursive(ep, input);
    // }

    /// Convert the given input into a graph.
    ///
    /// Returns the resulting graph and the entry node.
    fn build(input: Self::Input) -> (G, G::NodeId)
        where G: Default {
        let mut g = G::new();
        let entry = Self::entry_node(&mut g, &input);

        let mut builder = Builder::new(g, entry);
        Self::build_recursive(&mut builder, Target::AutoOutput, input);
        Self::finish(&mut builder);
        (builder.finish(), entry)
    }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use std::cell::RefCell;
use std::fmt;

use crate::numeric::{Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(Vec<(u64, Exponent)>);

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(Vec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);

        if let Some((_, e)) = self.0.iter_mut().find(|(f, _)| *f == factor) {
            *e += exp;
        } else {
            self.0.push((factor, exp))
        }
    }

    fn is_one(&self) -> bool {
        self.0.is_empty()
    }

    fn pop(&mut self) -> Option<(u64, Exponent)> {
        self.0.pop()
    }

    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    #[cfg(test)]
    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _find_factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Option<u64> {
    use miller_rabin::Result::*;

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => None,
        Composite(d) => Some(d),
        Pseudoprime => Some(rho::find_divisor::<A>(n)),
    }
}

fn find_factor(num: u64) -> Option<u64> {
    if num < (1 << 32) {
        _find_factor::<Montgomery<u32>>(num)
    } else {
        _find_factor::<Montgomery<u64>>(num)
    }
}

pub fn factor(num: u64) -> Factors {
    let mut factors = Factors::one();

    if num < 2 {
        return factors;
    }

    let mut n = num;
    let z = num.trailing_zeros();
    if z > 0 {
        factors.add(2, z as Exponent);
        n >>= z;
    }
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    table::factor(&mut n, &mut factors);
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    let mut dec = Decomposition::one();
    dec.add(n, 1);

    while !dec.is_one() {
        // Check correctness invariant
        debug_assert_eq!(num, factors.product() * dec.product());

        let (f, e) = dec.pop().unwrap();

        if let Some(d) = find_factor(f) {
            dec.add(f / d, e);
            dec.add(d, e);
        } else {
            // f is prime
            factors.add(f, e);
        }
    }

    factors
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<commit_msg>factor: Ensure we only need to find every single factor once  [WiP]<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use std::cell::RefCell;
use std::fmt;

use crate::numeric::{gcd, Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(Vec<(u64, Exponent)>);

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(Vec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);

        if let Some((_, e)) = self.0.iter_mut().find(|(f, _)| *f == factor) {
            *e += exp;
        } else {
            self.0.push((factor, exp))
        }
    }

    fn is_one(&self) -> bool {
        self.0.is_empty()
    }

    fn pop(&mut self) -> Option<(u64, Exponent)> {
        self.0.pop()
    }

    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    #[cfg(test)]
    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _find_factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Option<u64> {
    use miller_rabin::Result::*;

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => None,
        Composite(d) => Some(d),
        Pseudoprime => Some(rho::find_divisor::<A>(n)),
    }
}

fn find_factor(num: u64) -> Option<u64> {
    if num < (1 << 32) {
        _find_factor::<Montgomery<u32>>(num)
    } else {
        _find_factor::<Montgomery<u64>>(num)
    }
}

pub fn factor(num: u64) -> Factors {
    let mut factors = Factors::one();

    if num < 2 {
        return factors;
    }

    let mut n = num;
    let z = num.trailing_zeros();
    if z > 0 {
        factors.add(2, z as Exponent);
        n >>= z;
    }
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    table::factor(&mut n, &mut factors);
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    let mut dec = Decomposition::one();
    dec.add(n, 1);

    while !dec.is_one() {
        // Check correctness invariant
        debug_assert_eq!(num, factors.product() * dec.product());

        let (f, e) = dec.pop().unwrap();

        if let Some(d) = find_factor(f) {
            let mut gcd_queue = Decomposition::one();
            gcd_queue.add(d, e);
            gcd_queue.add(f / d, e);

            let mut non_trivial_gcd = true;
            while non_trivial_gcd {
                debug_assert_eq!(f, gcd_queue.product());

                let mut tmp = Decomposition::one();
                non_trivial_gcd = false;
                for i in 0..gcd_queue.0.len() - 1 {
                    let (a, e_a) = gcd_queue.0[i];
                    let (b, e_b) = gcd_queue.0[i + 1];

                    let g = gcd(a, b);
                    if g != 1 {
                        non_trivial_gcd = true;
                        tmp.add(a / g, e_a);
                        tmp.add(g, e_a + e_b);
                        if i + 1 == gcd_queue.0.len() {
                            tmp.add(b / g, e_b)
                        } else {
                            gcd_queue.0[i + 1] = (b / g, e_b);
                        }
                    } else {
                        tmp.add(a, e_a);
                        if i + 1 == gcd_queue.0.len() - 1 {
                            tmp.add(b, e_b)
                        }
                    }
                }
                gcd_queue = tmp;
            }

            debug_assert_eq!(f, gcd_queue.product());
            dec.0.extend(gcd_queue.0);
        } else {
            // f is prime
            factors.add(f, e);
        }
    }

    factors
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use std::collections::BTreeMap;
use std::fmt;

use crate::numeric::{Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

pub struct Factors {
    f: BTreeMap<u64, u8>,
}

impl Factors {
    pub fn one() -> Factors {
        Factors { f: BTreeMap::new() }
    }

    pub fn add(&mut self, prime: u64, exp: u8) {
        debug_assert!(miller_rabin::is_prime(prime));
        debug_assert!(exp > 0);
        let n = *self.f.get(&prime).unwrap_or(&0);
        self.f.insert(prime, exp + n);
    }

    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.f
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (p, exp) in self.f.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _factor<A: Arithmetic>(num: u64, f: Factors) -> Factors {
    use miller_rabin::Result::*;
    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n, f| {
        // TODO: Optimise with 32 and 64b versions
        _factor::<A>(n, f)
    };

    if num == 1 {
        return f;
    }

    let n = A::new(num);
    let divisor = match miller_rabin::test::<A>(n) {
        Prime => {
            let mut r = f;
            r.push(num);
            return r;
        }

        Composite(d) => d,
        Pseudoprime => rho::find_divisor::<A>(n),
    };

    let f = _factor(divisor, f);
    _factor(num / divisor, f)
}

pub fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::one();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (factors, n) = table::factor(n, factors);

    // TODO: Optimise with 32 and 64b versions
    _factor::<Montgomery>(n, factors)
}

#[cfg(test)]
mod tests {
    use super::factor;
    use quickcheck::quickcheck;

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }
    }
}
<commit_msg>factor::Factors: Derive Clone and Debug<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use std::collections::BTreeMap;
use std::fmt;

use crate::numeric::{Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

#[derive(Clone, Debug)]
pub struct Factors {
    f: BTreeMap<u64, u8>,
}

impl Factors {
    pub fn one() -> Factors {
        Factors { f: BTreeMap::new() }
    }

    pub fn add(&mut self, prime: u64, exp: u8) {
        debug_assert!(miller_rabin::is_prime(prime));
        debug_assert!(exp > 0);
        let n = *self.f.get(&prime).unwrap_or(&0);
        self.f.insert(prime, exp + n);
    }

    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.f
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (p, exp) in self.f.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _factor<A: Arithmetic>(num: u64, f: Factors) -> Factors {
    use miller_rabin::Result::*;
    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n, f| {
        // TODO: Optimise with 32 and 64b versions
        _factor::<A>(n, f)
    };

    if num == 1 {
        return f;
    }

    let n = A::new(num);
    let divisor = match miller_rabin::test::<A>(n) {
        Prime => {
            let mut r = f;
            r.push(num);
            return r;
        }

        Composite(d) => d,
        Pseudoprime => rho::find_divisor::<A>(n),
    };

    let f = _factor(divisor, f);
    _factor(num / divisor, f)
}

pub fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::one();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (factors, n) = table::factor(n, factors);

    // TODO: Optimise with 32 and 64b versions
    _factor::<Montgomery>(n, factors)
}

#[cfg(test)]
mod tests {
    use super::factor;
    use quickcheck::quickcheck;

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(rustfmt, rustfmt::skip)]
use boxcars::ParserBuilder;

macro_rules! frame_len_test {
    ($test_name:ident, $test_asset:expr, $frame_len:expr) => {
        #[test]
        fn $test_name() {
            let data = include_bytes!($test_asset);
            let parsing = ParserBuilder::new(&data[..])
                .always_check_crc()
                .must_parse_network_data()
                .parse();

            match parsing {
                Ok(replay) => assert_eq!(replay.network_frames.unwrap().frames.len(), $frame_len),
                Err(ref e) => panic!(format!("{}", e)),
            }
        }
    };
}

frame_len_test!(test_b0867_replay, "../assets/replays/good/b0867.replay", 8599);
frame_len_test!(test_small_frames, "../assets/replays/good/small-frames.replay", 231);
frame_len_test!(test_3381_replay, "../assets/replays/good/3381.replay", 13320);
frame_len_test!(test_3d07e_replay, "../assets/replays/good/3d07e.replay", 8727);
frame_len_test!(test_e7fb9_replay, "../assets/replays/good/e7fb9.replay", 7472);
frame_len_test!(test_e4598_replay, "../assets/replays/good/e4598.replay", 6898);
frame_len_test!(test_65e98_replay, "../assets/replays/good/65e98.replay", 7174);
frame_len_test!(test_7083_replay, "../assets/replays/good/7083.replay", 8346);
frame_len_test!(test_6688_replay, "../assets/replays/good/6688.replay", 0);
frame_len_test!(test_07e9_replay, "../assets/replays/good/07e9.replay", 319);
frame_len_test!(test_16d5_replay, "../assets/replays/good/16d5.replay", 405);
frame_len_test!(test_551c_replay, "../assets/replays/good/551c.replay", 8247);
frame_len_test!(test_2266_replay, "../assets/replays/good/2266.replay", 8136);
frame_len_test!(test_rumble_body, "../assets/replays/good/rumble.replay", 7744);
frame_len_test!(test_no_frames, "../assets/replays/good/no-frames.replay", 0);
frame_len_test!(test_net_version, "../assets/replays/good/netversion.replay", 7901);
frame_len_test!(test_159a4_replay, "../assets/replays/good/159a4.replay", 7104);
frame_len_test!(test_c0bca_replay, "../assets/replays/good/c0bca.replay", 7290);
frame_len_test!(test_db70_replay, "../assets/replays/good/db70.replay", 9781);
frame_len_test!(test_6cc24_replay, "../assets/replays/good/6cc24.replay", 7319);
frame_len_test!(test_57a6c_replay, "../assets/replays/good/57a6c.replay", 378);
frame_len_test!(test_01d3e5_replay, "../assets/replays/good/01d3e5.replay", 393);
frame_len_test!(test_a9df3_replay, "../assets/replays/good/a9df3.replay", 330);
frame_len_test!(test_419a_replay, "../assets/replays/good/419a.replay", 10183);
frame_len_test!(test_4bc3b_replay, "../assets/replays/good/4bc3b.replay", 9536);
frame_len_test!(test_d52eb_replay, "../assets/replays/good/d52eb.replay", 17815);
frame_len_test!(test_edbb_replay, "../assets/replays/good/edbb.replay", 356);
frame_len_test!(test_7256_replay, "../assets/replays/good/7256.replay", 9634);
frame_len_test!(test_5a06_replay, "../assets/replays/good/5a06.replay", 515);
frame_len_test!(test_60dfe_replay, "../assets/replays/good/60dfe.replay", 9737);
frame_len_test!(test_70865_replay, "../assets/replays/good/70865.replay", 8912);
frame_len_test!(test_72ae1_replay, "../assets/replays/good/72ae1.replay", 8545);
frame_len_test!(test_fc427_replay, "../assets/replays/good/fc427.replay", 9343);
frame_len_test!(test_7f79f_replay, "../assets/replays/good/7f79f.replay", 12273);
frame_len_test!(test_c23b0_replay, "../assets/replays/good/c23b0.replay", 9811);
frame_len_test!(test_c4abb_replay, "../assets/replays/good/c4abb.replay", 9093);
frame_len_test!(test_70204_replay, "../assets/replays/good/70204.replay", 9574);
frame_len_test!(test_74936_replay, "../assets/replays/good/74936.replay", 10609);
frame_len_test!(test_1ec9_replay, "../assets/replays/good/1ec9.replay", 332);
frame_len_test!(test_9a2cd_replay, "../assets/replays/good/9a2cd.replay", 2616);
frame_len_test!(test_9e35b_replay, "../assets/replays/good/9e35b.replay", 12859);
frame_len_test!(test_21a81_replay, "../assets/replays/good/21a81.replay", 13539);
frame_len_test!(test_d1d5_replay, "../assets/replays/good/d1d5.replay", 4454);
frame_len_test!(test_7588d_replay, "../assets/replays/good/7588d.replay", 0);
frame_len_test!(test_42f2_replay, "../assets/replays/good/42f2.replay", 11642);
frame_len_test!(test_qq_platform_0ca5_replay, "../assets/replays/good/0ca5.replay", 472);
frame_len_test!(test_tutorial_43a9_replay, "../assets/replays/good/43a9.replay", 9143);
frame_len_test!(test_dedicated_server_ip_43a9_replay, "../assets/replays/good/160c.replay", 9408);
frame_len_test!(test_hoops_mutator_d044_replay, "../assets/replays/good/d044.replay", 10497);
frame_len_test!(test_soccar_lan_replay, "../assets/replays/good/soccar-lan.replay", 7398);
frame_len_test!(test_c62cb_replay, "../assets/replays/good/c62cb.replay", 7136);
frame_len_test!(test_podium_51235_replay, "../assets/replays/good/51235.replay", 8002);
frame_len_test!(test_54aed_replay, "../assets/replays/good/54aed.replay", 7407);
frame_len_test!(test_ae466_replay, "../assets/replays/good/ae466.replay", 7067);
frame_len_test!(test_d5d6c_replay, "../assets/replays/good/d5d6c.replay", 11009);
frame_len_test!(test_128ed_replay, "../assets/replays/good/128ed.replay", 8313);
frame_len_test!(test_rlcs_replay, "../assets/replays/good/rlcs.replay", 7651);
frame_len_test!(test_many_actors_replay, "../assets/replays/good/many_actors.replay", 4179);
frame_len_test!(test_max_score_replay, "../assets/replays/good/a184.replay", 604);
frame_len_test!(test_is_distracted, "../assets/replays/good/e978.replay", 9501);
frame_len_test!(test_d4f3b_heat_replay, "../assets/replays/good/d4f3b_heat.replay", 8920);
frame_len_test!(test_ed6ce_heat_replay, "../assets/replays/good/ed6ce_heat.replay", 10920);
frame_len_test!(test_rl178_replay, "../assets/replays/good/rl-178.replay", 8901);
frame_len_test!(test_epic_replay, "../assets/replays/good/epic.replay", 7231);
frame_len_test!(test_tourny_replay, "../assets/replays/good/tourny.replay", 10275);
frame_len_test!(test_difficulty_replay, "../assets/replays/good/difficulty.replay", 3897);
frame_len_test!(test_rumble_pickup_replay, "../assets/replays/good/140a5.replay", 9082);
frame_len_test!(test_rlcs2_replay, "../assets/replays/good/rlcs2.replay", 10664);
frame_len_test!(test_00bb_replay, "../assets/replays/good/00bb.replay", 8175);
frame_len_test!(test_gridiron_replay, "../assets/replays/good/gridiron.replay", 11118);
<commit_msg>Remove redundant format in tests<commit_after>#![cfg_attr(rustfmt, rustfmt::skip)]
use boxcars::ParserBuilder;

macro_rules! frame_len_test {
    ($test_name:ident, $test_asset:expr, $frame_len:expr) => {
        #[test]
        fn $test_name() {
            let data = include_bytes!($test_asset);
            let parsing = ParserBuilder::new(&data[..])
                .always_check_crc()
                .must_parse_network_data()
                .parse();

            match parsing {
                Ok(replay) => assert_eq!(replay.network_frames.unwrap().frames.len(), $frame_len),
                Err(ref e) => panic!("{}", e),
            }
        }
    };
}

frame_len_test!(test_b0867_replay, "../assets/replays/good/b0867.replay", 8599);
frame_len_test!(test_small_frames, "../assets/replays/good/small-frames.replay", 231);
frame_len_test!(test_3381_replay, "../assets/replays/good/3381.replay", 13320);
frame_len_test!(test_3d07e_replay, "../assets/replays/good/3d07e.replay", 8727);
frame_len_test!(test_e7fb9_replay, "../assets/replays/good/e7fb9.replay", 7472);
frame_len_test!(test_e4598_replay, "../assets/replays/good/e4598.replay", 6898);
frame_len_test!(test_65e98_replay, "../assets/replays/good/65e98.replay", 7174);
frame_len_test!(test_7083_replay, "../assets/replays/good/7083.replay", 8346);
frame_len_test!(test_6688_replay, "../assets/replays/good/6688.replay", 0);
frame_len_test!(test_07e9_replay, "../assets/replays/good/07e9.replay", 319);
frame_len_test!(test_16d5_replay, "../assets/replays/good/16d5.replay", 405);
frame_len_test!(test_551c_replay, "../assets/replays/good/551c.replay", 8247);
frame_len_test!(test_2266_replay, "../assets/replays/good/2266.replay", 8136);
frame_len_test!(test_rumble_body, "../assets/replays/good/rumble.replay", 7744);
frame_len_test!(test_no_frames, "../assets/replays/good/no-frames.replay", 0);
frame_len_test!(test_net_version, "../assets/replays/good/netversion.replay", 7901);
frame_len_test!(test_159a4_replay, "../assets/replays/good/159a4.replay", 7104);
frame_len_test!(test_c0bca_replay, "../assets/replays/good/c0bca.replay", 7290);
frame_len_test!(test_db70_replay, "../assets/replays/good/db70.replay", 9781);
frame_len_test!(test_6cc24_replay, "../assets/replays/good/6cc24.replay", 7319);
frame_len_test!(test_57a6c_replay, "../assets/replays/good/57a6c.replay", 378);
frame_len_test!(test_01d3e5_replay, "../assets/replays/good/01d3e5.replay", 393);
frame_len_test!(test_a9df3_replay, "../assets/replays/good/a9df3.replay", 330);
frame_len_test!(test_419a_replay, "../assets/replays/good/419a.replay", 10183);
frame_len_test!(test_4bc3b_replay, "../assets/replays/good/4bc3b.replay", 9536);
frame_len_test!(test_d52eb_replay, "../assets/replays/good/d52eb.replay", 17815);
frame_len_test!(test_edbb_replay, "../assets/replays/good/edbb.replay", 356);
frame_len_test!(test_7256_replay, "../assets/replays/good/7256.replay", 9634);
frame_len_test!(test_5a06_replay, "../assets/replays/good/5a06.replay", 515);
frame_len_test!(test_60dfe_replay, "../assets/replays/good/60dfe.replay", 9737);
frame_len_test!(test_70865_replay, "../assets/replays/good/70865.replay", 8912);
frame_len_test!(test_72ae1_replay, "../assets/replays/good/72ae1.replay", 8545);
frame_len_test!(test_fc427_replay, "../assets/replays/good/fc427.replay", 9343);
frame_len_test!(test_7f79f_replay, "../assets/replays/good/7f79f.replay", 12273);
frame_len_test!(test_c23b0_replay, "../assets/replays/good/c23b0.replay", 9811);
frame_len_test!(test_c4abb_replay, "../assets/replays/good/c4abb.replay", 9093);
frame_len_test!(test_70204_replay, "../assets/replays/good/70204.replay", 9574);
frame_len_test!(test_74936_replay, "../assets/replays/good/74936.replay", 10609);
frame_len_test!(test_1ec9_replay, "../assets/replays/good/1ec9.replay", 332);
frame_len_test!(test_9a2cd_replay, "../assets/replays/good/9a2cd.replay", 2616);
frame_len_test!(test_9e35b_replay, "../assets/replays/good/9e35b.replay", 12859);
frame_len_test!(test_21a81_replay, "../assets/replays/good/21a81.replay", 13539);
frame_len_test!(test_d1d5_replay, "../assets/replays/good/d1d5.replay", 4454);
frame_len_test!(test_7588d_replay, "../assets/replays/good/7588d.replay", 0);
frame_len_test!(test_42f2_replay, "../assets/replays/good/42f2.replay", 11642);
frame_len_test!(test_qq_platform_0ca5_replay, "../assets/replays/good/0ca5.replay", 472);
frame_len_test!(test_tutorial_43a9_replay, "../assets/replays/good/43a9.replay", 9143);
frame_len_test!(test_dedicated_server_ip_43a9_replay, "../assets/replays/good/160c.replay", 9408);
frame_len_test!(test_hoops_mutator_d044_replay, "../assets/replays/good/d044.replay", 10497);
frame_len_test!(test_soccar_lan_replay, "../assets/replays/good/soccar-lan.replay", 7398);
frame_len_test!(test_c62cb_replay, "../assets/replays/good/c62cb.replay", 7136);
frame_len_test!(test_podium_51235_replay, "../assets/replays/good/51235.replay", 8002);
frame_len_test!(test_54aed_replay, "../assets/replays/good/54aed.replay", 7407);
frame_len_test!(test_ae466_replay, "../assets/replays/good/ae466.replay", 7067);
frame_len_test!(test_d5d6c_replay, "../assets/replays/good/d5d6c.replay", 11009);
frame_len_test!(test_128ed_replay, "../assets/replays/good/128ed.replay", 8313);
frame_len_test!(test_rlcs_replay, "../assets/replays/good/rlcs.replay", 7651);
frame_len_test!(test_many_actors_replay, "../assets/replays/good/many_actors.replay", 4179);
frame_len_test!(test_max_score_replay, "../assets/replays/good/a184.replay", 604);
frame_len_test!(test_is_distracted, "../assets/replays/good/e978.replay", 9501);
frame_len_test!(test_d4f3b_heat_replay, "../assets/replays/good/d4f3b_heat.replay", 8920);
frame_len_test!(test_ed6ce_heat_replay, "../assets/replays/good/ed6ce_heat.replay", 10920);
frame_len_test!(test_rl178_replay, "../assets/replays/good/rl-178.replay", 8901);
frame_len_test!(test_epic_replay, "../assets/replays/good/epic.replay", 7231);
frame_len_test!(test_tourny_replay, "../assets/replays/good/tourny.replay", 10275);
frame_len_test!(test_difficulty_replay, "../assets/replays/good/difficulty.replay", 3897);
frame_len_test!(test_rumble_pickup_replay, "../assets/replays/good/140a5.replay", 9082);
frame_len_test!(test_rlcs2_replay, "../assets/replays/good/rlcs2.replay", 10664);
frame_len_test!(test_00bb_replay, "../assets/replays/good/00bb.replay", 8175);
frame_len_test!(test_gridiron_replay, "../assets/replays/good/gridiron.replay", 11118);
<|endoftext|>


<commit_before>use desync::scheduler::*;

use super::timeout::*;

use std::thread;
use std::time::*;
use std::sync::*;
use std::sync::mpsc::*;

#[test]
fn suspend_queue() {
    for _x in 0..1000 {
        timeout(|| {
            use futures::executor;

            let queue           = queue();
            let scheduler       = scheduler();
            let (tx, rx)        = channel();

            let pos             = Arc::new(Mutex::new(0));

            // Send the current position when the async methods run
            let pos2 = pos.clone();
            let tx2 = tx.clone();
            desync(&queue, move || { tx2.send(*pos2.lock().unwrap()).unwrap(); });

            // Suspend after the first send
            let suspended = scheduler.suspend(&queue);
            executor::block_on(suspended).unwrap();

            // Send again
            let pos2 = pos.clone();
            let tx2 = tx.clone();
            desync(&queue, move || { tx2.send(*pos2.lock().unwrap()).unwrap(); });

            // Wait for the first queue to send
            assert!(rx.recv().unwrap() == 0);

            thread::yield_now();

            // Update the position and resume
            *pos.lock().unwrap() = 1;
            scheduler.resume(&queue);

            // The resumption will send us a value when it occurs
            assert!(rx.recv().unwrap() == 1);
        }, 500);
    }
}

#[test]
fn suspend_queue_with_local_drain() {
    timeout(|| {
        use futures::executor;

        // Want a scheduler with 0 threads to force a 'drain on current thread' situation
        let scheduler = Arc::new(Scheduler::new());
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let queue = scheduler.create_job_queue();

        // Job so there's something to drain
        scheduler.desync(&queue, ||{});

        // Start suspending the queue
        let suspended = scheduler.suspend(&queue);

        // Resume after a delay
        let to_resume           = queue.clone();
        let resume_scheduler    = scheduler.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_millis(100));
            resume_scheduler.resume(&to_resume);

            // The scheduler will need to be able to finish the task on a thread
            resume_scheduler.set_max_threads(1);
        });

        // Should be able to retrieve a value once the queue resumes
        assert!(scheduler.sync(&queue, || 42) == 42);

        // Check that suspension actually occurred (as we have 0 threads, it'll get queued with the 'retrieve' request above
        // so it would get cancelled by the resume if we blocked earlier)
        executor::block_on(suspended).unwrap();
    }, 500);
}

#[test]
fn resume_before_suspend() {
    for _x in 0..1000 {
        timeout(|| {
            let (tx, rx)    = channel();
            let queue       = queue();
            let scheduler   = scheduler();

            // Increment the position, suspend the queue, increment it again
            let tx2         = tx.clone();
            desync(&queue, move || { tx2.send(1).unwrap(); });
            scheduler.resume(&queue);
            scheduler.suspend(&queue);
            let tx2         = tx.clone();
            desync(&queue, move || { tx2.send(2).unwrap(); });

            assert!(rx.recv_timeout(Duration::from_millis(100)) == Ok(1));
            assert!(rx.recv_timeout(Duration::from_millis(100)) == Ok(2));
        }, 500);
    }
}

#[test]
fn safe_to_drop_suspended_queue() {
    timeout(|| {
        let queue       = queue();
        let scheduler   = scheduler();

        let pos         = Arc::new(Mutex::new(0));

        // Increment the position, suspend the queue, increment it again
        let pos2        = pos.clone();
        desync(&queue, move || { let mut pos2 = pos2.lock().unwrap(); *pos2 += 1 });
        scheduler.suspend(&queue);
        let pos2        = pos.clone();
        desync(&queue, move || { let mut pos2 = pos2.lock().unwrap(); *pos2 += 1 });

        // Wait for long enough for these events to take place and check the queue
        while *pos.lock().unwrap() == 0 {
            thread::sleep(Duration::from_millis(100));
        }
        assert!(*pos.lock().unwrap() == 1);
    }, 500);
}
<commit_msg>resume_before_suspend should cancel its suspend operation<commit_after>use desync::scheduler::*;

use super::timeout::*;

use std::thread;
use std::time::*;
use std::sync::*;
use std::sync::mpsc::*;

#[test]
fn suspend_queue() {
    for _x in 0..1000 {
        timeout(|| {
            use futures::executor;

            let queue           = queue();
            let scheduler       = scheduler();
            let (tx, rx)        = channel();

            let pos             = Arc::new(Mutex::new(0));

            // Send the current position when the async methods run
            let pos2 = pos.clone();
            let tx2 = tx.clone();
            desync(&queue, move || { tx2.send(*pos2.lock().unwrap()).unwrap(); });

            // Suspend after the first send
            let suspended = scheduler.suspend(&queue);
            executor::block_on(suspended).unwrap();

            // Send again
            let pos2 = pos.clone();
            let tx2 = tx.clone();
            desync(&queue, move || { tx2.send(*pos2.lock().unwrap()).unwrap(); });

            // Wait for the first queue to send
            assert!(rx.recv().unwrap() == 0);

            thread::yield_now();

            // Update the position and resume
            *pos.lock().unwrap() = 1;
            scheduler.resume(&queue);

            // The resumption will send us a value when it occurs
            assert!(rx.recv().unwrap() == 1);
        }, 500);
    }
}

#[test]
fn suspend_queue_with_local_drain() {
    timeout(|| {
        use futures::executor;

        // Want a scheduler with 0 threads to force a 'drain on current thread' situation
        let scheduler = Arc::new(Scheduler::new());
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let queue = scheduler.create_job_queue();

        // Job so there's something to drain
        scheduler.desync(&queue, ||{});

        // Start suspending the queue
        let suspended = scheduler.suspend(&queue);

        // Resume after a delay
        let to_resume           = queue.clone();
        let resume_scheduler    = scheduler.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_millis(100));
            resume_scheduler.resume(&to_resume);

            // The scheduler will need to be able to finish the task on a thread
            resume_scheduler.set_max_threads(1);
        });

        // Should be able to retrieve a value once the queue resumes
        assert!(scheduler.sync(&queue, || 42) == 42);

        // Check that suspension actually occurred (as we have 0 threads, it'll get queued with the 'retrieve' request above
        // so it would get cancelled by the resume if we blocked earlier)
        executor::block_on(suspended).unwrap();
    }, 500);
}

#[test]
fn resume_before_suspend() {
    for _x in 0..1000 {
        timeout(|| {
            use futures::executor;
            use futures::channel::oneshot;

            let (tx, rx)        = channel();
            let queue           = queue();
            let scheduler       = scheduler();

            // Increment the position, suspend the queue, increment it again
            let tx2             = tx.clone();
            desync(&queue, move || { tx2.send(1).unwrap(); });
            scheduler.resume(&queue);
            let wont_suspend    = scheduler.suspend(&queue);
            let tx2             = tx.clone();
            desync(&queue, move || { tx2.send(2).unwrap(); });

            // As we resumed then suspended, the suspension gets canceled, which we can detect via the error
            assert!(executor::block_on(wont_suspend) == Err(oneshot::Canceled));

            assert!(rx.recv_timeout(Duration::from_millis(100)) == Ok(1));
            assert!(rx.recv_timeout(Duration::from_millis(100)) == Ok(2));
        }, 500);
    }
}

#[test]
fn safe_to_drop_suspended_queue() {
    timeout(|| {
        let queue       = queue();
        let scheduler   = scheduler();

        let pos         = Arc::new(Mutex::new(0));

        // Increment the position, suspend the queue, increment it again
        let pos2        = pos.clone();
        desync(&queue, move || { let mut pos2 = pos2.lock().unwrap(); *pos2 += 1 });
        scheduler.suspend(&queue);
        let pos2        = pos.clone();
        desync(&queue, move || { let mut pos2 = pos2.lock().unwrap(); *pos2 += 1 });

        // Wait for long enough for these events to take place and check the queue
        while *pos.lock().unwrap() == 0 {
            thread::sleep(Duration::from_millis(100));
        }
        assert!(*pos.lock().unwrap() == 1);
    }, 500);
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Formatter};
use std::io::{self, prelude::*};
use std::str;

pub struct MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    value: DisplayValue<T>,
    escaper: E,
}

impl<E, T> MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    pub fn new_unsafe(value: T, escaper: E) -> Self {
        Self {
            value: DisplayValue::Unsafe(value),
            escaper,
        }
    }

    pub fn new_safe(value: T, escaper: E) -> Self {
        Self {
            value: DisplayValue::Safe(value),
            escaper,
        }
    }

    pub fn mark_safe(mut self) -> MarkupDisplay<E, T> {
        self.value = match self.value {
            DisplayValue::Unsafe(t) => DisplayValue::Safe(t),
            _ => self.value,
        };
        self
    }
}

impl<E, T> Display for MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        match self.value {
            DisplayValue::Unsafe(ref t) => write!(
                EscapeWriter {
                    fmt,
                    escaper: &self.escaper
                },
                "{}",
                t
            )
            .map_err(|_| fmt::Error),
            DisplayValue::Safe(ref t) => t.fmt(fmt),
        }
    }
}

pub struct EscapeWriter<'a, 'b: 'a, E> {
    fmt: &'a mut fmt::Formatter<'b>,
    escaper: &'a E,
}

impl<E> io::Write for EscapeWriter<'_, '_, E>
where
    E: Escaper,
{
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        self.escaper
            .write_escaped_bytes(self.fmt, bytes)
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
        Ok(bytes.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

pub fn escape<E>(s: &str, escaper: E) -> Escaped<'_, E>
where
    E: Escaper,
{
    Escaped {
        bytes: s.as_bytes(),
        escaper,
    }
}

pub struct Escaped<'a, E>
where
    E: Escaper,
{
    bytes: &'a [u8],
    escaper: E,
}

impl<'a, E> ::std::fmt::Display for Escaped<'a, E>
where
    E: Escaper,
{
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.escaper.write_escaped_bytes(fmt, self.bytes)
    }
}

pub struct Html;

macro_rules! escaping_body {
    ($start:ident, $i:ident, $fmt:ident, $bytes:ident, $quote:expr) => {{
        if $start < $i {
            $fmt.write_str(unsafe { str::from_utf8_unchecked(&$bytes[$start..$i]) })?;
        }
        $fmt.write_str($quote)?;
        $start = $i + 1;
    }};
}

impl Escaper for Html {
    fn write_escaped_bytes(&self, fmt: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result {
        let mut start = 0;
        for (i, b) in bytes.iter().enumerate() {
            if b.wrapping_sub(b'"') <= FLAG {
                match *b {
                    b'<' => escaping_body!(start, i, fmt, bytes, "<"),
                    b'>' => escaping_body!(start, i, fmt, bytes, ">"),
                    b'&' => escaping_body!(start, i, fmt, bytes, "&"),
                    b'"' => escaping_body!(start, i, fmt, bytes, """),
                    b'\'' => escaping_body!(start, i, fmt, bytes, "'"),
                    b'/' => escaping_body!(start, i, fmt, bytes, "/"),
                    _ => (),
                }
            }
        }
        fmt.write_str(unsafe { str::from_utf8_unchecked(&bytes[start..]) })
    }
}

pub struct Text;

impl Escaper for Text {
    fn write_escaped_bytes(&self, fmt: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result {
        fmt.write_str(unsafe { str::from_utf8_unchecked(bytes) })
    }
}

#[derive(Debug, PartialEq)]
enum DisplayValue<T>
where
    T: Display,
{
    Safe(T),
    Unsafe(T),
}

pub trait Escaper {
    fn write_escaped_bytes(&self, fmt: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result;
}

const FLAG: u8 = b'>' - b'"';

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_escape() {
        assert_eq!(escape("", Html).to_string(), "");
        assert_eq!(escape("<&>", Html).to_string(), "<&>");
        assert_eq!(escape("bla&", Html).to_string(), "bla&");
        assert_eq!(escape("<foo", Html).to_string(), "<foo");
        assert_eq!(escape("bla&h", Html).to_string(), "bla&h");
    }
}
<commit_msg>Change askama_escape to require UTF-8 strings<commit_after>use std::fmt::{self, Display, Formatter, Write};
use std::str;

pub struct MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    value: DisplayValue<T>,
    escaper: E,
}

impl<E, T> MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    pub fn new_unsafe(value: T, escaper: E) -> Self {
        Self {
            value: DisplayValue::Unsafe(value),
            escaper,
        }
    }

    pub fn new_safe(value: T, escaper: E) -> Self {
        Self {
            value: DisplayValue::Safe(value),
            escaper,
        }
    }

    pub fn mark_safe(mut self) -> MarkupDisplay<E, T> {
        self.value = match self.value {
            DisplayValue::Unsafe(t) => DisplayValue::Safe(t),
            _ => self.value,
        };
        self
    }
}

impl<E, T> Display for MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        match self.value {
            DisplayValue::Unsafe(ref t) => write!(
                EscapeWriter {
                    fmt,
                    escaper: &self.escaper
                },
                "{}",
                t
            ),
            DisplayValue::Safe(ref t) => t.fmt(fmt),
        }
    }
}

pub struct EscapeWriter<'a, E, W> {
    fmt: W,
    escaper: &'a E,
}

impl<'a, E, W> Write for EscapeWriter<'a, E, W>
where
    W: Write,
    E: Escaper,
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.escaper.write_escaped(&mut self.fmt, s)
    }
}

pub fn escape<E>(string: &str, escaper: E) -> Escaped<'_, E>
where
    E: Escaper,
{
    Escaped {
        string,
        escaper,
    }
}

pub struct Escaped<'a, E>
where
    E: Escaper,
{
    string: &'a str,
    escaper: E,
}

impl<'a, E> ::std::fmt::Display for Escaped<'a, E>
where
    E: Escaper,
{
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.escaper.write_escaped(fmt, self.string)
    }
}

pub struct Html;

macro_rules! escaping_body {
    ($start:ident, $i:ident, $fmt:ident, $bytes:ident, $quote:expr) => {{
        if $start < $i {
            $fmt.write_str(unsafe { str::from_utf8_unchecked(&$bytes[$start..$i]) })?;
        }
        $fmt.write_str($quote)?;
        $start = $i + 1;
    }};
}

impl Escaper for Html {
    fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
    where
        W: Write,
    {
        let bytes = string.as_bytes();
        let mut start = 0;
        for (i, b) in bytes.iter().enumerate() {
            if b.wrapping_sub(b'"') <= FLAG {
                match *b {
                    b'<' => escaping_body!(start, i, fmt, bytes, "<"),
                    b'>' => escaping_body!(start, i, fmt, bytes, ">"),
                    b'&' => escaping_body!(start, i, fmt, bytes, "&"),
                    b'"' => escaping_body!(start, i, fmt, bytes, """),
                    b'\'' => escaping_body!(start, i, fmt, bytes, "'"),
                    b'/' => escaping_body!(start, i, fmt, bytes, "/"),
                    _ => (),
                }
            }
        }
        fmt.write_str(unsafe { str::from_utf8_unchecked(&bytes[start..]) })
    }
}

pub struct Text;

impl Escaper for Text {
    fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
    where
        W: Write,
    {
        fmt.write_str(string)
    }
}

#[derive(Debug, PartialEq)]
enum DisplayValue<T>
where
    T: Display,
{
    Safe(T),
    Unsafe(T),
}

pub trait Escaper {
    fn write_escaped<W>(&self, fmt: W, string: &str) -> fmt::Result
    where
        W: Write;
}

const FLAG: u8 = b'>' - b'"';

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_escape() {
        assert_eq!(escape("", Html).to_string(), "");
        assert_eq!(escape("<&>", Html).to_string(), "<&>");
        assert_eq!(escape("bla&", Html).to_string(), "bla&");
        assert_eq!(escape("<foo", Html).to_string(), "<foo");
        assert_eq!(escape("bla&h", Html).to_string(), "bla&h");
    }
}
<|endoftext|>


<commit_before>// #![feature(trace_macros)]
//
// trace_macros!(true);

#[macro_use]
extern crate asn1_cereal;
extern crate argparse;

use std::io;

use asn1_cereal::{BerSerialize, BerDeserialize, DER, BER, BERAlt};
use argparse::{ArgumentParser, StoreTrue};

fn main() {
  let opts = parse_args();

  let mut buffer: Vec<u8> = Vec::new();
  let mut output = io::BufWriter::new(io::stdout());

  let seq = IntSequence { a: 3, b: vec![4], c: SomeString("Hello".into()) };

  if opts.dump {
    let mut writer = io::BufWriter::new(&mut output);
    seq.serialize_enc(BER, &mut writer).unwrap();
    return;
  }
  {
    let mut writer = io::BufWriter::new(&mut buffer);
    seq.serialize_enc(BER, &mut writer).unwrap();
  }
  println!("{:?}", buffer);
  {
    let mut reader = buffer.iter().map(|x| Ok(*x) as Result<u8, std::io::Error>);
    let seq = IntSequence::deserialize_enc(BER, &mut reader).unwrap();
    println!("{:?}", seq);
  }
}

#[derive(Debug, PartialEq)]
struct SomeString(String);

asn1_info!(
  SomeString,
  asn1_cereal::tag::Class::Private,
  1,
  true,
  "SOMESTRING"
);

ber_newtype!(SomeString);

#[derive(Debug, PartialEq)]
struct IntSequence {
  a: u64,
  b: Vec<i32>,
  c: SomeString,
}

ber_sequence!(
  IntSequence,
  "INTSEQ",
  a;
  b;
  c;
);

struct ProgOpts {
  dump: bool,
}

fn parse_args() -> ProgOpts {
  let mut opts = ProgOpts {
    dump: false,
  };
  {
    let mut ap = ArgumentParser::new();
    ap.refer(&mut opts.dump)
      .add_option(&["-d", "--dump"], StoreTrue, "Dump asn.1 packet");
    ap.parse_args_or_exit();
  }
  opts
}
<commit_msg>Update simple.rs to test more features<commit_after>// #![feature(trace_macros)]
//
// trace_macros!(true);

#[macro_use]
extern crate asn1_cereal;
extern crate argparse;

use std::io;

use asn1_cereal::{BerSerialize, BerDeserialize, DER, BER, BERAlt};
use argparse::{ArgumentParser, StoreTrue};

fn main() {
  let opts = parse_args();

  let mut buffer: Vec<u8> = Vec::new();
  let mut output = io::BufWriter::new(io::stdout());
  let enc = BER;

  let seq = IntSequence {
    a: 4,
    b: vec![4],
    c: Some(SomeString("Hello".into()))
  };

  if opts.dump {
    let mut writer = io::BufWriter::new(&mut output);
    seq.serialize_enc(enc, &mut writer).unwrap();
    return;
  }
  {
    let mut writer = io::BufWriter::new(&mut buffer);
    seq.serialize_enc(enc, &mut writer).unwrap();
  }
  println!("Before: {:?}", buffer);
  {
    let mut reader = buffer.iter().map(|x| Ok(*x) as Result<u8, std::io::Error>);
    let seq = IntSequence::deserialize_enc(enc, &mut reader).unwrap();
    println!("{:?}", seq);
  }
}

#[derive(Debug, PartialEq)]
struct SomeString(String);

ber_alias!(
  SomeString ::= [PRIVATE 1] String,
  "SOMESTRING"
);

#[derive(Debug, PartialEq)]
struct IntSequence {
  a: u64,
  b: Vec<i32>,
  c: Option<SomeString>,
}

ber_sequence!(
  IntSequence,
  "INTSEQ",
  a (DEFAULT 4);
  b;
  c (OPTIONAL);
);

struct ProgOpts {
  dump: bool,
}

fn parse_args() -> ProgOpts {
  let mut opts = ProgOpts {
    dump: false,
  };
  {
    let mut ap = ArgumentParser::new();
    ap.refer(&mut opts.dump)
      .add_option(&["-d", "--dump"], StoreTrue, "Dump asn.1 packet");
    ap.parse_args_or_exit();
  }
  opts
}
<|endoftext|>


<commit_before>use std::collections::LinkedList;

#[derive(Debug)]
pub struct Graph {
    edges: Vec<Vec<usize>>,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Distance {
    Unreachable,
    Reachable(usize),
}

impl Distance {
    fn increase(self) -> Self {
        match self {
            Self::Unreachable => unreachable!("DFS implementation is incorrect"),
            Self::Reachable(v) => Self::Reachable(v + 1),
        }
    }
}

impl Graph {
    pub fn bfs(&self, from: usize, to: usize) -> Distance {
        // Check that the start and end nodes exist.
        assert!(from < self.edges.len());
        assert!(to < self.edges.len());

        let mut distances = vec![Distance::Unreachable; self.edges.len()];
        // Next nodes to visit.
        let mut queue = LinkedList::new();
        let mut visited = vec![false; self.edges.len()];

        // Initialization: where is an information about the start node.
        queue.push_back(from);
        // Distance from the `from` node to the `from` node always is zero.
        distances[from] = Distance::Reachable(0);
        // Mark `from` node as visited.
        visited[from] = true;
        // While have nodes to visit perform `DFS`.
        while !queue.is_empty() {
            // Get first node from the queue
            let node = queue.pop_front().unwrap();
            // Go through all node neighbors
            for &neighbor in &self.edges[node] {
                // Check if neighbor is still `white`
                if !visited[neighbor] {
                    // Compute distance between start node and neighbor.
                    distances[neighbor] = distances[node].increase();
                    // Mark neighbor as `gray`.
                    visited[neighbor] = true;
                    // Add node to lookup queue.
                    queue.push_back(neighbor);
                }
            }
        }

        // Return distance to desired node.
        distances[to]
    }
}

#[test]
fn simple() {
    let graph = Graph {
        edges: vec![
            vec![1, 2, 3],
            vec![2, 0],
            vec![0, 1],
            vec![0, 4],
            vec![1, 3],
            vec![],
        ],
    };

    assert_eq!(graph.bfs(0, 0), Distance::Reachable(0));
    assert_eq!(graph.bfs(0, 2), Distance::Reachable(1));
    assert_eq!(graph.bfs(0, 4), Distance::Reachable(2));
    assert_eq!(graph.bfs(2, 3), Distance::Reachable(2));

    assert_eq!(graph.bfs(5, 5), Distance::Reachable(0));
    assert_eq!(graph.bfs(5, 0), Distance::Unreachable);
    assert_eq!(graph.bfs(0, 5), Distance::Unreachable);
}

#[test]
fn two_components() {
    let graph = Graph {
        edges: vec![
            // First connectivity component
            vec![1],
            vec![0, 3],
            vec![3],
            vec![1, 2],
            // Second connectivity component
            vec![5, 6],
            vec![6, 4],
            vec![4, 5],
        ]
    };

    assert_eq!(graph.bfs(0, 2), Distance::Reachable(3));
    assert_eq!(graph.bfs(2, 0), Distance::Reachable(3));
    assert_eq!(graph.bfs(4, 5), Distance::Reachable(1));
    assert_eq!(graph.bfs(4, 0), Distance::Unreachable);
    assert_eq!(graph.bfs(0, 4), Distance::Unreachable);
}<commit_msg>Colored dfs with path<commit_after>use std::collections::LinkedList;

#[derive(Debug)]
pub struct Graph {
    edges: Vec<Vec<usize>>,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Distance {
    Unreachable,
    Reachable(usize),
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum NodeColor {
    /// Unvisited node,
    White,
    /// Currently visiting node.
    Gray,
    /// Visited node; all iterations with it are finished.
    Black,
}

impl Distance {
    fn increase(self) -> Self {
        match self {
            Self::Unreachable => unreachable!("DFS implementation is incorrect"),
            Self::Reachable(v) => Self::Reachable(v + 1),
        }
    }
}

impl Graph {
    pub fn bfs(&self, from: usize, to: usize) -> Distance {
        // Check that the start and end nodes exist.
        assert!(from < self.edges.len());
        assert!(to < self.edges.len());

        let mut distances = vec![Distance::Unreachable; self.edges.len()];
        // Next nodes to visit.
        let mut queue = LinkedList::new();
        let mut visited = vec![false; self.edges.len()];

        // Initialization: where is an information about the start node.
        queue.push_back(from);
        // Distance from the `from` node to the `from` node always is zero.
        distances[from] = Distance::Reachable(0);
        // Mark `from` node as visited.
        visited[from] = true;
        // While have nodes to visit perform `BFS`.
        while !queue.is_empty() {
            // Get first node from the queue
            let node = queue.pop_front().unwrap();
            // Go through all node neighbors
            for &neighbor in &self.edges[node] {
                // Check if neighbor is still `white`
                if !visited[neighbor] {
                    // Compute distance between start node and neighbor.
                    distances[neighbor] = distances[node].increase();
                    // Mark neighbor as `gray`.
                    visited[neighbor] = true;
                    // Add node to lookup queue.
                    queue.push_back(neighbor);
                }
            }
        }

        // Return distance to desired node.
        distances[to]
    }

    pub fn dfs(&self, from: usize, to: usize) -> Option<Vec<usize>> {
        // Check that the start and end nodes exist.
        assert!(from < self.edges.len());
        assert!(to < self.edges.len());

        // Recursive 'dfs' implementation
        fn do_dfs(
            edges: &[Vec<usize>],
            visited: &mut [NodeColor],
            prior: &mut [Option<usize>],
            node: usize,
            from: usize,
            to: usize,
        ) {
            // If we have already visited this node, there is nothing to do.
            if visited[node] != NodeColor::White {
                return;
            }
            // Mark current node as `gray`.
            visited[node] = NodeColor::Gray;
            // Store node in the prior array.
            prior[node] = Some(from);

            // Go through all node neighbors.
            for &neighbor in &edges[node] {
                do_dfs(edges, visited, prior, neighbor, node, to);
            }
            // Mark current node as `black`
            visited[node] = NodeColor::Black;
        }

        // Visited nodes.
        let mut visited = vec![NodeColor::White; self.edges.len()];
        // Remember node from where did we come.
        let mut prior = vec![None; self.edges.len()];
        // Go through all `from` node neighbors.
        for &neighbor in &self.edges[from] {
            do_dfs(&self.edges, &mut visited, &mut prior, neighbor, from, to);
        }

        // Restore complete path `from` -> `to`
        let mut prev = prior[to]?;
        let mut path = vec![prev];
        while prev != from {
            prev = prior[prev]?;
            path.push(prev);
        }
        path.reverse();
        path.push(to);

        Some(path)
    }
}

#[test]
fn bfs_simple() {
    let graph = Graph {
        edges: vec![
            vec![1, 2, 3],
            vec![2, 0],
            vec![0, 1],
            vec![0, 4],
            vec![1, 3],
            vec![],
        ],
    };

    assert_eq!(graph.bfs(0, 0), Distance::Reachable(0));
    assert_eq!(graph.bfs(0, 2), Distance::Reachable(1));
    assert_eq!(graph.bfs(0, 4), Distance::Reachable(2));
    assert_eq!(graph.bfs(2, 3), Distance::Reachable(2));

    assert_eq!(graph.bfs(5, 5), Distance::Reachable(0));
    assert_eq!(graph.bfs(5, 0), Distance::Unreachable);
    assert_eq!(graph.bfs(0, 5), Distance::Unreachable);
}

#[test]
fn bfs_two_components() {
    let graph = Graph {
        edges: vec![
            // First connectivity component
            vec![1],
            vec![0, 3],
            vec![3],
            vec![1, 2],
            // Second connectivity component
            vec![5, 6],
            vec![6, 4],
            vec![4, 5],
        ],
    };

    assert_eq!(graph.bfs(0, 2), Distance::Reachable(3));
    assert_eq!(graph.bfs(2, 0), Distance::Reachable(3));
    assert_eq!(graph.bfs(4, 5), Distance::Reachable(1));
    assert_eq!(graph.bfs(4, 0), Distance::Unreachable);
    assert_eq!(graph.bfs(0, 4), Distance::Unreachable);
}

#[test]
fn dfs_simple() {
    let graph = Graph {
        edges: vec![
            vec![1, 2, 3],
            vec![2, 0],
            vec![0, 1],
            vec![0, 4],
            vec![1, 3],
            vec![],
        ],
    };

    assert_eq!(graph.dfs(0, 4), Some(vec![0, 3, 4]));
    assert_eq!(graph.dfs(1, 3), Some(vec![1, 2, 0, 3]));
    assert_eq!(graph.dfs(0, 5), None);
}

#[test]
fn dfs_two_components() {
    let graph = Graph {
        edges: vec![
            // First connectivity component
            vec![1],
            vec![0, 3],
            vec![3],
            vec![1, 2],
            // Second connectivity component
            vec![5, 6],
            vec![6, 4],
            vec![4, 5],
        ],
    };

    assert_eq!(graph.dfs(2, 0), Some(vec![2, 3, 1, 0]));
    assert_eq!(graph.dfs(2, 4), None);
}<|endoftext|>


<commit_before>// compile-flags: -C no-prepopulate-passes
// ignore-tidy-linelength

// ignore-arm
// ignore-mips
// ignore-mips64
// ignore-powerpc
// ignore-powerpc64
// See repr-transparent.rs

#![feature(transparent_enums, transparent_unions)]

#![crate_type="lib"]

#[derive(Clone, Copy)]
#[repr(C)]
pub struct BigS([u32; 16]);

#[repr(transparent)]
pub struct TsBigS(BigS);

#[repr(transparent)]
pub union TuBigS {
    field: BigS,
}

#[repr(transparent)]
pub enum TeBigS {
    Variant(BigS),
}

// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS:.*]], %BigS* [[BIGS_ARG_ATTRS:.*]])
#[no_mangle]
pub extern fn test_BigS(_: BigS) -> BigS { loop {} }

// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS]], %TsBigS* [[BIGS_ARG_ATTRS]])
#[no_mangle]
pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }

// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS]], %TuBigS* [[BIGS_ARG_ATTRS]])
#[no_mangle]
pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }

// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS]], %"TeBigS::Variant"* [[BIGS_ARG_ATTRS]])
#[no_mangle]
pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }

#[derive(Clone, Copy)]
#[repr(C)]
pub union BigU {
    foo: [u32; 16],
}

#[repr(transparent)]
pub struct TsBigU(BigU);

#[repr(transparent)]
pub union TuBigU {
    field: BigU,
}

#[repr(transparent)]
pub enum TeBigU {
    Variant(BigU),
}

// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], %BigU* [[BIGU_ARG_ATTRS:.*]])
#[no_mangle]
pub extern fn test_BigU(_: BigU) -> BigU { loop {} }

// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS:.*]], %TsBigU* [[BIGU_ARG_ATTRS]])
#[no_mangle]
pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }

// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS]], %TuBigU* [[BIGU_ARG_ATTRS]])
#[no_mangle]
pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }

// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS]], %"TeBigU::Variant"* [[BIGU_ARG_ATTRS]])
#[no_mangle]
pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
<commit_msg>Update transparent aggregate codegen test for byval changes<commit_after>// compile-flags: -C no-prepopulate-passes
// ignore-tidy-linelength

// min-system-llvm-version: 9.0
// ignore-arm
// ignore-mips
// ignore-mips64
// ignore-powerpc
// ignore-powerpc64
// ignore-windows
// See repr-transparent.rs

#![feature(transparent_enums, transparent_unions)]

#![crate_type="lib"]

#[derive(Clone, Copy)]
#[repr(C)]
pub struct BigS([u32; 16]);

#[repr(transparent)]
pub struct TsBigS(BigS);

#[repr(transparent)]
pub union TuBigS {
    field: BigS,
}

#[repr(transparent)]
pub enum TeBigS {
    Variant(BigS),
}

// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS:.*]], %BigS* [[BIGS_ARG_ATTRS1:.*]] byval(%BigS) [[BIGS_ARG_ATTRS2:.*]])
#[no_mangle]
pub extern fn test_BigS(_: BigS) -> BigS { loop {} }

// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS]], %TsBigS* [[BIGS_ARG_ATTRS1]] byval(%TsBigS) [[BIGS_ARG_ATTRS2:.*]])
#[no_mangle]
pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }

// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS]], %TuBigS* [[BIGS_ARG_ATTRS1]] byval(%TuBigS) [[BIGS_ARG_ATTRS2:.*]])
#[no_mangle]
pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }

// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS]], %"TeBigS::Variant"* [[BIGS_ARG_ATTRS1]] byval(%"TeBigS::Variant") [[BIGS_ARG_ATTRS2]])
#[no_mangle]
pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }

#[derive(Clone, Copy)]
#[repr(C)]
pub union BigU {
    foo: [u32; 16],
}

#[repr(transparent)]
pub struct TsBigU(BigU);

#[repr(transparent)]
pub union TuBigU {
    field: BigU,
}

#[repr(transparent)]
pub enum TeBigU {
    Variant(BigU),
}

// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], %BigU* [[BIGU_ARG_ATTRS1:.*]] byval(%BigU) [[BIGU_ARG_ATTRS2:.*]])
#[no_mangle]
pub extern fn test_BigU(_: BigU) -> BigU { loop {} }

// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS:.*]], %TsBigU* [[BIGU_ARG_ATTRS1]] byval(%TsBigU) [[BIGU_ARG_ATTRS2]])
#[no_mangle]
pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }

// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS]], %TuBigU* [[BIGU_ARG_ATTRS1]] byval(%TuBigU) [[BIGU_ARG_ATTRS2]])
#[no_mangle]
pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }

// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS]], %"TeBigU::Variant"* [[BIGU_ARG_ATTRS1]] byval(%"TeBigU::Variant") [[BIGU_ARG_ATTRS2]])
#[no_mangle]
pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
<|endoftext|>