<commit_before>use std::cell::RefCell;
use std::fmt;
use std::mem;
use std::rc::Rc;

use dense;
use state_id::{StateID, dead_id};

type DFARepr<S> = dense::Repr<Vec<S>, S>;

/// An implementation of Hopcroft's algorithm for minimizing DFAs.
///
/// The algorithm implemented here is mostly taken from Wikipedia:
/// https://en.wikipedia.org/wiki/DFA_minimization#Hopcroft's_algorithm
///
/// This code has had some light optimization attention paid to it,
/// particularly in the form of reducing allocation as much as possible.
/// However, it is still generally slow. Future optimization work should
/// probably focus on the bigger picture rather than micro-optimizations. For
/// example:
///
/// 1. Figure out how to more intelligently create initial partitions. That is,
///    Hopcroft's algorithm starts by creating two partitions of DFA states
///    that are known to NOT be equivalent: match states and non-match states.
///    The algorithm proceeds by progressively refining these partitions into
///    smaller partitions. If we could start with more partitions, then we
///    could reduce the amount of work that Hopcroft's algorithm needs to do.
/// 2. For every partition that we visit, we find all incoming transitions to
///    every state in the partition for *every* element in the alphabet. (This
///    is why using byte classes can significantly decrease minimization times,
///    since byte classes shrink the alphabet.) This is quite costly and there
///    is perhaps some redundant work being performed depending on the specific
///    states in the set. For example, we might be able to only visit some
///    elements of the alphabet based on the transitions.
/// 3. Move parts of minimization into determinization. If minimization has
///    fewer states to deal with, then it should run faster. A prime example
///    of this might be large Unicode classes, which are generated in way that
///    can create a lot of redundant states.
pub(crate) struct Minimizer<'a, S: 'a> {
    dfa: &'a mut DFARepr<S>,
    in_transitions: Vec<Vec<Vec<S>>>,
    partitions: Vec<StateSet<S>>,
    waiting: Vec<StateSet<S>>,
}

impl<'a, S: StateID> fmt::Debug for Minimizer<'a, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Minimizer")
            .field("dfa", &self.dfa)
            .field("in_transitions", &self.in_transitions)
            .field("partitions", &self.partitions)
            .field("waiting", &self.waiting)
            .finish()
    }
}

/// A set of states. A state set makes up a single partition in Hopcroft's
/// algorithm.
///
/// It is represented by an ordered set of state identifiers. We use shared
/// ownership so that a single state set can be in both the set of partitions
/// and in set of waiting sets simultaneously without an additional allocation.
/// Generally, once a state set is built, it becomes immutable.
///
/// We use this representation because it avoids the overhead of more
/// traditional set data structures (HashSet/BTreeSet), and also because
/// computing intersection/subtraction on this representation is especially
/// fast.
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
struct StateSet<S>(Rc<RefCell<Vec<S>>>);

impl<'a, S: StateID> Minimizer<'a, S> {
    pub fn new(dfa: &'a mut DFARepr<S>) -> Minimizer<'a, S> {
        let in_transitions = Minimizer::incoming_transitions(dfa);
        let partitions = Minimizer::initial_partitions(dfa);
        let waiting = vec![partitions[0].clone()];

        Minimizer { dfa, in_transitions, partitions, waiting }
    }

    pub fn run(mut self) {
        let mut incoming = StateSet::empty();
        let mut scratch1 = StateSet::empty();
        let mut scratch2 = StateSet::empty();
        let mut newparts = vec![];

        while let Some(set) = self.waiting.pop() {
            for b in (0..self.dfa.alphabet_len()).map(|b| b as u8) {
                self.find_incoming_to(b, &set, &mut incoming);

                for p in 0..self.partitions.len() {
                    self.partitions[p].intersection(&incoming, &mut scratch1);
                    if scratch1.is_empty() {
                        newparts.push(self.partitions[p].clone());
                        continue;
                    }

                    self.partitions[p].subtract(&incoming, &mut scratch2);
                    if scratch2.is_empty() {
                        newparts.push(self.partitions[p].clone());
                        continue;
                    }

                    let (x, y) = (scratch1.deep_clone(), scratch2.deep_clone());
                    newparts.push(x.clone());
                    newparts.push(y.clone());
                    match self.find_waiting(&self.partitions[p]) {
                        Some(i) => {
                            self.waiting[i] = x;
                            self.waiting.push(y);
                        }
                        None => {
                            if x.len() <= y.len() {
                                self.waiting.push(x);
                            } else {
                                self.waiting.push(y);
                            }
                        }
                    }
                }
                newparts = mem::replace(&mut self.partitions, newparts);
                newparts.clear();
            }
        }

        let mut state_to_part = vec![dead_id(); self.dfa.state_count()];
        for p in &self.partitions {
            p.iter(|id| state_to_part[id.to_usize()] = p.min());
        }

        let mut minimal_ids = vec![dead_id(); self.dfa.state_count()];
        let mut new_id = S::from_usize(0);
        for (id, _) in self.dfa.states() {
            if state_to_part[id.to_usize()] == id {
                minimal_ids[id.to_usize()] = new_id;
                new_id = S::from_usize(new_id.to_usize() + 1);
            }
        }
        let minimal_count = new_id.to_usize();

        for id in (0..self.dfa.state_count()).map(S::from_usize) {
            if state_to_part[id.to_usize()] != id {
                continue;
            }
            for (_, next) in self.dfa.get_state_mut(id).iter_mut() {
                *next = minimal_ids[state_to_part[next.to_usize()].to_usize()];
            }
            self.dfa.swap_states(id, minimal_ids[id.to_usize()]);
        }

        let old_start = self.dfa.start_state();
        self.dfa.set_start_state(
            minimal_ids[state_to_part[old_start.to_usize()].to_usize()],
        );
        self.dfa.truncate_states(minimal_count);

        let old_max = self.dfa.max_match_state();
        self.dfa.set_max_match_state(dead_id());
        for id in (0..(old_max.to_usize() + 1)).map(S::from_usize) {
            let part = state_to_part[id.to_usize()];
            let new_id = minimal_ids[part.to_usize()];
            if new_id > self.dfa.max_match_state() {
                self.dfa.set_max_match_state(new_id);
            }
        }
    }

    fn find_waiting(&self, set: &StateSet<S>) -> Option<usize> {
        self.waiting.iter().position(|s| s == set)
    }

    fn find_incoming_to(
        &self,
        b: u8,
        set: &StateSet<S>,
        incoming: &mut StateSet<S>,
    ) {
        incoming.clear();
        set.iter(|id| {
            for &inid in &self.in_transitions[id.to_usize()][b as usize] {
                incoming.add(inid);
            }
        });
        incoming.canonicalize();
    }

    fn initial_partitions(dfa: &DFARepr<S>) -> Vec<StateSet<S>> {
        let mut is_match = StateSet::empty();
        let mut no_match = StateSet::empty();
        for (id, _) in dfa.states() {
            if dfa.is_match_state(id) {
                is_match.add(id);
            } else {
                no_match.add(id);
            }
        }

        let mut sets = vec![is_match];
        if !no_match.is_empty() {
            sets.push(no_match);
        }
        sets.sort_by_key(|s| s.len());
        sets
    }

    fn incoming_transitions(dfa: &DFARepr<S>) -> Vec<Vec<Vec<S>>> {
        let mut incoming = vec![];
        for _ in dfa.states() {
            incoming.push(vec![vec![]; dfa.alphabet_len()]);
        }
        for (id, state) in dfa.states() {
            for (b, next) in state.transitions() {
                incoming[next.to_usize()][b as usize].push(id);
            }
        }
        incoming
    }
}

impl<S: StateID> StateSet<S> {
    fn empty() -> StateSet<S> {
        StateSet(Rc::new(RefCell::new(vec![])))
    }

    fn add(&mut self, id: S) {
        self.0.borrow_mut().push(id);
    }

    fn min(&self) -> S {
        self.0.borrow()[0]
    }

    fn canonicalize(&mut self) {
        self.0.borrow_mut().sort();
        self.0.borrow_mut().dedup();
    }

    fn clear(&mut self) {
        self.0.borrow_mut().clear();
    }

    fn len(&self) -> usize {
        self.0.borrow().len()
    }

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

    fn deep_clone(&self) -> StateSet<S> {
        let ids = self.0.borrow().iter().cloned().collect();
        StateSet(Rc::new(RefCell::new(ids)))
    }

    fn iter<F: FnMut(S)>(&self, mut f: F) {
        for &id in self.0.borrow().iter() {
            f(id);
        }
    }

    fn intersection(&self, other: &StateSet<S>, dest: &mut StateSet<S>) {
        dest.clear();
        if self.is_empty() || other.is_empty() {
            return;
        }

        let (seta, setb) = (self.0.borrow(), other.0.borrow());
        let (mut ita, mut itb) = (seta.iter().cloned(), setb.iter().cloned());
        let (mut a, mut b) = (ita.next().unwrap(), itb.next().unwrap());
        loop {
            if a == b {
                dest.add(a);
                a = match ita.next() {
                    None => break,
                    Some(a) => a,
                };
                b = match itb.next() {
                    None => break,
                    Some(b) => b,
                };
            } else if a < b {
                a = match ita.next() {
                    None => break,
                    Some(a) => a,
                };
            } else {
                b = match itb.next() {
                    None => break,
                    Some(b) => b,
                };
            }
        }
    }

    fn subtract(&self, other: &StateSet<S>, dest: &mut StateSet<S>) {
        dest.clear();
        if self.is_empty() || other.is_empty() {
            self.iter(|s| dest.add(s));
            return;
        }

        let (seta, setb) = (self.0.borrow(), other.0.borrow());
        let (mut ita, mut itb) = (seta.iter().cloned(), setb.iter().cloned());
        let (mut a, mut b) = (ita.next().unwrap(), itb.next().unwrap());
        loop {
            if a == b {
                a = match ita.next() {
                    None => break,
                    Some(a) => a,
                };
                b = match itb.next() {
                    None => { dest.add(a); break; }
                    Some(b) => b,
                };
            } else if a < b {
                dest.add(a);
                a = match ita.next() {
                    None => break,
                    Some(a) => a,
                };
            } else {
                b = match itb.next() {
                    None => { dest.add(a); break; }
                    Some(b) => b,
                };
            }
        }
        for a in ita {
            dest.add(a);
        }
    }
}
<commit_msg>minimize: add some internal docs<commit_after>use std::cell::RefCell;
use std::fmt;
use std::mem;
use std::rc::Rc;

use dense;
use state_id::{StateID, dead_id};

type DFARepr<S> = dense::Repr<Vec<S>, S>;

/// An implementation of Hopcroft's algorithm for minimizing DFAs.
///
/// The algorithm implemented here is mostly taken from Wikipedia:
/// https://en.wikipedia.org/wiki/DFA_minimization#Hopcroft's_algorithm
///
/// This code has had some light optimization attention paid to it,
/// particularly in the form of reducing allocation as much as possible.
/// However, it is still generally slow. Future optimization work should
/// probably focus on the bigger picture rather than micro-optimizations. For
/// example:
///
/// 1. Figure out how to more intelligently create initial partitions. That is,
///    Hopcroft's algorithm starts by creating two partitions of DFA states
///    that are known to NOT be equivalent: match states and non-match states.
///    The algorithm proceeds by progressively refining these partitions into
///    smaller partitions. If we could start with more partitions, then we
///    could reduce the amount of work that Hopcroft's algorithm needs to do.
/// 2. For every partition that we visit, we find all incoming transitions to
///    every state in the partition for *every* element in the alphabet. (This
///    is why using byte classes can significantly decrease minimization times,
///    since byte classes shrink the alphabet.) This is quite costly and there
///    is perhaps some redundant work being performed depending on the specific
///    states in the set. For example, we might be able to only visit some
///    elements of the alphabet based on the transitions.
/// 3. Move parts of minimization into determinization. If minimization has
///    fewer states to deal with, then it should run faster. A prime example
///    of this might be large Unicode classes, which are generated in way that
///    can create a lot of redundant states.
pub(crate) struct Minimizer<'a, S: 'a> {
    dfa: &'a mut DFARepr<S>,
    in_transitions: Vec<Vec<Vec<S>>>,
    partitions: Vec<StateSet<S>>,
    waiting: Vec<StateSet<S>>,
}

impl<'a, S: StateID> fmt::Debug for Minimizer<'a, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Minimizer")
            .field("dfa", &self.dfa)
            .field("in_transitions", &self.in_transitions)
            .field("partitions", &self.partitions)
            .field("waiting", &self.waiting)
            .finish()
    }
}

/// A set of states. A state set makes up a single partition in Hopcroft's
/// algorithm.
///
/// It is represented by an ordered set of state identifiers. We use shared
/// ownership so that a single state set can be in both the set of partitions
/// and in set of waiting sets simultaneously without an additional allocation.
/// Generally, once a state set is built, it becomes immutable.
///
/// We use this representation because it avoids the overhead of more
/// traditional set data structures (HashSet/BTreeSet), and also because
/// computing intersection/subtraction on this representation is especially
/// fast.
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
struct StateSet<S>(Rc<RefCell<Vec<S>>>);

impl<'a, S: StateID> Minimizer<'a, S> {
    pub fn new(dfa: &'a mut DFARepr<S>) -> Minimizer<'a, S> {
        let in_transitions = Minimizer::incoming_transitions(dfa);
        let partitions = Minimizer::initial_partitions(dfa);
        let waiting = vec![partitions[0].clone()];

        Minimizer { dfa, in_transitions, partitions, waiting }
    }

    pub fn run(mut self) {
        let mut incoming = StateSet::empty();
        let mut scratch1 = StateSet::empty();
        let mut scratch2 = StateSet::empty();
        let mut newparts = vec![];

        while let Some(set) = self.waiting.pop() {
            for b in (0..self.dfa.alphabet_len()).map(|b| b as u8) {
                self.find_incoming_to(b, &set, &mut incoming);

                for p in 0..self.partitions.len() {
                    self.partitions[p].intersection(&incoming, &mut scratch1);
                    if scratch1.is_empty() {
                        newparts.push(self.partitions[p].clone());
                        continue;
                    }

                    self.partitions[p].subtract(&incoming, &mut scratch2);
                    if scratch2.is_empty() {
                        newparts.push(self.partitions[p].clone());
                        continue;
                    }

                    let (x, y) = (scratch1.deep_clone(), scratch2.deep_clone());
                    newparts.push(x.clone());
                    newparts.push(y.clone());
                    match self.find_waiting(&self.partitions[p]) {
                        Some(i) => {
                            self.waiting[i] = x;
                            self.waiting.push(y);
                        }
                        None => {
                            if x.len() <= y.len() {
                                self.waiting.push(x);
                            } else {
                                self.waiting.push(y);
                            }
                        }
                    }
                }
                newparts = mem::replace(&mut self.partitions, newparts);
                newparts.clear();
            }
        }

        // At this point, we now have a minimal partitioning of states, where
        // each partition is an equivalence class of DFA states. Now we need to
        // use this partioning to update the DFA to only contain one state for
        // each partition.

        // Create a map from DFA state ID to the representative ID of the
        // equivalence class to which it belongs. The representative ID of an
        // equivalence class of states is the minimum ID in that class.
        let mut state_to_part = vec![dead_id(); self.dfa.state_count()];
        for p in &self.partitions {
            p.iter(|id| state_to_part[id.to_usize()] = p.min());
        }

        // Generate a new contiguous sequence of IDs for minimal states, and
        // create a map from equivalence IDs to the new IDs. Thus, the new
        // minimal ID of *any* state in the unminimized DFA can be obtained
        // with minimals_ids[state_to_part[old_id]].
        let mut minimal_ids = vec![dead_id(); self.dfa.state_count()];
        let mut new_id = S::from_usize(0);
        for (id, _) in self.dfa.states() {
            if state_to_part[id.to_usize()] == id {
                minimal_ids[id.to_usize()] = new_id;
                new_id = S::from_usize(new_id.to_usize() + 1);
            }
        }
        // The total number of states in the minimal DFA.
        let minimal_count = new_id.to_usize();

        // Re-map this DFA in place such that the only states remaining
        // correspond to the representative states of every equivalence class.
        for id in (0..self.dfa.state_count()).map(S::from_usize) {
            // If this state isn't a representative for an equivalence class,
            // then we skip it since it won't appear in the minimal DFA.
            if state_to_part[id.to_usize()] != id {
                continue;
            }
            for (_, next) in self.dfa.get_state_mut(id).iter_mut() {
                *next = minimal_ids[state_to_part[next.to_usize()].to_usize()];
            }
            self.dfa.swap_states(id, minimal_ids[id.to_usize()]);
        }
        // Trim off all unused states from the pre-minimized DFA. This
        // represents all states that were merged into a non-singleton
        // equivalence class of states, and appeared after the first state
        // in each such class. (Because the state with the smallest ID in each
        // equivalence class is its representative ID.)
        self.dfa.truncate_states(minimal_count);

        // Update the new start state, which is now just the minimal ID of
        // whatever state the old start state was collapsed into.
        let old_start = self.dfa.start_state();
        self.dfa.set_start_state(
            minimal_ids[state_to_part[old_start.to_usize()].to_usize()],
        );

        // In order to update the ID of the maximum match state, we need to
        // find the maximum ID among all of the match states in the minimized
        // DFA. This is not necessarily the new ID of the unminimized maximum
        // match state, since that could have been collapsed with a much
        // earlier match state. Therefore, to find the new max match state,
        // we iterate over all previous match states, find their corresponding
        // new minimal ID, and take the maximum of those.
        let old_max = self.dfa.max_match_state();
        self.dfa.set_max_match_state(dead_id());
        for id in (0..(old_max.to_usize() + 1)).map(S::from_usize) {
            let part = state_to_part[id.to_usize()];
            let new_id = minimal_ids[part.to_usize()];
            if new_id > self.dfa.max_match_state() {
                self.dfa.set_max_match_state(new_id);
            }
        }
    }

    fn find_waiting(&self, set: &StateSet<S>) -> Option<usize> {
        self.waiting.iter().position(|s| s == set)
    }

    fn find_incoming_to(
        &self,
        b: u8,
        set: &StateSet<S>,
        incoming: &mut StateSet<S>,
    ) {
        incoming.clear();
        set.iter(|id| {
            for &inid in &self.in_transitions[id.to_usize()][b as usize] {
                incoming.add(inid);
            }
        });
        incoming.canonicalize();
    }

    fn initial_partitions(dfa: &DFARepr<S>) -> Vec<StateSet<S>> {
        let mut is_match = StateSet::empty();
        let mut no_match = StateSet::empty();
        for (id, _) in dfa.states() {
            if dfa.is_match_state(id) {
                is_match.add(id);
            } else {
                no_match.add(id);
            }
        }

        let mut sets = vec![is_match];
        if !no_match.is_empty() {
            sets.push(no_match);
        }
        sets.sort_by_key(|s| s.len());
        sets
    }

    fn incoming_transitions(dfa: &DFARepr<S>) -> Vec<Vec<Vec<S>>> {
        let mut incoming = vec![];
        for _ in dfa.states() {
            incoming.push(vec![vec![]; dfa.alphabet_len()]);
        }
        for (id, state) in dfa.states() {
            for (b, next) in state.transitions() {
                incoming[next.to_usize()][b as usize].push(id);
            }
        }
        incoming
    }
}

impl<S: StateID> StateSet<S> {
    fn empty() -> StateSet<S> {
        StateSet(Rc::new(RefCell::new(vec![])))
    }

    fn add(&mut self, id: S) {
        self.0.borrow_mut().push(id);
    }

    fn min(&self) -> S {
        self.0.borrow()[0]
    }

    fn canonicalize(&mut self) {
        self.0.borrow_mut().sort();
        self.0.borrow_mut().dedup();
    }

    fn clear(&mut self) {
        self.0.borrow_mut().clear();
    }

    fn len(&self) -> usize {
        self.0.borrow().len()
    }

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

    fn deep_clone(&self) -> StateSet<S> {
        let ids = self.0.borrow().iter().cloned().collect();
        StateSet(Rc::new(RefCell::new(ids)))
    }

    fn iter<F: FnMut(S)>(&self, mut f: F) {
        for &id in self.0.borrow().iter() {
            f(id);
        }
    }

    fn intersection(&self, other: &StateSet<S>, dest: &mut StateSet<S>) {
        dest.clear();
        if self.is_empty() || other.is_empty() {
            return;
        }

        let (seta, setb) = (self.0.borrow(), other.0.borrow());
        let (mut ita, mut itb) = (seta.iter().cloned(), setb.iter().cloned());
        let (mut a, mut b) = (ita.next().unwrap(), itb.next().unwrap());
        loop {
            if a == b {
                dest.add(a);
                a = match ita.next() {
                    None => break,
                    Some(a) => a,
                };
                b = match itb.next() {
                    None => break,
                    Some(b) => b,
                };
            } else if a < b {
                a = match ita.next() {
                    None => break,
                    Some(a) => a,
                };
            } else {
                b = match itb.next() {
                    None => break,
                    Some(b) => b,
                };
            }
        }
    }

    fn subtract(&self, other: &StateSet<S>, dest: &mut StateSet<S>) {
        dest.clear();
        if self.is_empty() || other.is_empty() {
            self.iter(|s| dest.add(s));
            return;
        }

        let (seta, setb) = (self.0.borrow(), other.0.borrow());
        let (mut ita, mut itb) = (seta.iter().cloned(), setb.iter().cloned());
        let (mut a, mut b) = (ita.next().unwrap(), itb.next().unwrap());
        loop {
            if a == b {
                a = match ita.next() {
                    None => break,
                    Some(a) => a,
                };
                b = match itb.next() {
                    None => { dest.add(a); break; }
                    Some(b) => b,
                };
            } else if a < b {
                dest.add(a);
                a = match ita.next() {
                    None => break,
                    Some(a) => a,
                };
            } else {
                b = match itb.next() {
                    None => { dest.add(a); break; }
                    Some(b) => b,
                };
            }
        }
        for a in ita {
            dest.add(a);
        }
    }
}
<|endoftext|>


<commit_before>extern crate polydraw;

use std::cmp::Ordering;
use std::i64;

use polydraw::geom::point::Point;
use polydraw::{Application, Renderer, Frame};
use polydraw::raster::{Scene, Rasterizer, EdgeType, Poly, create_default_vec};

#[derive(Debug, Clone, Copy)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, x1: i64, y1: i64, x2: i64, y2: i64) -> Self {
      Edge {
         edge_type: edge_type,
         p1: Point::new(x1, y1),
         p2: Point::new(x2, y2),
      }
   }

   #[inline]
   pub fn vert_top(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LVT, x1, y1, x2, y2)
   }

   #[inline]
   pub fn vert_bottom(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LVB, x1, y1, x2, y2)
   }

   #[inline]
   pub fn hori_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LHR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn hori_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LHL, x1, y1, x2, y2)
   }

   #[inline]
   pub fn top_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LTR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn top_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LTL, x1, y1, x2, y2)
   }

   #[inline]
   pub fn bottom_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LBR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn bottom_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LBL, x1, y1, x2, y2)
   }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct Section {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
   pub edge: usize,
   pub poly: usize,
}

struct ClipRenderer {
   rasterizer: Rasterizer,
   div_per_pixel: i64,

   edges: Vec<Edge>,
   polys: Vec<Poly>,

   sections: Vec<Section>,
   sections_end: usize,

   sections_min_y: Vec<i64>,
   sections_max_y: Vec<i64>,
   sections_order: Vec<usize>,
}

impl ClipRenderer {
   fn new() -> Self {
      let edges = vec![
         Edge::top_left(5, 1, 1, 6),       // 0
         Edge::top_right(1, 6, 8, 9),      // 1
         Edge::bottom_right(8, 9, 9, 6),   // 2
         Edge::bottom_left(9, 6, 5, 1),    // 3
         Edge::top_right(1, 1, 3, 8),      // 4
         Edge::bottom_right(3, 8, 10, 4),  // 5
         Edge::bottom_left(10, 4, 1, 1),   // 6
      ];

      let polys = vec![
         Poly::new(0, 4, 0),    // 0
         Poly::new(4, 7, 1),    // 1
      ];

      let sections = create_default_vec(65536);

      let sections_min_y = create_default_vec(65536);
      let sections_max_y = create_default_vec(65536);
      let sections_order = create_default_vec(65536);

      ClipRenderer {
         rasterizer: Rasterizer::new(),
         div_per_pixel: 1000,

         edges: edges,
         polys: polys,

         sections: sections,
         sections_end: 0,

         sections_min_y: sections_min_y,
         sections_max_y: sections_max_y,
         sections_order: sections_order,
      }
   }

   fn create_scene(&self) -> Scene {
      let points = vec![];

      let segments = vec![];

      let circles = vec![];

      let edges = vec![];

      let polys = vec![];

      let colors = vec![];

      Scene {
         points: points,
         segments: segments,
         circles: circles,
         edges: edges,
         polys: polys,
         colors: colors,
      }
   }

   fn eval_sections_min_max_y(&mut self) {
      for section_index in 0..self.sections_end {
         let ref section = self.sections[section_index];

         let mut min_y = i64::MAX;
         let mut max_y = i64::MIN;

         let (section_min_y, section_max_y) = if section.edge_type.reversed() {
            (section.p2.y, section.p1.y)
         } else {
            (section.p1.y, section.p2.y)
         };

         if section_min_y < min_y  {
            min_y = section_min_y;
         }

         if section_max_y > max_y {
            max_y = section_max_y;
         }

         self.sections_min_y[section_index] = min_y;
         self.sections_max_y[section_index] = max_y;
         self.sections_order[section_index] = section_index;
      }

      self.sort_sections_order();

      println!("MIN Y {:?}", &self.sections_min_y[..self.sections_end]);
      println!("MAX Y {:?}", &self.sections_max_y[..self.sections_end]);
      println!("ORDER {:?}", &self.sections_order[..self.sections_end]);

      self.iterate_sections();

      panic!("END");
   }

   fn sort_sections_order(&mut self) {
      let sections_order = &mut self.sections_order[..self.sections_end];
      let sections_min_y = &self.sections_min_y;
      let sections_max_y = &self.sections_max_y;

      sections_order.sort_by(|a, b| {
         match sections_min_y[*a].cmp(&sections_min_y[*b]) {
            Ordering::Less => Ordering::Less,
            Ordering::Greater => Ordering::Greater,
            Ordering::Equal => sections_max_y[*a].cmp(&sections_max_y[*b])
         }
      });
   }

   fn iterate_sections(&self) {
      let mut prev_y = i64::MIN;
      for order_index in 0..self.sections_end {
         let section_index = self.sections_order[order_index];
         let min_y = self.sections_min_y[section_index];

         println!("I MIN Y {:?} {:?}", section_index, min_y);

         if min_y != prev_y {
            println!("HOR {:?}", min_y);
            prev_y = min_y;
         }
      }
   }

   fn transfer_sections(&mut self) {
      self.sections_end = 0;

      for poly_index in 0..self.polys.len() {
         let ref poly = self.polys[poly_index];

         for edge_index in poly.start..poly.end {
            let ref edge = self.edges[edge_index];

            self.sections[self.sections_end] = Section {
               edge_type: edge.edge_type,
               p1: edge.p1,
               p2: edge.p2,
               edge: edge_index,
               poly: poly_index,
            };

            self.sections_end += 1;
         }
      }

      println!("SECTIONS {:?}", &self.sections[..self.sections_end]);
   }
}

impl Renderer for ClipRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      self.transfer_sections();

      self.eval_sections_min_max_y();

      let scene = self.create_scene();

      self.rasterizer.render(&scene, frame, self.div_per_pixel);
   }
}

fn main() {
   let mut renderer = ClipRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Clip")
      .run();
}
<commit_msg>Starting a clip sections algorithm<commit_after>extern crate polydraw;

use std::cmp::Ordering;
use std::i64;

use polydraw::geom::point::Point;
use polydraw::{Application, Renderer, Frame};
use polydraw::raster::{Scene, Rasterizer, EdgeType, Poly, create_default_vec};

#[derive(Debug, Clone, Copy)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, x1: i64, y1: i64, x2: i64, y2: i64) -> Self {
      Edge {
         edge_type: edge_type,
         p1: Point::new(x1, y1),
         p2: Point::new(x2, y2),
      }
   }

   #[inline]
   pub fn vert_top(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LVT, x1, y1, x2, y2)
   }

   #[inline]
   pub fn vert_bottom(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LVB, x1, y1, x2, y2)
   }

   #[inline]
   pub fn hori_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LHR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn hori_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LHL, x1, y1, x2, y2)
   }

   #[inline]
   pub fn top_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LTR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn top_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LTL, x1, y1, x2, y2)
   }

   #[inline]
   pub fn bottom_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LBR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn bottom_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LBL, x1, y1, x2, y2)
   }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct Section {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
   pub edge: usize,
   pub poly: usize,
}

struct ClipRenderer {
   rasterizer: Rasterizer,
   div_per_pixel: i64,

   edges: Vec<Edge>,
   polys: Vec<Poly>,

   sections: Vec<Section>,
   sections_end: usize,

   sections_min_y: Vec<i64>,
   sections_max_y: Vec<i64>,
   sections_order: Vec<usize>,

   active: Vec<Section>,
   active_end: usize,
}

impl ClipRenderer {
   fn new() -> Self {
      let edges = vec![
         Edge::top_left(5, 1, 1, 6),       // 0
         Edge::top_right(1, 6, 8, 9),      // 1
         Edge::bottom_right(8, 9, 9, 6),   // 2
         Edge::bottom_left(9, 6, 5, 1),    // 3
         Edge::top_right(1, 1, 3, 8),      // 4
         Edge::bottom_right(3, 8, 10, 4),  // 5
         Edge::bottom_left(10, 4, 1, 1),   // 6
      ];

      let polys = vec![
         Poly::new(0, 4, 0),    // 0
         Poly::new(4, 7, 1),    // 1
      ];

      let sections = create_default_vec(65536);

      let sections_min_y = create_default_vec(65536);
      let sections_max_y = create_default_vec(65536);
      let sections_order = create_default_vec(65536);

      let active = create_default_vec(65536);

      ClipRenderer {
         rasterizer: Rasterizer::new(),
         div_per_pixel: 1000,

         edges: edges,
         polys: polys,

         sections: sections,
         sections_end: 0,

         sections_min_y: sections_min_y,
         sections_max_y: sections_max_y,
         sections_order: sections_order,

         active: active,
         active_end: 0,
      }
   }

   fn create_scene(&self) -> Scene {
      let points = vec![];

      let segments = vec![];

      let circles = vec![];

      let edges = vec![];

      let polys = vec![];

      let colors = vec![];

      Scene {
         points: points,
         segments: segments,
         circles: circles,
         edges: edges,
         polys: polys,
         colors: colors,
      }
   }

   fn eval_sections_min_max_y(&mut self) {
      for section_index in 0..self.sections_end {
         let ref section = self.sections[section_index];

         let mut min_y = i64::MAX;
         let mut max_y = i64::MIN;

         let (section_min_y, section_max_y) = if section.edge_type.reversed() {
            (section.p2.y, section.p1.y)
         } else {
            (section.p1.y, section.p2.y)
         };

         if section_min_y < min_y  {
            min_y = section_min_y;
         }

         if section_max_y > max_y {
            max_y = section_max_y;
         }

         self.sections_min_y[section_index] = min_y;
         self.sections_max_y[section_index] = max_y;
         self.sections_order[section_index] = section_index;
      }

      self.sort_sections_order();

      println!("MIN Y {:?}", &self.sections_min_y[..self.sections_end]);
      println!("MAX Y {:?}", &self.sections_max_y[..self.sections_end]);
      println!("ORDER {:?}", &self.sections_order[..self.sections_end]);

      self.iterate_sections();

      panic!("END");
   }

   fn sort_sections_order(&mut self) {
      let sections_order = &mut self.sections_order[..self.sections_end];
      let sections_min_y = &self.sections_min_y;
      let sections_max_y = &self.sections_max_y;

      sections_order.sort_by(|a, b| {
         match sections_min_y[*a].cmp(&sections_min_y[*b]) {
            Ordering::Less => Ordering::Less,
            Ordering::Greater => Ordering::Greater,
            Ordering::Equal => sections_max_y[*a].cmp(&sections_max_y[*b])
         }
      });
   }

   fn iterate_sections(&self) {
      let mut prev_y = i64::MIN;
      for order_index in 0..self.sections_end {
         let section_index = self.sections_order[order_index];
         let min_y = self.sections_min_y[section_index];

         println!("I MIN Y {:?} {:?}", section_index, min_y);

         if min_y != prev_y {
            println!("HOR {:?}", min_y);
            prev_y = min_y;
         }
      }
   }

   fn transfer_sections(&mut self) {
      self.sections_end = 0;

      for poly_index in 0..self.polys.len() {
         let ref poly = self.polys[poly_index];

         for edge_index in poly.start..poly.end {
            let ref edge = self.edges[edge_index];

            self.sections[self.sections_end] = Section {
               edge_type: edge.edge_type,
               p1: edge.p1,
               p2: edge.p2,
               edge: edge_index,
               poly: poly_index,
            };

            self.sections_end += 1;
         }
      }

      println!("SECTIONS {:?}", &self.sections[..self.sections_end]);
   }

   fn clip_sections(&mut self) {

   }
}

impl Renderer for ClipRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      self.transfer_sections();

      self.eval_sections_min_max_y();

      let scene = self.create_scene();

      self.rasterizer.render(&scene, frame, self.div_per_pixel);
   }
}

fn main() {
   let mut renderer = ClipRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Clip")
      .run();
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate sdl2_ttf;

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

use sdl2::*;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Rect;
use sdl2::render::TextureQuery;
use sdl2::pixels::Color;

static SCREEN_WIDTH : u32 = 800;
static SCREEN_HEIGHT : u32 = 600;

// handle the annoying Rect i32
macro_rules! rect(
    ($x:expr, $y:expr, $w:expr, $h:expr) => (
        Rect::new_unwrap($x as i32, $y as i32, $w as u32, $h as u32)
    )
);

// Scale fonts to a reasonable size when they're too big (though they might look less smooth)
fn get_centered_rect(rect_width: u32, rect_height: u32, cons_width: u32, cons_height: u32) -> Rect {
    let wr = rect_width as f32 / cons_width as f32;
    let hr = rect_height as f32 / cons_height as f32;

    let (w, h) = if wr > 1f32 || hr > 1f32 {
        if wr > hr {
            println!("Scaling down! The text will look worse!");
            let h = (rect_height as f32 / wr) as i32;
            (cons_width as i32, h)
        } else {
            println!("Scaling down! The text will look worse!");
            let w = (rect_width as f32 / hr) as i32;
            (w, cons_height as i32)
        }
    } else {
        (rect_width as i32, rect_height as i32)
    };

    let cx = (SCREEN_WIDTH as i32 - w) / 2;
    let cy = (SCREEN_HEIGHT as i32 - h) / 2;
    rect!(cx, cy, w, h)
}

fn run(filename: &Path) {
    let sdl_context = sdl2::init().unwrap();
    let video_subsys = sdl_context.video().unwrap();
    let ttf_context = sdl2_ttf::init();

    let window = video_subsys.window("SDL2_TTF Example", SCREEN_WIDTH, SCREEN_HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    // Load a font
    let font = sdl2_ttf::Font::from_file(filename, 128).unwrap();

    // render a surface, and convert it to a texture bound to the renderer
    let surface = font.render("Hello Rust!",
        sdl2_ttf::blended(Color::RGBA(255, 0, 0, 255))).unwrap();
    let mut texture = renderer.create_texture_from_surface(&surface).unwrap();

    renderer.set_draw_color(Color::RGBA(195, 217, 255, 255));
    renderer.clear();

    let TextureQuery { width, height, .. } = texture.query();

    // If the example text is too big for the screen, downscale it (and center irregardless)
    let padding = 64;
    let target = get_centered_rect(width, height, SCREEN_WIDTH - padding, SCREEN_HEIGHT - padding);

    renderer.copy(&mut texture, None, Some(target));
    renderer.present();

    'mainloop: loop {
        for event in sdl_context.event_pump().unwrap().poll_iter() {
            match event {
                Event::Quit{..} => break 'mainloop,
                Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'mainloop,
                _ => {}
            }
        }
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();

    println!("linked sdl2_ttf: {}", sdl2_ttf::get_linked_version());

    if args.len() < 2 {
        println!("Usage: ./demo font.[ttf|ttc|fon]")
    } else {
        let path: &Path = Path::new(&args[1]);
        run(path);
    }
}
<commit_msg>demo: fix compile warnings<commit_after>extern crate sdl2;
extern crate sdl2_ttf;

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

use sdl2::*;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Rect;
use sdl2::render::TextureQuery;
use sdl2::pixels::Color;

static SCREEN_WIDTH : u32 = 800;
static SCREEN_HEIGHT : u32 = 600;

// handle the annoying Rect i32
macro_rules! rect(
    ($x:expr, $y:expr, $w:expr, $h:expr) => (
        Rect::new_unwrap($x as i32, $y as i32, $w as u32, $h as u32)
    )
);

// Scale fonts to a reasonable size when they're too big (though they might look less smooth)
fn get_centered_rect(rect_width: u32, rect_height: u32, cons_width: u32, cons_height: u32) -> Rect {
    let wr = rect_width as f32 / cons_width as f32;
    let hr = rect_height as f32 / cons_height as f32;

    let (w, h) = if wr > 1f32 || hr > 1f32 {
        if wr > hr {
            println!("Scaling down! The text will look worse!");
            let h = (rect_height as f32 / wr) as i32;
            (cons_width as i32, h)
        } else {
            println!("Scaling down! The text will look worse!");
            let w = (rect_width as f32 / hr) as i32;
            (w, cons_height as i32)
        }
    } else {
        (rect_width as i32, rect_height as i32)
    };

    let cx = (SCREEN_WIDTH as i32 - w) / 2;
    let cy = (SCREEN_HEIGHT as i32 - h) / 2;
    rect!(cx, cy, w, h)
}

fn run(filename: &Path) {
    let sdl_context = sdl2::init().unwrap();
    let video_subsys = sdl_context.video().unwrap();
    let _ttf_context = sdl2_ttf::init();

    let window = video_subsys.window("SDL2_TTF Example", SCREEN_WIDTH, SCREEN_HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    // Load a font
    let font = sdl2_ttf::Font::from_file(filename, 128).unwrap();

    // render a surface, and convert it to a texture bound to the renderer
    let surface = font.render("Hello Rust!",
        sdl2_ttf::blended(Color::RGBA(255, 0, 0, 255))).unwrap();
    let mut texture = renderer.create_texture_from_surface(&surface).unwrap();

    renderer.set_draw_color(Color::RGBA(195, 217, 255, 255));
    renderer.clear();

    let TextureQuery { width, height, .. } = texture.query();

    // If the example text is too big for the screen, downscale it (and center irregardless)
    let padding = 64;
    let target = get_centered_rect(width, height, SCREEN_WIDTH - padding, SCREEN_HEIGHT - padding);

    renderer.copy(&mut texture, None, Some(target));
    renderer.present();

    'mainloop: loop {
        for event in sdl_context.event_pump().unwrap().poll_iter() {
            match event {
                Event::Quit{..} => break 'mainloop,
                Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'mainloop,
                _ => {}
            }
        }
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();

    println!("linked sdl2_ttf: {}", sdl2_ttf::get_linked_version());

    if args.len() < 2 {
        println!("Usage: ./demo font.[ttf|ttc|fon]")
    } else {
        let path: &Path = Path::new(&args[1]);
        run(path);
    }
}
<|endoftext|>


<commit_before>use super::{ExpressionError, Expression, ElementType};
use std::ops::{Add, Sub, Mul, Div};
use std::num::{Zero, One};
use asexp::Sexp;

pub trait NumType: ElementType + Zero + One + Add<Output=Self> +
Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> {}

impl ElementType for f32 {}
impl NumType for f32 {}
impl ElementType for f64 {}
impl NumType for f64 {}

/// An expression evaluates to a numeric value of type `NumType`.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum NumExpr<T: NumType> {
    /// A constant value.
    Const(T),

    /// References a variable by position
    Var(usize),

    Add(Box<NumExpr<T>>, Box<NumExpr<T>>),
    Sub(Box<NumExpr<T>>, Box<NumExpr<T>>),
    Mul(Box<NumExpr<T>>, Box<NumExpr<T>>),
    Div(Box<NumExpr<T>>, Box<NumExpr<T>>),

    /// Safe division with x/0 = 0.0
    Divz(Box<NumExpr<T>>, Box<NumExpr<T>>),

    /// Reciprocal (1 / x).
    Recip(Box<NumExpr<T>>),

    /// Reciprocal using safe division
    Recipz(Box<NumExpr<T>>),
}

impl<T: NumType> Expression for NumExpr<T> {
    type Element = T;

    fn evaluate(&self, variables: &[NumExpr<T>]) -> Result<Self::Element, ExpressionError> {
        Ok(match self {
            &NumExpr::Var(n) => {
                let no_vars: &[NumExpr<T>] = &[];
                try!(try!(variables.get(n).ok_or(ExpressionError::InvalidVariable))
                         .evaluate(no_vars))
            }
            &NumExpr::Const(val) => val,
            &NumExpr::Add(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) + try!(e2.evaluate(variables))
            }
            &NumExpr::Sub(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) - try!(e2.evaluate(variables))
            }
            &NumExpr::Mul(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) * try!(e2.evaluate(variables))
            }
            &NumExpr::Div(ref e1, ref e2) => {
                let a = try!(e1.evaluate(variables));
                let div = try!(e2.evaluate(variables));
                if div == T::zero() {
                    return Err(ExpressionError::DivByZero);
                }
                a / div
            }
            &NumExpr::Divz(ref e1, ref e2) => {
                let a = try!(e1.evaluate(variables));
                let div = try!(e2.evaluate(variables));
                if div == T::zero() {
                    div
                } else {
                    a / div
                }
            }
            &NumExpr::Recip(ref e1) => {
                let div = try!(e1.evaluate(variables));
                if div == T::zero() {
                    return Err(ExpressionError::DivByZero);
                } else {
                    T::one() / div
                }
            }
            &NumExpr::Recipz(ref e1) => {
                let div = try!(e1.evaluate(variables));
                if div == T::zero() {
                    div
                } else {
                    T::one() / div
                }
            }
        })
    }
}

impl<'a, T: NumType + Into<Sexp>> Into<Sexp> for &'a NumExpr<T> {
    fn into(self) -> Sexp {
        match self {
            &NumExpr::Const(n) => n.into(),
            &NumExpr::Var(n) => Sexp::from(format!("${}", n)),
            &NumExpr::Add(ref a, ref b) => {
                Sexp::from(("+",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Sub(ref a, ref b) => {
                Sexp::from(("-",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Mul(ref a, ref b) => {
                Sexp::from(("*",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Div(ref a, ref b) => {
                Sexp::from(("/",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Divz(ref a, ref b) => {
                Sexp::from(("divz",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Recip(ref a) => Sexp::from(("recip", Into::<Sexp>::into(a.as_ref()))),
            &NumExpr::Recipz(ref a) => Sexp::from(("recipz", Into::<Sexp>::into(a.as_ref()))),
        }
    }
}

#[cfg(test)]
const NO_VARS: [NumExpr<f32>; 0] = [];

#[test]
fn test_expr_divz() {
    let expr = NumExpr::Divz(box NumExpr::Const(1.0), box NumExpr::Const(0.0));
    assert_eq!(Ok(0.0), expr.evaluate(&NO_VARS));
}

#[test]
fn test_expr_recipz() {
    let expr = NumExpr::Recipz(box NumExpr::Const(0.0));
    assert_eq!(Ok(0.0), expr.evaluate(&NO_VARS));

    let expr = NumExpr::Recipz(box NumExpr::Const(1.0));
    assert_eq!(Ok(1.0), expr.evaluate(&NO_VARS));

    let expr = NumExpr::Recipz(box NumExpr::Const(0.5));
    assert_eq!(Ok(2.0), expr.evaluate(&NO_VARS));
}

#[test]
fn test_expr() {
    let expr =
        NumExpr::Sub(box NumExpr::Const(0.0),
                     box NumExpr::Div(box NumExpr::Mul(box NumExpr::Add(box NumExpr::Const(1.0),
                                                                        box NumExpr::Var(0)),
                                                       box NumExpr::Var(1)),
                                      box NumExpr::Const(2.0)));

    fn fun(a: f32, b: f32) -> f32 {
        0.0 - ((1.0 + a) * b) / 2.0
    }

    fn check(expr: &NumExpr<f32>, a: f32, b: f32) {
        assert_eq!(Ok(fun(a, b)),
                   expr.evaluate(&[NumExpr::Const(a), NumExpr::Const(b)]))
    }

    check(&expr, 123.0, 4444.0);
    check(&expr, 0.0, -12.0);
}
<commit_msg>Add Default to trait NumType<commit_after>use super::{ExpressionError, Expression, ElementType};
use std::ops::{Add, Sub, Mul, Div};
use std::num::{Zero, One};
use asexp::Sexp;

pub trait NumType: ElementType + Default + Zero + One + Add<Output=Self> +
Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> {}

impl ElementType for f32 {}
impl NumType for f32 {}
impl ElementType for f64 {}
impl NumType for f64 {}

/// An expression evaluates to a numeric value of type `NumType`.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum NumExpr<T: NumType> {
    /// A constant value.
    Const(T),

    /// References a variable by position
    Var(usize),

    Add(Box<NumExpr<T>>, Box<NumExpr<T>>),
    Sub(Box<NumExpr<T>>, Box<NumExpr<T>>),
    Mul(Box<NumExpr<T>>, Box<NumExpr<T>>),
    Div(Box<NumExpr<T>>, Box<NumExpr<T>>),

    /// Safe division with x/0 = 0.0
    Divz(Box<NumExpr<T>>, Box<NumExpr<T>>),

    /// Reciprocal (1 / x).
    Recip(Box<NumExpr<T>>),

    /// Reciprocal using safe division
    Recipz(Box<NumExpr<T>>),
}

impl<T: NumType> Expression for NumExpr<T> {
    type Element = T;

    fn evaluate(&self, variables: &[NumExpr<T>]) -> Result<Self::Element, ExpressionError> {
        Ok(match self {
            &NumExpr::Var(n) => {
                let no_vars: &[NumExpr<T>] = &[];
                try!(try!(variables.get(n).ok_or(ExpressionError::InvalidVariable))
                         .evaluate(no_vars))
            }
            &NumExpr::Const(val) => val,
            &NumExpr::Add(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) + try!(e2.evaluate(variables))
            }
            &NumExpr::Sub(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) - try!(e2.evaluate(variables))
            }
            &NumExpr::Mul(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) * try!(e2.evaluate(variables))
            }
            &NumExpr::Div(ref e1, ref e2) => {
                let a = try!(e1.evaluate(variables));
                let div = try!(e2.evaluate(variables));
                if div == T::zero() {
                    return Err(ExpressionError::DivByZero);
                }
                a / div
            }
            &NumExpr::Divz(ref e1, ref e2) => {
                let a = try!(e1.evaluate(variables));
                let div = try!(e2.evaluate(variables));
                if div == T::zero() {
                    div
                } else {
                    a / div
                }
            }
            &NumExpr::Recip(ref e1) => {
                let div = try!(e1.evaluate(variables));
                if div == T::zero() {
                    return Err(ExpressionError::DivByZero);
                } else {
                    T::one() / div
                }
            }
            &NumExpr::Recipz(ref e1) => {
                let div = try!(e1.evaluate(variables));
                if div == T::zero() {
                    div
                } else {
                    T::one() / div
                }
            }
        })
    }
}

impl<'a, T: NumType + Into<Sexp>> Into<Sexp> for &'a NumExpr<T> {
    fn into(self) -> Sexp {
        match self {
            &NumExpr::Const(n) => n.into(),
            &NumExpr::Var(n) => Sexp::from(format!("${}", n)),
            &NumExpr::Add(ref a, ref b) => {
                Sexp::from(("+",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Sub(ref a, ref b) => {
                Sexp::from(("-",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Mul(ref a, ref b) => {
                Sexp::from(("*",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Div(ref a, ref b) => {
                Sexp::from(("/",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Divz(ref a, ref b) => {
                Sexp::from(("divz",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &NumExpr::Recip(ref a) => Sexp::from(("recip", Into::<Sexp>::into(a.as_ref()))),
            &NumExpr::Recipz(ref a) => Sexp::from(("recipz", Into::<Sexp>::into(a.as_ref()))),
        }
    }
}

#[cfg(test)]
const NO_VARS: [NumExpr<f32>; 0] = [];

#[test]
fn test_expr_divz() {
    let expr = NumExpr::Divz(box NumExpr::Const(1.0), box NumExpr::Const(0.0));
    assert_eq!(Ok(0.0), expr.evaluate(&NO_VARS));
}

#[test]
fn test_expr_recipz() {
    let expr = NumExpr::Recipz(box NumExpr::Const(0.0));
    assert_eq!(Ok(0.0), expr.evaluate(&NO_VARS));

    let expr = NumExpr::Recipz(box NumExpr::Const(1.0));
    assert_eq!(Ok(1.0), expr.evaluate(&NO_VARS));

    let expr = NumExpr::Recipz(box NumExpr::Const(0.5));
    assert_eq!(Ok(2.0), expr.evaluate(&NO_VARS));
}

#[test]
fn test_expr() {
    let expr =
        NumExpr::Sub(box NumExpr::Const(0.0),
                     box NumExpr::Div(box NumExpr::Mul(box NumExpr::Add(box NumExpr::Const(1.0),
                                                                        box NumExpr::Var(0)),
                                                       box NumExpr::Var(1)),
                                      box NumExpr::Const(2.0)));

    fn fun(a: f32, b: f32) -> f32 {
        0.0 - ((1.0 + a) * b) / 2.0
    }

    fn check(expr: &NumExpr<f32>, a: f32, b: f32) {
        assert_eq!(Ok(fun(a, b)),
                   expr.evaluate(&[NumExpr::Const(a), NumExpr::Const(b)]))
    }

    check(&expr, 123.0, 4444.0);
    check(&expr, 0.0, -12.0);
}
<|endoftext|>


<commit_before>use getopts;

pub fn run(args: Vec<String>) -> Result<String, String> {
    let options = getopts::Options::new();
    let matches = match options.parse(args.iter().skip(1)) {
        Ok(matches) => matches,
        Err(fail) => return Err(fail.to_err_msg())
    };
    let usage = Ok(options.usage("Usage: corectl COMMAND [OPTIONS]"));

    if matches.free.len() == 0 {
        return usage;
    }

    let command = matches.free[0].as_slice();

    match command {
        "help" => usage,
        unknown => { Err(format!("Unknown command: {}. Run `corectl help` for help.", unknown)) }
    }
}

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

    #[test]
    fn it_prints_help_with_no_args() {
        let output = run(vec!["corectl".to_string()]);

        assert!(output.unwrap().starts_with("Usage: corectl COMMAND [OPTIONS]\n\nOptions:"));
    }
}
<commit_msg>Improve help output, add version command, add stub deploy command.<commit_after>use getopts;

const USAGE: &'static str = "Usage: corectl [OPTIONS] COMMAND [COMMAND OPTIONS]

Commands:
    deploy      Deploy fleet units
    help        Output this help message
    version     Output corectl's version number";

pub fn run(args: Vec<String>) -> Result<String, String> {
    let mut options = getopts::Options::new();
    options.optflag("h", "help", "Output this help message");
    options.optflag("v", "version", "Output corectl's version number");
    let matches = match options.parse(args.iter().skip(1)) {
        Ok(matches) => matches,
        Err(fail) => return Err(fail.to_err_msg())
    };
    let usage = Ok(options.usage(USAGE));

    if matches.opt_present("v") {
        return version();
    } else if matches.opt_present("h") {
        return usage;
    }

    if matches.free.len() == 0 {
        return usage;
    }

    let command = matches.free[0].as_slice();

    match command {
        "version" => version(),
        "deploy" => deploy(matches.free.clone()),
        "help" => usage,
        unknown => { Err(format!("Unknown command: {}. Run `corectl` for help.", unknown)) }
    }
}

fn deploy(args: Vec<String>) -> Result<String, String> {
    Ok("Deployed stuff.".to_string())
}

fn version() -> Result<String, String> {
    Ok(env!("CARGO_PKG_VERSION").to_string())
}

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

    #[test]
    fn it_prints_help_with_no_args() {
        let output = run(vec!["corectl".to_string()]);

        assert!(output.unwrap().starts_with("Usage: corectl [OPTIONS] COMMAND [COMMAND OPTIONS]\n\nOptions:"));
    }
}
<|endoftext|>


<commit_before>use std::ptr;

use env::NapiEnv;
use result::NapiResult;
use sys;

use super::NapiValue;

#[derive(Clone, Copy, Debug)]
pub struct NapiString<'a> {
    value: sys::napi_value,
    env: &'a NapiEnv,
}

impl<'a> NapiString<'a> {
    pub fn from_str(env: &'a NapiEnv, value: &str) -> NapiResult<Self> {
        let mut sys_value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_string_utf8(
                env.as_sys_env(),
                value.as_ptr() as *const i8,
                value.as_bytes().len(),
                &mut sys_value,
            )
        })?;

        Ok(Self {
            value: sys_value,
            env,
        })
    }

    pub fn from_latin1(env: &'a NapiEnv, value: &[u8]) -> NapiResult<Self> {
        let mut sys_value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_string_latin1(
                env.as_sys_env(),
                value.as_ptr() as *const i8,
                value.len(),
                &mut sys_value,
            )
        })?;

        Ok(Self {
            value: sys_value,
            env,
        })
    }

    pub fn from_utf16(env: &'a NapiEnv, value: &[u16]) -> NapiResult<Self> {
        let mut sys_value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_string_utf16(
                env.as_sys_env(),
                value.as_ptr(),
                value.len(),
                &mut sys_value,
            )
        })?;

        Ok(Self {
            value: sys_value,
            env,
        })
    }
}

impl<'a> NapiValue for NapiString<'a> {
    fn as_sys_value(&self) -> sys::napi_value {
        self.value
    }

    fn env(&self) -> &NapiEnv {
        self.env
    }
}

pub fn construct<'a>(
    value: sys::napi_value,
    env: &'a NapiEnv,
) -> NapiString<'a> {
    NapiString { value, env }
}
<commit_msg>feat(napi): implement NapiString::{to_*}<commit_after>use std::ptr;

use env::NapiEnv;
use result::NapiResult;
use sys;

use super::NapiValue;

#[derive(Clone, Copy, Debug)]
pub struct NapiString<'a> {
    value: sys::napi_value,
    env: &'a NapiEnv,
}

impl<'a> NapiString<'a> {
    pub fn from_str(env: &'a NapiEnv, value: &str) -> NapiResult<Self> {
        let mut sys_value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_string_utf8(
                env.as_sys_env(),
                value.as_ptr() as *const i8,
                value.as_bytes().len(),
                &mut sys_value,
            )
        })?;

        Ok(Self {
            value: sys_value,
            env,
        })
    }

    pub fn from_latin1(env: &'a NapiEnv, value: &[u8]) -> NapiResult<Self> {
        let mut sys_value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_string_latin1(
                env.as_sys_env(),
                value.as_ptr() as *const i8,
                value.len(),
                &mut sys_value,
            )
        })?;

        Ok(Self {
            value: sys_value,
            env,
        })
    }

    pub fn from_utf16(env: &'a NapiEnv, value: &[u16]) -> NapiResult<Self> {
        let mut sys_value = ptr::null_mut();
        env.handle_status(unsafe {
            sys::napi_create_string_utf16(
                env.as_sys_env(),
                value.as_ptr(),
                value.len(),
                &mut sys_value,
            )
        })?;

        Ok(Self {
            value: sys_value,
            env,
        })
    }

    fn to_vec<T, U>(
        &self,
        get_value: unsafe extern "C" fn(
            sys::napi_env,
            sys::napi_value,
            *mut U,
            usize,
            *mut usize,
        ) -> sys::napi_status,
    ) -> NapiResult<Vec<T>>
    where
        T: Default + Copy,
        U: Copy,
    {
        let mut bufsize = 0;

        self.env.handle_status(unsafe {
            get_value(
                self.env.as_sys_env(),
                self.value,
                ptr::null_mut(),
                0,
                &mut bufsize,
            )
        })?;

        let mut buffer = vec![T::default(); bufsize + 1];

        self.env.handle_status(unsafe {
            get_value(
                self.env.as_sys_env(),
                self.value,
                buffer.as_mut_ptr() as *mut U,
                bufsize + 1,
                ptr::null_mut(),
            )
        })?;

        buffer.pop();

        Ok(buffer)
    }

    pub fn to_bytes(&self) -> NapiResult<Vec<u8>> {
        self.to_vec::<_, i8>(sys::napi_get_value_string_utf8)
    }

    pub fn to_latin1(&self) -> NapiResult<Vec<u8>> {
        self.to_vec::<_, i8>(sys::napi_get_value_string_latin1)
    }

    pub fn to_utf16(&self) -> NapiResult<Vec<u16>> {
        self.to_vec::<_, u16>(sys::napi_get_value_string_utf16)
    }

    pub fn to_string(&self) -> NapiResult<String> {
        let bytes = self.to_bytes()?;
        Ok(unsafe { String::from_utf8_unchecked(bytes) })
    }
}

impl<'a> NapiValue for NapiString<'a> {
    fn as_sys_value(&self) -> sys::napi_value {
        self.value
    }

    fn env(&self) -> &NapiEnv {
        self.env
    }
}

pub fn construct<'a>(
    value: sys::napi_value,
    env: &'a NapiEnv,
) -> NapiString<'a> {
    NapiString { value, env }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate model;
#[macro_use]
extern crate proptest;
extern crate crossbeam_epoch as epoch;
extern crate pagetable;

use std::collections::HashMap;

use epoch::{pin, Owned, Shared as EpochShared};
use model::Shared;
use pagetable::PageTable;

#[test]
fn test_model() {
    model! {
        Model => let mut m = HashMap::new(),
        Implementation => let i = PageTable::default(),
        Insert((usize, usize))((k, new) in (0usize..4, 0usize..4)) => {
            if !m.contains_key(&k) {
                m.insert(k, new);

                let guard = pin();
                let v = Owned::new(new).into_shared(&guard);
                i.cas(k, EpochShared::null(), v, &guard ).expect("should be able to insert a value");
            }
        },
        Get(usize)(k in 0usize..4) => {
            let guard = pin();
            let expected = m.get(&k);
            let actual = i.get(k, &guard).map(|s| unsafe { s.deref() });
            assert_eq!(expected, actual);
        },
        Cas((usize, usize, usize))((k, old, new) in (0usize..4, 0usize..4, 0usize..4)) => {
            let guard = pin();
            let expected_current = m.get(&k).cloned();
            let actual_current = i.get(k, &guard);
            assert_eq!(expected_current, actual_current.map(|s| unsafe { *s.deref() }));
            if expected_current.is_none() {
                continue;
            }

            let new_v = epoch::Owned::new(new).into_shared(&guard);

            if expected_current == Some(old) {
                m.insert(k, new);
                let cas_res = i.cas(k, actual_current.unwrap(), new_v, &guard);
                assert!(cas_res.is_ok());
            };
        }
    }
}

#[test]
#[ignore]
fn test_linearizability() {
    linearizable! {
        Implementation => let i = Shared::new(PageTable::default()),
        Get(usize)(k in any::<usize>()) -> Option<usize> {
            let guard = pin();
            unsafe {
                i.get(k, &guard).map(|s| *s.deref())
            }
        },
        Insert((usize, usize))((k, new) in (0usize..4, 0usize..4)) -> bool {
            let guard = pin();
            let v = Owned::new(new).into_shared(&guard);
            i.cas(k, EpochShared::null(), v, &guard).is_err()
        },
        Cas((usize, usize, usize))((k, old, new)
            in (0usize..4, 0usize..4, 0usize..4))
            -> Result<(), usize> {
            let guard = pin();
            i.cas(k, epoch::Owned::new(old).into_shared(&guard), epoch::Owned::new(new).into_shared(&guard), &guard)
                .map(|_| ())
                .map_err(|s| unsafe { *s.deref() })
        }
    }
}
<commit_msg>Remove proptest dep<commit_after>#[macro_use]
extern crate model;
extern crate crossbeam_epoch as epoch;
extern crate pagetable;

use std::collections::HashMap;

use epoch::{pin, Owned, Shared as EpochShared};
use model::Shared;
use pagetable::PageTable;

#[test]
fn test_model() {
    model! {
        Model => let mut m = HashMap::new(),
        Implementation => let i = PageTable::default(),
        Insert((usize, usize))((k, new) in (0usize..4, 0usize..4)) => {
            if !m.contains_key(&k) {
                m.insert(k, new);

                let guard = pin();
                let v = Owned::new(new).into_shared(&guard);
                i.cas(k, EpochShared::null(), v, &guard ).expect("should be able to insert a value");
            }
        },
        Get(usize)(k in 0usize..4) => {
            let guard = pin();
            let expected = m.get(&k);
            let actual = i.get(k, &guard).map(|s| unsafe { s.deref() });
            assert_eq!(expected, actual);
        },
        Cas((usize, usize, usize))((k, old, new) in (0usize..4, 0usize..4, 0usize..4)) => {
            let guard = pin();
            let expected_current = m.get(&k).cloned();
            let actual_current = i.get(k, &guard);
            assert_eq!(expected_current, actual_current.map(|s| unsafe { *s.deref() }));
            if expected_current.is_none() {
                continue;
            }

            let new_v = epoch::Owned::new(new).into_shared(&guard);

            if expected_current == Some(old) {
                m.insert(k, new);
                let cas_res = i.cas(k, actual_current.unwrap(), new_v, &guard);
                assert!(cas_res.is_ok());
            };
        }
    }
}

#[test]
#[ignore]
fn test_linearizability() {
    linearizable! {
        Implementation => let i = Shared::new(PageTable::default()),
        Get(usize)(k in any::<usize>()) -> Option<usize> {
            let guard = pin();
            unsafe {
                i.get(k, &guard).map(|s| *s.deref())
            }
        },
        Insert((usize, usize))((k, new) in (0usize..4, 0usize..4)) -> bool {
            let guard = pin();
            let v = Owned::new(new).into_shared(&guard);
            i.cas(k, EpochShared::null(), v, &guard).is_err()
        },
        Cas((usize, usize, usize))((k, old, new)
            in (0usize..4, 0usize..4, 0usize..4))
            -> Result<(), usize> {
            let guard = pin();
            i.cas(k, epoch::Owned::new(old).into_shared(&guard), epoch::Owned::new(new).into_shared(&guard), &guard)
                .map(|_| ())
                .map_err(|s| unsafe { *s.deref() })
        }
    }
}
<|endoftext|>


<commit_before>use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_events_macros::event_enum;
use ruma_identifiers::{EventId, RoomId, RoomVersionId, UserId};
use serde::{de, Serialize};
use serde_json::value::RawValue as RawJsonValue;

use crate::{from_raw_json_value, room::redaction::SyncRedactionEvent, EventDeHelper, Redact};

event_enum! {
    /// Any global account data event.
    enum GlobalAccountData {
        "m.direct",
        "m.ignored_user_list",
        "m.push_rules",
    }

    /// Any room account data event.
    enum RoomAccountData {
        "m.fully_read",
        "m.tag",
    }

    /// Any ephemeral room event.
    enum EphemeralRoom {
        "m.receipt",
        "m.typing",
    }

    /// Any message event.
    enum Message {
        "m.call.answer",
        "m.call.invite",
        "m.call.hangup",
        "m.call.candidates",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.ready",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.start",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.cancel",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.accept",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.key",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.mac",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.done",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.reaction",
        "m.room.encrypted",
        "m.room.message",
        "m.room.message.feedback",
        "m.room.redaction",
        "m.sticker",
    }

    /// Any state event.
    enum State {
        "m.policy.rule.room",
        "m.policy.rule.server",
        "m.policy.rule.user",
        "m.room.aliases",
        "m.room.avatar",
        "m.room.canonical_alias",
        "m.room.create",
        "m.room.encryption",
        "m.room.guest_access",
        "m.room.history_visibility",
        "m.room.join_rules",
        "m.room.member",
        "m.room.name",
        "m.room.pinned_events",
        "m.room.power_levels",
        "m.room.server_acl",
        "m.room.third_party_invite",
        "m.room.tombstone",
        "m.room.topic",
    }

    /// Any to-device event.
    enum ToDevice {
        "m.dummy",
        "m.room_key",
        "m.room_key_request",
        "m.forwarded_room_key",
        "m.key.verification.request",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.ready",
        "m.key.verification.start",
        "m.key.verification.cancel",
        "m.key.verification.accept",
        "m.key.verification.key",
        "m.key.verification.mac",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.done",
        "m.room.encrypted",
    }
}

/// Declares an item with a doc attribute computed by some macro expression.
/// This allows documentation to be dynamically generated based on input.
/// Necessary to work around <https://github.com/rust-lang/rust/issues/52607>.
macro_rules! doc_concat {
    ( $( #[doc = $doc:expr] $( $thing:tt )* )* ) => ( $( #[doc = $doc] $( $thing )* )* );
}

macro_rules! room_ev_accessor {
    ($field:ident: $ty:ty) => {
        doc_concat! {
            #[doc = concat!("Returns this event's `", stringify!($field), "` field.")]
            pub fn $field(&self) -> $ty {
                match self {
                    Self::Message(ev) => ev.$field(),
                    Self::State(ev) => ev.$field(),
                    Self::RedactedMessage(ev) => ev.$field(),
                    Self::RedactedState(ev) => ev.$field(),
                }
            }
        }
    };
}

/// Any room event.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum AnyRoomEvent {
    /// Any message event.
    Message(AnyMessageEvent),

    /// Any state event.
    State(AnyStateEvent),

    /// Any message event that has been redacted.
    RedactedMessage(AnyRedactedMessageEvent),

    /// Any state event that has been redacted.
    RedactedState(AnyRedactedStateEvent),
}

impl AnyRoomEvent {
    room_ev_accessor!(origin_server_ts: &MilliSecondsSinceUnixEpoch);
    room_ev_accessor!(room_id: &RoomId);
    room_ev_accessor!(event_id: &EventId);
    room_ev_accessor!(sender: &UserId);

    /// Redacts `self`, referencing the given event in `unsigned.redacted_because`.
    ///
    /// Does nothing for events that are already redacted.
    pub fn redact(self, redaction: SyncRedactionEvent, version: &RoomVersionId) -> Self {
        match self {
            Self::Message(ev) => Self::RedactedMessage(ev.redact(redaction, version)),
            Self::State(ev) => Self::RedactedState(ev.redact(redaction, version)),
            Self::RedactedMessage(_) | Self::RedactedState(_) => self,
        }
    }
}

/// Any sync room event (room event without a `room_id`, as returned in `/sync` responses)
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum AnySyncRoomEvent {
    /// Any sync message event
    Message(AnySyncMessageEvent),

    /// Any sync state event
    State(AnySyncStateEvent),

    /// Any sync message event that has been redacted.
    RedactedMessage(AnyRedactedSyncMessageEvent),

    /// Any sync state event that has been redacted.
    RedactedState(AnyRedactedSyncStateEvent),
}

impl AnySyncRoomEvent {
    room_ev_accessor!(origin_server_ts: &MilliSecondsSinceUnixEpoch);
    room_ev_accessor!(event_id: &EventId);
    room_ev_accessor!(sender: &UserId);

    /// Converts `self` to an `AnyRoomEvent` by adding the given a room ID.
    pub fn into_full_event(self, room_id: RoomId) -> AnyRoomEvent {
        match self {
            Self::Message(ev) => AnyRoomEvent::Message(ev.into_full_event(room_id)),
            Self::State(ev) => AnyRoomEvent::State(ev.into_full_event(room_id)),
            Self::RedactedMessage(ev) => AnyRoomEvent::RedactedMessage(ev.into_full_event(room_id)),
            Self::RedactedState(ev) => AnyRoomEvent::RedactedState(ev.into_full_event(room_id)),
        }
    }

    /// Redacts `self`, referencing the given event in `unsigned.redacted_because`.
    ///
    /// Does nothing for events that are already redacted.
    pub fn redact(self, redaction: SyncRedactionEvent, version: &RoomVersionId) -> Self {
        match self {
            Self::Message(ev) => Self::RedactedMessage(ev.redact(redaction, version)),
            Self::State(ev) => Self::RedactedState(ev.redact(redaction, version)),
            Self::RedactedMessage(_) | Self::RedactedState(_) => self,
        }
    }
}

impl<'de> de::Deserialize<'de> for AnyRoomEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let EventDeHelper { state_key, unsigned, .. } = from_raw_json_value(&json)?;

        if state_key.is_some() {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    AnyRoomEvent::RedactedState(from_raw_json_value(&json)?)
                }
                _ => AnyRoomEvent::State(from_raw_json_value(&json)?),
            })
        } else {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    AnyRoomEvent::RedactedMessage(from_raw_json_value(&json)?)
                }
                _ => AnyRoomEvent::Message(from_raw_json_value(&json)?),
            })
        }
    }
}

impl<'de> de::Deserialize<'de> for AnySyncRoomEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let EventDeHelper { state_key, unsigned, .. } = from_raw_json_value(&json)?;

        if state_key.is_some() {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    AnySyncRoomEvent::RedactedState(from_raw_json_value(&json)?)
                }
                _ => AnySyncRoomEvent::State(from_raw_json_value(&json)?),
            })
        } else {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    AnySyncRoomEvent::RedactedMessage(from_raw_json_value(&json)?)
                }
                _ => AnySyncRoomEvent::Message(from_raw_json_value(&json)?),
            })
        }
    }
}
<commit_msg>events: Introduce AnyRedacted[Sync]RoomEvent<commit_after>use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_events_macros::event_enum;
use ruma_identifiers::{EventId, RoomId, RoomVersionId, UserId};
use serde::{de, Serialize};
use serde_json::value::RawValue as RawJsonValue;

use crate::{from_raw_json_value, room::redaction::SyncRedactionEvent, EventDeHelper, Redact};

event_enum! {
    /// Any global account data event.
    enum GlobalAccountData {
        "m.direct",
        "m.ignored_user_list",
        "m.push_rules",
    }

    /// Any room account data event.
    enum RoomAccountData {
        "m.fully_read",
        "m.tag",
    }

    /// Any ephemeral room event.
    enum EphemeralRoom {
        "m.receipt",
        "m.typing",
    }

    /// Any message event.
    enum Message {
        "m.call.answer",
        "m.call.invite",
        "m.call.hangup",
        "m.call.candidates",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.ready",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.start",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.cancel",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.accept",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.key",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.mac",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.done",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.reaction",
        "m.room.encrypted",
        "m.room.message",
        "m.room.message.feedback",
        "m.room.redaction",
        "m.sticker",
    }

    /// Any state event.
    enum State {
        "m.policy.rule.room",
        "m.policy.rule.server",
        "m.policy.rule.user",
        "m.room.aliases",
        "m.room.avatar",
        "m.room.canonical_alias",
        "m.room.create",
        "m.room.encryption",
        "m.room.guest_access",
        "m.room.history_visibility",
        "m.room.join_rules",
        "m.room.member",
        "m.room.name",
        "m.room.pinned_events",
        "m.room.power_levels",
        "m.room.server_acl",
        "m.room.third_party_invite",
        "m.room.tombstone",
        "m.room.topic",
    }

    /// Any to-device event.
    enum ToDevice {
        "m.dummy",
        "m.room_key",
        "m.room_key_request",
        "m.forwarded_room_key",
        "m.key.verification.request",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.ready",
        "m.key.verification.start",
        "m.key.verification.cancel",
        "m.key.verification.accept",
        "m.key.verification.key",
        "m.key.verification.mac",
        #[cfg(feature = "unstable-pre-spec")]
        #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
        "m.key.verification.done",
        "m.room.encrypted",
    }
}

/// Declares an item with a doc attribute computed by some macro expression.
/// This allows documentation to be dynamically generated based on input.
/// Necessary to work around <https://github.com/rust-lang/rust/issues/52607>.
macro_rules! doc_concat {
    ( $( #[doc = $doc:expr] $( $thing:tt )* )* ) => ( $( #[doc = $doc] $( $thing )* )* );
}

macro_rules! room_ev_accessor {
    ($field:ident: $ty:ty) => {
        doc_concat! {
            #[doc = concat!("Returns this event's `", stringify!($field), "` field.")]
            pub fn $field(&self) -> $ty {
                match self {
                    Self::Message(ev) => ev.$field(),
                    Self::State(ev) => ev.$field(),
                    Self::RedactedMessage(ev) => ev.$field(),
                    Self::RedactedState(ev) => ev.$field(),
                }
            }
        }
    };
}

/// Any room event.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum AnyRoomEvent {
    /// Any message event.
    Message(AnyMessageEvent),

    /// Any state event.
    State(AnyStateEvent),

    /// Any message event that has been redacted.
    RedactedMessage(AnyRedactedMessageEvent),

    /// Any state event that has been redacted.
    RedactedState(AnyRedactedStateEvent),
}

impl AnyRoomEvent {
    room_ev_accessor!(origin_server_ts: &MilliSecondsSinceUnixEpoch);
    room_ev_accessor!(room_id: &RoomId);
    room_ev_accessor!(event_id: &EventId);
    room_ev_accessor!(sender: &UserId);
}

/// Any sync room event (room event without a `room_id`, as returned in `/sync` responses)
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
pub enum AnySyncRoomEvent {
    /// Any sync message event
    Message(AnySyncMessageEvent),

    /// Any sync state event
    State(AnySyncStateEvent),

    /// Any sync message event that has been redacted.
    RedactedMessage(AnyRedactedSyncMessageEvent),

    /// Any sync state event that has been redacted.
    RedactedState(AnyRedactedSyncStateEvent),
}

impl AnySyncRoomEvent {
    room_ev_accessor!(origin_server_ts: &MilliSecondsSinceUnixEpoch);
    room_ev_accessor!(event_id: &EventId);
    room_ev_accessor!(sender: &UserId);

    /// Converts `self` to an `AnyRoomEvent` by adding the given a room ID.
    pub fn into_full_event(self, room_id: RoomId) -> AnyRoomEvent {
        match self {
            Self::Message(ev) => AnyRoomEvent::Message(ev.into_full_event(room_id)),
            Self::State(ev) => AnyRoomEvent::State(ev.into_full_event(room_id)),
            Self::RedactedMessage(ev) => AnyRoomEvent::RedactedMessage(ev.into_full_event(room_id)),
            Self::RedactedState(ev) => AnyRoomEvent::RedactedState(ev.into_full_event(room_id)),
        }
    }
}

impl<'de> de::Deserialize<'de> for AnyRoomEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let EventDeHelper { state_key, unsigned, .. } = from_raw_json_value(&json)?;

        if state_key.is_some() {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    AnyRoomEvent::RedactedState(from_raw_json_value(&json)?)
                }
                _ => AnyRoomEvent::State(from_raw_json_value(&json)?),
            })
        } else {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    AnyRoomEvent::RedactedMessage(from_raw_json_value(&json)?)
                }
                _ => AnyRoomEvent::Message(from_raw_json_value(&json)?),
            })
        }
    }
}

impl<'de> de::Deserialize<'de> for AnySyncRoomEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let EventDeHelper { state_key, unsigned, .. } = from_raw_json_value(&json)?;

        if state_key.is_some() {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    AnySyncRoomEvent::RedactedState(from_raw_json_value(&json)?)
                }
                _ => AnySyncRoomEvent::State(from_raw_json_value(&json)?),
            })
        } else {
            Ok(match unsigned {
                Some(unsigned) if unsigned.redacted_because.is_some() => {
                    AnySyncRoomEvent::RedactedMessage(from_raw_json_value(&json)?)
                }
                _ => AnySyncRoomEvent::Message(from_raw_json_value(&json)?),
            })
        }
    }
}

/// Any redacted room event.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug)]
pub enum AnyRedactedRoomEvent {
    /// Any message event that has been redacted.
    Message(AnyRedactedMessageEvent),

    /// Any state event that has been redacted.
    State(AnyRedactedStateEvent),
}

impl Redact for AnyRoomEvent {
    type Redacted = AnyRedactedRoomEvent;

    /// Redacts `self`, referencing the given event in `unsigned.redacted_because`.
    ///
    /// Does nothing for events that are already redacted.
    fn redact(self, redaction: SyncRedactionEvent, version: &RoomVersionId) -> Self::Redacted {
        match self {
            Self::Message(ev) => Self::Redacted::Message(ev.redact(redaction, version)),
            Self::State(ev) => Self::Redacted::State(ev.redact(redaction, version)),
            Self::RedactedMessage(ev) => Self::Redacted::Message(ev),
            Self::RedactedState(ev) => Self::Redacted::State(ev),
        }
    }
}

impl From<AnyRedactedRoomEvent> for AnyRoomEvent {
    fn from(ev: AnyRedactedRoomEvent) -> Self {
        match ev {
            AnyRedactedRoomEvent::Message(ev) => Self::RedactedMessage(ev),
            AnyRedactedRoomEvent::State(ev) => Self::RedactedState(ev),
        }
    }
}

/// Any redacted sync room event (room event without a `room_id`, as returned in `/sync` responses)
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug)]
pub enum AnyRedactedSyncRoomEvent {
    /// Any sync message event that has been redacted.
    Message(AnyRedactedSyncMessageEvent),

    /// Any sync state event that has been redacted.
    State(AnyRedactedSyncStateEvent),
}

impl Redact for AnySyncRoomEvent {
    type Redacted = AnyRedactedSyncRoomEvent;

    /// Redacts `self`, referencing the given event in `unsigned.redacted_because`.
    ///
    /// Does nothing for events that are already redacted.
    fn redact(self, redaction: SyncRedactionEvent, version: &RoomVersionId) -> Self::Redacted {
        match self {
            Self::Message(ev) => Self::Redacted::Message(ev.redact(redaction, version)),
            Self::State(ev) => Self::Redacted::State(ev.redact(redaction, version)),
            Self::RedactedMessage(ev) => Self::Redacted::Message(ev),
            Self::RedactedState(ev) => Self::Redacted::State(ev),
        }
    }
}

impl From<AnyRedactedSyncRoomEvent> for AnySyncRoomEvent {
    fn from(ev: AnyRedactedSyncRoomEvent) -> Self {
        match ev {
            AnyRedactedSyncRoomEvent::Message(ev) => Self::RedactedMessage(ev),
            AnyRedactedSyncRoomEvent::State(ev) => Self::RedactedState(ev),
        }
    }
}
<|endoftext|>