<commit_before>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! # Example template
//!
//! ```text
//! {% extends "layout.html" %}
//! {% block body %}
//!   <ul>
//!     {% for user in users %}
//!       <li><a href="{{ user.url }}">{{ user.username }}</a></li>
//!     {% endfor %}
//!   </ul>
//! {% endblock %}
//! ```
//!
//! # Feature highlights
//!
//! * Construct templates using a familiar, easy-to-use syntax
//! * Benefit from the safety provided by Rust's type system
//! * Template code is compiled into your crate for optimal performance
//! * Templates only convert your data as needed
//! * Templates can access your Rust types directly, according to Rust's
//!   privacy rules
//! * Debugging features to assist you in template development
//! * Templates must be valid UTF-8 and produce UTF-8 when rendered
//! * Works on stable Rust
//!
//! # Creating Askama templates
//!
//! An Askama template is just a text file, in the UTF-8 encoding.
//! It can be used to generate any kind of text-based format.
//! You can use whatever extension you like.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## Variables
//!
//! Template variables are defined by the template context linked to the
//! template by deriving a `struct`'s implementation for `Template` from
//! a template file's contents.
//! You can use a dot (`.`) to get a variable's attributes.
//! Reading from variables is subject to the usual borrowing policies.
//! For example, `{{ name }}` will get the ``name`` field from the template
//! context,
//! while `{{ user.name }}` will get the ``name`` field of the ``user``
//! field of the template context.
//!
//! ## Filters
//!
//! Values such as those obtained from variables can be post-processed
//! using **filters**.
//! Filters are applied to values using the pipe symbol (`|`) and may
//! have optional extra arguments in parentheses.
//! Filters can be chained, in which case the output from one filter
//! is passed to the next.
//!
//! For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
//! characters from the value obtained by accessing the `name` field,
//! and print the resulting string as a Rust literal.
//!
//! Consult the [filters module documentation](filters/index.html) for a list
//! of available filters. User-defined filters are currently not supported.
//!
//! ## Whitespace control
//!
//! Askama preserves all whitespace in template code by default,
//! except that final trailing newline characters are suppressed.
//! However, whitespace before and after expression and block delimiters
//! can be suppressed by writing a minus sign directly following a
//! start delimiter or leading into an end delimiter.
//! Askama considers all tabs, spaces, newlines and carriage returns to be
//! whitespace.
//!
//! ## Template inheritance
//!
//! Template inheritance allows you to build a base template with common
//! elements that can then be shared by all inheriting templates.
//! A base template defines **blocks** that child templates can then override.
//!
//! ### Base template
//!
//! ```text
//! <!DOCTYPE html>
//! <html lang="en">
//!   <head>
//!     <title>{{ block title %}{{ title }}{% endblock %} - My Site</title>
//!     {% block head %}{% endblock %}
//!   </head>
//!   <body>
//!     <div id="content">
//!       {% block content %}{% endblock %}
//!     </div>
//!   </body>
//! </html>
//! ```
//!
//! The `block` tags define three blocks that can be filled in by child
//! templates. The base template defines a default version of the block.
//!
//! ### Child template
//!
//! Here's an example child template:
//!
//! ```text
//! {% extends "base.html" %}
//!
//! {% block title %}Index{% endblock %}
//!
//! {% block head %}
//!   <style>
//!   </style>
//! {% endblock %}
//!
//! {% block content %}
//!   <h1>Index</h1>
//!   <p>Hello, world!</p>
//! {% endblock %}
//! ```
//!
//! The `extends` tag tells the code generator that this template inherits
//! from another template. It will render the top-level content from the
//! base template, and substitute blocks from the base template with those
//! from the child template. The inheriting template context `struct` must
//! have a field called `_parent` of the type used as the base template
//! context. Blocks can only refer to the context of their own template.
//!
//! ## HTML escaping
//!
//! Askama does not yet support automatic escaping. Care must be taken to
//! escape content that may contain HTML control characters. You can use
//! the `escape` filter (or its `e` alias) to escape data for use in HTML.
//!
//! ## Control structures
//!
//! ### For
//!
//! Loop over each item in an iterator. For example:
//!
//! ```text
//! <h1>Users</h1>
//! <ul>
//! {% for user in users %}
//!   <li>{{ user.name|e }}</li>
//! {% endfor %}
//! </ul>
//! ```
//!
//! Inside for-loop blocks, some useful variables are accessible:
//!
//! * *loop.index*: current loop iteration (starting from 1)
//! * *loop.index0*: current loop iteration (starting from 0)
//!
//! ### If
//!
//! The *if* statement is used as you might expect:
//!
//! ```text
//! {% if users.len() == 0 %}
//!   No users
//! {% else if users.len() == 1 %}
//!   1 user
//! {% else %}
//!   {{ users.len() }} users
//! {% endif %}
//! ```
//!
//! ## Expressions
//!
//! Askama supports string literals (`"foo"`) and integer literals (`1`).
//! It supports almost all binary operators that Rust supports,
//! including arithmetic, comparison and logic operators.
//! The same precedence order as Rust uses is applied.
//! Expressions can be grouped using parentheses.

#![allow(unused_imports)]
#[macro_use]
extern crate askama_derive;

use std::env;
use std::fs::{self, DirEntry};
use std::io;
use std::path::{Path, PathBuf};

/// Main `Template` trait; implementations are generally derived
pub trait Template {
    /// Renders the template to the given `writer` buffer
    fn render_to(&self, writer: &mut std::fmt::Write);
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> String {
        let mut buf = String::new();
        self.render_to(&mut buf);
        buf
    }
}

pub mod filters;
pub use askama_derive::*;

// Duplicates askama_derive::path::template_dir()
fn template_dir() -> PathBuf {
    let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    path.push("templates");
    path
}

fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

/// Build script helper to rebuild crates if contained templates have changed
///
/// Iterates over all files in the template dir (`templates` in
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
/// of them to stdout.
///
/// This helper method can be used in build scripts (`build.rs`) in crates
/// that have templates, to make sure the crate gets rebuilt when template
/// source code changes.
pub fn rerun_if_templates_changed() {
    visit_dirs(&template_dir(), &|e: &DirEntry| {
        println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
    }).unwrap();
}
<commit_msg>Change preposition in "Variables" section of docs<commit_after>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! # Example template
//!
//! ```text
//! {% extends "layout.html" %}
//! {% block body %}
//!   <ul>
//!     {% for user in users %}
//!       <li><a href="{{ user.url }}">{{ user.username }}</a></li>
//!     {% endfor %}
//!   </ul>
//! {% endblock %}
//! ```
//!
//! # Feature highlights
//!
//! * Construct templates using a familiar, easy-to-use syntax
//! * Benefit from the safety provided by Rust's type system
//! * Template code is compiled into your crate for optimal performance
//! * Templates only convert your data as needed
//! * Templates can access your Rust types directly, according to Rust's
//!   privacy rules
//! * Debugging features to assist you in template development
//! * Templates must be valid UTF-8 and produce UTF-8 when rendered
//! * Works on stable Rust
//!
//! # Creating Askama templates
//!
//! An Askama template is just a text file, in the UTF-8 encoding.
//! It can be used to generate any kind of text-based format.
//! You can use whatever extension you like.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## Variables
//!
//! Template variables are defined by the template context linked to the
//! template by deriving a `struct`'s implementation for `Template` from
//! a template file's contents.
//! You can use a dot (`.`) to get a variable's attributes.
//! Reading from variables is subject to the usual borrowing policies.
//! For example, `{{ name }}` will get the ``name`` field from the template
//! context,
//! while `{{ user.name }}` will get the ``name`` field of the ``user``
//! field from the template context.
//!
//! ## Filters
//!
//! Values such as those obtained from variables can be post-processed
//! using **filters**.
//! Filters are applied to values using the pipe symbol (`|`) and may
//! have optional extra arguments in parentheses.
//! Filters can be chained, in which case the output from one filter
//! is passed to the next.
//!
//! For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
//! characters from the value obtained by accessing the `name` field,
//! and print the resulting string as a Rust literal.
//!
//! Consult the [filters module documentation](filters/index.html) for a list
//! of available filters. User-defined filters are currently not supported.
//!
//! ## Whitespace control
//!
//! Askama preserves all whitespace in template code by default,
//! except that final trailing newline characters are suppressed.
//! However, whitespace before and after expression and block delimiters
//! can be suppressed by writing a minus sign directly following a
//! start delimiter or leading into an end delimiter.
//! Askama considers all tabs, spaces, newlines and carriage returns to be
//! whitespace.
//!
//! ## Template inheritance
//!
//! Template inheritance allows you to build a base template with common
//! elements that can then be shared by all inheriting templates.
//! A base template defines **blocks** that child templates can then override.
//!
//! ### Base template
//!
//! ```text
//! <!DOCTYPE html>
//! <html lang="en">
//!   <head>
//!     <title>{{ block title %}{{ title }}{% endblock %} - My Site</title>
//!     {% block head %}{% endblock %}
//!   </head>
//!   <body>
//!     <div id="content">
//!       {% block content %}{% endblock %}
//!     </div>
//!   </body>
//! </html>
//! ```
//!
//! The `block` tags define three blocks that can be filled in by child
//! templates. The base template defines a default version of the block.
//!
//! ### Child template
//!
//! Here's an example child template:
//!
//! ```text
//! {% extends "base.html" %}
//!
//! {% block title %}Index{% endblock %}
//!
//! {% block head %}
//!   <style>
//!   </style>
//! {% endblock %}
//!
//! {% block content %}
//!   <h1>Index</h1>
//!   <p>Hello, world!</p>
//! {% endblock %}
//! ```
//!
//! The `extends` tag tells the code generator that this template inherits
//! from another template. It will render the top-level content from the
//! base template, and substitute blocks from the base template with those
//! from the child template. The inheriting template context `struct` must
//! have a field called `_parent` of the type used as the base template
//! context. Blocks can only refer to the context of their own template.
//!
//! ## HTML escaping
//!
//! Askama does not yet support automatic escaping. Care must be taken to
//! escape content that may contain HTML control characters. You can use
//! the `escape` filter (or its `e` alias) to escape data for use in HTML.
//!
//! ## Control structures
//!
//! ### For
//!
//! Loop over each item in an iterator. For example:
//!
//! ```text
//! <h1>Users</h1>
//! <ul>
//! {% for user in users %}
//!   <li>{{ user.name|e }}</li>
//! {% endfor %}
//! </ul>
//! ```
//!
//! Inside for-loop blocks, some useful variables are accessible:
//!
//! * *loop.index*: current loop iteration (starting from 1)
//! * *loop.index0*: current loop iteration (starting from 0)
//!
//! ### If
//!
//! The *if* statement is used as you might expect:
//!
//! ```text
//! {% if users.len() == 0 %}
//!   No users
//! {% else if users.len() == 1 %}
//!   1 user
//! {% else %}
//!   {{ users.len() }} users
//! {% endif %}
//! ```
//!
//! ## Expressions
//!
//! Askama supports string literals (`"foo"`) and integer literals (`1`).
//! It supports almost all binary operators that Rust supports,
//! including arithmetic, comparison and logic operators.
//! The same precedence order as Rust uses is applied.
//! Expressions can be grouped using parentheses.

#![allow(unused_imports)]
#[macro_use]
extern crate askama_derive;

use std::env;
use std::fs::{self, DirEntry};
use std::io;
use std::path::{Path, PathBuf};

/// Main `Template` trait; implementations are generally derived
pub trait Template {
    /// Renders the template to the given `writer` buffer
    fn render_to(&self, writer: &mut std::fmt::Write);
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> String {
        let mut buf = String::new();
        self.render_to(&mut buf);
        buf
    }
}

pub mod filters;
pub use askama_derive::*;

// Duplicates askama_derive::path::template_dir()
fn template_dir() -> PathBuf {
    let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    path.push("templates");
    path
}

fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

/// Build script helper to rebuild crates if contained templates have changed
///
/// Iterates over all files in the template dir (`templates` in
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
/// of them to stdout.
///
/// This helper method can be used in build scripts (`build.rs`) in crates
/// that have templates, to make sure the crate gets rebuilt when template
/// source code changes.
pub fn rerun_if_templates_changed() {
    visit_dirs(&template_dir(), &|e: &DirEntry| {
        println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
    }).unwrap();
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(rand)]
/**
 * Simulate Bell's quantum entanglement experiments
 */

extern crate test;

use std::thread::Thread;
use std::rand::random;
use std::fmt;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Trivial, OddBall};

#[derive(Copy, Debug, PartialEq)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::Display for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

impl fmt::Display for Detector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Detector::{D12, D3, D9};
        let r = match self {
            &D12 => "12 oclock",
            &D3 => "3 oclock",
            &D9 => "9 oclock"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Trivial, // up-up-up -> down-down-down
    OddBall  // up-down-up -> down-up-down
}

#[derive(Debug, PartialEq)]
enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, detector: &Detector) {
        self.spin = match detector {
            &Detector::D12 => SpinUp,
            &Detector::D3 => match rand32() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
            &Detector::D9 => match rand32() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
        };
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let detector1 = Detector::D12;
        let detector2 = Particle::get_detector_direction();

        self.measure (&detector1);

        if detector1 == detector2 { // 1/3
            friend.spin = match self.spin {
                SpinUp => SpinDown,
                SpinDown => SpinUp,
                _ => unreachable!()
            };
        } else { // 2/3
            friend.measure(&detector2);
        }

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    fn get_detector_direction () -> Detector {

        let detector = match rand32() {
            0.0       ... 0.3333333 => Detector::D12,
            0.3333333 ... 0.6666666 => Detector::D3,
            0.6666666 ... 1.00 => Detector::D9,
            _ => unreachable!()
        };

        return detector;
    }

    pub fn hidden_information (&mut self, friend: &mut Particle, plan: Plan) -> Pair<Direction> {

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinUp,
            OddBall => match detector {
                Detector::D3 => SpinDown,
                _ => SpinUp
            }
        };
        friend.spin = spin;

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinDown,
            OddBall => match detector {
                Detector::D3 => SpinUp,
                _ => SpinDown
            }
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

fn rand32 () -> f32 {
    return random::<f32>();
}

/**
 * run spooky for trials number of trials
 */
fn get_spooky (trials: f64) -> usize {
    let mut num_different = 0;

    let mut lhs;
    let mut rhs;

    for _ in 0 .. trials as usize {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        lhs.spooky(&mut rhs);

        if lhs.spin != rhs.spin {
            num_different += 1;
        }
    }

    return num_different;
}

fn run_spooky (trials: f64) {

    let num_different = get_spooky(trials) as f64;

    println!("Percent different for spooky {}%", 100f64 * (num_different) / trials as f64);
    println!("      Should be about 1/2 or 50%");

}

/**
 * Run test for hidden information, set the plan_probability to choose
 * OddBall vs Trivial
 */
fn get_hidden(trials: f64, plan_probability: f32) -> usize {

    let mut num_different = 0;
    let mut lhs;
    let mut rhs;

    for _ in 0 .. trials as usize {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        if rand32() < plan_probability {
            lhs.hidden_information(&mut rhs, OddBall);
        } else {
            lhs.hidden_information(&mut rhs, Trivial);
        }

        if lhs.spin != rhs.spin {
            num_different += 1;
        }
    }

    return num_different;
}

fn run_hidden (trials: f64, plan_probability: f32) {

    let num_different = get_hidden(trials, plan_probability) as f64;

    println!("Percent different for hidden info {}%", 100f64 * (num_different) / trials as f64);
    println!("  Should be greater than 5/9th or {}%", 100.0 * 5.0/9.0);
    println!("With OddBall choosen {}% of the time and Trivial {}% of the time",
             100.0 * plan_probability,
             100.0 * (1.0 - plan_probability));

}

// hidden_information should give +55.6% difference, spooky would give 50%
fn main () {

    let trials: f64 = 1000000f64;

    run_spooky(trials);
    run_hidden(trials, 0.5);
    run_hidden(trials, 1.0);
    run_hidden(trials, 0.0);
}

#[bench]
fn run_linear (b: &mut test::Bencher) {
    b.iter(|| {
        let trials: f64 = 10f64;

        get_spooky(trials);
        get_hidden(trials, 0.5);
        get_hidden(trials, 1.0);
        get_hidden(trials, 0.0);
    })
}

<commit_msg>benchmark using threads and not threads<commit_after>#![feature(core)]
#![feature(rand)]
/**
 * Simulate Bell's quantum entanglement experiments
 */

extern crate test;

use std::thread::Thread;
use std::rand::random;
use std::fmt;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Trivial, OddBall};

#[derive(Copy, Debug, PartialEq)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::Display for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

impl fmt::Display for Detector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Detector::{D12, D3, D9};
        let r = match self {
            &D12 => "12 oclock",
            &D3 => "3 oclock",
            &D9 => "9 oclock"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Trivial, // up-up-up -> down-down-down
    OddBall  // up-down-up -> down-up-down
}

#[derive(Debug, PartialEq)]
enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, detector: &Detector) {
        self.spin = match detector {
            &Detector::D12 => SpinUp,
            &Detector::D3 => match rand32() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
            &Detector::D9 => match rand32() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
        };
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let detector1 = Detector::D12;
        let detector2 = Particle::get_detector_direction();

        self.measure (&detector1);

        if detector1 == detector2 { // 1/3
            friend.spin = match self.spin {
                SpinUp => SpinDown,
                SpinDown => SpinUp,
                _ => unreachable!()
            };
        } else { // 2/3
            friend.measure(&detector2);
        }

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    fn get_detector_direction () -> Detector {

        let detector = match rand32() {
            0.0       ... 0.3333333 => Detector::D12,
            0.3333333 ... 0.6666666 => Detector::D3,
            0.6666666 ... 1.00 => Detector::D9,
            _ => unreachable!()
        };

        return detector;
    }

    pub fn hidden_information (&mut self, friend: &mut Particle, plan: Plan) -> Pair<Direction> {

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinUp,
            OddBall => match detector {
                Detector::D3 => SpinDown,
                _ => SpinUp
            }
        };
        friend.spin = spin;

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinDown,
            OddBall => match detector {
                Detector::D3 => SpinUp,
                _ => SpinDown
            }
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

fn rand32 () -> f32 {
    return random::<f32>();
}

/**
 * run spooky for trials number of trials
 */
fn get_spooky (trials: f64) -> usize {
    let mut num_different = 0;

    let mut lhs;
    let mut rhs;

    for _ in 0 .. trials as usize {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        lhs.spooky(&mut rhs);

        if lhs.spin != rhs.spin {
            num_different += 1;
        }
    }

    return num_different;
}

fn run_spooky (trials: f64) {

    let num_different = get_spooky(trials) as f64;

    println!("Percent different for spooky {}%", 100f64 * (num_different) / trials as f64);
    println!("      Should be about 1/2 or 50%");

}

/**
 * Run test for hidden information, set the plan_probability to choose
 * OddBall vs Trivial
 */
fn get_hidden(trials: f64, plan_probability: f32) -> usize {

    let mut num_different = 0;
    let mut lhs;
    let mut rhs;

    for _ in 0 .. trials as usize {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        if rand32() < plan_probability {
            lhs.hidden_information(&mut rhs, OddBall);
        } else {
            lhs.hidden_information(&mut rhs, Trivial);
        }

        if lhs.spin != rhs.spin {
            num_different += 1;
        }
    }

    return num_different;
}

fn run_hidden (trials: f64, plan_probability: f32) {

    let num_different = get_hidden(trials, plan_probability) as f64;

    println!("Percent different for hidden info {}%", 100f64 * (num_different) / trials as f64);
    println!("  Should be greater than 5/9th or {}%", 100.0 * 5.0/9.0);
    println!("With OddBall choosen {}% of the time and Trivial {}% of the time",
             100.0 * plan_probability,
             100.0 * (1.0 - plan_probability));

}

// hidden_information should give +55.6% difference, spooky would give 50%
fn main () {

    let trials: f64 = 1000000f64;

    run_spooky(trials);
    run_hidden(trials, 0.5);
    run_hidden(trials, 1.0);
    run_hidden(trials, 0.0);
}

static BENCH_ITTERS: f64 = 10000f64;

#[bench]
fn bench_one_spooky (b: &mut test::Bencher) {
    b.iter(|| {
        let trials: f64 = BENCH_ITTERS;
        get_spooky(trials);
    });
}

#[bench]
fn bench_one_hidden (b: &mut test::Bencher) {
    b.iter(|| {
        let trials: f64 = BENCH_ITTERS;
        get_hidden(trials, 0.5);
    });
}

#[bench]
fn bench_many_linear (b: &mut test::Bencher) {
    b.iter(|| {
        let trials: f64 = BENCH_ITTERS;

        get_spooky(trials);
        get_hidden(trials, 0.5);
        get_hidden(trials, 1.0);
        get_hidden(trials, 0.0);
    })
}

#[bench]
fn bench_many_threads (b: &mut test::Bencher) {
    b.iter(|| {
        let trials: f64 = BENCH_ITTERS;

        Thread::spawn(move || {
            get_spooky(trials);
        });
        Thread::spawn(move || {
            get_hidden(trials, 0.5);
        });
        Thread::spawn(move || {
            get_hidden(trials, 1.0);
        });
        Thread::spawn(move || {
            get_hidden(trials, 0.0);
        });

    })
}

<|endoftext|>


<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

//! Log directories on local disk.

use log::{error, warn};
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufReader};
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

use crate::logdir::{EventFileBuf, Logdir, EVENT_FILE_BASENAME_INFIX};
use crate::types::Run;

/// A log directory on local disk.
pub struct DiskLogdir {
    root: PathBuf,
}

impl DiskLogdir {
    /// Creates a `DiskLogdir` with the given root directory.
    pub fn new(root: PathBuf) -> Self {
        DiskLogdir { root }
    }
}

impl Logdir for DiskLogdir {
    type File = BufReader<File>;

    fn discover(&self) -> io::Result<HashMap<Run, Vec<EventFileBuf>>> {
        let mut run_map: HashMap<Run, Vec<EventFileBuf>> = HashMap::new();
        let walker = WalkDir::new(&self.root)
            .sort_by(|a, b| a.file_name().cmp(b.file_name()))
            .follow_links(true);
        for walkdir_item in walker {
            let dirent = match walkdir_item {
                Ok(dirent) => dirent,
                Err(e) => {
                    error!("While walking log directory: {}", e);
                    continue;
                }
            };
            if !dirent.file_type().is_file() {
                continue;
            }
            let filename = dirent.file_name().to_string_lossy();
            if !filename.contains(EVENT_FILE_BASENAME_INFIX) {
                continue;
            }
            let run_dir = match dirent.path().parent() {
                Some(parent) => parent,
                None => {
                    // I don't know of any circumstance where this can happen, but I would believe
                    // that some weird filesystem can hit it, so just proceed.
                    warn!(
                        "Path {} is a file but has no parent",
                        dirent.path().display()
                    );
                    continue;
                }
            };
            let mut run_relpath = match run_dir.strip_prefix(&self.root) {
                Ok(rp) => rp.to_path_buf(),
                Err(_) => {
                    error!(
                        "Log directory {} is not a prefix of run directory {}",
                        &self.root.display(),
                        &run_dir.display(),
                    );
                    continue;
                }
            };
            // Render the root run as ".", not "".
            if run_relpath == Path::new("") {
                run_relpath.push(".");
            }
            let run = Run(run_relpath.display().to_string());
            run_map
                .entry(run)
                .or_default()
                .push(EventFileBuf(dirent.into_path()));
        }
        Ok(run_map)
    }

    fn open(&self, path: &EventFileBuf) -> io::Result<Self::File> {
        File::open(self.root.join(&path.0)).map(BufReader::new)
    }
}
<commit_msg>rust: fix disk logdir reading for relative paths (#4684)<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

//! Log directories on local disk.

use log::{error, warn};
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufReader};
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

use crate::logdir::{EventFileBuf, Logdir, EVENT_FILE_BASENAME_INFIX};
use crate::types::Run;

/// A log directory on local disk.
pub struct DiskLogdir {
    root: PathBuf,
}

impl DiskLogdir {
    /// Creates a `DiskLogdir` with the given root directory.
    pub fn new(root: PathBuf) -> Self {
        DiskLogdir { root }
    }
}

impl Logdir for DiskLogdir {
    type File = BufReader<File>;

    fn discover(&self) -> io::Result<HashMap<Run, Vec<EventFileBuf>>> {
        let mut run_map: HashMap<Run, Vec<EventFileBuf>> = HashMap::new();
        let walker = WalkDir::new(&self.root)
            .sort_by(|a, b| a.file_name().cmp(b.file_name()))
            .follow_links(true);
        for walkdir_item in walker {
            let dirent = match walkdir_item {
                Ok(dirent) => dirent,
                Err(e) => {
                    error!("While walking log directory: {}", e);
                    continue;
                }
            };
            if !dirent.file_type().is_file() {
                continue;
            }
            let filename = dirent.file_name().to_string_lossy();
            if !filename.contains(EVENT_FILE_BASENAME_INFIX) {
                continue;
            }
            let run_dir = match dirent.path().parent() {
                Some(parent) => parent,
                None => {
                    // I don't know of any circumstance where this can happen, but I would believe
                    // that some weird filesystem can hit it, so just proceed.
                    warn!(
                        "Path {} is a file but has no parent",
                        dirent.path().display()
                    );
                    continue;
                }
            };
            let mut run_relpath = match run_dir.strip_prefix(&self.root) {
                Ok(rp) => rp.to_path_buf(),
                Err(_) => {
                    error!(
                        "Log directory {} is not a prefix of run directory {}",
                        &self.root.display(),
                        &run_dir.display(),
                    );
                    continue;
                }
            };
            // Render the root run as ".", not "".
            if run_relpath == Path::new("") {
                run_relpath.push(".");
            }
            let run = Run(run_relpath.display().to_string());
            run_map
                .entry(run)
                .or_default()
                .push(EventFileBuf(dirent.into_path()));
        }
        Ok(run_map)
    }

    fn open(&self, path: &EventFileBuf) -> io::Result<Self::File> {
        File::open(&path.0).map(BufReader::new)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::{Read, Write};

    fn test_in_logdir(logdir: &Path) -> std::io::Result<()> {
        let run_dir = logdir.join("train");
        std::fs::create_dir(&run_dir)?;
        {
            let mut f = File::create(run_dir.join("foo.tfevents.123"))?;
            f.write_all(b"hello")?;
            f.sync_all()?;
        }

        let disk_logdir = DiskLogdir::new(logdir.to_path_buf());
        let discoveries = disk_logdir.discover()?;
        assert_eq!(discoveries.len(), 1, "{:?}", discoveries);
        let train_event_files = &discoveries[&Run("train".to_string())];
        assert_eq!(train_event_files.len(), 1, "{:?}", train_event_files);

        let mut event_file = disk_logdir.open(&train_event_files[0])?;
        let mut contents = String::new();
        event_file.read_to_string(&mut contents)?;
        assert_eq!(contents, "hello");

        Ok(())
    }

    #[test]
    fn test_absolute() -> std::io::Result<()> {
        let tmpdir = tempfile::tempdir_in(".")?;
        let logdir = tmpdir.path();
        assert!(logdir.is_absolute(), "expected absolute: {:?}", logdir);
        test_in_logdir(logdir)
    }

    #[test]
    fn test_relative() -> std::io::Result<()> {
        let tmpdir = tempfile::tempdir_in(".")?;
        let logdir = tmpdir
            .path()
            .strip_prefix(std::env::current_dir()?)
            .expect("tmpdir not under $PWD");
        assert!(logdir.is_relative(), "expected relative: {:?}", logdir);
        test_in_logdir(logdir)
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate parser_combinators as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Parser, State, Stream};
use pc::combinator::{any, between, many, many1, optional, parser, satisfy, sep_by, unexpected, With, ParserExt};
use pc::char::{char, digit, spaces, Spaces, string, ParseResult};

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>)
}

fn lex<'a, P>(p: P) -> With<Spaces<P::Input>, P>
    where P: Parser
        , P::Input: Stream<Item=char> {
    spaces().with(p)
}
struct Json<I>(::std::marker::PhantomData<fn (I) -> I>);

impl <I> Json<I>
    where I: Stream<Item=char> {

    fn integer(input: State<I>) -> ParseResult<i64, I> {
        let (s, input) = try!(many1::<String, _>(digit())
            .expected("integer")
            .parse_state(input));
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number(input: State<I>) -> ParseResult<f64, I> {
        let i = char('0').map(|_| 0.0)
                 .or(parser(Json::<I>::integer).map(|x| x as f64));
        let fractional = many(digit())
            .map(|digits: String| {
                let mut magnitude = 1.0;
                digits.chars().fold(0.0, |acc, d| {
                    magnitude /= 10.0;
                    match d.to_digit(10) {
                        Some(d) => acc + (d as f64) * magnitude,
                        None => panic!("Not a digit")
                    }
                })
            });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(char('-')).and(parser(Json::<I>::integer)));
        optional(char('-'))
            .and(i)
            .map(|(sign, n)| if sign.is_some() { -n } else { n })
            .and(optional(char('.')).with(fractional))
            .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
            .and(optional(exp))
            .map(|(n, exp_option)| {
                match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n
                }
            })
        .parse_state(input)
    }

    fn char(input: State<I>) -> ParseResult<char, I> {
        let (c, input) = try!(any().parse_state(input));
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().find(|x| *x == c).is_some()).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_state(input)),
            '"'  => unexpected("\"").parse_state(input.into_inner()).map(|_| unreachable!()),
            _    => Ok((c, input))
        }
    }
    fn string(input: State<I>) -> ParseResult<String, I> {
        between(char('"'), char('"'), many(parser(Json::<I>::char)))
            .parse_state(input)
    }
    fn object(input: State<I>) -> ParseResult<Value, I> {
        let field = (lex(parser(Json::<I>::string)), lex(char(':')), lex(parser(Json::<I>::value)))
            .map(|t| (t.0, t.2));
        let fields = sep_by(field, char(','));
        between(char('{'), lex(char('}')), fields)
            .map(Value::Object)
            .parse_state(input)
    }

    #[allow(unconditional_recursion)]
    fn value(input: State<I>) -> ParseResult<Value, I>
        where I: Stream<Item=char> {
        let array = between(lex(char('[')), lex(char(']')), sep_by(parser(Json::<I>::value), char(',')))
            .map(Value::Array);

        //Wrap a few of the value parsers to workaround the slow compiletimes
        fn rest<I>(input: State<I>) -> ParseResult<Value, I>
            where I: Stream<Item=char> {
            string("false").map(|_| Value::Bool(false))
                .or(string("true").map(|_| Value::Bool(true)))
                .or(string("null").map(|_| Value::Null))
                .parse_state(input)
        }
        lex(parser(Json::<I>::string).map(Value::String)
            .or(parser(Json::<I>::object))
            .or(array)
            .or(parser(Json::<I>::number).map(Value::Number))
            .or(parser(rest))
        )
            .parse_state(input)
    }

}

#[test]
fn json_test() {
    use self::Value::*;
    let input =
r#"
{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = parser(Json::value)
        .parse(input);
    let expected = Object(vec![
        ("array", Array(vec![Number(1.0), String("".to_string())])),
        ("object", Object(HashMap::new())),
        ("number", Number(3.14)),
        ("int", Number(-100.)),
        ("exp", Number(-1e2)),
        ("exp_neg", Number(23E-2)),
        ("true", Bool(true)),
        ("false", Bool(false)),
        ("null", Null)
    ].into_iter().map(|(k, v)| (k.to_string(), v)).collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = parser(Json::value);
    match parser.parse(&data[..]) {
        Ok((Value::Array(_), "\r\n")) => (),
        Ok(x) => { println!("{:?}", x); assert!(false); }
        Err(err) => { println!("{}", err); assert!(false); }
    }
    bencher.iter(|| {
        let result = parser.parse(&data);
        ::test::black_box(result)
    });
}
<commit_msg>Do some minor improvements to the json parser example<commit_after>#![feature(test)]
extern crate parser_combinators as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Parser, State, Stream};
use pc::combinator::{any, between, many, many1, optional, parser, satisfy, sep_by, unexpected, Expected, FnParser, Skip, ParserExt};
use pc::char::{char, digit, spaces, Spaces, string, ParseResult};

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>)
}

fn lex<'a, P>(p: P) -> Skip<P, Spaces<P::Input>>
    where P: Parser
        , P::Input: Stream<Item=char> {
    p.skip(spaces())
}
struct Json<I>(::std::marker::PhantomData<fn (I) -> I>);

type JsonParser<O, I> = Expected<FnParser<I, fn (State<I>) -> ParseResult<O, I>>>;

fn fn_parser<O, I>(f: fn(State<I>) -> ParseResult<O, I>, err: &'static str) -> JsonParser<O, I>
    where I: Stream<Item=char> {
    parser(f).expected(err)
}

impl <I> Json<I>
    where I: Stream<Item=char> {

    fn integer() -> JsonParser<i64, I> {
        fn_parser(Json::<I>::integer_, "integer")
    }
    fn integer_(input: State<I>) -> ParseResult<i64, I> {
        let (s, input) = try!(lex(many1::<String, _>(digit()))
            .parse_state(input));
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number() -> JsonParser<f64, I> {
        fn_parser(Json::<I>::number_, "number")
    }
    fn number_(input: State<I>) -> ParseResult<f64, I> {
        let i = char('0').map(|_| 0.0)
                 .or(Json::<I>::integer().map(|x| x as f64));
        let fractional = many(digit())
            .map(|digits: String| {
                let mut magnitude = 1.0;
                digits.chars().fold(0.0, |acc, d| {
                    magnitude /= 10.0;
                    match d.to_digit(10) {
                        Some(d) => acc + (d as f64) * magnitude,
                        None => panic!("Not a digit")
                    }
                })
            });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(char('-')).and(Json::<I>::integer()));
        lex(optional(char('-'))
            .and(i)
            .map(|(sign, n)| if sign.is_some() { -n } else { n })
            .and(optional(char('.')).with(fractional))
            .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
            .and(optional(exp))
            .map(|(n, exp_option)| {
                match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n
                }
            }))
        .parse_state(input)
    }

    fn char() -> JsonParser<char, I> {
        fn_parser(Json::<I>::char_, "char")
    }
    fn char_(input: State<I>) -> ParseResult<char, I> {
        let (c, input) = try!(any().parse_state(input));
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().find(|x| *x == c).is_some()).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_state(input)),
            '"'  => unexpected("\"").parse_state(input.into_inner()).map(|_| unreachable!()),
            _    => Ok((c, input))
        }
    }
    fn string() -> JsonParser<String, I> {
        fn_parser(Json::<I>::string_, "string")
    }
    fn string_(input: State<I>) -> ParseResult<String, I> {
        between(char('"'), lex(char('"')), many(Json::<I>::char()))
            .parse_state(input)
    }

    fn object() -> JsonParser<Value, I> {
        fn_parser(Json::<I>::object_, "object")
    }
    fn object_(input: State<I>) -> ParseResult<Value, I> {
        let field = (Json::<I>::string(), lex(char(':')), Json::<I>::value())
            .map(|t| (t.0, t.2));
        let fields = sep_by(field, lex(char(',')));
        between(lex(char('{')), lex(char('}')), fields)
            .map(Value::Object)
            .parse_state(input)
    }

    fn value() -> FnParser<I, fn (State<I>) -> ParseResult<Value, I>> {
        parser({ let f: fn (_) -> _ = Json::<I>::value_; f })
    }
    #[allow(unconditional_recursion)]
    fn value_(input: State<I>) -> ParseResult<Value, I> {
        let array = between(lex(char('[')), lex(char(']')), sep_by(Json::<I>::value(), lex(char(','))))
            .map(Value::Array);

        Json::<I>::string().map(Value::String)
            .or(Json::<I>::object())
            .or(array)
            .or(Json::<I>::number().map(Value::Number))
            .or(lex(string("false").map(|_| Value::Bool(false))
                .or(string("true").map(|_| Value::Bool(true)))
                .or(string("null").map(|_| Value::Null))))
            .parse_state(input)
    }
}

#[test]
fn json_test() {
    use self::Value::*;
    let input =
r#"
{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = Json::value()
        .parse(input);
    let expected = Object(vec![
        ("array", Array(vec![Number(1.0), String("".to_string())])),
        ("object", Object(HashMap::new())),
        ("number", Number(3.14)),
        ("int", Number(-100.)),
        ("exp", Number(-1e2)),
        ("exp_neg", Number(23E-2)),
        ("true", Bool(true)),
        ("false", Bool(false)),
        ("null", Null)
    ].into_iter().map(|(k, v)| (k.to_string(), v)).collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = Json::value();
    match parser.parse(&data[..]) {
        Ok((Value::Array(_), "")) => (),
        Ok(x) => { println!("{:?}", x); assert!(false); }
        Err(err) => { println!("{}", err); assert!(false); }
    }
    bencher.iter(|| {
        let result = parser.parse(&data);
        ::test::black_box(result)
    });
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! CSS Multi-column layout http://dev.w3.org/csswg/css-multicol/

#![deny(unsafe_code)]

use ServoArc;
use app_units::Au;
use block::BlockFlow;
use context::LayoutContext;
use display_list::{DisplayListBuildState, StackingContextCollectionState};
use euclid::{Point2D, Vector2D};
use floats::FloatKind;
use flow::{Flow, FlowClass, OpaqueFlow, FragmentationContext, GetBaseFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx_traits::print_tree::PrintTree;
use std::cmp::{min, max};
use std::fmt;
use std::sync::Arc;
use style::logical_geometry::LogicalSize;
use style::properties::ComputedValues;
use style::values::Either;
use style::values::computed::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone};

#[allow(unsafe_code)]
unsafe impl ::flow::HasBaseFlow for MulticolFlow {}

#[repr(C)]
pub struct MulticolFlow {
    pub block_flow: BlockFlow,

    /// Length between the inline-start edge of a column and that of the next.
    /// That is, the used column-width + used column-gap.
    pub column_pitch: Au,
}

#[allow(unsafe_code)]
unsafe impl ::flow::HasBaseFlow for MulticolColumnFlow {}

#[repr(C)]
pub struct MulticolColumnFlow {
    pub block_flow: BlockFlow,
}

impl MulticolFlow {
    pub fn from_fragment(fragment: Fragment, float_kind: Option<FloatKind>) -> MulticolFlow {
        MulticolFlow {
            block_flow: BlockFlow::from_fragment_and_float_kind(fragment, float_kind),
            column_pitch: Au(0),
        }
    }
}

impl MulticolColumnFlow {
    pub fn from_fragment(fragment: Fragment) -> MulticolColumnFlow {
        MulticolColumnFlow {
            block_flow: BlockFlow::from_fragment(fragment),
        }
    }
}

impl Flow for MulticolFlow {
    fn class(&self) -> FlowClass {
        FlowClass::Multicol
    }

    fn as_mut_block(&mut self) -> &mut BlockFlow {
        &mut self.block_flow
    }

    fn as_block(&self) -> &BlockFlow {
        &self.block_flow
    }

    fn as_mut_multicol(&mut self) -> &mut MulticolFlow {
        self
    }

    fn bubble_inline_sizes(&mut self) {
        // FIXME(SimonSapin) http://dev.w3.org/csswg/css-sizing/#multicol-intrinsic
        self.block_flow.bubble_inline_sizes();
    }

    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
        debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol");
        let shared_context = layout_context.shared_context();
        self.block_flow.compute_inline_sizes(shared_context);

        // Move in from the inline-start border edge.
        let inline_start_content_edge = self.block_flow.fragment.border_box.start.i +
            self.block_flow.fragment.border_padding.inline_start;

        // Distance from the inline-end margin edge to the inline-end content edge.
        let inline_end_content_edge =
            self.block_flow.fragment.margin.inline_end +
            self.block_flow.fragment.border_padding.inline_end;

        self.block_flow.assign_inline_sizes(layout_context);
        let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
        let content_inline_size =
            self.block_flow.fragment.border_box.size.inline - padding_and_borders;
        let column_width;
        {
            let column_style = self.block_flow.fragment.style.get_column();

            let column_gap = match column_style.column_gap {
                Either::First(len) => len.into(),
                Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size.size(),
            };

            let mut column_count;
            if let Either::First(column_width) = column_style.column_width {
                let column_width = Au::from(column_width);
                column_count =
                    max(1, (content_inline_size + column_gap).0 / (column_width + column_gap).0);
                if let Either::First(specified_column_count) = column_style.column_count {
                    column_count = min(column_count, specified_column_count.0 as i32);
                }
            } else {
                column_count = match column_style.column_count {
                    Either::First(n) => n.0,
                    _ => unreachable!(),
                }
            }
            column_width =
                max(Au(0), (content_inline_size + column_gap) / column_count - column_gap);
            self.column_pitch = column_width + column_gap;
        }

        self.block_flow.fragment.border_box.size.inline = content_inline_size + padding_and_borders;

        self.block_flow.propagate_assigned_inline_size_to_children(
            shared_context, inline_start_content_edge, inline_end_content_edge, column_width,
            |_, _, _, _, _, _| {});
    }

    fn assign_block_size(&mut self, ctx: &LayoutContext) {
        debug!("assign_block_size: assigning block_size for multicol");

        let fragmentation_context = Some(FragmentationContext {
            this_fragment_is_empty: true,
            available_block_size: {
                let style = &self.block_flow.fragment.style;
                if let LengthOrPercentageOrAuto::Length(length) = style.content_block_size() {
                    Au::from(length)
                } else if let LengthOrPercentageOrNone::Length(length) = style.max_block_size() {
                    Au::from(length)
                } else {
                    // FIXME: do column balancing instead
                    // FIXME: (until column balancing) substract margins/borders/padding
                    LogicalSize::from_physical(
                        self.block_flow.base.writing_mode,
                        ctx.shared_context().viewport_size(),
                    ).block
                }
            }
        });

        // Before layout, everything is in a single "column"
        assert!(self.block_flow.base.children.len() == 1);
        let mut column = self.block_flow.base.children.pop_front_arc().unwrap();

        // Pretend there is no children for this:
        self.block_flow.assign_block_size(ctx);

        loop {
            let remaining = Arc::get_mut(&mut column).unwrap().fragment(ctx, fragmentation_context);
            self.block_flow.base.children.push_back_arc(column);
            column = match remaining {
                Some(remaining) => remaining,
                None => break
            };
        }
    }

    fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
        self.block_flow.compute_stacking_relative_position(layout_context);
        let pitch = LogicalSize::new(self.block_flow.base.writing_mode, self.column_pitch, Au(0));
        let pitch = pitch.to_physical(self.block_flow.base.writing_mode);
        for (i, child) in self.block_flow.base.children.iter_mut().enumerate() {
            let point = &mut child.mut_base().stacking_relative_position;
            *point = *point + Vector2D::new(pitch.width * i as i32, pitch.height * i as i32);
        }
    }

    fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
        self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
    }

    fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
        self.block_flow.update_late_computed_block_position_if_necessary(block_position)
    }

    fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
        debug!("build_display_list_multicol");
        self.block_flow.build_display_list(state);
    }

    fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
        self.block_flow.collect_stacking_contexts(state);
    }

    fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
        self.block_flow.repair_style(new_style)
    }

    fn compute_overflow(&self) -> Overflow {
        self.block_flow.compute_overflow()
    }

    fn contains_roots_of_absolute_flow_tree(&self) -> bool {
        self.block_flow.contains_roots_of_absolute_flow_tree()
    }

    fn is_absolute_containing_block(&self) -> bool {
        self.block_flow.is_absolute_containing_block()
    }

    fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
        self.block_flow.generated_containing_block_size(flow)
    }

    fn iterate_through_fragment_border_boxes(&self,
                                             iterator: &mut FragmentBorderBoxIterator,
                                             level: i32,
                                             stacking_context_position: &Point2D<Au>) {
        self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
    }

    fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
        self.block_flow.mutate_fragments(mutator);
    }

    fn print_extra_flow_children(&self, print_tree: &mut PrintTree) {
        self.block_flow.print_extra_flow_children(print_tree);
    }
}

impl Flow for MulticolColumnFlow {
    fn class(&self) -> FlowClass {
        FlowClass::MulticolColumn
    }

    fn as_mut_block(&mut self) -> &mut BlockFlow {
        &mut self.block_flow
    }

    fn as_block(&self) -> &BlockFlow {
        &self.block_flow
    }

    fn bubble_inline_sizes(&mut self) {
        self.block_flow.bubble_inline_sizes();
    }

    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
        debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol column");
        self.block_flow.assign_inline_sizes(layout_context);
    }

    fn assign_block_size(&mut self, ctx: &LayoutContext) {
        debug!("assign_block_size: assigning block_size for multicol column");
        self.block_flow.assign_block_size(ctx);
    }

    fn fragment(&mut self, layout_context: &LayoutContext,
                fragmentation_context: Option<FragmentationContext>)
                -> Option<Arc<Flow>> {
        Flow::fragment(&mut self.block_flow, layout_context, fragmentation_context)
    }

    fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
        self.block_flow.compute_stacking_relative_position(layout_context)
    }

    fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
        self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
    }

    fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
        self.block_flow.update_late_computed_block_position_if_necessary(block_position)
    }

    fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
        debug!("build_display_list_multicol column");
        self.block_flow.build_display_list(state);
    }

    fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
        self.block_flow.collect_stacking_contexts(state);
    }

    fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
        self.block_flow.repair_style(new_style)
    }

    fn compute_overflow(&self) -> Overflow {
        self.block_flow.compute_overflow()
    }

    fn contains_roots_of_absolute_flow_tree(&self) -> bool {
        self.block_flow.contains_roots_of_absolute_flow_tree()
    }

    fn is_absolute_containing_block(&self) -> bool {
        self.block_flow.is_absolute_containing_block()
    }

    fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
        self.block_flow.generated_containing_block_size(flow)
    }

    fn iterate_through_fragment_border_boxes(&self,
                                             iterator: &mut FragmentBorderBoxIterator,
                                             level: i32,
                                             stacking_context_position: &Point2D<Au>) {
        self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
    }

    fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
        self.block_flow.mutate_fragments(mutator);
    }

    fn print_extra_flow_children(&self, print_tree: &mut PrintTree) {
        self.block_flow.print_extra_flow_children(print_tree);
    }
}

impl fmt::Debug for MulticolFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MulticolFlow: {:?}", self.block_flow)
    }
}

impl fmt::Debug for MulticolColumnFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MulticolColumnFlow: {:?}", self.block_flow)
    }
}
<commit_msg>Use specific assertion for layout multicol<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! CSS Multi-column layout http://dev.w3.org/csswg/css-multicol/

#![deny(unsafe_code)]

use ServoArc;
use app_units::Au;
use block::BlockFlow;
use context::LayoutContext;
use display_list::{DisplayListBuildState, StackingContextCollectionState};
use euclid::{Point2D, Vector2D};
use floats::FloatKind;
use flow::{Flow, FlowClass, OpaqueFlow, FragmentationContext, GetBaseFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx_traits::print_tree::PrintTree;
use std::cmp::{min, max};
use std::fmt;
use std::sync::Arc;
use style::logical_geometry::LogicalSize;
use style::properties::ComputedValues;
use style::values::Either;
use style::values::computed::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone};

#[allow(unsafe_code)]
unsafe impl ::flow::HasBaseFlow for MulticolFlow {}

#[repr(C)]
pub struct MulticolFlow {
    pub block_flow: BlockFlow,

    /// Length between the inline-start edge of a column and that of the next.
    /// That is, the used column-width + used column-gap.
    pub column_pitch: Au,
}

#[allow(unsafe_code)]
unsafe impl ::flow::HasBaseFlow for MulticolColumnFlow {}

#[repr(C)]
pub struct MulticolColumnFlow {
    pub block_flow: BlockFlow,
}

impl MulticolFlow {
    pub fn from_fragment(fragment: Fragment, float_kind: Option<FloatKind>) -> MulticolFlow {
        MulticolFlow {
            block_flow: BlockFlow::from_fragment_and_float_kind(fragment, float_kind),
            column_pitch: Au(0),
        }
    }
}

impl MulticolColumnFlow {
    pub fn from_fragment(fragment: Fragment) -> MulticolColumnFlow {
        MulticolColumnFlow {
            block_flow: BlockFlow::from_fragment(fragment),
        }
    }
}

impl Flow for MulticolFlow {
    fn class(&self) -> FlowClass {
        FlowClass::Multicol
    }

    fn as_mut_block(&mut self) -> &mut BlockFlow {
        &mut self.block_flow
    }

    fn as_block(&self) -> &BlockFlow {
        &self.block_flow
    }

    fn as_mut_multicol(&mut self) -> &mut MulticolFlow {
        self
    }

    fn bubble_inline_sizes(&mut self) {
        // FIXME(SimonSapin) http://dev.w3.org/csswg/css-sizing/#multicol-intrinsic
        self.block_flow.bubble_inline_sizes();
    }

    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
        debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol");
        let shared_context = layout_context.shared_context();
        self.block_flow.compute_inline_sizes(shared_context);

        // Move in from the inline-start border edge.
        let inline_start_content_edge = self.block_flow.fragment.border_box.start.i +
            self.block_flow.fragment.border_padding.inline_start;

        // Distance from the inline-end margin edge to the inline-end content edge.
        let inline_end_content_edge =
            self.block_flow.fragment.margin.inline_end +
            self.block_flow.fragment.border_padding.inline_end;

        self.block_flow.assign_inline_sizes(layout_context);
        let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
        let content_inline_size =
            self.block_flow.fragment.border_box.size.inline - padding_and_borders;
        let column_width;
        {
            let column_style = self.block_flow.fragment.style.get_column();

            let column_gap = match column_style.column_gap {
                Either::First(len) => len.into(),
                Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size.size(),
            };

            let mut column_count;
            if let Either::First(column_width) = column_style.column_width {
                let column_width = Au::from(column_width);
                column_count =
                    max(1, (content_inline_size + column_gap).0 / (column_width + column_gap).0);
                if let Either::First(specified_column_count) = column_style.column_count {
                    column_count = min(column_count, specified_column_count.0 as i32);
                }
            } else {
                column_count = match column_style.column_count {
                    Either::First(n) => n.0,
                    _ => unreachable!(),
                }
            }
            column_width =
                max(Au(0), (content_inline_size + column_gap) / column_count - column_gap);
            self.column_pitch = column_width + column_gap;
        }

        self.block_flow.fragment.border_box.size.inline = content_inline_size + padding_and_borders;

        self.block_flow.propagate_assigned_inline_size_to_children(
            shared_context, inline_start_content_edge, inline_end_content_edge, column_width,
            |_, _, _, _, _, _| {});
    }

    fn assign_block_size(&mut self, ctx: &LayoutContext) {
        debug!("assign_block_size: assigning block_size for multicol");

        let fragmentation_context = Some(FragmentationContext {
            this_fragment_is_empty: true,
            available_block_size: {
                let style = &self.block_flow.fragment.style;
                if let LengthOrPercentageOrAuto::Length(length) = style.content_block_size() {
                    Au::from(length)
                } else if let LengthOrPercentageOrNone::Length(length) = style.max_block_size() {
                    Au::from(length)
                } else {
                    // FIXME: do column balancing instead
                    // FIXME: (until column balancing) substract margins/borders/padding
                    LogicalSize::from_physical(
                        self.block_flow.base.writing_mode,
                        ctx.shared_context().viewport_size(),
                    ).block
                }
            }
        });

        // Before layout, everything is in a single "column"
        assert_eq!(self.block_flow.base.children.len(), 1);
        let mut column = self.block_flow.base.children.pop_front_arc().unwrap();

        // Pretend there is no children for this:
        self.block_flow.assign_block_size(ctx);

        loop {
            let remaining = Arc::get_mut(&mut column).unwrap().fragment(ctx, fragmentation_context);
            self.block_flow.base.children.push_back_arc(column);
            column = match remaining {
                Some(remaining) => remaining,
                None => break
            };
        }
    }

    fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
        self.block_flow.compute_stacking_relative_position(layout_context);
        let pitch = LogicalSize::new(self.block_flow.base.writing_mode, self.column_pitch, Au(0));
        let pitch = pitch.to_physical(self.block_flow.base.writing_mode);
        for (i, child) in self.block_flow.base.children.iter_mut().enumerate() {
            let point = &mut child.mut_base().stacking_relative_position;
            *point = *point + Vector2D::new(pitch.width * i as i32, pitch.height * i as i32);
        }
    }

    fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
        self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
    }

    fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
        self.block_flow.update_late_computed_block_position_if_necessary(block_position)
    }

    fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
        debug!("build_display_list_multicol");
        self.block_flow.build_display_list(state);
    }

    fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
        self.block_flow.collect_stacking_contexts(state);
    }

    fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
        self.block_flow.repair_style(new_style)
    }

    fn compute_overflow(&self) -> Overflow {
        self.block_flow.compute_overflow()
    }

    fn contains_roots_of_absolute_flow_tree(&self) -> bool {
        self.block_flow.contains_roots_of_absolute_flow_tree()
    }

    fn is_absolute_containing_block(&self) -> bool {
        self.block_flow.is_absolute_containing_block()
    }

    fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
        self.block_flow.generated_containing_block_size(flow)
    }

    fn iterate_through_fragment_border_boxes(&self,
                                             iterator: &mut FragmentBorderBoxIterator,
                                             level: i32,
                                             stacking_context_position: &Point2D<Au>) {
        self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
    }

    fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
        self.block_flow.mutate_fragments(mutator);
    }

    fn print_extra_flow_children(&self, print_tree: &mut PrintTree) {
        self.block_flow.print_extra_flow_children(print_tree);
    }
}

impl Flow for MulticolColumnFlow {
    fn class(&self) -> FlowClass {
        FlowClass::MulticolColumn
    }

    fn as_mut_block(&mut self) -> &mut BlockFlow {
        &mut self.block_flow
    }

    fn as_block(&self) -> &BlockFlow {
        &self.block_flow
    }

    fn bubble_inline_sizes(&mut self) {
        self.block_flow.bubble_inline_sizes();
    }

    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
        debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol column");
        self.block_flow.assign_inline_sizes(layout_context);
    }

    fn assign_block_size(&mut self, ctx: &LayoutContext) {
        debug!("assign_block_size: assigning block_size for multicol column");
        self.block_flow.assign_block_size(ctx);
    }

    fn fragment(&mut self, layout_context: &LayoutContext,
                fragmentation_context: Option<FragmentationContext>)
                -> Option<Arc<Flow>> {
        Flow::fragment(&mut self.block_flow, layout_context, fragmentation_context)
    }

    fn compute_stacking_relative_position(&mut self, layout_context: &LayoutContext) {
        self.block_flow.compute_stacking_relative_position(layout_context)
    }

    fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
        self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
    }

    fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
        self.block_flow.update_late_computed_block_position_if_necessary(block_position)
    }

    fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
        debug!("build_display_list_multicol column");
        self.block_flow.build_display_list(state);
    }

    fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
        self.block_flow.collect_stacking_contexts(state);
    }

    fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
        self.block_flow.repair_style(new_style)
    }

    fn compute_overflow(&self) -> Overflow {
        self.block_flow.compute_overflow()
    }

    fn contains_roots_of_absolute_flow_tree(&self) -> bool {
        self.block_flow.contains_roots_of_absolute_flow_tree()
    }

    fn is_absolute_containing_block(&self) -> bool {
        self.block_flow.is_absolute_containing_block()
    }

    fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
        self.block_flow.generated_containing_block_size(flow)
    }

    fn iterate_through_fragment_border_boxes(&self,
                                             iterator: &mut FragmentBorderBoxIterator,
                                             level: i32,
                                             stacking_context_position: &Point2D<Au>) {
        self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
    }

    fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
        self.block_flow.mutate_fragments(mutator);
    }

    fn print_extra_flow_children(&self, print_tree: &mut PrintTree) {
        self.block_flow.print_extra_flow_children(print_tree);
    }
}

impl fmt::Debug for MulticolFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MulticolFlow: {:?}", self.block_flow)
    }
}

impl fmt::Debug for MulticolColumnFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MulticolColumnFlow: {:?}", self.block_flow)
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate glob;
extern crate log;

extern crate protoc;
extern crate protoc_rust;

extern crate protobuf_test_common;

use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;

use protobuf_test_common::build::*;
use protoc::Protoc;

fn test_protoc_bin_path() -> PathBuf {
    let path = protoc_bin_vendored::protoc_bin_path().unwrap();
    assert!(Protoc::from_path(&path).version().unwrap().is_3());
    path
}

fn codegen() -> protoc_rust::Codegen {
    let mut codegen = protoc_rust::Codegen::new();
    codegen.protoc_path(test_protoc_bin_path());
    codegen.extra_arg("--experimental_allow_proto3_optional");
    codegen
}

fn gen_in_dir(dir: &str, include_dir: &str) {
    gen_in_dir_impl(
        dir,
        |GenInDirArgs {
             out_dir,
             input,
             customize,
         }| {
            codegen()
                .out_dir(out_dir)
                .inputs(input)
                .includes(&["../proto", include_dir])
                .customize(customize)
                .run()
        },
    );
}

fn generate_in_common() {
    gen_in_dir("src/common/v2", "src/common/v2");

    copy_tests_v2_v3("src/common/v2", "src/common/v3");
    gen_in_dir("src/common/v3", "src/common/v3");
}

fn generate_in_v2_v3() {
    gen_in_dir("src/v2", "src/v2");

    gen_in_dir("src/v3", "src/v3");

    gen_in_dir("src/google/protobuf", "src");
}

fn generate_interop() {
    codegen()
        .out_dir("src/interop")
        .includes(&["../interop/cxx", "../proto"])
        .input("../interop/cxx/interop_pb.proto")
        .run()
        .unwrap();
}

fn generate_include_generated() {
    let dir = format!("{}/include_generated", env::var("OUT_DIR").unwrap());
    if Path::new(&dir).exists() {
        fs::remove_dir_all(&dir).unwrap();
    }
    fs::create_dir(&dir).unwrap();
    protoc_rust::Codegen::new()
        .out_dir(dir)
        .input("src/include_generated/v2.proto")
        .input("src/include_generated/v3.proto")
        .customize(Customize {
            gen_mod_rs: Some(true),
            ..Default::default()
        })
        .include("src/include_generated")
        .run()
        .unwrap();
}

fn generate_pb_rs() {
    generate_in_common();
    generate_in_v2_v3();
    generate_interop();
    generate_include_generated();
}

fn main() {
    env_logger::init();

    cfg_serde();

    clean_old_files();

    generate_pb_rs();
}
<commit_msg>Unused include<commit_after>extern crate env_logger;
extern crate glob;
extern crate log;

extern crate protoc;
extern crate protoc_rust;

extern crate protobuf_test_common;

use std::env;
use std::fs;
use std::path::Path;
use std::path::PathBuf;

use protobuf_test_common::build::*;
use protoc::Protoc;

fn test_protoc_bin_path() -> PathBuf {
    let path = protoc_bin_vendored::protoc_bin_path().unwrap();
    assert!(Protoc::from_path(&path).version().unwrap().is_3());
    path
}

fn codegen() -> protoc_rust::Codegen {
    let mut codegen = protoc_rust::Codegen::new();
    codegen.protoc_path(test_protoc_bin_path());
    codegen.extra_arg("--experimental_allow_proto3_optional");
    codegen
}

fn gen_in_dir(dir: &str, include_dir: &str) {
    gen_in_dir_impl(
        dir,
        |GenInDirArgs {
             out_dir,
             input,
             customize,
         }| {
            codegen()
                .out_dir(out_dir)
                .inputs(input)
                .includes(&["../proto", include_dir])
                .customize(customize)
                .run()
        },
    );
}

fn generate_in_common() {
    gen_in_dir("src/common/v2", "src/common/v2");

    copy_tests_v2_v3("src/common/v2", "src/common/v3");
    gen_in_dir("src/common/v3", "src/common/v3");
}

fn generate_in_v2_v3() {
    gen_in_dir("src/v2", "src/v2");

    gen_in_dir("src/v3", "src/v3");

    gen_in_dir("src/google/protobuf", "src");
}

fn generate_interop() {
    codegen()
        .out_dir("src/interop")
        .includes(&["../interop/cxx", "../proto"])
        .input("../interop/cxx/interop_pb.proto")
        .run()
        .unwrap();
}

fn generate_include_generated() {
    let dir = format!("{}/include_generated", env::var("OUT_DIR").unwrap());
    if Path::new(&dir).exists() {
        fs::remove_dir_all(&dir).unwrap();
    }
    fs::create_dir(&dir).unwrap();
    protoc_rust::Codegen::new()
        .out_dir(dir)
        .input("src/include_generated/v2.proto")
        .input("src/include_generated/v3.proto")
        .customize(Customize {
            gen_mod_rs: Some(true),
            ..Default::default()
        })
        .include("src/include_generated")
        .run()
        .unwrap();
}

fn generate_pb_rs() {
    generate_in_common();
    generate_in_v2_v3();
    generate_interop();
    generate_include_generated();
}

fn main() {
    env_logger::init();

    cfg_serde();

    clean_old_files();

    generate_pb_rs();
}
<|endoftext|>