<commit_before>use {N, P2, THICKNESS};
use rough_eq::RoughEq;

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Intersection {
    pub along_a: N,
    pub along_b: N,
    pub position: P2,
}

pub trait Intersect {
    fn intersect(&self) -> Vec<Intersection>;
}

use line_path::LineSegment;

impl Intersect for (LineSegment, LineSegment) {
    fn intersect(&self) -> Vec<Intersection> {
        let (a, b) = *self;
        let a_direction = a.direction();
        let b_direction = b.direction();

        match (
            b.project_with_max_distance(a.start(), THICKNESS, THICKNESS),
            b.project_with_max_distance(a.end(), THICKNESS, THICKNESS),
            a.project_with_max_distance(b.start(), THICKNESS, THICKNESS),
            a.project_with_max_distance(b.end(), THICKNESS, THICKNESS),
        ) {
            // a rough subset of b
            (Some((a_start_along_b, _)), Some((a_end_along_b, _)), ..) => vec![
                Intersection {
                    along_a: 0.0,
                    along_b: a_start_along_b,
                    position: a.start(),
                },
                Intersection {
                    along_a: a.length(),
                    along_b: a_end_along_b,
                    position: a.end(),
                },
            ],
            // b rough subset of a
            (_, _, Some((b_start_along_a, _)), Some((b_end_along_a, _))) => vec![
                Intersection {
                    along_b: 0.0,
                    along_a: b_start_along_a,
                    position: b.start(),
                },
                Intersection {
                    along_b: b.length(),
                    along_a: b_end_along_a,
                    position: b.end(),
                },
            ],
            // single point touches at ends
            (Some((a_start_along_b, _)), None, ..) => vec![Intersection {
                along_a: 0.0,
                along_b: a_start_along_b,
                position: a.start(),
            }],
            (None, Some((a_end_along_b, _)), ..) => vec![Intersection {
                along_a: a.length(),
                along_b: a_end_along_b,
                position: a.end(),
            }],
            (_, _, Some((b_start_along_a, _)), None) => vec![Intersection {
                along_b: 0.0,
                along_a: b_start_along_a,
                position: b.start(),
            }],
            (_, _, None, Some((b_end_along_a, _))) => vec![Intersection {
                along_b: b.length(),
                along_a: b_end_along_a,
                position: b.end(),
            }],
            (None, None, None, None) => {
                let det = b_direction.x * a_direction.y - b_direction.y * a_direction.x;
                let parallel = det.rough_eq(0.0);
                if parallel {
                    // parallel and apart
                    vec![]
                } else {
                    let delta = b.start() - a.start();
                    let along_a = (delta.y * b_direction.x - delta.x * b_direction.y) / det;
                    let along_b = (delta.y * a_direction.x - delta.x * a_direction.y) / det;

                    if along_a > -THICKNESS
                        && along_b > -THICKNESS
                        && along_a < a.length() + THICKNESS
                        && along_b < b.length() + THICKNESS
                    {
                        // single point roughly within segments
                        vec![Intersection {
                            along_a,
                            along_b,
                            position: a.start() + a_direction * along_a,
                        }]
                    } else {
                        // single point outside of segments
                        vec![]
                    }
                }
            }
        }
    }
}

use line_path::LinePath;

impl<'a, 'b> Intersect for (&'a LinePath, &'b LinePath) {
    fn intersect(&self) -> Vec<Intersection> {
        let mut intersections = Vec::<Intersection>::new();
        let (a, b) = *self;

        for (segment_a, a_distance_pair) in a.segments_with_distances() {
            for (segment_b, b_distance_pair) in b.segments_with_distances() {
                for intersection in (segment_a, segment_b).intersect() {
                    let close_exists = intersections.iter().any(|existing| {
                        existing
                            .position
                            .rough_eq_by(intersection.position, THICKNESS)
                    });

                    if !close_exists {
                        intersections.push(Intersection {
                            along_a: a_distance_pair[0] + intersection.along_a,
                            along_b: b_distance_pair[0] + intersection.along_b,
                            position: intersection.position,
                        })
                    }
                }
            }
        }

        intersections
    }
}

#[cfg(test)]
const TINY_BIT: N = THICKNESS / 3.0;

#[test]
fn line_segments_apart() {
    // ----
    // ----

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(0.0, 1.0), P2::new(1.0, 1.0)),
        ).intersect(),
        vec![]
    );

    // ----  /
    //      /

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(0.0, 1.0), P2::new(2.0, 0.0)),
        ).intersect(),
        vec![]
    );

    // ----  ----

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(2.0, 0.0), P2::new(3.0, 0.0)),
        ).intersect(),
        vec![]
    );
}

use closed_line_path::ClosedLinePath;

#[test]
fn line_segments_intersecting() {
    //    /
    // --/--
    //  /

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(0.0, 1.0), P2::new(1.0, -1.0)),
        ).intersect(),
        vec![Intersection {
            along_a: 0.5,
            along_b: 1.118034,
            position: P2::new(0.5, 0.0),
        }]
    );

    // |
    // |----
    // |

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(0.0, 1.0), P2::new(0.0, -1.0)),
        ).intersect(),
        vec![Intersection {
            along_a: 0.0,
            along_b: 1.0,
            position: P2::new(0.0, 0.0),
        }]
    );
}

#[test]
fn line_segments_barely_intersecting() {
    // |
    // (----
    // |

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(-TINY_BIT, 1.0), P2::new(-TINY_BIT, -1.0)),
        ).intersect(),
        vec![Intersection {
            along_a: 0.0,
            along_b: 1.0,
            position: P2::new(0.0, 0.0),
        }]
    );
}

#[cfg(test)]
use curved_path::CurvedPath;

impl<'a, 'b> Intersect for (&'a ClosedLinePath, &'b ClosedLinePath) {
    fn intersect(&self) -> Vec<Intersection> {
        let (a, b) = *self;
        (a.path(), b.path()).intersect()
    }
}

#[test]
fn path_intersecting_at_curved_segment_start() {
    use V2;
    //     |
    // ----|-.
    //     |  \
    assert_eq!(
        (
            &CurvedPath::line(P2::new(0.0, 0.0), P2::new(1.0, 0.0))
                .unwrap()
                .concat(
                    &CurvedPath::arc(P2::new(1.0, 0.0), V2::new(1.0, 0.0), P2::new(2.0, 1.0),)
                        .unwrap()
                )
                .unwrap()
                .to_line_path(),
            &LinePath::new(vec![P2::new(1.0, 1.0), P2::new(1.0, -1.0)]).unwrap(),
        ).intersect(),
        vec![Intersection {
            along_a: 1.0,
            along_b: 1.0,
            position: P2::new(1.0, 0.0),
        }]
    );
}

#[test]
fn path_intersecting_close_before_curved_segment_start() {
    use V2;
    //     |
    // ----(-.
    //     |  \
    assert_eq!(
        (
            &CurvedPath::line(P2::new(0.0, 0.0), P2::new(1.0, 0.0))
                .unwrap()
                .concat(
                    &CurvedPath::arc(P2::new(1.0, 0.0), V2::new(1.0, 0.0), P2::new(2.0, 1.0),)
                        .unwrap()
                )
                .unwrap()
                .to_line_path(),
            &LinePath::new(vec![
                P2::new(1.0 - TINY_BIT, 1.0),
                P2::new(1.0 - TINY_BIT, -1.0),
            ]).unwrap(),
        ).intersect(),
        vec![Intersection {
            along_a: 1.0,
            along_b: 1.0,
            position: P2::new(1.0, 0.0),
        }]
    );
}

#[test]
fn path_intersecting_close_after_curved_segment_start() {
    use V2;
    //     |
    // ----)-.
    //     |  \
    assert_eq!(
        (
            &CurvedPath::line(P2::new(0.0, 0.0), P2::new(1.0, 0.0))
                .unwrap()
                .concat(
                    &CurvedPath::arc(P2::new(1.0, 0.0), V2::new(1.0, 0.0), P2::new(2.0, 1.0),)
                        .unwrap()
                )
                .unwrap()
                .to_line_path(),
            &LinePath::new(vec![
                P2::new(1.0 - TINY_BIT, 1.0),
                P2::new(1.0 - TINY_BIT, -1.0),
            ]).unwrap(),
        ).intersect(),
        vec![Intersection {
            along_a: 1.0,
            along_b: 1.0,
            position: P2::new(1.0, 0.0),
        }]
    );
}
<commit_msg>use bounding boxes again<commit_after>use {N, P2, THICKNESS};
use rough_eq::RoughEq;

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Intersection {
    pub along_a: N,
    pub along_b: N,
    pub position: P2,
}

pub trait Intersect {
    fn intersect(&self) -> Vec<Intersection>;
}

use line_path::LineSegment;
use bbox::HasBoundingBox;

impl Intersect for (LineSegment, LineSegment) {
    fn intersect(&self) -> Vec<Intersection> {
        let (a, b) = *self;

        if !a.bounding_box().overlaps(&b.bounding_box()) {
            return vec![];
        }

        let a_direction = a.direction();
        let b_direction = b.direction();

        match (
            b.project_with_max_distance(a.start(), THICKNESS, THICKNESS),
            b.project_with_max_distance(a.end(), THICKNESS, THICKNESS),
            a.project_with_max_distance(b.start(), THICKNESS, THICKNESS),
            a.project_with_max_distance(b.end(), THICKNESS, THICKNESS),
        ) {
            // a rough subset of b
            (Some((a_start_along_b, _)), Some((a_end_along_b, _)), ..) => vec![
                Intersection {
                    along_a: 0.0,
                    along_b: a_start_along_b,
                    position: a.start(),
                },
                Intersection {
                    along_a: a.length(),
                    along_b: a_end_along_b,
                    position: a.end(),
                },
            ],
            // b rough subset of a
            (_, _, Some((b_start_along_a, _)), Some((b_end_along_a, _))) => vec![
                Intersection {
                    along_b: 0.0,
                    along_a: b_start_along_a,
                    position: b.start(),
                },
                Intersection {
                    along_b: b.length(),
                    along_a: b_end_along_a,
                    position: b.end(),
                },
            ],
            // single point touches at ends
            (Some((a_start_along_b, _)), None, ..) => vec![Intersection {
                along_a: 0.0,
                along_b: a_start_along_b,
                position: a.start(),
            }],
            (None, Some((a_end_along_b, _)), ..) => vec![Intersection {
                along_a: a.length(),
                along_b: a_end_along_b,
                position: a.end(),
            }],
            (_, _, Some((b_start_along_a, _)), None) => vec![Intersection {
                along_b: 0.0,
                along_a: b_start_along_a,
                position: b.start(),
            }],
            (_, _, None, Some((b_end_along_a, _))) => vec![Intersection {
                along_b: b.length(),
                along_a: b_end_along_a,
                position: b.end(),
            }],
            (None, None, None, None) => {
                let det = b_direction.x * a_direction.y - b_direction.y * a_direction.x;
                let parallel = det.rough_eq(0.0);
                if parallel {
                    // parallel and apart
                    vec![]
                } else {
                    let delta = b.start() - a.start();
                    let along_a = (delta.y * b_direction.x - delta.x * b_direction.y) / det;
                    let along_b = (delta.y * a_direction.x - delta.x * a_direction.y) / det;

                    if along_a > -THICKNESS
                        && along_b > -THICKNESS
                        && along_a < a.length() + THICKNESS
                        && along_b < b.length() + THICKNESS
                    {
                        // single point roughly within segments
                        vec![Intersection {
                            along_a,
                            along_b,
                            position: a.start() + a_direction * along_a,
                        }]
                    } else {
                        // single point outside of segments
                        vec![]
                    }
                }
            }
        }
    }
}

use line_path::LinePath;

impl<'a, 'b> Intersect for (&'a LinePath, &'b LinePath) {
    fn intersect(&self) -> Vec<Intersection> {
        let mut intersections = Vec::<Intersection>::new();
        let (a, b) = *self;

        for (segment_a, a_distance_pair) in a.segments_with_distances() {
            for (segment_b, b_distance_pair) in b.segments_with_distances() {
                for intersection in (segment_a, segment_b).intersect() {
                    let close_exists = intersections.iter().any(|existing| {
                        existing
                            .position
                            .rough_eq_by(intersection.position, THICKNESS)
                    });

                    if !close_exists {
                        intersections.push(Intersection {
                            along_a: a_distance_pair[0] + intersection.along_a,
                            along_b: b_distance_pair[0] + intersection.along_b,
                            position: intersection.position,
                        })
                    }
                }
            }
        }

        intersections
    }
}

#[cfg(test)]
const TINY_BIT: N = THICKNESS / 3.0;

#[test]
fn line_segments_apart() {
    // ----
    // ----

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(0.0, 1.0), P2::new(1.0, 1.0)),
        ).intersect(),
        vec![]
    );

    // ----  /
    //      /

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(0.0, 1.0), P2::new(2.0, 0.0)),
        ).intersect(),
        vec![]
    );

    // ----  ----

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(2.0, 0.0), P2::new(3.0, 0.0)),
        ).intersect(),
        vec![]
    );
}

use closed_line_path::ClosedLinePath;

#[test]
fn line_segments_intersecting() {
    //    /
    // --/--
    //  /

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(0.0, 1.0), P2::new(1.0, -1.0)),
        ).intersect(),
        vec![Intersection {
            along_a: 0.5,
            along_b: 1.118034,
            position: P2::new(0.5, 0.0),
        }]
    );

    // |
    // |----
    // |

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(0.0, 1.0), P2::new(0.0, -1.0)),
        ).intersect(),
        vec![Intersection {
            along_a: 0.0,
            along_b: 1.0,
            position: P2::new(0.0, 0.0),
        }]
    );
}

#[test]
fn line_segments_barely_intersecting() {
    // |
    // (----
    // |

    assert_eq!(
        (
            LineSegment(P2::new(0.0, 0.0), P2::new(1.0, 0.0)),
            LineSegment(P2::new(-TINY_BIT, 1.0), P2::new(-TINY_BIT, -1.0)),
        ).intersect(),
        vec![Intersection {
            along_a: 0.0,
            along_b: 1.0,
            position: P2::new(0.0, 0.0),
        }]
    );
}

#[cfg(test)]
use curved_path::CurvedPath;

impl<'a, 'b> Intersect for (&'a ClosedLinePath, &'b ClosedLinePath) {
    fn intersect(&self) -> Vec<Intersection> {
        let (a, b) = *self;
        (a.path(), b.path()).intersect()
    }
}

#[test]
fn path_intersecting_at_curved_segment_start() {
    use V2;
    //     |
    // ----|-.
    //     |  \
    assert_eq!(
        (
            &CurvedPath::line(P2::new(0.0, 0.0), P2::new(1.0, 0.0))
                .unwrap()
                .concat(
                    &CurvedPath::arc(P2::new(1.0, 0.0), V2::new(1.0, 0.0), P2::new(2.0, 1.0),)
                        .unwrap()
                )
                .unwrap()
                .to_line_path(),
            &LinePath::new(vec![P2::new(1.0, 1.0), P2::new(1.0, -1.0)]).unwrap(),
        ).intersect(),
        vec![Intersection {
            along_a: 1.0,
            along_b: 1.0,
            position: P2::new(1.0, 0.0),
        }]
    );
}

#[test]
fn path_intersecting_close_before_curved_segment_start() {
    use V2;
    //     |
    // ----(-.
    //     |  \
    assert_eq!(
        (
            &CurvedPath::line(P2::new(0.0, 0.0), P2::new(1.0, 0.0))
                .unwrap()
                .concat(
                    &CurvedPath::arc(P2::new(1.0, 0.0), V2::new(1.0, 0.0), P2::new(2.0, 1.0),)
                        .unwrap()
                )
                .unwrap()
                .to_line_path(),
            &LinePath::new(vec![
                P2::new(1.0 - TINY_BIT, 1.0),
                P2::new(1.0 - TINY_BIT, -1.0),
            ]).unwrap(),
        ).intersect(),
        vec![Intersection {
            along_a: 1.0,
            along_b: 1.0,
            position: P2::new(1.0, 0.0),
        }]
    );
}

#[test]
fn path_intersecting_close_after_curved_segment_start() {
    use V2;
    //     |
    // ----)-.
    //     |  \
    assert_eq!(
        (
            &CurvedPath::line(P2::new(0.0, 0.0), P2::new(1.0, 0.0))
                .unwrap()
                .concat(
                    &CurvedPath::arc(P2::new(1.0, 0.0), V2::new(1.0, 0.0), P2::new(2.0, 1.0),)
                        .unwrap()
                )
                .unwrap()
                .to_line_path(),
            &LinePath::new(vec![
                P2::new(1.0 - TINY_BIT, 1.0),
                P2::new(1.0 - TINY_BIT, -1.0),
            ]).unwrap(),
        ).intersect(),
        vec![Intersection {
            along_a: 1.0,
            along_b: 1.0,
            position: P2::new(1.0, 0.0),
        }]
    );
}
<|endoftext|>


<commit_before>extern crate orbclient;

use orbclient::Color;

use std::env;
use std::io::{Read, Write};
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::thread;

use window::{ConsoleEvent, ConsoleWindow};

mod window;

fn main() {
    let mut window = ConsoleWindow::new(-1, -1, 576, 400, "Terminal");

    let shell = env::args().nth(1).unwrap_or("sh".to_string());
    match Command::new(&shell)
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
    {
        Ok(process) => {
            let output_mutex = Arc::new(Mutex::new(Vec::new()));

            {
                let mut stdout = process.stdout.unwrap();
                let stdout_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    'stdout: loop {
                        let mut buf = [0; 4096];
                        match stdout.read(&mut buf) {
                            Ok(0) => break 'stdout,
                            Ok(count) => match stdout_output_mutex.lock() {
                                Ok(mut stdout_output) => stdout_output.extend_from_slice(&buf[..count]),
                                Err(err) => {
                                    println!("failed to lock stdout output mutex: {}", err);
                                    break 'stdout;
                                }
                            },
                            Err(err) => {
                                println!("failed to read stdout: {}", err);
                                break 'stdout;
                            }
                        }
                    }
                });
            }

            {
                let mut stderr = process.stderr.unwrap();
                let stderr_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    'stderr: loop {
                        let mut buf = [0; 4096];
                        match stderr.read(&mut buf) {
                            Ok(0) => break 'stderr,
                            Ok(count) => match stderr_output_mutex.lock() {
                                Ok(mut stderr_output) => stderr_output.extend_from_slice(&buf[..count]),
                                Err(err) => {
                                    println!("failed to lock stderr output mutex: {}", err);
                                    break 'stderr;
                                }
                            },
                            Err(err) => {
                                println!("failed to read stderr: {}", err);
                                break 'stderr;
                            }
                        }
                    }
                });
            }

            let mut stdin = process.stdin.unwrap();
            'events: loop {
                match output_mutex.lock() {
                    Ok(mut output) => {
                        let mut string = String::new();
                        for byte in output.drain(..) {
                            string.push(byte as char);
                        }
                        window.print(&string, Color::rgb(255, 255, 255));
                    },
                    Err(err) => {
                        println!("failed to lock print output mutex: {}", err);
                        break 'events;
                    }
                }

                for console_event in window.read() {
                    match console_event {
                        ConsoleEvent::Line(mut line) => {
                            line.push('\n');
                            match stdin.write(&line.as_bytes()) {
                                Ok(_) => (),
                                Err(err) => {
                                    println!("failed to write stdin: {}", err);
                                    break 'events;
                                }
                            }
                        },
                        ConsoleEvent::Quit => break 'events
                    }
                }

                thread::sleep_ms(30);
            }
        },
        Err(err) => println!("failed to execute '{}': {}\n", shell, err)
    }
}
<commit_msg>Ignore error messages on lock to fix redox compat<commit_after>extern crate orbclient;

use orbclient::Color;

use std::env;
use std::io::{Read, Write};
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::thread;

use window::{ConsoleEvent, ConsoleWindow};

mod window;

fn main() {
    let mut window = ConsoleWindow::new(-1, -1, 576, 400, "Terminal");

    let shell = env::args().nth(1).unwrap_or("sh".to_string());
    match Command::new(&shell)
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
    {
        Ok(process) => {
            let output_mutex = Arc::new(Mutex::new(Vec::new()));

            {
                let mut stdout = process.stdout.unwrap();
                let stdout_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    'stdout: loop {
                        let mut buf = [0; 4096];
                        match stdout.read(&mut buf) {
                            Ok(0) => break 'stdout,
                            Ok(count) => match stdout_output_mutex.lock() {
                                Ok(mut stdout_output) => stdout_output.extend_from_slice(&buf[..count]),
                                Err(_) => {
                                    println!("failed to lock stdout output mutex");
                                    break 'stdout;
                                }
                            },
                            Err(err) => {
                                println!("failed to read stdout: {}", err);
                                break 'stdout;
                            }
                        }
                    }
                });
            }

            {
                let mut stderr = process.stderr.unwrap();
                let stderr_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    'stderr: loop {
                        let mut buf = [0; 4096];
                        match stderr.read(&mut buf) {
                            Ok(0) => break 'stderr,
                            Ok(count) => match stderr_output_mutex.lock() {
                                Ok(mut stderr_output) => stderr_output.extend_from_slice(&buf[..count]),
                                Err(_) => {
                                    println!("failed to lock stderr output mutex");
                                    break 'stderr;
                                }
                            },
                            Err(err) => {
                                println!("failed to read stderr: {}", err);
                                break 'stderr;
                            }
                        }
                    }
                });
            }

            let mut stdin = process.stdin.unwrap();
            'events: loop {
                match output_mutex.lock() {
                    Ok(mut output) => {
                        let mut string = String::new();
                        for byte in output.drain(..) {
                            string.push(byte as char);
                        }
                        window.print(&string, Color::rgb(255, 255, 255));
                    },
                    Err(_) => {
                        println!("failed to lock print output mutex");
                        break 'events;
                    }
                }

                for console_event in window.read() {
                    match console_event {
                        ConsoleEvent::Line(mut line) => {
                            line.push('\n');
                            match stdin.write(&line.as_bytes()) {
                                Ok(_) => (),
                                Err(err) => {
                                    println!("failed to write stdin: {}", err);
                                    break 'events;
                                }
                            }
                        },
                        ConsoleEvent::Quit => break 'events
                    }
                }

                thread::sleep_ms(30);
            }
        },
        Err(err) => println!("failed to execute '{}': {}\n", shell, err)
    }
}
<|endoftext|>


<commit_before>//! VM Runtime
use utils::bigint::M256;
use utils::gas::Gas;
use utils::address::Address;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Memory, AccountCommitment, Log};

use std::str::FromStr;

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas, code_deposit_gas};
use self::utils::copy_into_memory;

mod cost;
mod run;
mod check;
mod utils;

/// A VM state without PC.
pub struct State<M> {
    pub memory: M,
    pub stack: Stack,

    pub context: Context,
    pub block: BlockHeader,
    pub patch: &'static Patch,

    pub out: Vec<u8>,

    pub memory_cost: Gas,
    pub used_gas: Gas,
    pub refunded_gas: Gas,

    pub account_state: AccountState,
    pub blockhash_state: BlockhashState,
    pub logs: Vec<Log>,

    pub depth: usize,
}

impl<M> State<M> {
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M> {
    state: State<M>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
/// Represents the current runtime status.
pub enum MachineStatus {
    /// This runtime is actively running or has just been started.
    Running,
    /// This runtime has exited successfully. Calling `step` on this
    /// runtime again would panic.
    ExitedOk,
    /// This runtime has exited with errors. Calling `step` on this
    /// runtime again would panic.
    ExitedErr(MachineError),
    /// This runtime requires execution of a sub runtime, which is a
    /// ContractCreation instruction.
    InvokeCreate(Context),
    /// This runtime requires execution of a sub runtime, which is a
    /// MessageCall instruction.
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
/// Used for `check` for additional checks related to the runtime.
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
/// Used for `step` for additional operations related to the runtime.
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default> Machine<M> {
    /// Create a new runtime.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: block,
                patch: patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: AccountState::default(),
                blockhash_state: BlockhashState::default(),
                logs: Vec::new(),

                depth: depth,
            },
        }
    }

    /// Derive this runtime to create a sub runtime. This will not
    /// modify the current runtime, and it will have a chance to
    /// review whether it wants to accept the result of this sub
    /// runtime afterwards.
    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    /// Commit a new account into this runtime.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    /// Commit a new blockhash into this runtime.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    #[allow(unused_variables)]
    /// Apply a sub runtime into the current runtime. This sub runtime
    /// should have been created by the current runtime's `derive`
    /// function. Depending whether the current runtime is invoking a
    /// ContractCreation or MessageCall instruction, it will apply
    /// various states back.
    pub fn apply_sub(&mut self, sub: Machine<M>) {
        use std::mem::swap;
        let mut status = MachineStatus::Running;
        swap(&mut status, &mut self.status);
        match status {
            MachineStatus::InvokeCreate(_) => {
                self.apply_create(sub);
            },
            MachineStatus::InvokeCall(_, (out_start, out_len)) => {
                self.apply_call(sub, out_start, out_len);
            },
            _ => panic!(),
        }
    }

    fn apply_create(&mut self, sub: Machine<M>) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                if self.state.available_gas() >= code_deposit_gas(sub.state.out.len()) {
                    self.state.account_state.decrease_balance(self.state.context.address,
                                                              sub.state.context.value);
                    self.state.account_state.create(sub.state.context.address,
                                                    sub.state.context.value,
                                                    sub.state.out.as_slice());
                }

            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                // self.state.stack.pop().unwrap();
                // self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    fn apply_call(&mut self, sub: Machine<M>, out_start: M256, out_len: M256) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                self.state.account_state.decrease_balance(self.state.context.address,
                                                          sub.state.context.value);
                self.state.account_state.increase_balance(sub.state.context.address,
                                                          sub.state.context.value);
                copy_into_memory(&mut self.state.memory, sub.state.out.as_slice(),
                                 out_start, M256::zero(), out_len);
            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::from(1u64)).unwrap();
            },
            _ => panic!(),
        }
    }

    /// Check the next instruction about whether it will return
    /// errors.
    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.into()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    #[allow(unused_variables)]
    fn step_precompiled(&mut self) -> bool {
        let ecrec_address = Address::from_str("0x0000000000000000000000000000000000000001").unwrap();
        let sha256_address = Address::from_str("0x0000000000000000000000000000000000000002").unwrap();
        let rip160_address = Address::from_str("0x0000000000000000000000000000000000000003").unwrap();
        let id_address = Address::from_str("0x0000000000000000000000000000000000000004").unwrap();

        if self.state.context.address == id_address {
            let gas = Gas::from(15u64) +
                Gas::from(3u64) * (Gas::from(self.state.context.data.len()) / Gas::from(32u64));
            if gas > self.state.context.gas_limit {
                self.state.used_gas = self.state.context.gas_limit;
                self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            } else {
                self.state.used_gas = gas;
                self.state.out = self.state.context.data.clone();
                self.status = MachineStatus::ExitedOk;
            }
            return true;
        } else {
            return false;
        }
    }

    /// Step an instruction in the PC. The eval result is refected by
    /// the runtime status, and it will only return an error if
    /// there're accounts or blockhashes to be committed to this
    /// runtime for it to run. In that case, the state of the current
    /// runtime will not be affected.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.step_precompiled() {
            return Ok(());
        }

        if self.state.depth >= 2 {
            self.status = MachineStatus::ExitedErr(MachineError::CallstackOverflow);
            return Ok(());
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);
        let after_gas = self.state.context.gas_limit - memory_gas - self.state.used_gas - gas_cost + gas_stipend;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        if self.state.context.gas_limit < memory_gas + self.state.used_gas + gas_cost - gas_stipend {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.into()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    /// Get the runtime state.
    pub fn state(&self) -> &State<M> {
        &self.state
    }

    /// Get the current runtime status.
    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<commit_msg>Problem: #152 wrapping transactions for VM<commit_after>//! VM Runtime
use utils::bigint::M256;
use utils::gas::Gas;
use utils::address::Address;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Memory, AccountCommitment, Log};

use std::str::FromStr;

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas, code_deposit_gas};
use self::utils::copy_into_memory;

mod cost;
mod run;
mod check;
mod utils;

/// A VM state without PC.
pub struct State<M> {
    pub memory: M,
    pub stack: Stack,

    pub context: Context,
    pub block: BlockHeader,
    pub patch: &'static Patch,

    pub out: Vec<u8>,

    pub memory_cost: Gas,
    pub used_gas: Gas,
    pub refunded_gas: Gas,

    pub account_state: AccountState,
    pub blockhash_state: BlockhashState,
    pub logs: Vec<Log>,

    pub depth: usize,
}

impl<M> State<M> {
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M> {
    state: State<M>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
/// Represents the current runtime status.
pub enum MachineStatus {
    /// This runtime is actively running or has just been started.
    Running,
    /// This runtime has exited successfully. Calling `step` on this
    /// runtime again would panic.
    ExitedOk,
    /// This runtime has exited with errors. Calling `step` on this
    /// runtime again would panic.
    ExitedErr(MachineError),
    /// This runtime requires execution of a sub runtime, which is a
    /// ContractCreation instruction.
    InvokeCreate(Context),
    /// This runtime requires execution of a sub runtime, which is a
    /// MessageCall instruction.
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
/// Used for `check` for additional checks related to the runtime.
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
/// Used for `step` for additional operations related to the runtime.
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default> Machine<M> {
    /// Create a new runtime.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
        Self::with_states(context, block, patch, depth,
                          AccountState::default(), BlockhashState::default())
    }

    pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
                       depth: usize, account_state: AccountState,
                       blockhash_state: BlockhashState) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context,
                block,
                patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state,
                blockhash_state,
                logs: Vec::new(),

                depth,
            },
        }
    }

    /// Derive this runtime to create a sub runtime. This will not
    /// modify the current runtime, and it will have a chance to
    /// review whether it wants to accept the result of this sub
    /// runtime afterwards.
    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    /// Commit a new account into this runtime.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    /// Commit a new blockhash into this runtime.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    #[allow(unused_variables)]
    /// Apply a sub runtime into the current runtime. This sub runtime
    /// should have been created by the current runtime's `derive`
    /// function. Depending whether the current runtime is invoking a
    /// ContractCreation or MessageCall instruction, it will apply
    /// various states back.
    pub fn apply_sub(&mut self, sub: Machine<M>) {
        use std::mem::swap;
        let mut status = MachineStatus::Running;
        swap(&mut status, &mut self.status);
        match status {
            MachineStatus::InvokeCreate(_) => {
                self.apply_create(sub);
            },
            MachineStatus::InvokeCall(_, (out_start, out_len)) => {
                self.apply_call(sub, out_start, out_len);
            },
            _ => panic!(),
        }
    }

    fn apply_create(&mut self, sub: Machine<M>) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                if self.state.available_gas() >= code_deposit_gas(sub.state.out.len()) {
                    self.state.account_state.decrease_balance(self.state.context.address,
                                                              sub.state.context.value);
                    self.state.account_state.create(sub.state.context.address,
                                                    sub.state.context.value,
                                                    sub.state.out.as_slice());
                }

            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                // self.state.stack.pop().unwrap();
                // self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    fn apply_call(&mut self, sub: Machine<M>, out_start: M256, out_len: M256) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                self.state.account_state.decrease_balance(self.state.context.address,
                                                          sub.state.context.value);
                self.state.account_state.increase_balance(sub.state.context.address,
                                                          sub.state.context.value);
                copy_into_memory(&mut self.state.memory, sub.state.out.as_slice(),
                                 out_start, M256::zero(), out_len);
            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::from(1u64)).unwrap();
            },
            _ => panic!(),
        }
    }

    /// Check the next instruction about whether it will return
    /// errors.
    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.into()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    #[allow(unused_variables)]
    fn step_precompiled(&mut self) -> bool {
        let ecrec_address = Address::from_str("0x0000000000000000000000000000000000000001").unwrap();
        let sha256_address = Address::from_str("0x0000000000000000000000000000000000000002").unwrap();
        let rip160_address = Address::from_str("0x0000000000000000000000000000000000000003").unwrap();
        let id_address = Address::from_str("0x0000000000000000000000000000000000000004").unwrap();

        if self.state.context.address == id_address {
            let gas = Gas::from(15u64) +
                Gas::from(3u64) * (Gas::from(self.state.context.data.len()) / Gas::from(32u64));
            if gas > self.state.context.gas_limit {
                self.state.used_gas = self.state.context.gas_limit;
                self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            } else {
                self.state.used_gas = gas;
                self.state.out = self.state.context.data.clone();
                self.status = MachineStatus::ExitedOk;
            }
            return true;
        } else {
            return false;
        }
    }

    /// Step an instruction in the PC. The eval result is refected by
    /// the runtime status, and it will only return an error if
    /// there're accounts or blockhashes to be committed to this
    /// runtime for it to run. In that case, the state of the current
    /// runtime will not be affected.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.step_precompiled() {
            return Ok(());
        }

        if self.state.depth >= 2 {
            self.status = MachineStatus::ExitedErr(MachineError::CallstackOverflow);
            return Ok(());
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);
        let after_gas = self.state.context.gas_limit - memory_gas - self.state.used_gas - gas_cost + gas_stipend;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        if self.state.context.gas_limit < memory_gas + self.state.used_gas + gas_cost - gas_stipend {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.into()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    /// Get the runtime state.
    pub fn state(&self) -> &State<M> {
        &self.state
    }

    /// Get the current runtime status.
    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate file;
extern crate fall_gen;
extern crate lang_fall;
extern crate fall_tree;

use std::error::Error;
use std::io::Write;
use std::path::{PathBuf, Path};
use std::fs;
use std::process::{Command, Stdio};

use clap::{App, Arg};

enum Task {
    Generate(PathBuf),
    Examples(PathBuf)
}

fn main() {
    let matches = App::new("Fall parser generator")
        .arg(Arg::with_name("grammar").index(1).required(true))
        .arg(Arg::with_name("examples").long("examples"))
        .get_matches();
    let grammar = PathBuf::from(matches.value_of("grammar").unwrap());
    let command = if matches.is_present("examples") {
        Task::Examples(grammar)
    } else {
        Task::Generate(grammar)
    };

    let return_code = if let Err(e) = main_inner(command) {
        writeln!(::std::io::stderr(), "Error occurred: {}", e).unwrap();
        101
    } else {
        0
    };
    std::process::exit(return_code)
}

fn main_inner(command: Task) -> Result<(), Box<Error>> {
    match command {
        Task::Generate(grammar) => {
            let input = file::get_text(&grammar)?;
            let file = lang_fall::LANG_FALL.parse(input);
            let ast = lang_fall::ast(&file);
            let result = fall_gen::generate(ast)?;
            file::put_text(grammar.with_extension("rs"), result)?;
        }
        Task::Examples(grammar) => {
            let input = file::get_text(&grammar)?;
            let result = render_examples(input)?;
            file::put_text(grammar.with_extension("txt"), result)?;
        }
    }
    Ok(())
}

fn render_examples(grammar: String) -> Result<String, Box<Error>> {
    let file = lang_fall::LANG_FALL.parse(grammar);
    let ast = lang_fall::ast(&file);
    let parser = match fall_gen::generate(ast) {
        Ok(parser) => parser,
        Err(e) => return Ok(format!("error:\n{}", e))
    };
    let base_dir = base_directory()?;
    let syntax = base_dir.join("src").join("syntax.rs");
    put_text_if_changed(&syntax, &parser)?;
    let toml = base_dir.join("Cargo.toml");
    put_text_if_changed(&toml, &format!(r##"
        [package]
        name = "fall_examples"
        version = "0.1.0"
        authors = []

        [workspace]

        [dependencies]
        fall_tree = {{ path = "{fall_dir}/fall_tree" }}
        fall_parse = {{ path = "{fall_dir}/fall_parse" }}
    "##, fall_dir = fall_dir().display()))?;
    put_text_if_changed(&base_dir.join("src").join("main.rs"), r##"
        #![allow(warnings)]
        extern crate fall_tree;
        extern crate fall_parse;
        mod syntax;

        use std::io::Read;

        fn main() {
            let mut input = String::new();
            ::std::io::stdin().read_to_string(&mut input).unwrap();
            for example in input.split("\n***###***\n") {
                let file = syntax::LANG.parse(example.to_owned());
                println!("{}\n", fall_tree::dump_file(&file));
            }
        }
    "##)?;

    let build = Command::new("cargo")
        .arg("build")
        .arg("--manifest-path")
        .arg(&toml)
        .spawn()?
        .wait_with_output()?;

    if !build.status.success() {
        return Ok(String::from_utf8(build.stderr).unwrap());
    }

    let mut child = Command::new("cargo")
        .arg("run")
        .arg("--manifest-path")
        .arg(&toml)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;

    let examples: String = ast.examples().map(|ex| ex.contents().to_string())
        .collect::<Vec<_>>()
        .join("\n***###***\n");

    {
        let mut stdin = child.stdin.as_mut().unwrap();
        stdin.write_all(examples.as_bytes()).unwrap();
        stdin.flush().unwrap();
    }

    let rendered = child.wait_with_output()?;
    assert!(rendered.status.success());
    let mut result = String::new();
    if !rendered.stderr.is_empty() {
        result += &::std::str::from_utf8(&rendered.stderr).unwrap();
        result += "\n\n";
    }
    result += &::std::str::from_utf8(&rendered.stdout).unwrap();
    Ok(result)
}

fn base_directory() -> Result<PathBuf, Box<Error>> {
    let result = ::std::env::temp_dir().join("fall-examples");
    fs::create_dir_all(&result)?;
    fs::create_dir_all(&result.join("src"))?;
    Ok(result)
}

fn fall_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir).parent().unwrap().to_owned()
}

fn put_text_if_changed(path: &Path, text: &str) -> ::std::io::Result<()> {
    if path.exists() {
        let old_text = file::get_text(path)?;
        if old_text == text {
            return Ok(());
        }
    }
    file::put_text(path, text)
}
<commit_msg>More whitespace<commit_after>extern crate clap;
extern crate file;
extern crate fall_gen;
extern crate lang_fall;
extern crate fall_tree;

use std::error::Error;
use std::io::Write;
use std::path::{PathBuf, Path};
use std::fs;
use std::process::{Command, Stdio};

use clap::{App, Arg};

enum Task {
    Generate(PathBuf),
    Examples(PathBuf)
}

fn main() {
    let matches = App::new("Fall parser generator")
        .arg(Arg::with_name("grammar").index(1).required(true))
        .arg(Arg::with_name("examples").long("examples"))
        .get_matches();
    let grammar = PathBuf::from(matches.value_of("grammar").unwrap());
    let command = if matches.is_present("examples") {
        Task::Examples(grammar)
    } else {
        Task::Generate(grammar)
    };

    let return_code = if let Err(e) = main_inner(command) {
        writeln!(::std::io::stderr(), "Error occurred: {}", e).unwrap();
        101
    } else {
        0
    };
    std::process::exit(return_code)
}

fn main_inner(command: Task) -> Result<(), Box<Error>> {
    match command {
        Task::Generate(grammar) => {
            let input = file::get_text(&grammar)?;
            let file = lang_fall::LANG_FALL.parse(input);
            let ast = lang_fall::ast(&file);
            let result = fall_gen::generate(ast)?;
            file::put_text(grammar.with_extension("rs"), result)?;
        }
        Task::Examples(grammar) => {
            let input = file::get_text(&grammar)?;
            let result = render_examples(input)?;
            file::put_text(grammar.with_extension("txt"), result)?;
        }
    }
    Ok(())
}

fn render_examples(grammar: String) -> Result<String, Box<Error>> {
    let file = lang_fall::LANG_FALL.parse(grammar);
    let ast = lang_fall::ast(&file);
    let parser = match fall_gen::generate(ast) {
        Ok(parser) => parser,
        Err(e) => return Ok(format!("error:\n{}", e))
    };
    let base_dir = base_directory()?;

    let syntax = base_dir.join("src").join("syntax.rs");
    put_text_if_changed(&syntax, &parser)?;

    let toml = base_dir.join("Cargo.toml");
    put_text_if_changed(&toml, &format!(r##"
        [package]
        name = "fall_examples"
        version = "0.1.0"
        authors = []

        [workspace]

        [dependencies]
        fall_tree = {{ path = "{fall_dir}/fall_tree" }}
        fall_parse = {{ path = "{fall_dir}/fall_parse" }}
    "##, fall_dir = fall_dir().display()))?;

    put_text_if_changed(&base_dir.join("src").join("main.rs"), r##"
        #![allow(warnings)]
        extern crate fall_tree;
        extern crate fall_parse;
        mod syntax;

        use std::io::Read;

        fn main() {
            let mut input = String::new();
            ::std::io::stdin().read_to_string(&mut input).unwrap();
            for example in input.split("\n***###***\n") {
                let file = syntax::LANG.parse(example.to_owned());
                println!("{}\n", fall_tree::dump_file(&file));
            }
        }
    "##)?;

    let build = Command::new("cargo")
        .arg("build")
        .arg("--manifest-path")
        .arg(&toml)
        .spawn()?
        .wait_with_output()?;

    if !build.status.success() {
        return Ok(String::from_utf8(build.stderr).unwrap());
    }

    let mut child = Command::new("cargo")
        .arg("run")
        .arg("--manifest-path")
        .arg(&toml)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;

    let examples: String = ast.examples().map(|ex| ex.contents().to_string())
        .collect::<Vec<_>>()
        .join("\n***###***\n");

    {
        let mut stdin = child.stdin.as_mut().unwrap();
        stdin.write_all(examples.as_bytes()).unwrap();
        stdin.flush().unwrap();
    }

    let rendered = child.wait_with_output()?;
    assert!(rendered.status.success());
    let mut result = String::new();
    if !rendered.stderr.is_empty() {
        result += &::std::str::from_utf8(&rendered.stderr).unwrap();
        result += "\n\n";
    }
    result += &::std::str::from_utf8(&rendered.stdout).unwrap();
    Ok(result)
}

fn base_directory() -> Result<PathBuf, Box<Error>> {
    let result = ::std::env::temp_dir().join("fall-examples");
    fs::create_dir_all(&result)?;
    fs::create_dir_all(&result.join("src"))?;
    Ok(result)
}

fn fall_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir).parent().unwrap().to_owned()
}

fn put_text_if_changed(path: &Path, text: &str) -> ::std::io::Result<()> {
    if path.exists() {
        let old_text = file::get_text(path)?;
        if old_text == text {
            return Ok(());
        }
    }
    file::put_text(path, text)
}
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) * st.force(y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) + st.force(y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);

                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<commit_msg>minor debug<commit_after>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) * st.force(y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            println!("depend_add:({:?},{:?})", x, y);
            st.force(x) + st.force(y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);

                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<|endoftext|>


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

use std::collections::HashSet;

use criterion::{
    AxisScale, Bencher, Criterion, ParameterizedBenchmark, PlotConfiguration, Throughput,
};
use rand::{Rng, RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use tempfile::TempDir;

use exonum_crypto::Hash;
use exonum_merkledb::{
    proof_map_index::PROOF_MAP_KEY_SIZE as KEY_SIZE, Database, DbOptions, ProofListIndex,
    ProofMapIndex, RocksDB,
};

const NAME: &str = "name";
const SAMPLE_SIZE: usize = 10;
const CHUNK_SIZE: usize = 64;
const SEED: [u8; 16] = [100; 16];
const ITEM_COUNTS: [usize; 3] = [1_000, 10_000, 100_000];

trait DatabaseFactory: Sized {
    fn create(&mut self) -> Box<dyn Database>;
}

struct RocksdbDatabaseFactory(Option<TempDir>);

impl Default for RocksdbDatabaseFactory {
    fn default() -> Self {
        RocksdbDatabaseFactory(None)
    }
}

impl DatabaseFactory for RocksdbDatabaseFactory {
    fn create(&mut self) -> Box<dyn Database> {
        if let Some(dir) = self.0.take() {
            dir.close().unwrap();
        }

        let dir = TempDir::new().unwrap();
        let options = DbOptions::default();
        let db = RocksDB::open(dir.path(), &options).unwrap();
        self.0 = Some(dir);
        Box::new(db)
    }
}

fn generate_random_kv(len: usize) -> Vec<(Hash, Vec<u8>)> {
    let mut rng = XorShiftRng::from_seed(SEED);
    let mut exists_keys = HashSet::new();
    let mut base = [0; KEY_SIZE];
    rng.fill_bytes(&mut base);
    let base = base;

    let kv_generator = |_| {
        let mut v = vec![0; CHUNK_SIZE];
        // Generate only unique keys.
        let mut k = base;
        let byte: usize = rng.gen_range(0, 31);
        k[byte] = rng.gen::<u8>();

        rng.fill_bytes(&mut v);
        while exists_keys.contains(&k) {
            rng.fill_bytes(&mut k);
        }
        exists_keys.insert(k);
        (Hash::new(k), v)
    };

    (0..len).map(kv_generator).collect::<Vec<_>>()
}

fn proof_list_append(b: &mut Bencher, mut factory: impl DatabaseFactory, len: usize) {
    let mut rng = XorShiftRng::from_seed(SEED);
    let data = (0..len)
        .map(|_| {
            let mut chunk = vec![0; CHUNK_SIZE];
            rng.fill_bytes(&mut chunk);
            chunk
        })
        .collect::<Vec<_>>();

    let db = factory.create();
    b.iter_with_setup(
        || db.fork(),
        |mut storage| {
            let mut table = ProofListIndex::new(NAME, &mut storage);
            assert!(table.is_empty());
            for item in &data {
                table.push(item.clone());
            }
        },
    );
}

fn proof_map_insert_without_merge(b: &mut Bencher, mut factory: impl DatabaseFactory, len: usize) {
    let data = generate_random_kv(len);
    let db = factory.create();
    b.iter_with_setup(
        || db.fork(),
        |mut storage| {
            let mut table = ProofMapIndex::new(NAME, &mut storage);
            assert!(table.keys().next().is_none());
            for item in &data {
                table.put(&item.0, item.1.clone());
            }
        },
    );
}

fn proof_map_insert_with_merge(b: &mut Bencher, mut factory: impl DatabaseFactory, len: usize) {
    let data = generate_random_kv(len);
    b.iter_with_setup(
        || factory.create(),
        |db| {
            let mut fork = db.fork();
            {
                let mut table = ProofMapIndex::new(NAME, &mut fork);
                assert!(table.keys().next().is_none());
                for item in &data {
                    table.put(&item.0, item.1.clone());
                }
            }
            db.merge(fork.into_patch()).unwrap();
        },
    );
}

fn proof_map_index_build_proofs(b: &mut Bencher, mut factory: impl DatabaseFactory, len: usize) {
    let data = generate_random_kv(len);
    let db = factory.create();
    let mut storage = db.fork();
    let mut table = ProofMapIndex::new(NAME, &mut storage);

    for item in &data {
        table.put(&item.0, item.1.clone());
    }
    let table_merkle_root = table.merkle_root();
    let mut proofs = Vec::with_capacity(data.len());

    b.iter(|| {
        proofs.clear();
        proofs.extend(data.iter().map(|item| table.get_proof(item.0)));
    });

    for (i, proof) in proofs.into_iter().enumerate() {
        let checked_proof = proof.check().unwrap();
        assert_eq!(*checked_proof.entries().next().unwrap().1, data[i].1);
        assert_eq!(checked_proof.merkle_root(), table_merkle_root);
    }
}

fn proof_map_index_verify_proofs(b: &mut Bencher, mut factory: impl DatabaseFactory, len: usize) {
    let data = generate_random_kv(len);
    let db = factory.create();
    let mut storage = db.fork();
    let mut table = ProofMapIndex::new(NAME, &mut storage);

    for item in &data {
        table.put(&item.0, item.1.clone());
    }
    let table_merkle_root = table.merkle_root();
    let proofs: Vec<_> = data.iter().map(|item| table.get_proof(item.0)).collect();

    b.iter(|| {
        for (i, proof) in proofs.iter().enumerate() {
            let checked_proof = proof.clone().check().unwrap();
            assert_eq!(*checked_proof.entries().next().unwrap().1, data[i].1);
            assert_eq!(checked_proof.merkle_root(), table_merkle_root);
        }
    });
}

fn bench_fn_rocksdb<F>(c: &mut Criterion, name: &str, benchmark: F)
where
    F: Fn(&mut Bencher, RocksdbDatabaseFactory, usize) + 'static,
{
    let item_counts = ITEM_COUNTS.iter().cloned();
    c.bench(
        name,
        ParameterizedBenchmark::new(
            "items",
            move |b: &mut Bencher, &len: &usize| {
                benchmark(b, RocksdbDatabaseFactory::default(), len)
            },
            item_counts,
        )
        .throughput(|s| Throughput::Elements(*s as u32))
        .plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic))
        .sample_size(SAMPLE_SIZE),
    );
}

pub fn bench_storage(c: &mut Criterion) {
    exonum_crypto::init();

    bench_fn_rocksdb(c, "proof_list/append", proof_list_append);
    bench_fn_rocksdb(
        c,
        "proof_map/insert/no_merge",
        proof_map_insert_without_merge,
    );
    bench_fn_rocksdb(c, "proof_map/insert/merge", proof_map_insert_with_merge);
    bench_fn_rocksdb(c, "proof_map/proofs/build", proof_map_index_build_proofs);
    bench_fn_rocksdb(
        c,
        "proof_map/proofs/validate",
        proof_map_index_verify_proofs,
    );
}
<commit_msg>Use TemporaryDB in benchmarks<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashSet;

use criterion::{
    AxisScale, Bencher, Criterion, ParameterizedBenchmark, PlotConfiguration, Throughput,
};
use rand::{Rng, RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;

use exonum_crypto::Hash;
use exonum_merkledb::{
    proof_map_index::PROOF_MAP_KEY_SIZE as KEY_SIZE, Database, ProofListIndex,
    ProofMapIndex, TemporaryDB,
};

const NAME: &str = "name";
const SAMPLE_SIZE: usize = 10;
const CHUNK_SIZE: usize = 64;
const SEED: [u8; 16] = [100; 16];
const ITEM_COUNTS: [usize; 3] = [1_000, 10_000, 100_000];

fn generate_random_kv(len: usize) -> Vec<(Hash, Vec<u8>)> {
    let mut rng = XorShiftRng::from_seed(SEED);
    let mut exists_keys = HashSet::new();
    let mut base = [0; KEY_SIZE];
    rng.fill_bytes(&mut base);
    let base = base;

    let kv_generator = |_| {
        let mut v = vec![0; CHUNK_SIZE];
        // Generate only unique keys.
        let mut k = base;
        let byte: usize = rng.gen_range(0, 31);
        k[byte] = rng.gen::<u8>();

        rng.fill_bytes(&mut v);
        while exists_keys.contains(&k) {
            rng.fill_bytes(&mut k);
        }
        exists_keys.insert(k);
        (Hash::new(k), v)
    };

    (0..len).map(kv_generator).collect::<Vec<_>>()
}

fn proof_list_append(b: &mut Bencher, len: usize) {
    let mut rng = XorShiftRng::from_seed(SEED);
    let data = (0..len)
        .map(|_| {
            let mut chunk = vec![0; CHUNK_SIZE];
            rng.fill_bytes(&mut chunk);
            chunk
        })
        .collect::<Vec<_>>();

    let db = TemporaryDB::default();
    b.iter_with_setup(
        || db.fork(),
        |mut storage| {
            let mut table = ProofListIndex::new(NAME, &mut storage);
            assert!(table.is_empty());
            for item in &data {
                table.push(item.clone());
            }
        },
    );
}

fn proof_map_insert_without_merge(b: &mut Bencher, len: usize) {
    let data = generate_random_kv(len);
    let db = TemporaryDB::default();
    b.iter_with_setup(
        || db.fork(),
        |mut storage| {
            let mut table = ProofMapIndex::new(NAME, &mut storage);
            assert!(table.keys().next().is_none());
            for item in &data {
                table.put(&item.0, item.1.clone());
            }
        },
    );
}

fn proof_map_insert_with_merge(b: &mut Bencher, len: usize) {
    let data = generate_random_kv(len);
    b.iter_with_setup(
        TemporaryDB::default,
        |db| {
            let mut fork = db.fork();
            {
                let mut table = ProofMapIndex::new(NAME, &mut fork);
                assert!(table.keys().next().is_none());
                for item in &data {
                    table.put(&item.0, item.1.clone());
                }
            }
            db.merge(fork.into_patch()).unwrap();
        },
    );
}

fn proof_map_index_build_proofs(b: &mut Bencher, len: usize) {
    let data = generate_random_kv(len);
    let db = TemporaryDB::default();
    let mut storage = db.fork();
    let mut table = ProofMapIndex::new(NAME, &mut storage);

    for item in &data {
        table.put(&item.0, item.1.clone());
    }
    let table_merkle_root = table.merkle_root();
    let mut proofs = Vec::with_capacity(data.len());

    b.iter(|| {
        proofs.clear();
        proofs.extend(data.iter().map(|item| table.get_proof(item.0)));
    });

    for (i, proof) in proofs.into_iter().enumerate() {
        let checked_proof = proof.check().unwrap();
        assert_eq!(*checked_proof.entries().next().unwrap().1, data[i].1);
        assert_eq!(checked_proof.merkle_root(), table_merkle_root);
    }
}

fn proof_map_index_verify_proofs(b: &mut Bencher, len: usize) {
    let data = generate_random_kv(len);
    let db = TemporaryDB::default();
    let mut storage = db.fork();
    let mut table = ProofMapIndex::new(NAME, &mut storage);

    for item in &data {
        table.put(&item.0, item.1.clone());
    }
    let table_merkle_root = table.merkle_root();
    let proofs: Vec<_> = data.iter().map(|item| table.get_proof(item.0)).collect();

    b.iter(|| {
        for (i, proof) in proofs.iter().enumerate() {
            let checked_proof = proof.clone().check().unwrap();
            assert_eq!(*checked_proof.entries().next().unwrap().1, data[i].1);
            assert_eq!(checked_proof.merkle_root(), table_merkle_root);
        }
    });
}

fn bench_fn<F>(c: &mut Criterion, name: &str, benchmark: F)
where
    F: Fn(&mut Bencher, usize) + 'static,
{
    let item_counts = ITEM_COUNTS.iter().cloned();
    c.bench(
        name,
        ParameterizedBenchmark::new(
            "items",
            move |b: &mut Bencher, &len: &usize| {
                benchmark(b, len)
            },
            item_counts,
        )
        .throughput(|s| Throughput::Elements(*s as u32))
        .plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic))
        .sample_size(SAMPLE_SIZE),
    );
}

pub fn bench_storage(c: &mut Criterion) {
    exonum_crypto::init();

    bench_fn(c, "proof_list/append", proof_list_append);
    bench_fn(
        c,
        "proof_map/insert/no_merge",
        proof_map_insert_without_merge,
    );
    bench_fn(c, "proof_map/insert/merge", proof_map_insert_with_merge);
    bench_fn(c, "proof_map/proofs/build", proof_map_index_build_proofs);
    bench_fn(
        c,
        "proof_map/proofs/validate",
        proof_map_index_verify_proofs,
    );
}
<|endoftext|>