<commit_before>#[allow(unused_variables)]
extern crate fnv;
extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use std::collections::HashMap;
use std::io::{BufReader, BufRead};
use std::fs::File;

use timely::dataflow::*;
use timely::dataflow::scopes::Child;
use timely::dataflow::operators::*;
use timely::dataflow::operators::feedback::Handle;
use timely::progress::timestamp::RootTimestamp;

use differential_dataflow::Data;
use differential_dataflow::operators::*;
use differential_dataflow::collection::LeastUpperBound;
use differential_dataflow::operators::join::JoinBy;

/// A collection defined by multiple mutually recursive rules.
pub struct Variable<G: Scope, D: Default+Data>
where G::Timestamp: LeastUpperBound {
    feedback: Option<Handle<G::Timestamp, u64,(D, i32)>>,
    current:  Stream<Child<G, u64>, (D,i32)>,
}

impl<G: Scope, D: Default+Data> Variable<G, D> where G::Timestamp: LeastUpperBound {
    /// Creates a new `Variable` and a `Stream` representing its output, from a supplied `source` stream.
    pub fn from(source: &Stream<Child<G, u64>, (D,i32)>) -> (Variable<G, D>, Stream<Child<G,u64>, (D, i32)>) {
        let (feedback, cycle) = source.scope().loop_variable(u64::max_value(), 1);
        let mut result = Variable { feedback: Some(feedback), current: cycle.clone() };
        let stream = cycle.clone();
        result.add(source);
        (result, stream)
    }
    /// Adds a new source of data to the `Variable`.
    pub fn add(&mut self, source: &Stream<Child<G, u64>, (D,i32)>) {
        self.current = self.current.concat(source);
    }
}

impl<G: Scope, D: Default+Data> Drop for Variable<G, D> where G::Timestamp: LeastUpperBound {
    fn drop(&mut self) {
        if let Some(feedback) = self.feedback.take() {
            self.current.threshold(|x| x.hashed(), |_| HashMap::new(), |_, w| if w > 0 { 1 } else { 0 })
                        .connect_loop(feedback);
        }
    }
}

macro_rules! rule {
    ($name1: ident ($($var1:ident),*) := $name2: ident ($($var2:ident),*) $name3: ident ($($var3:ident),*) : ($($var4:ident),*) = ($($var5:ident),*)) => {{
        let result =
            $name2.0.join_by(
                &$name3.0,
                |($( $var2, )*)| (($( $var4, )*), ( $($var2, )*)),
                |($( $var3, )*)| (($( $var5, )*), ( $($var3, )*)),
                |x| x.hashed(),
                |_, &($( $var2, )*), &($( $var3, )*)| (($( $var2, )*), ($( $var3, )*)));
        $name1.1.add(&result.map(|((($( $var2, )*), ($( $var3, )*)), __w)| (($( $var1, )*), __w)));

        let temp = result.semijoin_by(
            &$name1.2,
            |(($( $var2, )*), ($( $var3, )*))| (($( $var1, )*), (($( $var2, )*), ($( $var3, )*))),
            |x| x.hashed(),
            |_, &(($( $var2, )*), ($( $var3, )*))| (($( $var2, )*), ($( $var3, )*)));
        $name2.3.add(&temp.map(|(( ($( $var2, )*) ,_),__w)| (($( $var2, )*),__w)));
        $name3.3.add(&temp.map(|(( _, ($( $var3, )*)),__w)| (($( $var3, )*),__w)));

        temp
    }};
}

macro_rules! rule_3 {
    ($name1: ident ($($var1:ident),*) := $name2: ident ($($var2:ident),*) $name3: ident ($($var3:ident),*) $name4: ident ($($var4:ident),*) : ($($key1:ident),*) = ($($key2:ident),*), ($($key3:ident),*) = ($($key4:ident),*)) => {{
        let result =
            $name2.0.join_by(
                &$name3.0,
                |($( $var2, )*)| (($( $key1, )*), ( $($var2, )*)),
                |($( $var3, )*)| (($( $key2, )*), ( $($var3, )*)),
                |x| x.hashed(),
                |_, &($( $var2, )*), &($( $var3, )*)| (($( $var2, )*), ($( $var3, )*)));

        let result = result.join_by(
                &$name4.0,
                |(($( $var2, )*), ($( $var3, )*))| (($( $key3, )*), (($( $var2, )*), ($( $var3, )*))),
                |($( $var4, )*)| (($( $key4, )*), ( $($var4, )*)),
                |x| x.hashed(),
                |_, &(($( $var2, )*), ($( $var3, )*)), &($( $var4, )*)| (($( $var2, )*), ($( $var3, )*), ($( $var4, )*))
            );

        $name1.1.add(&result.map(|((($( $var2, )*), ($( $var3, )*), ($( $var4, )*)), __w)| (($( $var1, )*), __w)));

        let temp = result.semijoin_by(
            &$name1.2,
            |(($( $var2, )*), ($( $var3, )*), ($( $var4, )*))| (($( $var1, )*), (($( $var2, )*), ($( $var3, )*), ($( $var4, )*))),
            |x| x.hashed(),
            |_, &(($( $var2, )*), ($( $var3, )*), ($( $var4, )*))| (($( $var2, )*), ($( $var3, )*), ($( $var4, )*)));
        $name2.3.add(&temp.map(|((($( $var2, )*),_,_),__w)| (($( $var2, )*),__w)));
        $name3.3.add(&temp.map(|((_,($( $var3, )*),_),__w)| (($( $var3, )*),__w)));
        $name4.3.add(&temp.map(|((_,_,($( $var4, )*)),__w)| (($( $var4, )*),__w)));

        temp
    }};
}

macro_rules! rule_u {
    ($name1: ident ($($var1:ident),*) := $name2: ident ($($var2:ident),*) $name3: ident ($($var3:ident),*) : $var4:ident = $var5:ident) => {{
        let result =
            $name2.0.join_by_u(
                &$name3.0,
                |($( $var2, )*)| ($var4, ( $($var2, )*)),
                |($( $var3, )*)| ($var5, ( $($var3, )*)),
                |_, &($( $var2, )*), &($( $var3, )*)| (($( $var2, )*), ($( $var3, )*)));
        $name1.1.add(&result.map(|((($( $var2, )*), ($( $var3, )*)), __w)| (($( $var1, )*), __w)));

        let temp = result.semijoin_by(
            &$name1.2,
            |(($( $var2, )*), ($( $var3, )*))| (($( $var1, )*), (($( $var2, )*), ($( $var3, )*))),
            |x| x.hashed(),
            |_, &(($( $var2, )*), ($( $var3, )*))| (($( $var2, )*), ($( $var3, )*)));
        $name2.3.add(&temp.map(|(( ($( $var2, )*) ,_),__w)| (($( $var2, )*),__w)));
        $name3.3.add(&temp.map(|(( _, ($( $var3, )*)),__w)| (($( $var3, )*),__w)));

        temp
    }};
}

macro_rules! variable {
    ($name0: ident : $name1: ident, $name2: ident) => {{
        let temp1 = Variable::from(&$name0.enter(&$name1));
        let temp2 = Variable::from(&$name0.enter(&$name2));
        (temp1.1, temp1.0, temp2.1, temp2.0)
    }}
}

fn for_each_line<F: FnMut(String)>(filename: &str, mut logic: F) {
    let file = BufReader::new(File::open(filename).unwrap());
    for readline in file.lines() {
        let line = readline.ok().expect("read error");
        logic(line);
    }
}

fn for_each_pair_in<F: FnMut((u32, u32))>(filename: &str, mut logic: F) {
    for_each_line(filename, |string| {
        let mut fields = string[..].split(",");
        let a: u32 = fields.next().unwrap().parse().ok().expect("parse error");
        let b: u32 = fields.next().unwrap().parse().ok().expect("parse error");
        logic((a, b))
    });
}

fn for_each_trip_in<F: FnMut((u32, u32, u32))>(filename: &str, mut logic: F) {
    for_each_line(filename, |string| {
        let mut fields = string[..].split(",");
        let a: u32 = fields.next().unwrap().parse().ok().expect("parse error");
        let b: u32 = fields.next().unwrap().parse().ok().expect("parse error");
        let c: u32 = fields.next().unwrap().parse().ok().expect("parse error");
        logic((a, b, c))
    });
}

fn main() {

    timely::execute_from_args(std::env::args(), |root| {

        let start = time::precise_time_s();
        let (mut c, mut p, mut q, mut r, mut s, mut u, mut p_query, mut q_query, probe) = root.scoped::<u64, _, _>(move |outer| {

            // inputs for p, q, and u base facts.
            let (c_input, c) = outer.new_input();
            let (p_input, p) = outer.new_input();
            let (q_input, q) = outer.new_input();
            let (r_input, r) = outer.new_input();
            let (s_input, s) = outer.new_input();
            let (u_input, u) = outer.new_input();

            // inputs through which to demand explanations.
            let (_c_query_input, c_query) = outer.new_input();
            let (p_query_input, p_query) = outer.new_input();
            let (q_query_input, q_query) = outer.new_input();
            let (_r_query_input, r_query) = outer.new_input();
            let (_s_query_input, s_query) = outer.new_input();
            let (_u_query_input, u_query) = outer.new_input();

            // VERY IMPORTANT to define these here, not in the inner scope. That currently causes
            // timely to get VERY CONFUSED about who is named what. A timely bug, for sure.
            let p_empty = p.filter(|_| false);
            let q_empty = q.filter(|_| false);

            // derive each of the firings of each of the rules, as well as tuples deleted from
            // both p and q to ensure the emptiness of
            let (p_del, q_del, ir1, ir2, ir3, ir4, ir5, ir6) = outer.scoped::<u64,_,_>(|middle| {

                // an evolving set of things we may want to remove from p_edb and q_edb.
                let mut p_del = Variable::from(&middle.enter(&p_empty));
                let mut q_del = Variable::from(&middle.enter(&q_empty));

                let c_query = middle.enter(&c_query);
                let p_query = middle.enter(&p_query);
                let q_query = middle.enter(&q_query);
                let r_query = middle.enter(&r_query);
                let s_query = middle.enter(&s_query);
                let u_query = middle.enter(&u_query);

                let p_edb = middle.enter(&p).concat(&p_del.1.map(|(x,w)| (x,-w))).consolidate();
                let q_edb = middle.enter(&q).concat(&q_del.1.map(|(x,w)| (x,-w))).consolidate();
                let c_edb = middle.enter(&c);
                let r_edb = middle.enter(&r);
                let s_edb = middle.enter(&s);
                let u_edb = middle.enter(&u);

                // determine derived p and q tuples, instances of p and q tuples which participate
                // in the derivation of query (secret) tuples, and also which rules fire with what
                // variable settings.
                let (p_der, q_der, p_bad, q_bad, ir1, ir2, ir3, ir4, ir5, ir6) = middle.scoped::<u64, _, _>(|inner| {

                    // track derived P and Q tuples, and any that need explanation.
                    let mut c = variable!(inner : c_edb, c_query);
                    let mut p = variable!(inner : p_edb, p_query);
                    let mut q = variable!(inner : q_edb, q_query);
                    let mut r = variable!(inner : r_edb, r_query);
                    let mut s = variable!(inner : s_edb, s_query);
                    let mut u = variable!(inner : u_edb, u_query);

                    // IR1: P(x,z) := P(x,y), P(y,z)
                    let ir1 = rule_u!(p(x,z)   := p(x,_y1) p(_y2,z)   : _y1 = _y2);

                    // IR2: Q(x,r,z) := P(x,y), Q(y,r,z)
                    let ir2 = rule_u!(q(x,r,z) := p(x,_y1) q(_y2,r,z) : _y1 = _y2);

                    // IR3: P(x,z) := P(y,w), Q(x,r,y), U(w,r,z)
                    let ir3 = rule_3!(p(x,z) := p(_y1,_w1) q(x,_r1,_y2) u(_w2,_r2,z) : (_y1) = (_y2), (_w1,_r1) = (_w2,_r2));

                    // IR4: P(x,z) :- P(x,y), P(x,w), C(y,w,z)
                    let ir4 = rule_3!(p(_x1,z) := p(_x1,_y1) p(_x2,_w1) c(_y2,_w2,z) : (_x1) = (_x2), (_y1,_w1) = (_y2,_w2));

                    // IR5: Q(x,q,z) := Q(x,r,z), R(r,q)
                    let ir5 = rule_u!(q(x,q,z) := q(x,_r1,z) s(_r2,q) : _r1 = _r2);

                    // IR6: Q(x,e,o) :- Q(x,y,z), Q(z,u,o), Chain(y,u,e)
                    let ir6 = rule_3!(q(x,e,o) := q(x,_y1,_z1) q(_z2,_u1,o) r(_y2,_u2,e) : (_z1) = (_z2), (_y1,_u1) = (_y2,_u2));

                    // extract the results and return
                    (p.0.leave(), q.0.leave(), p.2.leave(), q.2.leave(), ir1.leave(), ir2.leave(), ir3.leave(), ir4.leave(), ir5.leave(), ir6.leave())
                });

                // p_der.inspect(|x| println!("P{:?}", x));
                // q_der.inspect(|x| println!("Q{:?}", x));

                // p_bad and q_bad are p and q tuples involved in the derivation.
                // we should remove some of them from p, q by adding them to p_del, q_del.
                let p_bad = p_bad.map(|(x,w)| ((x,()),w)).join(&p_edb.map(|(x,w)| ((x,()),w))).map(|((x,(),()),w)| (((),x),w));
                let q_bad = q_bad.map(|(x,w)| ((x,()),w)) .join(&q_edb.map(|(x,w)| ((x,()),w))).map(|((x,(),()),w)| (((),x),w));

                // p_bad.inspect(|x| println!("PBAD{:?}", x));
                // q_bad.inspect(|x| println!("QBAD{:?}", x));

                let p_bad_new = p_bad.cogroup_by_inner(&q_bad, |k| k.hashed(), |_,&x| x,
                            |_| HashMap::new(), |_key, input1, _input2, output| {
                     output.push(input1.next().map(|(&x,w)|(x,w)).unwrap());
                });

                let q_bad_new = p_bad.cogroup_by_inner(&q_bad, |k| k.hashed(), |_,&x| x,
                            |_| HashMap::new(), |_key, input1, input2, output| {
                    if input1.next() == None { input2.next().map(|(&x,w)| output.push((x,w))); }
                });

                p_del.0.add(&p_bad_new);
                q_del.0.add(&q_bad_new);

                (p_del.1.leave(), q_del.1.leave(), ir1.leave(), ir2.leave(), ir3.leave(), ir4.leave(), ir5.leave(), ir6.leave())
            });

            let (probe, _) = p_del.consolidate().probe();

            p_del.consolidate().inspect(|&x| println!("Deleted P{:?}", x));
            q_del.consolidate().inspect(|&x| println!("Deleted Q{:?}", x));

            ir1.consolidate().inspect(|&x| println!("Required IR1 {:?}", x));
            ir2.consolidate().inspect(|&x| println!("Required IR2 {:?}", x));
            ir3.consolidate().inspect(|&x| println!("Required IR3 {:?}", x));
            ir4.consolidate().inspect(|&x| println!("Required IR4 {:?}", x));
            ir5.consolidate().inspect(|&x| println!("Required IR5 {:?}", x));
            ir6.consolidate().inspect(|&x| println!("Required IR6 {:?}", x));

            (c_input, p_input, q_input, r_input, s_input, u_input, p_query_input, q_query_input, probe)
        });

        // worker 0 loads the data
        if root.index() == 0 {
            for_each_trip_in("/Users/mcsherry/Desktop/galen/c.txt", |x| c.send((x,1)));
            for_each_pair_in("/Users/mcsherry/Desktop/galen/p.txt", |x| p.send((x,1)));
            for_each_trip_in("/Users/mcsherry/Desktop/galen/q.txt", |x| q.send((x,1)));
            for_each_trip_in("/Users/mcsherry/Desktop/galen/r.txt", |x| r.send((x,1)));
            for_each_pair_in("/Users/mcsherry/Desktop/galen/s.txt", |x| s.send((x,1)));
            for_each_trip_in("/Users/mcsherry/Desktop/galen/u.txt", |x| u.send((x,1)));
        }

        println!("loading:\t{}", time::precise_time_s() - start);

        // close all of the data inputs, for now.
        // could leave them open to see perf hit.
        c.close();
        p.close();
        q.close();
        r.close();
        s.close();
        u.close();

        p_query.advance_to(1);
        q_query.advance_to(1);

        // step until clear, then once more to garbage collect.
        while probe.lt(&RootTimestamp::new(1)) { root.step(); }
        root.step();

        println!("derivation:\t{}", time::precise_time_s() - start);
        let timer = time::precise_time_s();

        // p_query.send(((1u32,3u32), 1));
        q_query.send(((1u32,4u32,5u32), 1));
        p_query.advance_to(2);
        q_query.advance_to(2);

        while probe.lt(&RootTimestamp::new(2)) { root.step(); }

        println!("query:\t{}", time::precise_time_s() - timer);
    });
}
<commit_msg>yoink<commit_after><|endoftext|>


<commit_before>///! Generate a base bitmap for drawing an overland map with a paint program.

extern crate world;
extern crate image;

use image::Pixel;
use world::{Sector, Location};

const COLS: i16 = 10;
const ROWS: i16 = 10;

fn overland_locs() -> Vec<Location> {
    let mut ret = Vec::new();
    for y in 0..ROWS {
        for x in 0..COLS {
            let sec = Sector::new(x, y, 0);
            for loc in sec.iter() {
                ret.push(loc);
            }
        }
    }
    ret
}

fn main() {
    let locs = overland_locs();
    let (mut min_x, mut min_y) = locs.iter().fold(
        (0, 0),
        |(x, y), loc| (x.min(loc.x), y.min(loc.y)),
    );
    min_x -= 1;
    min_y -= 1;

    let (max_x, max_y) = locs.iter().fold(
        (0, 0),
        |(x, y), loc| (x.max(loc.x), y.max(loc.y)),
    );
    println!("{} {} - {} {}", min_x, min_y, max_x, max_y);

    let mut buf = image::ImageBuffer::new((max_x - min_x + 1) as u32, (max_y - min_y + 1) as u32);

    for (x, y, p) in buf.enumerate_pixels_mut() {
        let loc = Location::new(x as i16 + min_x, y as i16 + min_y, 0);
        let sec = loc.sector();
        if sec.x < 0 || sec.y < 0 || sec.x >= COLS || sec.y >= ROWS {
            *p = image::Rgb::from_channels(0x00, 0x00, 0x00, 0xff);
            continue;
        }
        if (sec.x + sec.y) % 2 == 0 {
            *p = image::Rgb::from_channels(0x00, 0xaa, 0xaa, 0xff);
        } else {
            *p = image::Rgb::from_channels(0x88, 0x88, 0x88, 0xff);
        }
    }

    image::save_buffer(
        "overland_base.png",
        &buf,
        buf.width(),
        buf.height(),
        image::ColorType::RGB(8),
    ).unwrap();
}
<commit_msg>Tweak overland dimensions<commit_after>///! Generate a base bitmap for drawing an overland map with a paint program.

extern crate world;
extern crate image;

use image::Pixel;
use world::{Sector, Location};

const COLS: i16 = 8;
const ROWS: i16 = 12;

fn overland_locs() -> Vec<Location> {
    let mut ret = Vec::new();
    for y in 0..ROWS {
        for x in 0..COLS {
            let sec = Sector::new(x, y, 0);
            for loc in sec.iter() {
                ret.push(loc);
            }
        }
    }
    ret
}

fn main() {
    let locs = overland_locs();
    let (mut min_x, mut min_y) = locs.iter().fold(
        (0, 0),
        |(x, y), loc| (x.min(loc.x), y.min(loc.y)),
    );
    min_x -= 1;
    min_y -= 1;

    let (max_x, max_y) = locs.iter().fold(
        (0, 0),
        |(x, y), loc| (x.max(loc.x), y.max(loc.y)),
    );
    println!("{} {} - {} {}", min_x, min_y, max_x, max_y);

    let mut buf = image::ImageBuffer::new((max_x - min_x + 1) as u32, (max_y - min_y + 1) as u32);

    for (x, y, p) in buf.enumerate_pixels_mut() {
        let loc = Location::new(x as i16 + min_x, y as i16 + min_y, 0);
        let sec = loc.sector();
        if sec.x < 0 || sec.y < 0 || sec.x >= COLS || sec.y >= ROWS {
            *p = image::Rgb::from_channels(0x00, 0x00, 0x00, 0xff);
            continue;
        }
        if (sec.x + sec.y) % 2 == 0 {
            *p = image::Rgb::from_channels(0x00, 0xaa, 0xaa, 0xff);
        } else {
            *p = image::Rgb::from_channels(0x88, 0x88, 0x88, 0xff);
        }
    }

    image::save_buffer(
        "overland_base.png",
        &buf,
        buf.width(),
        buf.height(),
        image::ColorType::RGB(8),
    ).unwrap();
}
<|endoftext|>


<commit_before>extern crate timely;
extern crate graph_map;
extern crate differential_dataflow;

use timely::order::Product;
use timely::dataflow::{*, operators::Filter};

use differential_dataflow::Collection;
use differential_dataflow::lattice::Lattice;
use differential_dataflow::operators::{*, iterate::Variable};
use differential_dataflow::input::InputSession;
use differential_dataflow::AsCollection;

use graph_map::GraphMMap;

type Node = u32;
type Edge = (Node, Node);
type Time = u32;
type Iter = u32;
type Diff = isize;

fn main() {

    // snag a filename to use for the input graph.
    let filename = std::env::args().nth(1).unwrap();
    let iterations: Iter = std::env::args().nth(2).unwrap().parse().unwrap();
    let inspect = std::env::args().nth(3) == Some("inspect".to_string());

    timely::execute_from_args(std::env::args().skip(2), move |worker| {

        let peers = worker.peers();
        let index = worker.index();
        let timer = worker.timer();

        let mut input = InputSession::new();
        let mut probe = ProbeHandle::new();

        worker.dataflow::<Time,_,_>(|scope| {
            let edges = input.to_collection(scope);
            pagerank(iterations, &edges)
                .filter(move |_| inspect)
                .consolidate()
                .inspect(|x| println!("{:?}", x))
                .probe_with(&mut probe);
        });

        // // What you might do if you used GraphMMap:
        let graph = GraphMMap::new(&filename);
        let mut node = index;
        while node < graph.nodes() {
            for &edge in graph.edges(node) {
                input.update((node as Node, edge as Node), 1);
            }
            node += peers;
        }

        input.advance_to(1);
        input.flush();
        while probe.less_than(input.time()) {
            worker.step();
        }

        println!("{:?}\tinitial compute complete", timer.elapsed());

        for node in 1 .. graph.nodes() {
            if node % peers == index {
                if !graph.edges(node).is_empty() {
                    input.update((node as Node, graph.edges(node)[0] as Node), -1);
                }
            }
            input.advance_to((node + 1) as Time);
            input.flush();
            while probe.less_than(input.time()) {
                worker.step();
            }
            println!("{:?}\tround {} complete", timer.elapsed(), node);
        }

    }).unwrap();
}

// Returns a weighted collection in which the weight of each node is proportional
// to its PageRank in the input graph `edges`.
fn pagerank<G>(iters: Iter, edges: &Collection<G, Edge, Diff>) -> Collection<G, Node, Diff>
where
    G: Scope,
    G::Timestamp: Lattice,
{
    // initialize many surfers at each node.
    let nodes =
    edges.flat_map(|(x,y)| Some(x).into_iter().chain(Some(y)))
         .distinct();

    // snag out-degrees for each node.
    let degrs = edges.map(|(src,_dst)| src)
                     .count();

    edges.scope().iterative::<Iter,_,_>(|inner| {

        // Bring various collections into the scope.
        let edges = edges.enter(inner);
        let nodes = nodes.enter(inner);
        let degrs = degrs.enter(inner);

        // Initial and reset numbers of surfers at each node.
        let inits = nodes.explode(|node| Some((node, 6_000_000)));
        let reset = nodes.explode(|node| Some((node, 1_000_000)));

        // Define a recursive variable to track surfers.
        // We start from `inits` and cycle only `iters`.
        let ranks = Variable::new_from(inits, Product::new(Default::default(), 1));

        // Match each surfer with the degree, scale numbers down.
        let to_push =
        degrs.semijoin(&ranks)
             .threshold(|(_node, degr), rank| (5 * rank) / (6 * degr))
             .map(|(node, _degr)| node);

        // Propagate surfers along links, blend in reset surfers.
        let pushed =
        edges.semijoin(&to_push)
             .map(|(_node, dest)| dest)
             .concat(&reset)
             .consolidate()
             .inner
             .filter(move |(_d,t,_r)| t.inner < iters)
             .as_collection();

        // Bind the recursive variable, return its limit.
        ranks.set(&pushed);
        pushed.leave()
    })
}
<commit_msg>zero iters means unbounded<commit_after>extern crate timely;
extern crate graph_map;
extern crate differential_dataflow;

use timely::order::Product;
use timely::dataflow::{*, operators::Filter};

use differential_dataflow::Collection;
use differential_dataflow::lattice::Lattice;
use differential_dataflow::operators::{*, iterate::Variable};
use differential_dataflow::input::InputSession;
use differential_dataflow::AsCollection;

use graph_map::GraphMMap;

type Node = u32;
type Edge = (Node, Node);
type Time = u32;
type Iter = u32;
type Diff = isize;

fn main() {

    // snag a filename to use for the input graph.
    let filename = std::env::args().nth(1).unwrap();
    let iterations: Iter = std::env::args().nth(2).unwrap().parse().unwrap();
    let inspect = std::env::args().nth(3) == Some("inspect".to_string());

    timely::execute_from_args(std::env::args().skip(2), move |worker| {

        let peers = worker.peers();
        let index = worker.index();
        let timer = worker.timer();

        let mut input = InputSession::new();
        let mut probe = ProbeHandle::new();

        worker.dataflow::<Time,_,_>(|scope| {
            let edges = input.to_collection(scope);
            pagerank(iterations, &edges)
                .filter(move |_| inspect)
                .consolidate()
                .inspect(|x| println!("{:?}", x))
                .probe_with(&mut probe);
        });

        // // What you might do if you used GraphMMap:
        let graph = GraphMMap::new(&filename);
        let mut node = index;
        while node < graph.nodes() {
            for &edge in graph.edges(node) {
                input.update((node as Node, edge as Node), 1);
            }
            node += peers;
        }

        input.advance_to(1);
        input.flush();
        while probe.less_than(input.time()) {
            worker.step();
        }

        println!("{:?}\tinitial compute complete", timer.elapsed());

        for node in 1 .. graph.nodes() {
            if node % peers == index {
                if !graph.edges(node).is_empty() {
                    input.update((node as Node, graph.edges(node)[0] as Node), -1);
                }
            }
            input.advance_to((node + 1) as Time);
            input.flush();
            while probe.less_than(input.time()) {
                worker.step();
            }
            println!("{:?}\tround {} complete", timer.elapsed(), node);
        }

    }).unwrap();
}

// Returns a weighted collection in which the weight of each node is proportional
// to its PageRank in the input graph `edges`.
fn pagerank<G>(iters: Iter, edges: &Collection<G, Edge, Diff>) -> Collection<G, Node, Diff>
where
    G: Scope,
    G::Timestamp: Lattice,
{
    // initialize many surfers at each node.
    let nodes =
    edges.flat_map(|(x,y)| Some(x).into_iter().chain(Some(y)))
         .distinct();

    // snag out-degrees for each node.
    let degrs = edges.map(|(src,_dst)| src)
                     .count();

    edges.scope().iterative::<Iter,_,_>(|inner| {

        // Bring various collections into the scope.
        let edges = edges.enter(inner);
        let nodes = nodes.enter(inner);
        let degrs = degrs.enter(inner);

        // Initial and reset numbers of surfers at each node.
        let inits = nodes.explode(|node| Some((node, 6_000_000)));
        let reset = nodes.explode(|node| Some((node, 1_000_000)));

        // Define a recursive variable to track surfers.
        // We start from `inits` and cycle only `iters`.
        let ranks = Variable::new_from(inits, Product::new(Default::default(), 1));

        // Match each surfer with the degree, scale numbers down.
        let to_push =
        degrs.semijoin(&ranks)
             .threshold(|(_node, degr), rank| (5 * rank) / (6 * degr))
             .map(|(node, _degr)| node);

        // Propagate surfers along links, blend in reset surfers.
        let mut pushed =
        edges.semijoin(&to_push)
             .map(|(_node, dest)| dest)
             .concat(&reset)
             .consolidate();

        if iters > 0 {
            pushed =
            pushed
             .inner
             .filter(move |(_d,t,_r)| t.inner < iters)
             .as_collection();
        }

        // Bind the recursive variable, return its limit.
        ranks.set(&pushed);
        pushed.leave()
    })
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use raft::raftpb::{Entry, Snapshot};
use std::collections::VecDeque;

// unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
pub struct Unstable {
    // the incoming unstable snapshot, if any.
    snapshot: Option<Box<Snapshot>>,
    // all entries that have not yet been written to storage.
    entries: VecDeque<Entry>,
    offset: u64,
}

impl Unstable {
    // maybe_first_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_first_index(&self) -> Option<u64> {
        self.snapshot
            .as_ref()
            .map_or(None, |snap| Some(snap.get_metadata().get_index() + 1))
    }

    // maybe_last_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_last_index(&self) -> Option<u64> {
        match self.entries.len() {
            0 => {
                self.snapshot
                    .as_ref()
                    .map_or(None, |snap| Some(snap.get_metadata().get_index()))
            }
            len => Some(self.offset + len as u64 - 1),
        }
    }

    // maybe_term returns the term of the entry at index idx, if there
    // is any.
    fn maybe_term(&self, idx: u64) -> Option<u64> {
        if idx < self.offset {
            if self.snapshot.is_none() {
                return None;
            }

            let meta = self.snapshot.as_ref().unwrap().get_metadata().clone();
            if idx == meta.get_index() {
                return Some(meta.get_term());
            }
            return None;
        }
        match self.maybe_last_index() {
            None => None,
            Some(last) => {
                if idx > last {
                    return None;
                }
                Some(self.entries[(idx - self.offset) as usize].get_Term())
            }
        }
    }

    fn stable_to(&mut self, idx: u64, term: u64) {
        let t = self.maybe_term(idx);
        if t.is_none() {
            return;
        }

        if t.unwrap() == term && idx >= self.offset {
            let start = idx + 1 - self.offset;
            for _ in 0..start {
                self.entries.pop_front();
            }
            self.offset = idx + 1;
        }
    }

    fn stable_snap_to(&mut self, idx: u64) {
        if self.snapshot.is_none() {
            return;
        }
        if idx == self.snapshot.as_ref().unwrap().get_metadata().get_index() {
            self.snapshot = None;
        }
    }

    fn restore(&mut self, snap: Snapshot) {
        self.offset = snap.get_metadata().get_index() + 1;
        self.entries.clear();
        self.snapshot = Some(Box::new(snap));
    }

    fn truncate_and_append(&mut self, ents: &[Entry]) {
        let after = ents[0].get_Index() - 1;
        if after == self.offset + self.entries.len() as u64 - 1 {
            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else if after < self.offset {
            // The log is being truncated to before our current offset
            // portion, so set the offset and replace the entries
            self.offset = after + 1;
            self.entries.clear();

            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else {
            // truncate to after and copy to self.entries
            // then append
            let off = self.offset.clone();
            let cut_ents = self.cut_slice(off, after + 1);
            self.entries.clear();
            for e in cut_ents {
                self.entries.push_back(e);
            }

            for e in ents {
                self.entries.push_back(e.clone());
            }
        }
    }

    fn cut_slice(&mut self, lo: u64, hi: u64) -> Vec<Entry> {
        self.must_check_outofbounds(lo, hi);
        let l = lo as usize;
        let h = lo as usize;
        let off = self.offset as usize;
        return self.entries.drain(l - off..h - off).map(|e| e).collect();
    }

    fn must_check_outofbounds(&self, lo: u64, hi: u64) {
        if lo > hi {
            panic!("invalid unstable.slice {} > {}", lo, hi)
        }
        let upper = self.offset + self.entries.len() as u64;
        if lo < self.offset || hi > upper {
            panic!("unstable.slice[{}, {}] out of bound[{}, {}]",
                   lo,
                   hi,
                   self.offset,
                   upper)
        }
    }
}

#[cfg(test)]
mod test {
    use raft::raftpb::{Entry, Snapshot};
    use raft::log_unstable::Unstable;
    pub struct Obj {
        entry: Entry,
        offset: u64,
        snap: Option<Snapshot>,

        wok: bool,
        windex: u64,
    }

    fn new_entry(index: u64, term: u64) -> Entry {
        let mut e = Entry::new();
        e.set_Term(term);
        e.set_Index(index);
        e
    }

    fn new_obj(entry: Entry, offset: u64, snap: Option<Snapshot>, wok: bool, windex: u64) -> Obj {
        Obj {
            entry: entry,
            offset: offset,
            snap: snap,
            wok: wok,
            windex: windex,
        }
    }

    fn new_snapshot(index: u64, term: u64) -> Snapshot {
        use raft::raftpb::{SnapshotMetadata, Snapshot};
        let mut snap = Snapshot::new();
        let mut meta = SnapshotMetadata::new();
        meta.set_index(index);
        meta.set_term(term);
        snap.set_metadata(meta);
        snap
    }

    #[test]
    fn test_maybe_first_index() {
        let tests: Vec<Obj> = vec![
            // no snapshot
            new_obj(new_entry(5,1), 5, None, false, 0),
            new_obj(Entry::new(), 0, None, false, 0,),
            // has snapshot
            new_obj(new_entry(5, 1), 5, Some(new_snapshot(4,1)), true, 5,),
            new_obj(Entry::new(), 5, Some(new_snapshot(4,1)), true, 5,),
        ];

        for tt in tests {
            let u = Unstable {
                entries: vec![tt.entry].into_iter().collect(),
                offset: tt.offset,
                snapshot: tt.snap.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_first_index();
            match index {
                None => assert!(!tt.wok),
                Some(index) => assert_eq!(index, tt.windex),
            }
        }
    }
}
<commit_msg>raft: Clean up tests<commit_after>#![allow(dead_code)]
use raft::raftpb::{Entry, Snapshot};
use std::collections::VecDeque;

// unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
pub struct Unstable {
    // the incoming unstable snapshot, if any.
    snapshot: Option<Box<Snapshot>>,
    // all entries that have not yet been written to storage.
    entries: VecDeque<Entry>,
    offset: u64,
}

impl Unstable {
    // maybe_first_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_first_index(&self) -> Option<u64> {
        self.snapshot
            .as_ref()
            .map_or(None, |snap| Some(snap.get_metadata().get_index() + 1))
    }

    // maybe_last_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_last_index(&self) -> Option<u64> {
        match self.entries.len() {
            0 => {
                self.snapshot
                    .as_ref()
                    .map_or(None, |snap| Some(snap.get_metadata().get_index()))
            }
            len => Some(self.offset + len as u64 - 1),
        }
    }

    // maybe_term returns the term of the entry at index idx, if there
    // is any.
    fn maybe_term(&self, idx: u64) -> Option<u64> {
        if idx < self.offset {
            if self.snapshot.is_none() {
                return None;
            }

            let meta = self.snapshot.as_ref().unwrap().get_metadata().clone();
            if idx == meta.get_index() {
                return Some(meta.get_term());
            }
            return None;
        }
        match self.maybe_last_index() {
            None => None,
            Some(last) => {
                if idx > last {
                    return None;
                }
                Some(self.entries[(idx - self.offset) as usize].get_Term())
            }
        }
    }

    fn stable_to(&mut self, idx: u64, term: u64) {
        let t = self.maybe_term(idx);
        if t.is_none() {
            return;
        }

        if t.unwrap() == term && idx >= self.offset {
            let start = idx + 1 - self.offset;
            for _ in 0..start {
                self.entries.pop_front();
            }
            self.offset = idx + 1;
        }
    }

    fn stable_snap_to(&mut self, idx: u64) {
        if self.snapshot.is_none() {
            return;
        }
        if idx == self.snapshot.as_ref().unwrap().get_metadata().get_index() {
            self.snapshot = None;
        }
    }

    fn restore(&mut self, snap: Snapshot) {
        self.offset = snap.get_metadata().get_index() + 1;
        self.entries.clear();
        self.snapshot = Some(Box::new(snap));
    }

    fn truncate_and_append(&mut self, ents: &[Entry]) {
        let after = ents[0].get_Index() - 1;
        if after == self.offset + self.entries.len() as u64 - 1 {
            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else if after < self.offset {
            // The log is being truncated to before our current offset
            // portion, so set the offset and replace the entries
            self.offset = after + 1;
            self.entries.clear();

            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else {
            // truncate to after and copy to self.entries
            // then append
            let off = self.offset.clone();
            let cut_ents = self.cut_slice(off, after + 1);
            self.entries.clear();
            for e in cut_ents {
                self.entries.push_back(e);
            }

            for e in ents {
                self.entries.push_back(e.clone());
            }
        }
    }

    fn cut_slice(&mut self, lo: u64, hi: u64) -> Vec<Entry> {
        self.must_check_outofbounds(lo, hi);
        let l = lo as usize;
        let h = lo as usize;
        let off = self.offset as usize;
        return self.entries.drain(l - off..h - off).map(|e| e).collect();
    }

    fn must_check_outofbounds(&self, lo: u64, hi: u64) {
        if lo > hi {
            panic!("invalid unstable.slice {} > {}", lo, hi)
        }
        let upper = self.offset + self.entries.len() as u64;
        if lo < self.offset || hi > upper {
            panic!("unstable.slice[{}, {}] out of bound[{}, {}]",
                   lo,
                   hi,
                   self.offset,
                   upper)
        }
    }
}

#[cfg(test)]
mod test {
    use raft::raftpb::{Entry, Snapshot};
    use raft::log_unstable::Unstable;
    use std::collections::VecDeque;

    fn new_entry(index: u64, term: u64) -> Option<Entry> {
        let mut e = Entry::new();
        e.set_Term(term);
        e.set_Index(index);
        Some(e)
    }

    fn new_snapshot(index: u64, term: u64) -> Snapshot {
        use raft::raftpb::{SnapshotMetadata, Snapshot};
        let mut snap = Snapshot::new();
        let mut meta = SnapshotMetadata::new();
        meta.set_index(index);
        meta.set_term(term);
        snap.set_metadata(meta);
        snap
    }

    #[test]
    fn test_maybe_first_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            // no snapshot
            (new_entry(5,1), 5, None, false, 0),
            (None, 0, None, false, 0),
            // has snapshot
            (new_entry(5, 1), 5, Some(new_snapshot(4,1)), true, 5),
            (None, 5, Some(new_snapshot(4,1)), true, 5),
        ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(VecDeque::new(), |entry| {
                    vec![entry].into_iter().collect::<VecDeque<Entry>>()
                }),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_first_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    // #[test]
    fn test_maybe_last_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            (new_entry(5,1), 5, None, true, 5),
            (new_entry(5,1), 5, Some(new_snapshot(4,1)), true, 5),
            // last in snapshot
            (None, 5, Some(new_snapshot(4,1)), true, 4),
            // enpty unstable
            (None, 0, None, false, 0),
       ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(VecDeque::new(), |entry| {
                    vec![entry].into_iter().collect::<VecDeque<Entry>>()
                }),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_last_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    fn test_maybe_term() {}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate pest_derive;

pub mod error;
pub mod model;
pub mod parser;
pub mod partials;
pub mod runtime;

pub use error::{Error, Result};
pub use liquid_derive::{
    Display_filter, FilterParameters, FilterReflection, FromFilterParameters, ParseFilter,
};
pub use model::{to_object, Object};
pub use model::{to_value, Value, ValueCow};
pub use model::{ObjectView, ValueView};
pub use parser::Language;
pub use parser::TagTokenIter;
pub use parser::{BlockReflection, ParseBlock, TagBlock};
pub use parser::{Filter, FilterParameters, FilterReflection, ParseFilter};
pub use parser::{ParseTag, TagReflection};
pub use runtime::Expression;
pub use runtime::Renderable;
pub use runtime::Runtime;
pub use runtime::Template;

#[allow(unused_macros)]
#[macro_export]
macro_rules! call_filter {
    ($filter:expr, $input:expr) => {{
        $crate::call_filter!($filter, $input, )
    }};
    ($filter:expr, $input:expr, $($args:expr),*) => {{
        let positional = Box::new(vec![$($crate::Expression::Literal($crate::value!($args))),*].into_iter());
        let keyword = Box::new(Vec::new().into_iter());
        let args = $crate::parser::FilterArguments { positional, keyword };

        let runtime = $crate::Runtime::default();

        let input = $crate::value!($input);

        $crate::ParseFilter::parse(&$filter, args)
            .and_then(|filter| $crate::Filter::evaluate(&*filter, &input, &runtime))
    }};
}
<commit_msg>docs: Remove derives?<commit_after>#[macro_use]
extern crate pest_derive;

pub mod error;
pub mod model;
pub mod parser;
pub mod partials;
pub mod runtime;

pub use error::{Error, Result};
#[doc(hidden)]
pub use liquid_derive::{
    Display_filter, FilterParameters, FilterReflection, FromFilterParameters, ParseFilter,
};
pub use model::{to_object, Object};
pub use model::{to_value, Value, ValueCow};
pub use model::{ObjectView, ValueView};
pub use parser::Language;
pub use parser::TagTokenIter;
pub use parser::{BlockReflection, ParseBlock, TagBlock};
pub use parser::{Filter, FilterParameters, FilterReflection, ParseFilter};
pub use parser::{ParseTag, TagReflection};
pub use runtime::Expression;
pub use runtime::Renderable;
pub use runtime::Runtime;
pub use runtime::Template;

#[allow(unused_macros)]
#[macro_export]
macro_rules! call_filter {
    ($filter:expr, $input:expr) => {{
        $crate::call_filter!($filter, $input, )
    }};
    ($filter:expr, $input:expr, $($args:expr),*) => {{
        let positional = Box::new(vec![$($crate::Expression::Literal($crate::value!($args))),*].into_iter());
        let keyword = Box::new(Vec::new().into_iter());
        let args = $crate::parser::FilterArguments { positional, keyword };

        let runtime = $crate::Runtime::default();

        let input = $crate::value!($input);

        $crate::ParseFilter::parse(&$filter, args)
            .and_then(|filter| $crate::Filter::evaluate(&*filter, &input, &runtime))
    }};
}
<|endoftext|>


<commit_before>use display_list::DisplayListBuilder;
use euclid::Point2D;
use ipc_channel::ipc::{self, IpcSender};
use stacking_context::StackingContext;
use std::cell::Cell;
use types::{ColorF, DisplayListId, Epoch, FontKey, StackingContextId};
use types::{ImageKey, ImageFormat, NativeFontHandle, PipelineId};

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct IdNamespace(pub u32);

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ResourceId(pub u32);

#[derive(Serialize, Deserialize)]
pub enum ApiMsg {
    AddRawFont(FontKey, Vec<u8>),
    //AddNativeFont(FontKey, NativeFontHandle),
    AddImage(ImageKey, u32, u32, ImageFormat, Vec<u8>),
    UpdateImage(ImageKey, u32, u32, ImageFormat, Vec<u8>),
    AddDisplayList(DisplayListId, PipelineId, Epoch, DisplayListBuilder),
    AddStackingContext(StackingContextId, PipelineId, Epoch, StackingContext),
    CloneApi(IpcSender<IdNamespace>),
    SetRootStackingContext(StackingContextId, ColorF, Epoch, PipelineId),
    SetRootPipeline(PipelineId),
    Scroll(Point2D<f32>),
    TranslatePointToLayerSpace(Point2D<f32>, IpcSender<Point2D<f32>>),
}

#[derive(Serialize, Deserialize, Clone)]
pub struct RenderApiSender(IpcSender<ApiMsg>);

impl RenderApiSender {
    pub fn new(tx: IpcSender<ApiMsg>) -> RenderApiSender {
        RenderApiSender(tx)
    }

    pub fn create_api(&self) -> RenderApi {
        let RenderApiSender(ref tx) = *self;
        let (sync_tx, sync_rx) = ipc::channel().unwrap();
        let msg = ApiMsg::CloneApi(sync_tx);
        tx.send(msg).unwrap();
        RenderApi {
            tx: tx.clone(),
            id_namespace: sync_rx.recv().unwrap(),
            next_id: Cell::new(ResourceId(0)),
        }
    }
}

pub struct RenderApi {
    pub tx: IpcSender<ApiMsg>,
    pub id_namespace: IdNamespace,
    pub next_id: Cell<ResourceId>,
}

impl RenderApi {
    pub fn clone_sender(&self) -> RenderApiSender {
        RenderApiSender::new(self.tx.clone())
    }

    pub fn add_raw_font(&self, bytes: Vec<u8>) -> FontKey {
        let new_id = self.next_unique_id();
        let key = FontKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddRawFont(key, bytes);
        self.tx.send(msg).unwrap();
        key
    }

    pub fn add_native_font(&self, native_font_handle: NativeFontHandle) -> FontKey {
        panic!("TODO: Get this working again with the e10s changes!");
        /*
        let new_id = self.next_unique_id();
        let key = FontKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddNativeFont(key, native_font_handle);
        self.tx.send(msg).unwrap();
        key*/
    }

    pub fn alloc_image(&self) -> ImageKey {
        let new_id = self.next_unique_id();
        ImageKey::new(new_id.0, new_id.1)
    }

    pub fn add_image(&self,
                     width: u32,
                     height: u32,
                     format: ImageFormat,
                     bytes: Vec<u8>) -> ImageKey {
        let new_id = self.next_unique_id();
        let key = ImageKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddImage(key, width, height, format, bytes);
        self.tx.send(msg).unwrap();
        key
    }

    // TODO: Support changing dimensions (and format) during image update?
    pub fn update_image(&self,
                        key: ImageKey,
                        width: u32,
                        height: u32,
                        format: ImageFormat,
                        bytes: Vec<u8>) {
        let msg = ApiMsg::UpdateImage(key, width, height, format, bytes);
        self.tx.send(msg).unwrap();
    }

    pub fn add_display_list(&self,
                            display_list: DisplayListBuilder,
                            stacking_context: &mut StackingContext,
                            pipeline_id: PipelineId,
                            epoch: Epoch) -> Option<DisplayListId> {
        //TODO! debug_assert!(display_list.item_count() > 0, "Avoid adding empty lists!");
        let new_id = self.next_unique_id();
        let id = DisplayListId(new_id.0, new_id.1);
        stacking_context.has_stacking_contexts = stacking_context.has_stacking_contexts ||
                                                 display_list.has_stacking_contexts;
        let msg = ApiMsg::AddDisplayList(id, pipeline_id, epoch, display_list);
        self.tx.send(msg).unwrap();
        stacking_context.display_lists.push(id);

        Some(id)
    }

    pub fn add_stacking_context(&self,
                                stacking_context: StackingContext,
                                pipeline_id: PipelineId,
                                epoch: Epoch) -> StackingContextId {
        let new_id = self.next_unique_id();
        let id = StackingContextId(new_id.0, new_id.1);
        let msg = ApiMsg::AddStackingContext(id, pipeline_id, epoch, stacking_context);
        self.tx.send(msg).unwrap();
        id
    }

    pub fn set_root_pipeline(&self, pipeline_id: PipelineId) {
        let msg = ApiMsg::SetRootPipeline(pipeline_id);
        self.tx.send(msg).unwrap();
    }

    pub fn set_root_stacking_context(&self,
                                     stacking_context_id: StackingContextId,
                                     background_color: ColorF,
                                     epoch: Epoch,
                                     pipeline_id: PipelineId) {
        let msg = ApiMsg::SetRootStackingContext(stacking_context_id,
                                                 background_color,
                                                 epoch,
                                                 pipeline_id);
        self.tx.send(msg).unwrap();
    }

    pub fn scroll(&self, delta: Point2D<f32>) {
        let msg = ApiMsg::Scroll(delta);
        self.tx.send(msg).unwrap();
    }

    pub fn translate_point_to_layer_space(&self, point: &Point2D<f32>) -> Point2D<f32> {
        let (tx, rx) = ipc::channel().unwrap();
        let msg = ApiMsg::TranslatePointToLayerSpace(*point, tx);
        self.tx.send(msg).unwrap();
        rx.recv().unwrap()
    }

    fn next_unique_id(&self) -> (u32, u32) {
        let IdNamespace(namespace) = self.id_namespace;
        let ResourceId(id) = self.next_id.get();
        self.next_id.set(ResourceId(id + 1));
        (namespace, id)
    }
}
<commit_msg>Support native fonts again post-e10s.<commit_after>use display_list::DisplayListBuilder;
use euclid::Point2D;
use ipc_channel::ipc::{self, IpcSender};
use stacking_context::StackingContext;
use std::cell::Cell;
use types::{ColorF, DisplayListId, Epoch, FontKey, StackingContextId};
use types::{ImageKey, ImageFormat, NativeFontHandle, PipelineId};

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct IdNamespace(pub u32);

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ResourceId(pub u32);

#[derive(Serialize, Deserialize)]
pub enum ApiMsg {
    AddRawFont(FontKey, Vec<u8>),
    AddNativeFont(FontKey, NativeFontHandle),
    AddImage(ImageKey, u32, u32, ImageFormat, Vec<u8>),
    UpdateImage(ImageKey, u32, u32, ImageFormat, Vec<u8>),
    AddDisplayList(DisplayListId, PipelineId, Epoch, DisplayListBuilder),
    AddStackingContext(StackingContextId, PipelineId, Epoch, StackingContext),
    CloneApi(IpcSender<IdNamespace>),
    SetRootStackingContext(StackingContextId, ColorF, Epoch, PipelineId),
    SetRootPipeline(PipelineId),
    Scroll(Point2D<f32>),
    TranslatePointToLayerSpace(Point2D<f32>, IpcSender<Point2D<f32>>),
}

#[derive(Serialize, Deserialize, Clone)]
pub struct RenderApiSender(IpcSender<ApiMsg>);

impl RenderApiSender {
    pub fn new(tx: IpcSender<ApiMsg>) -> RenderApiSender {
        RenderApiSender(tx)
    }

    pub fn create_api(&self) -> RenderApi {
        let RenderApiSender(ref tx) = *self;
        let (sync_tx, sync_rx) = ipc::channel().unwrap();
        let msg = ApiMsg::CloneApi(sync_tx);
        tx.send(msg).unwrap();
        RenderApi {
            tx: tx.clone(),
            id_namespace: sync_rx.recv().unwrap(),
            next_id: Cell::new(ResourceId(0)),
        }
    }
}

pub struct RenderApi {
    pub tx: IpcSender<ApiMsg>,
    pub id_namespace: IdNamespace,
    pub next_id: Cell<ResourceId>,
}

impl RenderApi {
    pub fn clone_sender(&self) -> RenderApiSender {
        RenderApiSender::new(self.tx.clone())
    }

    pub fn add_raw_font(&self, bytes: Vec<u8>) -> FontKey {
        let new_id = self.next_unique_id();
        let key = FontKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddRawFont(key, bytes);
        self.tx.send(msg).unwrap();
        key
    }

    pub fn add_native_font(&self, native_font_handle: NativeFontHandle) -> FontKey {
        let new_id = self.next_unique_id();
        let key = FontKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddNativeFont(key, native_font_handle);
        self.tx.send(msg).unwrap();
        key
    }

    pub fn alloc_image(&self) -> ImageKey {
        let new_id = self.next_unique_id();
        ImageKey::new(new_id.0, new_id.1)
    }

    pub fn add_image(&self,
                     width: u32,
                     height: u32,
                     format: ImageFormat,
                     bytes: Vec<u8>) -> ImageKey {
        let new_id = self.next_unique_id();
        let key = ImageKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddImage(key, width, height, format, bytes);
        self.tx.send(msg).unwrap();
        key
    }

    // TODO: Support changing dimensions (and format) during image update?
    pub fn update_image(&self,
                        key: ImageKey,
                        width: u32,
                        height: u32,
                        format: ImageFormat,
                        bytes: Vec<u8>) {
        let msg = ApiMsg::UpdateImage(key, width, height, format, bytes);
        self.tx.send(msg).unwrap();
    }

    pub fn add_display_list(&self,
                            display_list: DisplayListBuilder,
                            stacking_context: &mut StackingContext,
                            pipeline_id: PipelineId,
                            epoch: Epoch) -> Option<DisplayListId> {
        //TODO! debug_assert!(display_list.item_count() > 0, "Avoid adding empty lists!");
        let new_id = self.next_unique_id();
        let id = DisplayListId(new_id.0, new_id.1);
        stacking_context.has_stacking_contexts = stacking_context.has_stacking_contexts ||
                                                 display_list.has_stacking_contexts;
        let msg = ApiMsg::AddDisplayList(id, pipeline_id, epoch, display_list);
        self.tx.send(msg).unwrap();
        stacking_context.display_lists.push(id);

        Some(id)
    }

    pub fn add_stacking_context(&self,
                                stacking_context: StackingContext,
                                pipeline_id: PipelineId,
                                epoch: Epoch) -> StackingContextId {
        let new_id = self.next_unique_id();
        let id = StackingContextId(new_id.0, new_id.1);
        let msg = ApiMsg::AddStackingContext(id, pipeline_id, epoch, stacking_context);
        self.tx.send(msg).unwrap();
        id
    }

    pub fn set_root_pipeline(&self, pipeline_id: PipelineId) {
        let msg = ApiMsg::SetRootPipeline(pipeline_id);
        self.tx.send(msg).unwrap();
    }

    pub fn set_root_stacking_context(&self,
                                     stacking_context_id: StackingContextId,
                                     background_color: ColorF,
                                     epoch: Epoch,
                                     pipeline_id: PipelineId) {
        let msg = ApiMsg::SetRootStackingContext(stacking_context_id,
                                                 background_color,
                                                 epoch,
                                                 pipeline_id);
        self.tx.send(msg).unwrap();
    }

    pub fn scroll(&self, delta: Point2D<f32>) {
        let msg = ApiMsg::Scroll(delta);
        self.tx.send(msg).unwrap();
    }

    pub fn translate_point_to_layer_space(&self, point: &Point2D<f32>) -> Point2D<f32> {
        let (tx, rx) = ipc::channel().unwrap();
        let msg = ApiMsg::TranslatePointToLayerSpace(*point, tx);
        self.tx.send(msg).unwrap();
        rx.recv().unwrap()
    }

    fn next_unique_id(&self) -> (u32, u32) {
        let IdNamespace(namespace) = self.id_namespace;
        let ResourceId(id) = self.next_id.get();
        self.next_id.set(ResourceId(id + 1));
        (namespace, id)
    }
}
<|endoftext|>


<commit_before>#![allow(nonstandard_style)]

use libc::{c_int, c_void, uintptr_t};

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum _Unwind_Reason_Code {
    _URC_NO_REASON = 0,
    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
    _URC_FATAL_PHASE2_ERROR = 2,
    _URC_FATAL_PHASE1_ERROR = 3,
    _URC_NORMAL_STOP = 4,
    _URC_END_OF_STACK = 5,
    _URC_HANDLER_FOUND = 6,
    _URC_INSTALL_CONTEXT = 7,
    _URC_CONTINUE_UNWIND = 8,
    _URC_FAILURE = 9, // used only by ARM EHABI
}
pub use _Unwind_Reason_Code::*;

pub type _Unwind_Exception_Class = u64;
pub type _Unwind_Word = uintptr_t;
pub type _Unwind_Ptr = uintptr_t;
pub type _Unwind_Trace_Fn =
    extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;

#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5;

#[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: usize = 6;

#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
pub const unwinder_private_data_size: usize = 20;

#[cfg(all(target_arch = "arm", target_os = "ios"))]
pub const unwinder_private_data_size: usize = 5;

#[cfg(target_arch = "aarch64")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "mips")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "mips64")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "s390x")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_os = "emscripten")]
pub const unwinder_private_data_size: usize = 20;

#[cfg(all(target_arch = "hexagon", target_os = "linux"))]
pub const unwinder_private_data_size: usize = 35;

#[repr(C)]
pub struct _Unwind_Exception {
    pub exception_class: _Unwind_Exception_Class,
    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
    pub private: [_Unwind_Word; unwinder_private_data_size],
}

pub enum _Unwind_Context {}

pub type _Unwind_Exception_Cleanup_Fn =
    extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
#[cfg_attr(
    all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
    link(name = "unwind", kind = "static")
)]
extern "C" {
    #[unwind(allowed)]
    pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
    pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
    pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
    pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
    pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
}

cfg_if::cfg_if! {
if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))] {
    // Not ARM EHABI
    #[repr(C)]
    #[derive(Copy, Clone, PartialEq)]
    pub enum _Unwind_Action {
        _UA_SEARCH_PHASE = 1,
        _UA_CLEANUP_PHASE = 2,
        _UA_HANDLER_FRAME = 4,
        _UA_FORCE_UNWIND = 8,
        _UA_END_OF_STACK = 16,
    }
    pub use _Unwind_Action::*;

    #[cfg_attr(all(feature = "llvm-libunwind",
                   any(target_os = "fuchsia", target_os = "linux")),
               link(name = "unwind", kind = "static"))]
    extern "C" {
        pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
        pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
        pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
        pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
        pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
                                 -> _Unwind_Word;
        pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
    }

} else {
    // ARM EHABI
    #[repr(C)]
    #[derive(Copy, Clone, PartialEq)]
    pub enum _Unwind_State {
        _US_VIRTUAL_UNWIND_FRAME = 0,
        _US_UNWIND_FRAME_STARTING = 1,
        _US_UNWIND_FRAME_RESUME = 2,
        _US_ACTION_MASK = 3,
        _US_FORCE_UNWIND = 8,
        _US_END_OF_STACK = 16,
    }
    pub use _Unwind_State::*;

    #[repr(C)]
    enum _Unwind_VRS_Result {
        _UVRSR_OK = 0,
        _UVRSR_NOT_IMPLEMENTED = 1,
        _UVRSR_FAILED = 2,
    }
    #[repr(C)]
    enum _Unwind_VRS_RegClass {
        _UVRSC_CORE = 0,
        _UVRSC_VFP = 1,
        _UVRSC_FPA = 2,
        _UVRSC_WMMXD = 3,
        _UVRSC_WMMXC = 4,
    }
    use _Unwind_VRS_RegClass::*;
    #[repr(C)]
    enum _Unwind_VRS_DataRepresentation {
        _UVRSD_UINT32 = 0,
        _UVRSD_VFPX = 1,
        _UVRSD_FPAX = 2,
        _UVRSD_UINT64 = 3,
        _UVRSD_FLOAT = 4,
        _UVRSD_DOUBLE = 5,
    }
    use _Unwind_VRS_DataRepresentation::*;

    pub const UNWIND_POINTER_REG: c_int = 12;
    pub const UNWIND_SP_REG: c_int = 13;
    pub const UNWIND_IP_REG: c_int = 15;

    #[cfg_attr(all(feature = "llvm-libunwind",
                   any(target_os = "fuchsia", target_os = "linux")),
               link(name = "unwind", kind = "static"))]
    extern "C" {
        fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
                           regclass: _Unwind_VRS_RegClass,
                           regno: _Unwind_Word,
                           repr: _Unwind_VRS_DataRepresentation,
                           data: *mut c_void)
                           -> _Unwind_VRS_Result;

        fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
                           regclass: _Unwind_VRS_RegClass,
                           regno: _Unwind_Word,
                           repr: _Unwind_VRS_DataRepresentation,
                           data: *mut c_void)
                           -> _Unwind_VRS_Result;
    }

    // On Android or ARM/Linux, these are implemented as macros:

    pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
        let mut val: _Unwind_Word = 0;
        _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
                        &mut val as *mut _ as *mut c_void);
        val
    }

    pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
        let mut value = value;
        _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
                        &mut value as *mut _ as *mut c_void);
    }

    pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
                                -> _Unwind_Word {
        let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
        (val & !1) as _Unwind_Word
    }

    pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
                                value: _Unwind_Word) {
        // Propagate thumb bit to instruction pointer
        let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1;
        let value = value | thumb_state;
        _Unwind_SetGR(ctx, UNWIND_IP_REG, value);
    }

    pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
                                    ip_before_insn: *mut c_int)
                                    -> _Unwind_Word {
        *ip_before_insn = 0;
        _Unwind_GetIP(ctx)
    }

    // This function also doesn't exist on Android or ARM/Linux, so make it a no-op
    pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
        pc
    }
}
} // cfg_if!

cfg_if::cfg_if! {
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
    // Not 32-bit iOS
    #[cfg_attr(all(feature = "llvm-libunwind",
                   any(target_os = "fuchsia", target_os = "linux")),
               link(name = "unwind", kind = "static"))]
    extern "C" {
        #[unwind(allowed)]
        pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
        pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
                                 trace_argument: *mut c_void)
                                 -> _Unwind_Reason_Code;
    }
} else {
    // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
    #[cfg_attr(all(feature = "llvm-libunwind",
                   any(target_os = "fuchsia", target_os = "linux")),
               link(name = "unwind", kind = "static"))]
    extern "C" {
        #[unwind(allowed)]
        pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
    }

    #[inline]
    pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
        _Unwind_SjLj_RaiseException(exc)
    }
}
} // cfg_if!

cfg_if::cfg_if! {
if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
    // We declare these as opaque types. This is fine since you just need to
    // pass them to _GCC_specific_handler and forget about them.
    pub enum EXCEPTION_RECORD {}
    pub type LPVOID = *mut c_void;
    pub enum CONTEXT {}
    pub enum DISPATCHER_CONTEXT {}
    pub type EXCEPTION_DISPOSITION = c_int;
    type PersonalityFn = unsafe extern "C" fn(version: c_int,
                                              actions: _Unwind_Action,
                                              exception_class: _Unwind_Exception_Class,
                                              exception_object: *mut _Unwind_Exception,
                                              context: *mut _Unwind_Context)
                                              -> _Unwind_Reason_Code;

    extern "C" {
        pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
                                establisherFrame: LPVOID,
                                contextRecord: *mut CONTEXT,
                                dispatcherContext: *mut DISPATCHER_CONTEXT,
                                personality: PersonalityFn)
                                -> EXCEPTION_DISPOSITION;
    }
}
} // cfg_if!
<commit_msg>Remove useless `all` in cfg<commit_after>#![allow(nonstandard_style)]

use libc::{c_int, c_void, uintptr_t};

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum _Unwind_Reason_Code {
    _URC_NO_REASON = 0,
    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
    _URC_FATAL_PHASE2_ERROR = 2,
    _URC_FATAL_PHASE1_ERROR = 3,
    _URC_NORMAL_STOP = 4,
    _URC_END_OF_STACK = 5,
    _URC_HANDLER_FOUND = 6,
    _URC_INSTALL_CONTEXT = 7,
    _URC_CONTINUE_UNWIND = 8,
    _URC_FAILURE = 9, // used only by ARM EHABI
}
pub use _Unwind_Reason_Code::*;

pub type _Unwind_Exception_Class = u64;
pub type _Unwind_Word = uintptr_t;
pub type _Unwind_Ptr = uintptr_t;
pub type _Unwind_Trace_Fn =
    extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;

#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5;

#[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: usize = 6;

#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
pub const unwinder_private_data_size: usize = 20;

#[cfg(all(target_arch = "arm", target_os = "ios"))]
pub const unwinder_private_data_size: usize = 5;

#[cfg(target_arch = "aarch64")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "mips")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "mips64")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "s390x")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_os = "emscripten")]
pub const unwinder_private_data_size: usize = 20;

#[cfg(all(target_arch = "hexagon", target_os = "linux"))]
pub const unwinder_private_data_size: usize = 35;

#[repr(C)]
pub struct _Unwind_Exception {
    pub exception_class: _Unwind_Exception_Class,
    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
    pub private: [_Unwind_Word; unwinder_private_data_size],
}

pub enum _Unwind_Context {}

pub type _Unwind_Exception_Cleanup_Fn =
    extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
#[cfg_attr(
    all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
    link(name = "unwind", kind = "static")
)]
extern "C" {
    #[unwind(allowed)]
    pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
    pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
    pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
    pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
    pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
}

cfg_if::cfg_if! {
if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] {
    // Not ARM EHABI
    #[repr(C)]
    #[derive(Copy, Clone, PartialEq)]
    pub enum _Unwind_Action {
        _UA_SEARCH_PHASE = 1,
        _UA_CLEANUP_PHASE = 2,
        _UA_HANDLER_FRAME = 4,
        _UA_FORCE_UNWIND = 8,
        _UA_END_OF_STACK = 16,
    }
    pub use _Unwind_Action::*;

    #[cfg_attr(all(feature = "llvm-libunwind",
                   any(target_os = "fuchsia", target_os = "linux")),
               link(name = "unwind", kind = "static"))]
    extern "C" {
        pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
        pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
        pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
        pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
        pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
                                 -> _Unwind_Word;
        pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
    }

} else {
    // ARM EHABI
    #[repr(C)]
    #[derive(Copy, Clone, PartialEq)]
    pub enum _Unwind_State {
        _US_VIRTUAL_UNWIND_FRAME = 0,
        _US_UNWIND_FRAME_STARTING = 1,
        _US_UNWIND_FRAME_RESUME = 2,
        _US_ACTION_MASK = 3,
        _US_FORCE_UNWIND = 8,
        _US_END_OF_STACK = 16,
    }
    pub use _Unwind_State::*;

    #[repr(C)]
    enum _Unwind_VRS_Result {
        _UVRSR_OK = 0,
        _UVRSR_NOT_IMPLEMENTED = 1,
        _UVRSR_FAILED = 2,
    }
    #[repr(C)]
    enum _Unwind_VRS_RegClass {
        _UVRSC_CORE = 0,
        _UVRSC_VFP = 1,
        _UVRSC_FPA = 2,
        _UVRSC_WMMXD = 3,
        _UVRSC_WMMXC = 4,
    }
    use _Unwind_VRS_RegClass::*;
    #[repr(C)]
    enum _Unwind_VRS_DataRepresentation {
        _UVRSD_UINT32 = 0,
        _UVRSD_VFPX = 1,
        _UVRSD_FPAX = 2,
        _UVRSD_UINT64 = 3,
        _UVRSD_FLOAT = 4,
        _UVRSD_DOUBLE = 5,
    }
    use _Unwind_VRS_DataRepresentation::*;

    pub const UNWIND_POINTER_REG: c_int = 12;
    pub const UNWIND_SP_REG: c_int = 13;
    pub const UNWIND_IP_REG: c_int = 15;

    #[cfg_attr(all(feature = "llvm-libunwind",
                   any(target_os = "fuchsia", target_os = "linux")),
               link(name = "unwind", kind = "static"))]
    extern "C" {
        fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
                           regclass: _Unwind_VRS_RegClass,
                           regno: _Unwind_Word,
                           repr: _Unwind_VRS_DataRepresentation,
                           data: *mut c_void)
                           -> _Unwind_VRS_Result;

        fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
                           regclass: _Unwind_VRS_RegClass,
                           regno: _Unwind_Word,
                           repr: _Unwind_VRS_DataRepresentation,
                           data: *mut c_void)
                           -> _Unwind_VRS_Result;
    }

    // On Android or ARM/Linux, these are implemented as macros:

    pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
        let mut val: _Unwind_Word = 0;
        _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
                        &mut val as *mut _ as *mut c_void);
        val
    }

    pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
        let mut value = value;
        _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
                        &mut value as *mut _ as *mut c_void);
    }

    pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
                                -> _Unwind_Word {
        let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
        (val & !1) as _Unwind_Word
    }

    pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
                                value: _Unwind_Word) {
        // Propagate thumb bit to instruction pointer
        let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1;
        let value = value | thumb_state;
        _Unwind_SetGR(ctx, UNWIND_IP_REG, value);
    }

    pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
                                    ip_before_insn: *mut c_int)
                                    -> _Unwind_Word {
        *ip_before_insn = 0;
        _Unwind_GetIP(ctx)
    }

    // This function also doesn't exist on Android or ARM/Linux, so make it a no-op
    pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
        pc
    }
}
} // cfg_if!

cfg_if::cfg_if! {
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
    // Not 32-bit iOS
    #[cfg_attr(all(feature = "llvm-libunwind",
                   any(target_os = "fuchsia", target_os = "linux")),
               link(name = "unwind", kind = "static"))]
    extern "C" {
        #[unwind(allowed)]
        pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
        pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
                                 trace_argument: *mut c_void)
                                 -> _Unwind_Reason_Code;
    }
} else {
    // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
    #[cfg_attr(all(feature = "llvm-libunwind",
                   any(target_os = "fuchsia", target_os = "linux")),
               link(name = "unwind", kind = "static"))]
    extern "C" {
        #[unwind(allowed)]
        pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
    }

    #[inline]
    pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
        _Unwind_SjLj_RaiseException(exc)
    }
}
} // cfg_if!

cfg_if::cfg_if! {
if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
    // We declare these as opaque types. This is fine since you just need to
    // pass them to _GCC_specific_handler and forget about them.
    pub enum EXCEPTION_RECORD {}
    pub type LPVOID = *mut c_void;
    pub enum CONTEXT {}
    pub enum DISPATCHER_CONTEXT {}
    pub type EXCEPTION_DISPOSITION = c_int;
    type PersonalityFn = unsafe extern "C" fn(version: c_int,
                                              actions: _Unwind_Action,
                                              exception_class: _Unwind_Exception_Class,
                                              exception_object: *mut _Unwind_Exception,
                                              context: *mut _Unwind_Context)
                                              -> _Unwind_Reason_Code;

    extern "C" {
        pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
                                establisherFrame: LPVOID,
                                contextRecord: *mut CONTEXT,
                                dispatcherContext: *mut DISPATCHER_CONTEXT,
                                personality: PersonalityFn)
                                -> EXCEPTION_DISPOSITION;
    }
}
} // cfg_if!
<|endoftext|>


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

use hyper::client::Client;

use super::errors::*;
use super::msg;
use super::resp;
use super::net::Open189Client;

const URL_SMS_TOKEN: &'static str = "http://api.189.cn/v2/dm/randcode/token";
const URL_SMS_SEND_WITH_CODE: &'static str = "http://api.189.cn/v2/dm/randcode/sendSms";

pub struct Open189App {
    app_id: String,
    secret: String,
    client: Open189Client,
}

impl Open189App {
    pub fn new<S: AsRef<str>>(app_id: S, secret: S) -> Open189App {
        Open189App::with_client(app_id, secret, Client::new())
    }

    pub fn with_client<S: AsRef<str>>(app_id: S, secret: S, client: Client) -> Open189App {
        Open189App {
            app_id: app_id.as_ref().to_string(),
            secret: secret.as_ref().to_string(),
            client: Open189Client::new(client),
        }
    }

    pub fn app_id(&self) -> &str {
        &self.app_id
    }

    pub fn secret(&self) -> &str {
        &self.secret
    }

    pub fn get_access_token_cc(&self) -> Result<msg::AccessToken> {
        let mut params = HashMap::new();
        params.insert("grant_type", "client_credentials".to_string());
        self.client
            .perform_access_token_req::<_, resp::AccessTokenResponse>(self.app_id(),
                                                                      self.secret(),
                                                                      params)
    }

    pub fn sms_get_token<S: AsRef<str>>(&self, access_token: S) -> Result<String> {
        let params = HashMap::new();
        self.client.get_sync::<_, _, resp::SmsTokenResponse>(self.app_id(),
                                                             self.secret(),
                                                             access_token.as_ref(),
                                                             URL_SMS_TOKEN,
                                                             params)
    }
}

pub struct PreparedSmsCode<'a> {
    phone: &'a str,
    code: &'a str,
    expire_time: Option<usize>,
}

pub enum SmsCodeConfig<'a> {
    Prepared(PreparedSmsCode<'a>),
}

impl<'a> SmsCodeConfig<'a> {
    pub fn prepared(phone: &'a str,
                    code: &'a str,
                    expire_time: Option<usize>)
                    -> SmsCodeConfig<'a> {
        SmsCodeConfig::Prepared(PreparedSmsCode {
            phone: phone,
            code: code,
            expire_time: expire_time,
        })
    }
}

impl Open189App {
    pub fn sms_send_verification_code<S: AsRef<str>>(&self,
                                                     access_token: S,
                                                     sms_token: S,
                                                     config: SmsCodeConfig)
                                                     -> Result<msg::SentSmsCode> {
        let mut params = HashMap::new();
        params.insert("token", sms_token.as_ref().to_string());

        let url;
        match config {
            SmsCodeConfig::Prepared(config) => {
                url = URL_SMS_SEND_WITH_CODE;

                let code = config.code;
                if code.len() != 6 {
                    return Err(ErrorKind::WrongSmsCodeLength(code.len(), 6).into());
                }
                if !code.chars().all(|ch| ch.is_digit(10)) {
                    return Err(ErrorKind::NonDigitInSmsCode(code.to_string()).into());
                }
                params.insert("randcode", code.to_string());

                params.insert("phone", config.phone.to_string());
                if let Some(expire_time) = config.expire_time {
                    params.insert("exp_time", format!("{}", expire_time));
                }
            }
        }

        self.client.post_sync::<_, _, resp::SmsCodeResponse>(self.app_id(),
                                                             self.secret(),
                                                             access_token.as_ref(),
                                                             url,
                                                             params)
    }
}
<commit_msg>init(app): port callback SMS verification code generation from pyopen189<commit_after>use std::collections::HashMap;

use hyper::client::Client;
use hyper::client::IntoUrl;

use url::Url;

use super::errors::*;
use super::msg;
use super::resp;
use super::net::Open189Client;

const URL_SMS_TOKEN: &'static str = "http://api.189.cn/v2/dm/randcode/token";
const URL_SMS_SEND_WITH_CODE: &'static str = "http://api.189.cn/v2/dm/randcode/sendSms";
const URL_SMS_SEND_WITH_CALLBACK: &'static str = "http://api.189.cn/v2/dm/randcode/send";

pub struct Open189App {
    app_id: String,
    secret: String,
    client: Open189Client,
}

impl Open189App {
    pub fn new<S: AsRef<str>>(app_id: S, secret: S) -> Open189App {
        Open189App::with_client(app_id, secret, Client::new())
    }

    pub fn with_client<S: AsRef<str>>(app_id: S, secret: S, client: Client) -> Open189App {
        Open189App {
            app_id: app_id.as_ref().to_string(),
            secret: secret.as_ref().to_string(),
            client: Open189Client::new(client),
        }
    }

    pub fn app_id(&self) -> &str {
        &self.app_id
    }

    pub fn secret(&self) -> &str {
        &self.secret
    }

    pub fn get_access_token_cc(&self) -> Result<msg::AccessToken> {
        let mut params = HashMap::new();
        params.insert("grant_type", "client_credentials".to_string());
        self.client
            .perform_access_token_req::<_, resp::AccessTokenResponse>(self.app_id(),
                                                                      self.secret(),
                                                                      params)
    }

    pub fn sms_get_token<S: AsRef<str>>(&self, access_token: S) -> Result<String> {
        let params = HashMap::new();
        self.client.get_sync::<_, _, resp::SmsTokenResponse>(self.app_id(),
                                                             self.secret(),
                                                             access_token.as_ref(),
                                                             URL_SMS_TOKEN,
                                                             params)
    }
}

pub struct PreparedSmsCode<'a> {
    phone: &'a str,
    code: &'a str,
    expire_time: Option<usize>,
}

pub struct CallbackSmsCode<'a> {
    phone: &'a str,
    url: Url,
    expire_time: Option<usize>,
}

pub enum SmsCodeConfig<'a> {
    Prepared(PreparedSmsCode<'a>),
    Callback(CallbackSmsCode<'a>),
}

impl<'a> SmsCodeConfig<'a> {
    pub fn prepared(phone: &'a str,
                    code: &'a str,
                    expire_time: Option<usize>)
                    -> SmsCodeConfig<'a> {
        SmsCodeConfig::Prepared(PreparedSmsCode {
            phone: phone,
            code: code,
            expire_time: expire_time,
        })
    }

    pub fn callback<U: IntoUrl>(phone: &'a str,
                                callback_url: U,
                                expire_time: Option<usize>)
                                -> Result<SmsCodeConfig<'a>> {
        Ok(SmsCodeConfig::Callback(CallbackSmsCode {
            phone: phone,
            url: callback_url.into_url()?,
            expire_time: expire_time,
        }))
    }
}

impl Open189App {
    pub fn sms_send_verification_code<S: AsRef<str>>(&self,
                                                     access_token: S,
                                                     sms_token: S,
                                                     config: SmsCodeConfig)
                                                     -> Result<msg::SentSmsCode> {
        let mut params = HashMap::new();
        params.insert("token", sms_token.as_ref().to_string());

        let url;
        match config {
            SmsCodeConfig::Prepared(config) => {
                url = URL_SMS_SEND_WITH_CODE;

                let code = config.code;
                if code.len() != 6 {
                    return Err(ErrorKind::WrongSmsCodeLength(code.len(), 6).into());
                }
                if !code.chars().all(|ch| ch.is_digit(10)) {
                    return Err(ErrorKind::NonDigitInSmsCode(code.to_string()).into());
                }
                params.insert("randcode", code.to_string());

                params.insert("phone", config.phone.to_string());
                if let Some(expire_time) = config.expire_time {
                    params.insert("exp_time", format!("{}", expire_time));
                }
            }
            SmsCodeConfig::Callback(config) => {
                url = URL_SMS_SEND_WITH_CALLBACK;

                params.insert("phone", config.phone.to_string());
                params.insert("url", config.url.into_string());
                if let Some(expire_time) = config.expire_time {
                    params.insert("exp_time", format!("{}", expire_time));
                }
            }
        }

        self.client.post_sync::<_, _, resp::SmsCodeResponse>(self.app_id(),
                                                             self.secret(),
                                                             access_token.as_ref(),
                                                             url,
                                                             params)
    }
}
<|endoftext|>


<commit_before>

/*

*/

use machine;

#[derive(Debug)]
pub struct Grammar {
    rules : Vec<Pattern>,
    main : u32
}

#[derive(Debug)]
pub enum Pattern {
    CharClass(Vec<(u8, Option<u8>)>),
    CharSequence(Vec<u8>),
    CharAny,
    Variable(i32),
    Choice(Box<Pattern>, Box<Pattern>),
    ZeroOrMore(Box<Pattern>),
    OneOrMore(Box<Pattern>),
    Sequence(Vec<Box<Pattern>>),
    Optional(Box<Pattern>),
    Lookahead(bool, Box<Pattern>)
}

impl Grammar {
    pub fn compile(&mut self) -> Vec<machine::Instruction> {
        let mut rules = Vec::new();
        let mut lookup = vec![];

        for p in &self.rules {
            rules.push(Grammar::compile_pattern(p));
        }

        let mut result = vec![
            machine::Instruction::Call(self.main as isize),
            machine::Instruction::Stop
        ];

        let mut k = 2;
        for mut rule in rules {
            lookup.push(k);
            result.push(machine::Instruction::PushPos);
            result.append(&mut rule);
            result.push(machine::Instruction::SavePos);
            result.push(machine::Instruction::Return);
            k += 3 + rule.len();
        }

        for i in 0..result.len() {
            if let machine::Instruction::Call(r) = result[i] {
                let dist = lookup[r as usize] - i;
                result[i] = machine::Instruction::Call(dist as isize);
            }
        }
        result
    }

    pub fn compile_pattern(p : &Pattern) -> Vec<machine::Instruction> {
        match p {
            &Pattern::CharClass(ref data) => Grammar::compile_char_class(data),
            &Pattern::CharSequence(ref data) => Grammar::compile_char_sequence(data),
            &Pattern::CharAny => Grammar::compile_char_any(),
            &Pattern::Variable(id) => Grammar::compile_variable(id),
            &Pattern::Choice(ref le, ref ri) => Grammar::compile_choice(le, ri),
            &Pattern::ZeroOrMore(ref data) => Grammar::compile_zero_or_more(data),
            &Pattern::OneOrMore(ref data) => Grammar::compile_one_or_more(data),
            &Pattern::Sequence(ref data) => Grammar::compile_sequence(data),
            &Pattern::Optional(ref data) => Grammar::compile_optional(data),
            &Pattern::Lookahead(flag, ref data) => Grammar::compile_lookahead(flag, data)
        }
    }

    fn compile_char_class(data : &Vec<(u8, Option<u8>)>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut jump = data.len();
        for range in data.iter().take(data.len() - 1) {
            let left = (*range).0;
            let right = (*range).1.unwrap_or(left);
            result.push(machine::Instruction::CharRangeLink(left, right, jump as isize));
            jump -= 1;
        }

        if let Some(last) = data.iter().last() {
            let left = (*last).0;
            let right = (*last).1.unwrap_or(left);
            result.push(machine::Instruction::CharRange(left, right));
        }
        result
    }

    fn compile_char_sequence(data : &Vec<u8>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        for c in data {
            result.push(machine::Instruction::Char(*c));
        }
        result
    }

    fn compile_char_any() -> Vec<machine::Instruction> {
        vec![machine::Instruction::Any]
    }

    fn compile_variable(id : i32) -> Vec<machine::Instruction> {
        vec![machine::Instruction::Call(id as isize)]
    }

    fn compile_choice(left : &Box<Pattern>, right : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner_left = Grammar::compile_pattern(left);
        let mut inner_right = Grammar::compile_pattern(right);
        let mut result = vec![];
        result.push(machine::Instruction::Choice(inner_left.len() as isize + 2));
        result.append(&mut inner_left);
        result.push(machine::Instruction::Commit(inner_right.len() as isize + 1));
        result.append(&mut inner_right);
        result
    }

    fn compile_zero_or_more(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner = Grammar::compile_pattern(data);
        let instr_count = inner.len() as isize;
        let mut result = vec![];
        result.push(machine::Instruction::Choice(instr_count + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::PartialCommit(-instr_count));
        result
    }

    fn compile_one_or_more(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner = Grammar::compile_pattern(data);
        let instr_count = inner.len() as isize;
        let mut result = vec![];
        result.append(&mut inner);
        result.push(machine::Instruction::Choice(instr_count + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::PartialCommit(-instr_count));
        result
    }

    fn compile_sequence(data : &Vec<Box<Pattern>>) -> Vec<machine::Instruction> {
        let mut result = vec![];

        for p in data {
            let mut inner = Grammar::compile_pattern(p);
            result.append(&mut inner);
        }
        result
    }

    fn compile_optional(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut inner = Grammar::compile_pattern(data);

        result.push(machine::Instruction::Choice(inner.len() as isize + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::Commit(1));
        result
    }

    fn compile_lookahead(success : bool, data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut inner = Grammar::compile_pattern(data);
        let mut instr_count = inner.len() as isize;
        if success {
            result.push(machine::Instruction::Choice(instr_count + 5));
            result.push(machine::Instruction::Choice(instr_count + 2));
            result.append(&mut inner);
            result.push(machine::Instruction::FailTwice);
            result.push(machine::Instruction::FailTwice);
        } else {
            result.push(machine::Instruction::Choice(instr_count + 2));
            result.append(&mut inner);
            result.push(machine::Instruction::FailTwice);
        }
        result
    }
}
<commit_msg>Fix compile_one_or_more bug<commit_after>

/*

*/

use machine;

#[derive(Debug)]
pub struct Grammar {
    rules : Vec<Pattern>,
    main : u32
}

#[derive(Debug)]
pub enum Pattern {
    CharClass(Vec<(u8, Option<u8>)>),
    CharSequence(Vec<u8>),
    CharAny,
    Variable(i32),
    Choice(Box<Pattern>, Box<Pattern>),
    ZeroOrMore(Box<Pattern>),
    OneOrMore(Box<Pattern>),
    Sequence(Vec<Box<Pattern>>),
    Optional(Box<Pattern>),
    Lookahead(bool, Box<Pattern>)
}

impl Grammar {
    pub fn compile(&mut self) -> Vec<machine::Instruction> {
        let mut rules = Vec::new();
        let mut lookup = vec![];

        for p in &self.rules {
            rules.push(Grammar::compile_pattern(p));
        }

        let mut result = vec![
            machine::Instruction::Call(self.main as isize),
            machine::Instruction::Stop
        ];

        let mut k = 2;
        for mut rule in rules {
            lookup.push(k);
            result.push(machine::Instruction::PushPos);
            result.append(&mut rule);
            result.push(machine::Instruction::SavePos);
            result.push(machine::Instruction::Return);
            k += 3 + rule.len();
        }

        for i in 0..result.len() {
            if let machine::Instruction::Call(r) = result[i] {
                let dist = lookup[r as usize] - i;
                result[i] = machine::Instruction::Call(dist as isize);
            }
        }
        result
    }

    pub fn compile_pattern(p : &Pattern) -> Vec<machine::Instruction> {
        match p {
            &Pattern::CharClass(ref data) => Grammar::compile_char_class(data),
            &Pattern::CharSequence(ref data) => Grammar::compile_char_sequence(data),
            &Pattern::CharAny => Grammar::compile_char_any(),
            &Pattern::Variable(id) => Grammar::compile_variable(id),
            &Pattern::Choice(ref le, ref ri) => Grammar::compile_choice(le, ri),
            &Pattern::ZeroOrMore(ref data) => Grammar::compile_zero_or_more(data),
            &Pattern::OneOrMore(ref data) => Grammar::compile_one_or_more(data),
            &Pattern::Sequence(ref data) => Grammar::compile_sequence(data),
            &Pattern::Optional(ref data) => Grammar::compile_optional(data),
            &Pattern::Lookahead(flag, ref data) => Grammar::compile_lookahead(flag, data)
        }
    }

    fn compile_char_class(data : &Vec<(u8, Option<u8>)>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut jump = data.len();
        for range in data.iter().take(data.len() - 1) {
            let left = (*range).0;
            let right = (*range).1.unwrap_or(left);
            result.push(machine::Instruction::CharRangeLink(left, right, jump as isize));
            jump -= 1;
        }

        if let Some(last) = data.iter().last() {
            let left = (*last).0;
            let right = (*last).1.unwrap_or(left);
            result.push(machine::Instruction::CharRange(left, right));
        }
        result
    }

    fn compile_char_sequence(data : &Vec<u8>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        for c in data {
            result.push(machine::Instruction::Char(*c));
        }
        result
    }

    fn compile_char_any() -> Vec<machine::Instruction> {
        vec![machine::Instruction::Any]
    }

    fn compile_variable(id : i32) -> Vec<machine::Instruction> {
        vec![machine::Instruction::Call(id as isize)]
    }

    fn compile_choice(left : &Box<Pattern>, right : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner_left = Grammar::compile_pattern(left);
        let mut inner_right = Grammar::compile_pattern(right);
        let mut result = vec![];
        result.push(machine::Instruction::Choice(inner_left.len() as isize + 2));
        result.append(&mut inner_left);
        result.push(machine::Instruction::Commit(inner_right.len() as isize + 1));
        result.append(&mut inner_right);
        result
    }

    fn compile_zero_or_more(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner = Grammar::compile_pattern(data);
        let instr_count = inner.len() as isize;
        let mut result = vec![];
        result.push(machine::Instruction::Choice(instr_count + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::PartialCommit(-instr_count));
        result
    }

    fn compile_one_or_more(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner = Grammar::compile_pattern(data);
        let mut inner_clone = inner.clone();
        let instr_count = inner.len() as isize;
        let mut result = vec![];
        result.append(&mut inner_clone);
        result.push(machine::Instruction::Choice(instr_count + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::PartialCommit(-instr_count));
        result
    }

    fn compile_sequence(data : &Vec<Box<Pattern>>) -> Vec<machine::Instruction> {
        let mut result = vec![];

        for p in data {
            let mut inner = Grammar::compile_pattern(p);
            result.append(&mut inner);
        }
        result
    }

    fn compile_optional(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut inner = Grammar::compile_pattern(data);

        result.push(machine::Instruction::Choice(inner.len() as isize + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::Commit(1));
        result
    }

    fn compile_lookahead(success : bool, data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut inner = Grammar::compile_pattern(data);
        let mut instr_count = inner.len() as isize;
        if success {
            result.push(machine::Instruction::Choice(instr_count + 5));
            result.push(machine::Instruction::Choice(instr_count + 2));
            result.append(&mut inner);
            result.push(machine::Instruction::FailTwice);
            result.push(machine::Instruction::FailTwice);
        } else {
            result.push(machine::Instruction::Choice(instr_count + 2));
            result.append(&mut inner);
            result.push(machine::Instruction::FailTwice);
        }
        result
    }
}
<|endoftext|>