<commit_before>use std::path::Path;

use error::PackageError;

/// Enum for representing the state of the package downloads.
pub enum PackageDownload<'a> {
    /// The state is switched to IsFinished when the download of the
    /// package is finished, leaving only a `&Path` which is the location
    /// of the downloaded package.
    IsFinished(&'a Path),
    /// The state is switched to InProgress when the download of the
    /// package is started, the `&Path` is the location where the
    /// half-downloaded package is located at, while the `u32` is the progress
    /// of the current download process.
    InProgress(&'a Path, u32),
    /// This is the initial state of PackageDownload, where the package is yet
    /// to be downloaded. It has a `&str` for storing the URL, and a `&Path`
    /// of which the package is going to be located at, when the package is
    /// downloaded.
    NotStarted(&'a str, &'a Path)
}

impl<'a> PackageDownload<'a> {
    /// Create a new PackageDownload.
    fn new(url: &'a str, path: &'a Path) -> Self {
        PackageDownload::NotStarted(url, path)
    }

    /// A bool to determine whether the package is downloaded.
    fn is_downloaded(&self) -> bool {
        match self {
            &PackageDownload::IsFinished(_) => true,
            _ => false
        }
    }

    /// Returns the path of where the package is (or is going to be) located
    /// at.
    fn store_path(&self) -> &'a Path {
        match self {
            &PackageDownload::IsFinished(ref path) => path,
            &PackageDownload::InProgress(ref path, _) => path,
            &PackageDownload::NotStarted(_, ref path) => path,
        }
    }
}<commit_msg>PackageDownload also stores the total filesize now<commit_after>use std::path::Path;

use error::PackageError;

/// Enum for representing the state of the package downloads.
pub enum PackageDownload<'a> {
    /// The state is switched to IsFinished when the download of the
    /// package is finished, leaving a `&Path` which is the location
    /// of the downloaded package, and a `u32` which is the file size.
    IsFinished(&'a Path, u32),
    /// The state is switched to InProgress when the download of the
    /// package is started, the `&Path` is the location where the
    /// half-downloaded package is located at, while the first `u32` is the
    /// progress of the current download process in bytes, the third `u32`
    /// is the total file size of the package.
    InProgress(&'a Path, u32, u32),
    /// This is the initial state of PackageDownload, where the package is yet
    /// to be downloaded. It has a `&str` for storing the URL, and a `&Path`
    /// of which the package is going to be located at, when the package is
    /// downloaded.
    NotStarted(&'a str, &'a Path)
}

impl<'a> PackageDownload<'a> {
    /// Create a new PackageDownload.
    fn new(url: &'a str, path: &'a Path) -> Self {
        PackageDownload::NotStarted(url, path)
    }

    /// A bool to determine whether the package is downloaded.
    fn is_downloaded(&self) -> bool {
        match self {
            &PackageDownload::IsFinished(_,_) => true,
            _ => false
        }
    }

    /// Returns the path of where the package is (or is going to be) located
    /// at.
    fn store_path(&self) -> &'a Path {
        match self {
            &PackageDownload::IsFinished(ref path, _) => path,
            &PackageDownload::InProgress(ref path, _, _) => path,
            &PackageDownload::NotStarted(_, ref path) => path,
        }
    }
}<|endoftext|>


<commit_before>//! Define explicit schemes

use ndarray::*;
use ndarray_linalg::*;
use super::traits::*;

use std::marker::PhantomData;

macro_rules! def_explicit {
    ($method:ident, $constructor:ident) => {

pub struct $method<A, D, F>
where A: Scalar,
      D: Dimension,
{
    f: F,
    dt: A::Real,
    phantom: PhantomData<D>
}

impl<A, D, F> ModelSize<D> for $method<A, D, F>
where A: Scalar,
      D: Dimension,
      F: ModelSize<D>
{
    fn model_size(&self) -> D::Pattern {
        self.f.model_size()
    }
}

impl<A, D, F> TimeStep for $method<A, D, F>
where A: Scalar,
      D: Dimension
{
    type Time = A::Real;
    fn get_dt(&self) -> Self::Time {
        self.dt
    }
    fn set_dt(&mut self, dt: Self::Time) {
        self.dt = dt;
    }
}

pub fn $constructor<A, D, F>(f: F, dt: A::Real) -> $method<A, D, F>
where A: Scalar,
      D: Dimension
{
    $method { f: f, dt: dt, phantom: PhantomData }
}

}} // def_explicit

def_explicit!(Euler, euler);
def_explicit!(Heun, heun);
def_explicit!(RK4, rk4);

pub struct EulerBuffer<A, D> {
    x: Array<A, D>,
}

impl<A, D, F> TimeEvolution<D> for Euler<A, D, F>
    where A: Scalar,
          D: Dimension,
          F: Explicit<D, Scalar = A, Time = A::Real>
{
    type Scalar = A;
    type Buffer = EulerBuffer<A, D>;

    fn new_buffer(&self) -> Self::Buffer {
        EulerBuffer { x: Array::zeros(self.f.model_size()) }
    }

    fn iterate<'a, S>(&self,
                      mut x: &'a mut ArrayBase<S, D>,
                      mut buf: &mut Self::Buffer)
                      -> &'a mut ArrayBase<S, D>
        where S: DataMut<Elem = A>
    {
        buf.x.zip_mut_with(x, |buf, x| *buf = *x);
        let mut fx = self.f.rhs(x);
        Zip::from(&mut *fx)
            .and(&buf.x)
            .apply(|vfx, vx| { *vfx = *vx + vfx.mul_real(self.dt); });
        fx
    }
}

pub struct HeunBuffer<A, D> {
    x: Array<A, D>,
    k1: Array<A, D>,
}

impl<A, D, F> TimeEvolution<D> for Heun<A, D, F>
    where A: Scalar,
          D: Dimension,
          F: Explicit<D, Time = A::Real, Scalar = A>
{
    type Scalar = A;
    type Buffer = HeunBuffer<A, D>;

    fn new_buffer(&self) -> Self::Buffer {
        HeunBuffer {
            x: Array::zeros(self.f.model_size()),
            k1: Array::zeros(self.f.model_size()),
        }
    }

    fn iterate<'a, S>(&self,
                      mut x: &'a mut ArrayBase<S, D>,
                      mut buf: &mut HeunBuffer<A, D>)
                      -> &'a mut ArrayBase<S, D>
        where S: DataMut<Elem = A>
    {
        let dt = self.dt;
        let dt_2 = self.dt * into_scalar(0.5);
        // calc
        buf.x.zip_mut_with(x, |buf, x| *buf = *x);
        let k1 = self.f.rhs(x);
        buf.k1.zip_mut_with(k1, |buf, k1| *buf = *k1);
        Zip::from(&mut *k1)
            .and(&buf.x)
            .apply(|k1, &x_| { *k1 = k1.mul_real(dt) + x_; });
        let k2 = self.f.rhs(k1);
        Zip::from(&mut *k2)
            .and(&buf.x)
            .and(&buf.k1)
            .apply(|k2, &x_, &k1_| { *k2 = x_ + (k1_ + *k2).mul_real(dt_2); });
        k2
    }
}

pub struct RK4Buffer<A, D> {
    x: Array<A, D>,
    k1: Array<A, D>,
    k2: Array<A, D>,
    k3: Array<A, D>,
}

impl<A, D, F> TimeEvolution<D> for RK4<A, D, F>
    where A: Scalar,
          D: Dimension,
          F: Explicit<D, Time = A::Real, Scalar = A>
{
    type Scalar = A;
    type Buffer = RK4Buffer<A, D>;

    fn new_buffer(&self) -> Self::Buffer {
        RK4Buffer {
            x: Array::zeros(self.f.model_size()),
            k1: Array::zeros(self.f.model_size()),
            k2: Array::zeros(self.f.model_size()),
            k3: Array::zeros(self.f.model_size()),
        }
    }

    fn iterate<'a, S>(&self,
                      mut x: &'a mut ArrayBase<S, D>,
                      mut buf: &mut RK4Buffer<A, D>)
                      -> &'a mut ArrayBase<S, D>
        where S: DataMut<Elem = A>
    {
        let two = into_scalar(2.0);
        let dt = self.dt;
        let dt_2 = self.dt * into_scalar(0.5);
        let dt_6 = self.dt / into_scalar(6.0);
        buf.x.zip_mut_with(x, |buf, x| *buf = *x);
        // k1
        let mut k1 = self.f.rhs(x);
        buf.k1.zip_mut_with(k1, |buf, k1| *buf = *k1);
        Zip::from(&mut *k1)
            .and(&buf.x)
            .apply(|k1, &x| { *k1 = k1.mul_real(dt_2) + x; });
        // k2
        let mut k2 = self.f.rhs(k1);
        buf.k2.zip_mut_with(k2, |buf, k| *buf = *k);
        Zip::from(&mut *k2)
            .and(&buf.x)
            .apply(|k2, &x| { *k2 = x + k2.mul_real(dt_2); });
        // k3
        let mut k3 = self.f.rhs(k2);
        buf.k3.zip_mut_with(k3, |buf, k| *buf = *k);
        Zip::from(&mut *k3)
            .and(&buf.x)
            .apply(|k3, &x| { *k3 = x + k3.mul_real(dt); });
        let mut k4 = self.f.rhs(k3);
        Zip::from(&mut *k4)
            .and(&buf.x)
            .and(&buf.k1)
            .and(&buf.k2)
            .and(&buf.k3)
            .apply(|k4, &x, &k1, &k2, &k3| {
                       *k4 = x + (k1 + (k2 + k3).mul_real(two) + *k4).mul_real(dt_6);
                   });
        k4
    }
}
<commit_msg>Add type traits for better inference<commit_after>//! Define explicit schemes

use ndarray::*;
use ndarray_linalg::*;
use super::traits::*;

use std::marker::PhantomData;

macro_rules! def_explicit {
    ($method:ident, $constructor:ident) => {

pub struct $method<A, D, F>
where A: Scalar,
      D: Dimension,
      F: Explicit<D, Scalar = A, Time = A::Real>
{
    f: F,
    dt: A::Real,
    phantom: PhantomData<D>
}

impl<A, D, F> ModelSize<D> for $method<A, D, F>
where A: Scalar,
      D: Dimension,
      F: Explicit<D, Scalar = A, Time = A::Real>
{
    fn model_size(&self) -> D::Pattern {
        self.f.model_size()
    }
}

impl<A, D, F> TimeStep for $method<A, D, F>
where A: Scalar,
      D: Dimension,
      F: Explicit<D, Scalar = A, Time = A::Real>
{
    type Time = A::Real;
    fn get_dt(&self) -> Self::Time {
        self.dt
    }
    fn set_dt(&mut self, dt: Self::Time) {
        self.dt = dt;
    }
}

pub fn $constructor<A, D, F>(f: F, dt: A::Real) -> $method<A, D, F>
where A: Scalar,
      D: Dimension,
      F: Explicit<D, Scalar = A, Time = A::Real>
{
    $method { f: f, dt: dt, phantom: PhantomData }
}

}} // def_explicit

def_explicit!(Euler, euler);
def_explicit!(Heun, heun);
def_explicit!(RK4, rk4);

pub struct EulerBuffer<A, D> {
    x: Array<A, D>,
}

impl<A, D, F> TimeEvolution<D> for Euler<A, D, F>
    where A: Scalar,
          D: Dimension,
          F: Explicit<D, Scalar = A, Time = A::Real>
{
    type Scalar = A;
    type Buffer = EulerBuffer<A, D>;

    fn new_buffer(&self) -> Self::Buffer {
        EulerBuffer { x: Array::zeros(self.f.model_size()) }
    }

    fn iterate<'a, S>(&self,
                      mut x: &'a mut ArrayBase<S, D>,
                      mut buf: &mut Self::Buffer)
                      -> &'a mut ArrayBase<S, D>
        where S: DataMut<Elem = A>
    {
        buf.x.zip_mut_with(x, |buf, x| *buf = *x);
        let mut fx = self.f.rhs(x);
        Zip::from(&mut *fx)
            .and(&buf.x)
            .apply(|vfx, vx| { *vfx = *vx + vfx.mul_real(self.dt); });
        fx
    }
}

pub struct HeunBuffer<A, D> {
    x: Array<A, D>,
    k1: Array<A, D>,
}

impl<A, D, F> TimeEvolution<D> for Heun<A, D, F>
    where A: Scalar,
          D: Dimension,
          F: Explicit<D, Time = A::Real, Scalar = A>
{
    type Scalar = A;
    type Buffer = HeunBuffer<A, D>;

    fn new_buffer(&self) -> Self::Buffer {
        HeunBuffer {
            x: Array::zeros(self.f.model_size()),
            k1: Array::zeros(self.f.model_size()),
        }
    }

    fn iterate<'a, S>(&self,
                      mut x: &'a mut ArrayBase<S, D>,
                      mut buf: &mut HeunBuffer<A, D>)
                      -> &'a mut ArrayBase<S, D>
        where S: DataMut<Elem = A>
    {
        let dt = self.dt;
        let dt_2 = self.dt * into_scalar(0.5);
        // calc
        buf.x.zip_mut_with(x, |buf, x| *buf = *x);
        let k1 = self.f.rhs(x);
        buf.k1.zip_mut_with(k1, |buf, k1| *buf = *k1);
        Zip::from(&mut *k1)
            .and(&buf.x)
            .apply(|k1, &x_| { *k1 = k1.mul_real(dt) + x_; });
        let k2 = self.f.rhs(k1);
        Zip::from(&mut *k2)
            .and(&buf.x)
            .and(&buf.k1)
            .apply(|k2, &x_, &k1_| { *k2 = x_ + (k1_ + *k2).mul_real(dt_2); });
        k2
    }
}

pub struct RK4Buffer<A, D> {
    x: Array<A, D>,
    k1: Array<A, D>,
    k2: Array<A, D>,
    k3: Array<A, D>,
}

impl<A, D, F> TimeEvolution<D> for RK4<A, D, F>
    where A: Scalar,
          D: Dimension,
          F: Explicit<D, Time = A::Real, Scalar = A>
{
    type Scalar = A;
    type Buffer = RK4Buffer<A, D>;

    fn new_buffer(&self) -> Self::Buffer {
        RK4Buffer {
            x: Array::zeros(self.f.model_size()),
            k1: Array::zeros(self.f.model_size()),
            k2: Array::zeros(self.f.model_size()),
            k3: Array::zeros(self.f.model_size()),
        }
    }

    fn iterate<'a, S>(&self,
                      mut x: &'a mut ArrayBase<S, D>,
                      mut buf: &mut RK4Buffer<A, D>)
                      -> &'a mut ArrayBase<S, D>
        where S: DataMut<Elem = A>
    {
        let two = into_scalar(2.0);
        let dt = self.dt;
        let dt_2 = self.dt * into_scalar(0.5);
        let dt_6 = self.dt / into_scalar(6.0);
        buf.x.zip_mut_with(x, |buf, x| *buf = *x);
        // k1
        let mut k1 = self.f.rhs(x);
        buf.k1.zip_mut_with(k1, |buf, k1| *buf = *k1);
        Zip::from(&mut *k1)
            .and(&buf.x)
            .apply(|k1, &x| { *k1 = k1.mul_real(dt_2) + x; });
        // k2
        let mut k2 = self.f.rhs(k1);
        buf.k2.zip_mut_with(k2, |buf, k| *buf = *k);
        Zip::from(&mut *k2)
            .and(&buf.x)
            .apply(|k2, &x| { *k2 = x + k2.mul_real(dt_2); });
        // k3
        let mut k3 = self.f.rhs(k2);
        buf.k3.zip_mut_with(k3, |buf, k| *buf = *k);
        Zip::from(&mut *k3)
            .and(&buf.x)
            .apply(|k3, &x| { *k3 = x + k3.mul_real(dt); });
        let mut k4 = self.f.rhs(k3);
        Zip::from(&mut *k4)
            .and(&buf.x)
            .and(&buf.k1)
            .and(&buf.k2)
            .and(&buf.k3)
            .apply(|k4, &x, &k1, &k2, &k3| {
                       *k4 = x + (k1 + (k2 + k3).mul_real(two) + *k4).mul_real(dt_6);
                   });
        k4
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! This crate provide the non-GUI part of relm:
//! Basic component and message connection methods.

#![warn(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
    unused_results,
)]

#[macro_use]
extern crate log;
extern crate relm_core;

mod into;
mod macros;

use std::time::SystemTime;

pub use relm_core::EventStream;

pub use into::{IntoOption, IntoPair};

/// Handle event stream to send messages to the [`update()`](trait.Update.html#tymethod.update) method.
pub struct Relm<UPDATE: Update> {
    stream: EventStream<UPDATE::Msg>,
}

impl<UPDATE: Update> Clone for Relm<UPDATE> {
    fn clone(&self) -> Self {
        Relm {
            stream: self.stream.clone(),
        }
    }
}

impl<UPDATE: Update> Relm<UPDATE> {
    /// Create a new relm stream handler.
    pub fn new(stream: EventStream<UPDATE::Msg>) -> Self {
        Relm {
            stream,
        }
    }

    /// Get the event stream of this stream.
    /// This is used internally by the library.
    pub fn stream(&self) -> &EventStream<UPDATE::Msg> {
        &self.stream
    }
}

/// Trait for a basic (non-widget) component.
/// A component has a model (data) associated with it and can mutate it when it receives a message
/// (in the `update()` method).
pub trait Update
    where Self: Sized,
          Self::Msg: DisplayVariant,
{
    /// The type of the model.
    type Model;
    /// The type of the parameter of the model() function used to initialize the model.
    type ModelParam: Sized;
    /// The type of the messages sent to the [`update()`](trait.Update.html#tymethod.update) method.
    type Msg;

    /// Create the initial model.
    fn model(relm: &Relm<Self>, param: Self::ModelParam) -> Self::Model;

    /// Connect the subscriptions.
    /// Subscriptions are `Future`/`Stream` that are spawn when the object is created.
    fn subscriptions(&mut self, _relm: &Relm<Self>) {
    }

    /// Method called when a message is received from an event.
    fn update(&mut self, event: Self::Msg);
}

/// Trait for an `Update` object that can be created directly.
/// This is useful for non-widget component.
pub trait UpdateNew: Update {
    /// Create a new component.
    fn new(_relm: &Relm<Self>, _model: Self::Model) -> Self;
}

/// Format trait for enum variants.
///
/// `DisplayVariant` is similar to `Debug`, but only works on enum and does not list the
/// variants' parameters.
///
/// This is used internally by the library.
pub trait DisplayVariant {
    /// Formats the current variant of the enum.
    fn display_variant(&self) -> &'static str;
}

impl DisplayVariant for () {
    fn display_variant(&self) -> &'static str {
        ""
    }
}

/// Create a bare component, i.e. a component only implementing the Update trait, not the Widget
/// trait.
pub fn execute<UPDATE>(model_param: UPDATE::ModelParam) -> EventStream<UPDATE::Msg>
where UPDATE: Update + UpdateNew + 'static
{
    let stream = EventStream::new();

    let relm = Relm::new(stream.clone());
    let model = UPDATE::model(&relm, model_param);
    let component = UPDATE::new(&relm, model);

    init_component::<UPDATE>(&stream, component, &relm);
    stream
}

/// Initialize a component by creating its subscriptions and dispatching the messages from the
/// stream.
pub fn init_component<UPDATE>(stream: &EventStream<UPDATE::Msg>, mut component: UPDATE, relm: &Relm<UPDATE>)
    where UPDATE: Update + 'static,
          UPDATE::Msg: DisplayVariant + 'static,
{
    let stream = stream.clone(); // FIXME: remove this line?
    component.subscriptions(relm);
    stream.set_callback(move |event| {
        update_component(&mut component, event);
    });
}

fn update_component<COMPONENT>(component: &mut COMPONENT, event: COMPONENT::Msg)
    where COMPONENT: Update,
{
    if cfg!(debug_assertions) {
        let time = SystemTime::now();
        let debug = event.display_variant();
        let debug =
            if debug.len() > 100 {
                format!("{}…", &debug[..100])
            }
            else {
                debug.to_string()
            };
        component.update(event);
        if let Ok(duration) = time.elapsed() {
            let ms = duration.subsec_nanos() as u64 / 1_000_000 + duration.as_secs() * 1000;
            if ms >= 16 {
                warn!("The update function was slow to execute for message {}: {}ms", debug, ms);
            }
        }
    }
    else {
        component.update(event)
    }
}
<commit_msg>Add comment<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! This crate provide the non-GUI part of relm:
//! Basic component and message connection methods.

#![warn(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
    unused_results,
)]

#[macro_use]
extern crate log;
extern crate relm_core;

mod into;
mod macros;

use std::time::SystemTime;

pub use relm_core::EventStream;

pub use into::{IntoOption, IntoPair};

/// Handle event stream to send messages to the [`update()`](trait.Update.html#tymethod.update) method.
pub struct Relm<UPDATE: Update> {
    stream: EventStream<UPDATE::Msg>,
}

impl<UPDATE: Update> Clone for Relm<UPDATE> {
    fn clone(&self) -> Self {
        Relm {
            stream: self.stream.clone(),
        }
    }
}

impl<UPDATE: Update> Relm<UPDATE> {
    /// Create a new relm stream handler.
    pub fn new(stream: EventStream<UPDATE::Msg>) -> Self {
        Relm {
            stream,
        }
    }

    /// Get the event stream of this stream.
    /// This is used internally by the library.
    pub fn stream(&self) -> &EventStream<UPDATE::Msg> {
        &self.stream
    }
}

/// Trait for a basic (non-widget) component.
/// A component has a model (data) associated with it and can mutate it when it receives a message
/// (in the `update()` method).
pub trait Update
    where Self: Sized,
          Self::Msg: DisplayVariant,
{
    /// The type of the model.
    type Model;
    /// The type of the parameter of the model() function used to initialize the model.
    type ModelParam: Sized;
    /// The type of the messages sent to the [`update()`](trait.Update.html#tymethod.update) method.
    type Msg;

    /// Create the initial model.
    fn model(relm: &Relm<Self>, param: Self::ModelParam) -> Self::Model;

    /// Connect the subscriptions.
    /// Subscriptions are `Future`/`Stream` that are spawn when the object is created.
    fn subscriptions(&mut self, _relm: &Relm<Self>) {
    }

    /// Method called when a message is received from an event.
    fn update(&mut self, event: Self::Msg);
}

/// Trait for an `Update` object that can be created directly.
/// This is useful for non-widget component.
pub trait UpdateNew: Update {
    /// Create a new component.
    fn new(_relm: &Relm<Self>, _model: Self::Model) -> Self;
}

/// Format trait for enum variants.
///
/// `DisplayVariant` is similar to `Debug`, but only works on enum and does not list the
/// variants' parameters.
///
/// This is used internally by the library.
pub trait DisplayVariant {
    /// Formats the current variant of the enum.
    fn display_variant(&self) -> &'static str;
}

impl DisplayVariant for () {
    fn display_variant(&self) -> &'static str {
        ""
    }
}

/// Create a bare component, i.e. a component only implementing the Update trait, not the Widget
/// trait.
pub fn execute<UPDATE>(model_param: UPDATE::ModelParam) -> EventStream<UPDATE::Msg>
where UPDATE: Update + UpdateNew + 'static
{
    let stream = EventStream::new();

    let relm = Relm::new(stream.clone());
    let model = UPDATE::model(&relm, model_param);
    let component = UPDATE::new(&relm, model);

    init_component::<UPDATE>(&stream, component, &relm);
    stream
}

/// Initialize a component by creating its subscriptions and dispatching the messages from the
/// stream.
pub fn init_component<UPDATE>(stream: &EventStream<UPDATE::Msg>, mut component: UPDATE, relm: &Relm<UPDATE>)
    where UPDATE: Update + 'static,
          UPDATE::Msg: DisplayVariant + 'static,
{
    component.subscriptions(relm);
    // FIXME: This callback contains the component and the component contains a copy of the stream,
    // so we have a reference cycle.
    stream.set_callback(move |event| {
        update_component(&mut component, event);
    });
}

fn update_component<COMPONENT>(component: &mut COMPONENT, event: COMPONENT::Msg)
    where COMPONENT: Update,
{
    if cfg!(debug_assertions) {
        let time = SystemTime::now();
        let debug = event.display_variant();
        let debug =
            if debug.len() > 100 {
                format!("{}…", &debug[..100])
            }
            else {
                debug.to_string()
            };
        component.update(event);
        if let Ok(duration) = time.elapsed() {
            let ms = duration.subsec_nanos() as u64 / 1_000_000 + duration.as_secs() * 1000;
            if ms >= 16 {
                warn!("The update function was slow to execute for message {}: {}ms", debug, ms);
            }
        }
    }
    else {
        component.update(event)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::alloc::AllocBox;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum, JsKey, JsKeyEnum};
use js_types::js_var::JsType::*;

use jsrs_parser::lalr::parse_Stmt;
use jsrs_common::ast::*;
use jsrs_common::ast::Exp::*;
use jsrs_common::ast::BinOp::*;
use jsrs_common::ast::Stmt::*;

/// Evaluate a string containing some JavaScript statements (or sequences of statements).
/// Returns a JsVar which is the return value of those statements.
pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => {
            eval_stmt(&stmt, state).0
        }
        Err(_) => panic!("parse error"),
    }
}

/// Evaluate a single JS statement (which may be a block or sequence of statements).
/// Returns tuple of (evaluated final value, return value), where return value requires that
/// `return` be used to generate it.
pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> (JsVar, Option<JsVar>) {
    match *s {
        // var_string = exp;
        Assign(ref var_string, ref exp) => {
            let mut js_var = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());

            // Clone the js_var to store into the ScopeManager
            let cloned = js_var.clone();
            match state.alloc(cloned, None) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

        // exp;
        BareExp(ref exp) => (eval_exp(exp, &mut state), None),

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let mut js_var = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            // TODO: must handle JsPtrEnum here.
            match state.alloc(js_var.clone(), None) {
                Ok(_) => (js_var, None),
                e @ Err(_) => panic!("{:?}", e),
            }
        },

        // if (condition) { if_block } else { else_block }
        If(ref condition, ref if_block, ref else_block) => {
            // evaluate expression
            if eval_exp(&condition, state).as_bool() {
                // condition = true, evaluate if-block.
                eval_stmt(&*if_block, state)
            } else {
                // condition = false
                // evaluate else-block if it exists, otherwise return undefined.
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    (JsVar::new(JsUndef), None)
                }
            }
        },

        // return exp
        Ret(ref exp) => {
            let js_var = eval_exp(&exp, &mut state);
            (js_var.clone(), Some(js_var))
        }

        // a sequence of any two expressions
        Seq(ref s1, ref s2) => {
            eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },

        // while (condition) { block }
        While(ref condition, ref block) => {
            let mut ret_val = None;
            loop {
                if eval_exp(&condition, state).as_bool() {
                    // TODO: check to see if a return stmt has been reached.
                    let (_, v) = eval_stmt(&*block, state);
                    ret_val = v;
                } else {
                    // condition is no longer true, return a return value
                    return (JsVar::new(JsUndef), ret_val);
                }
            }
        }
    }
}

/// Evaluate an expression into a JsVar.
pub fn eval_exp(e: &Exp, mut state: &mut ScopeManager) -> JsVar {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state);
            let val2 = eval_exp(e2, state);

            match *op {
                And => JsVar::new(JsBool(val1.as_bool() && val2.as_bool())),
                Or  => JsVar::new(JsBool(val1.as_bool() || val2.as_bool())),

                Ge  => JsVar::new(JsBool(val1.as_bool() >= val2.as_bool())),
                Gt  => JsVar::new(JsBool(val1.as_bool() >  val2.as_bool())),
                Le  => JsVar::new(JsBool(val1.as_bool() <= val2.as_bool())),
                Lt  => JsVar::new(JsBool(val1.as_bool() <  val2.as_bool())),
                Neq => JsVar::new(JsBool(val1.as_bool() != val2.as_bool())),
                Eql => JsVar::new(JsBool(val1.as_bool() == val2.as_bool())),

                Minus => JsVar::new(JsNum(val1.as_number() - val2.as_number())),
                Plus  => JsVar::new(JsNum(val1.as_number() + val2.as_number())),
                Slash => JsVar::new(JsNum(val1.as_number() / val2.as_number())),
                Star  => JsVar::new(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => JsVar::new(JsBool(b)),

        // fun_name([arg_exp1, arg_exps])
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state);

            // Create vector of arguments, evaluated to JsVars.
            let mut args = Vec::new();
            for exp in arg_exps {
                args.push(eval_exp(exp, state));
            }

            match state.load(&fun_binding.binding) {
                Ok((_, Some(JsPtrEnum::JsFn(js_fn_struct)))) => {
                    state.push_scope();

                    for param in js_fn_struct.params {
                        let mut arg = if args.is_empty() {
                            JsVar::new(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.binding = Binding::new(param.to_owned());
                        state.alloc(arg, None).expect("Unable to store function argument in scope");
                    }

                    let (_, v) = eval_stmt(&js_fn_struct.stmt, state);

                    // Should we yield here? Not sure, so for now it doesn't
                    state.pop_scope(false).expect("Unable to clear scope for function");
                    v.unwrap_or(JsVar::new(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {} is not defined")
            }
        },

        // function([param1, params]) { body }
        // function opt_binding([param1, params]) { body }
        &Defun(ref opt_binding, ref params, ref body) => {
            if let &Some(ref binding) = opt_binding {
                let js_fun = JsFnStruct::new(opt_binding, params, &**body);
                let mut var = JsVar::new(JsPtr);
                var.binding = Binding::new(binding.clone());
                if let Err(_) = state.alloc(var, Some(JsPtrEnum::JsFn(js_fun))) {
                    panic!("error storing function into state");
                }
                JsVar::new(JsPtr) // Doesn't store any information anyway
            } else {
                panic!("functions without bindings are not yet supported.")
            }
        },
        &Float(f) => JsVar::new(JsType::JsNum(f)),
        &Neg(ref exp) => JsVar::new(JsNum(-eval_exp(exp, state).as_number())),
        &Pos(ref exp) => JsVar::new(JsNum(eval_exp(exp, state).as_number())),

        &PostDec(ref exp) => eval_float_post_op!(exp, f, f - 1.0, state),
        &PostInc(ref exp) => eval_float_post_op!(exp, f, f + 1.0, state),
        &PreDec(ref exp)  => eval_float_pre_op!(exp, f, f - 1.0, state),
        &PreInc(ref exp)  => eval_float_pre_op!(exp, f, f + 1.0, state),

        &NewObject(_, _) => unimplemented!(),
        &Object(ref fields) => {
            let mut kv_tuples = Vec::new();
            for f in fields {
                let f_key = JsKey::new(JsKeyEnum::JsStr(JsStrStruct::new(&f.0)));
                let f_exp = eval_exp(&*f.1, state);
                kv_tuples.push((f_key, f_exp, None));
            }
            JsObjStruct::new(None, "", kv_tuples, &mut AllocBox::new());
            JsVar::new(JsPtr)
        },

        &Undefined => JsVar::new(JsUndef),
        &Var(ref var_binding) => {
            state.load(&Binding::new(var_binding.clone()))
                .expect("ReferenceError: {} is not defined").0
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::hash_set::HashSet;
    use french_press::init_gc;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(5.0f64), eval_string("5.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.0f64), eval_string("0.0;\n", &mut state).t);
        assert_eq!(JsType::JsUndef, eval_string("undefined;\n", &mut state).t);
    }

    //// TODO: handle `var` and no `var` separately
    //#[test]
    //fn test_store_state() {
    //    let mut state = HashMap::new();
    //    assert_eq!(JsUndefined, eval_string("var a = 1;\n", &mut state));
    //    assert_eq!(JsNumber(2.0f64), eval_string("a = 2;\n", &mut state));
    //    assert_eq!(JsUndefined, eval_string("var b = 3;\n", &mut state));
    //    assert_eq!(JsNumber(4.0f64), eval_string("c = 4;\n", &mut state));
    //}

    #[test]
    fn test_inc_dec() {
        let mut state = init_gc();
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.load(&Binding::new("a")).unwrap());

        //assert_eq!(JsType::JsNum(1.0f64), eval_string("a++;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("++a;\n", &mut state));
        //assert_eq!(&JsNumber(3.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("a--;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(1.0f64), eval_string("--a;\n", &mut state));
        //assert_eq!(&JsNumber(1.0f64), state.get("a").unwrap());
    }

    #[test]
    fn test_binexp() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(6.0f64),  eval_string("2.0 + 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.5f64),  eval_string("2.0 / 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(-2.0f64), eval_string("2.0 - 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(8.0f64),  eval_string("2.0 * 4.0;\n", &mut state).t);
    }
}
<commit_msg>better rust<commit_after>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::alloc::AllocBox;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum, JsKey, JsKeyEnum};
use js_types::js_var::JsType::*;

use jsrs_parser::lalr::parse_Stmt;
use jsrs_common::ast::*;
use jsrs_common::ast::Exp::*;
use jsrs_common::ast::BinOp::*;
use jsrs_common::ast::Stmt::*;

/// Evaluate a string containing some JavaScript statements (or sequences of statements).
/// Returns a JsVar which is the return value of those statements.
pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => {
            eval_stmt(&stmt, state).0
        }
        Err(_) => panic!("parse error"),
    }
}

/// Evaluate a single JS statement (which may be a block or sequence of statements).
/// Returns tuple of (evaluated final value, return value), where return value requires that
/// `return` be used to generate it.
pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> (JsVar, Option<JsVar>) {
    match *s {
        // var_string = exp;
        Assign(ref var_string, ref exp) => {
            let mut js_var = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());

            // Clone the js_var to store into the ScopeManager
            let cloned = js_var.clone();
            match state.alloc(cloned, None) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

        // exp;
        BareExp(ref exp) => (eval_exp(exp, &mut state), None),

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let mut js_var = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            // TODO: must handle JsPtrEnum here.
            match state.alloc(js_var.clone(), None) {
                Ok(_) => (js_var, None),
                e @ Err(_) => panic!("{:?}", e),
            }
        },

        // if (condition) { if_block } else { else_block }
        If(ref condition, ref if_block, ref else_block) => {
            // evaluate expression
            if eval_exp(&condition, state).as_bool() {
                // condition = true, evaluate if-block.
                eval_stmt(&*if_block, state)
            } else {
                // condition = false
                // evaluate else-block if it exists, otherwise return undefined.
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    (JsVar::new(JsUndef), None)
                }
            }
        },

        // return exp
        Ret(ref exp) => {
            let js_var = eval_exp(&exp, &mut state);
            (js_var.clone(), Some(js_var))
        }

        // a sequence of any two expressions
        Seq(ref s1, ref s2) => {
            eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },

        // while (condition) { block }
        While(ref condition, ref block) => {
            let mut ret_val = None;
            loop {
                if eval_exp(&condition, state).as_bool() {
                    // TODO: check to see if a return stmt has been reached.
                    let (_, v) = eval_stmt(&*block, state);
                    ret_val = v;
                } else {
                    // condition is no longer true, return a return value
                    return (JsVar::new(JsUndef), ret_val);
                }
            }
        }
    }
}

/// Evaluate an expression into a JsVar.
pub fn eval_exp(e: &Exp, mut state: &mut ScopeManager) -> JsVar {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state);
            let val2 = eval_exp(e2, state);

            match *op {
                And => JsVar::new(JsBool(val1.as_bool() && val2.as_bool())),
                Or  => JsVar::new(JsBool(val1.as_bool() || val2.as_bool())),

                Ge  => JsVar::new(JsBool(val1.as_bool() >= val2.as_bool())),
                Gt  => JsVar::new(JsBool(val1.as_bool() >  val2.as_bool())),
                Le  => JsVar::new(JsBool(val1.as_bool() <= val2.as_bool())),
                Lt  => JsVar::new(JsBool(val1.as_bool() <  val2.as_bool())),
                Neq => JsVar::new(JsBool(val1.as_bool() != val2.as_bool())),
                Eql => JsVar::new(JsBool(val1.as_bool() == val2.as_bool())),

                Minus => JsVar::new(JsNum(val1.as_number() - val2.as_number())),
                Plus  => JsVar::new(JsNum(val1.as_number() + val2.as_number())),
                Slash => JsVar::new(JsNum(val1.as_number() / val2.as_number())),
                Star  => JsVar::new(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => JsVar::new(JsBool(b)),

        // fun_name([arg_exp1, arg_exps])
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state);

            // Create vector of arguments, evaluated to JsVars.
            let mut args = Vec::new();
            for exp in arg_exps {
                args.push(eval_exp(exp, state));
            }

            match state.load(&fun_binding.binding) {
                Ok((_, Some(JsPtrEnum::JsFn(js_fn_struct)))) => {
                    state.push_scope();

                    for param in js_fn_struct.params {
                        let mut arg = if args.is_empty() {
                            JsVar::new(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.binding = Binding::new(param.to_owned());
                        state.alloc(arg, None)
                            .expect("Unable to store function argument in scope");
                    }

                    let (_, v) = eval_stmt(&js_fn_struct.stmt, state);

                    // Should we yield here? Not sure, so for now it doesn't
                    state.pop_scope(false).expect("Unable to clear scope for function");
                    v.unwrap_or(JsVar::new(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {} is not defined")
            }
        },

        // function([param1, params]) { body }
        // function opt_binding([param1, params]) { body }
        &Defun(ref opt_binding, ref params, ref body) => {
            if let &Some(ref binding) = opt_binding {
                let js_fun = JsFnStruct::new(opt_binding, params, &**body);
                let var = JsVar::bind(binding.clone(), JsPtr);
                state.alloc(var.clone(), Some(JsPtrEnum::JsFn(js_fun)))
                    .expect("error storing function into state");
                var
            } else {
                panic!("functions without bindings are not yet supported.")
            }
        },
        &Float(f) => JsVar::new(JsType::JsNum(f)),
        &Neg(ref exp) => JsVar::new(JsNum(-eval_exp(exp, state).as_number())),
        &Pos(ref exp) => JsVar::new(JsNum(eval_exp(exp, state).as_number())),

        &PostDec(ref exp) => eval_float_post_op!(exp, f, f - 1.0, state),
        &PostInc(ref exp) => eval_float_post_op!(exp, f, f + 1.0, state),
        &PreDec(ref exp)  => eval_float_pre_op!(exp, f, f - 1.0, state),
        &PreInc(ref exp)  => eval_float_pre_op!(exp, f, f + 1.0, state),

        &NewObject(_, _) => unimplemented!(),
        &Object(ref fields) => {
            let mut kv_tuples = Vec::new();
            for f in fields {
                let f_key = JsKey::new(JsKeyEnum::JsStr(JsStrStruct::new(&f.0)));
                let f_exp = eval_exp(&*f.1, state);
                kv_tuples.push((f_key, f_exp, None));
            }
            JsObjStruct::new(None, "", kv_tuples, &mut AllocBox::new());
            JsVar::new(JsPtr)
        },

        &Undefined => JsVar::new(JsUndef),
        &Var(ref var_binding) => {
            state.load(&Binding::new(var_binding.clone()))
                .expect("ReferenceError: {} is not defined").0
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::hash_set::HashSet;
    use french_press::init_gc;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(5.0f64), eval_string("5.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.0f64), eval_string("0.0;\n", &mut state).t);
        assert_eq!(JsType::JsUndef, eval_string("undefined;\n", &mut state).t);
    }

    //// TODO: handle `var` and no `var` separately
    //#[test]
    //fn test_store_state() {
    //    let mut state = HashMap::new();
    //    assert_eq!(JsUndefined, eval_string("var a = 1;\n", &mut state));
    //    assert_eq!(JsNumber(2.0f64), eval_string("a = 2;\n", &mut state));
    //    assert_eq!(JsUndefined, eval_string("var b = 3;\n", &mut state));
    //    assert_eq!(JsNumber(4.0f64), eval_string("c = 4;\n", &mut state));
    //}

    #[test]
    fn test_inc_dec() {
        let mut state = init_gc();
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.load(&Binding::new("a")).unwrap());

        //assert_eq!(JsType::JsNum(1.0f64), eval_string("a++;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("++a;\n", &mut state));
        //assert_eq!(&JsNumber(3.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("a--;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(1.0f64), eval_string("--a;\n", &mut state));
        //assert_eq!(&JsNumber(1.0f64), state.get("a").unwrap());
    }

    #[test]
    fn test_binexp() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(6.0f64),  eval_string("2.0 + 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.5f64),  eval_string("2.0 / 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(-2.0f64), eval_string("2.0 - 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(8.0f64),  eval_string("2.0 * 4.0;\n", &mut state).t);
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use std::ptr;
use libc::c_void;
use super::opt::OptVal;

type curl_slist = c_void;

#[link(name = "curl")]
extern {
    fn curl_slist_append(list: *mut curl_slist, val: *const u8) -> *mut curl_slist;
    fn curl_slist_free_all(list: *mut curl_slist);
}

pub struct List {
    len: uint,
    head: *mut curl_slist,
}

impl List {
    pub fn new() -> List {
        List {
            len: 0,
            head: ptr::mut_null()
        }
    }

    pub fn push_bytes(&mut self, val: &[u8]) {
        assert!(val[val.len() - 1] == 0);
        self.len += 1;
        self.head = unsafe { curl_slist_append(self.head, val.as_ptr()) };
    }
}

impl Collection for List {
    fn len(&self) -> uint {
        self.len
    }

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

impl Drop for List {
    fn drop(&mut self) {
        if !self.is_empty() {
            unsafe { curl_slist_free_all(self.head) }
        }
    }
}

impl<'a> OptVal for &'a List {
    fn with_c_repr(self, f: |*const c_void|) {
        f(self.head as *const c_void)
    }
}
<commit_msg>Track Rust master<commit_after>#![allow(non_camel_case_types)]

use std::ptr;
use libc::c_void;
use super::opt::OptVal;

type curl_slist = c_void;

#[link(name = "curl")]
extern {
    fn curl_slist_append(list: *mut curl_slist, val: *const u8) -> *mut curl_slist;
    fn curl_slist_free_all(list: *mut curl_slist);
}

pub struct List {
    len: uint,
    head: *mut curl_slist,
}

impl List {
    pub fn new() -> List {
        List {
            len: 0,
            head: ptr::null_mut()
        }
    }

    pub fn push_bytes(&mut self, val: &[u8]) {
        assert!(val[val.len() - 1] == 0);
        self.len += 1;
        self.head = unsafe { curl_slist_append(self.head, val.as_ptr()) };
    }
}

impl Collection for List {
    fn len(&self) -> uint {
        self.len
    }

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

impl Drop for List {
    fn drop(&mut self) {
        if !self.is_empty() {
            unsafe { curl_slist_free_all(self.head) }
        }
    }
}

impl<'a> OptVal for &'a List {
    fn with_c_repr(self, f: |*const c_void|) {
        f(self.head as *const c_void)
    }
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Debug)]
enum FileSize {
    B,
    KB,
    MB,
    GB,
    TB,
}

impl fmt::Display for FileSize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl FileSize {
    fn value(&self) -> u64 {
        match *self {
            FileSize::B => 1,
            FileSize::KB => 1_024,
            FileSize::MB => 1_048_576,
            FileSize::GB => 1_073_741_824,
            FileSize::TB => 1_099_511_627_776,
        }
    }
}

#[derive(Debug)]
pub struct StringFileType(String);

impl fmt::Display for StringFileType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl From<u64> for StringFileType {
    fn from(size: u64) -> Self {
        let (file_size, unit) = match size {
        0...999 => (size as f64, FileSize::B),
        1_000...999_999 => (size as f64 / FileSize::KB.value() as f64, FileSize::KB),
        1_000_000...999_999_999 => (size as f64 / FileSize::MB.value() as f64, FileSize::MB),
        1_000_000_000...999_999_999_999 => {
            (size as f64 / FileSize::GB.value() as f64, FileSize::GB)
        }
        _ => (size as f64 / FileSize::TB.value() as f64, FileSize::TB),
    };

        StringFileType(
            format!("{:.2} {}", file_size, unit)
        )
    }
}

<commit_msg>Move StringFileType to StringFileSize<commit_after>use std::fmt;

#[derive(Debug)]
enum FileSize {
    B,
    KB,
    MB,
    GB,
    TB,
}

impl fmt::Display for FileSize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl FileSize {
    fn value(&self) -> u64 {
        match *self {
            FileSize::B => 1,
            FileSize::KB => 1_024,
            FileSize::MB => 1_048_576,
            FileSize::GB => 1_073_741_824,
            FileSize::TB => 1_099_511_627_776,
        }
    }
}

#[derive(Debug)]
pub struct StringFileSize(String);

impl fmt::Display for StringFileSize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl From<u64> for StringFileSize {
    fn from(size: u64) -> Self {
        let (file_size, unit) = match size {
        0...999 => (size as f64, FileSize::B),
        1_000...999_999 => (size as f64 / FileSize::KB.value() as f64, FileSize::KB),
        1_000_000...999_999_999 => (size as f64 / FileSize::MB.value() as f64, FileSize::MB),
        1_000_000_000...999_999_999_999 => {
            (size as f64 / FileSize::GB.value() as f64, FileSize::GB)
        }
        _ => (size as f64 / FileSize::TB.value() as f64, FileSize::TB),
    };

        StringFileSize(
            format!("{:.2} {}", file_size, unit)
        )
    }
}

<|endoftext|>


<commit_before>// Dependency Graph Library in Rust
#![crate_type = "lib"]

// For log related macros:
#![feature(phase)]
#[phase(plugin, link)]
extern crate log;

use std::collections::hashmap::{HashMap,HashSet};

pub struct DepGraph {
    pub dependencies: HashMap<String,Vec<String>>,
}

struct WalkState {
    output: Vec<String>,
}

impl DepGraph {

    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
        }
    }

    pub fn add_dependency<'a>( &mut self,
                                thing: &'a str,
                                dependsOn: &'a str )
    {
        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            vec![String::from_str(dependsOn)],
            |_,v| { v.push(String::from_str(dependsOn)); }
            );
    }

    pub fn add_dependencies<'a>( &mut self,
                                  thing: &'a str,
                                  dependsOn: Vec<&'a str> )
    {
        let newvec: Vec<String> = dependsOn.iter().map(
            |s| String::from_str(*s)).collect();

        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            newvec.clone(),
            |_,v| { v.push_all(newvec.as_slice()); }
            );
    }

    pub fn get_ordered_dependencies_of(&self, thing: &str)
        -> Vec<String>
    {
        let mut state = WalkState {
            output: Vec::new(),
        };

        debug!("Recursing for the first time, with {}",thing);
        self.get_deps_of_recurse(&String::from_str(thing), &mut state);
        debug!("output is {}",state.output);
        state.output
    }

    fn get_deps_of_recurse(&self, thing: &String, state: &mut WalkState)
    {
        match self.dependencies.find(thing) {
            None => {
                debug!("{} has no dependencies",thing);
            },

            Some(deplist) => {
                debug!("Handling the dependencies of {}",thing);
                for n in deplist.iter() {
                    // If thing was not yet visited, recurse into it
                    if !state.output.contains(n) {

                        debug!("Recursing for {}",n);
                        self.get_deps_of_recurse(n, state);

                        debug!("Appending {} to output",n);
                        state.output.push(n.clone());
                    }
                }
            },
        }
    }
}

#[test]
fn dglr_test() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.add_dependencies("a",vec!["b","c","d"]);
    depgraph.add_dependency("b","d");
    depgraph.add_dependencies("c",vec!["e","m","g"]);
    depgraph.add_dependency("e","f");
    depgraph.add_dependency("g","h");
    depgraph.add_dependency("h","i");
    depgraph.add_dependencies("i",vec!["j","k"]);
    depgraph.add_dependencies("k",vec!["l","m"]);
    depgraph.add_dependency("m","n");

    let deps = depgraph.get_ordered_dependencies_of("a");

    println!("Deps of i = {}",deps);

    assert!( deps == vec![String::from_str("d"),
                          String::from_str("b"),
                          String::from_str("f"),
                          String::from_str("e"),
                          String::from_str("n"),
                          String::from_str("m"),
                          String::from_str("j"),
                          String::from_str("l"),
                          String::from_str("k"),
                          String::from_str("i"),
                          String::from_str("h"),
                          String::from_str("g"),
                          String::from_str("c")] );

    let deps2 = depgraph.get_ordered_dependencies_of("i");
    println!("Deps of i = {}",deps2);
    assert!( deps2 == vec![String::from_str("j"),
                           String::from_str("l"),
                           String::from_str("n"),
                           String::from_str("m"),
                           String::from_str("k")] );
}
<commit_msg>Circular dependency check (function signatures changed)<commit_after>// Dependency Graph Library in Rust
#![crate_type = "lib"]

// For log related macros:
#![feature(phase)]
#[phase(plugin, link)]
extern crate log;

use std::collections::hashmap::{HashMap,HashSet};

pub struct DepGraph {
    pub dependencies: HashMap<String,Vec<String>>,
}

struct WalkState {
    curpath: HashSet<String>,
    output: Vec<String>,
}

impl DepGraph {

    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
        }
    }

    pub fn add_dependency<'a>( &mut self,
                                thing: &'a str,
                                dependsOn: &'a str )
    {
        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            vec![String::from_str(dependsOn)],
            |_,v| { v.push(String::from_str(dependsOn)); }
            );
    }

    pub fn add_dependencies<'a>( &mut self,
                                  thing: &'a str,
                                  dependsOn: Vec<&'a str> )
    {
        let newvec: Vec<String> = dependsOn.iter().map(
            |s| String::from_str(*s)).collect();

        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            newvec.clone(),
            |_,v| { v.push_all(newvec.as_slice()); }
            );
    }

    pub fn get_ordered_dependencies_of(&self, thing: &str)
        -> Option<Vec<String>>
    {
        let mut state = WalkState {
            curpath: HashSet::new(),
            output: Vec::new(),
        };

        debug!("Recursing for the first time, with {}",thing);
        if ! self.get_deps_of_recurse(&String::from_str(thing), &mut state)
        {
            return None;
        }

        debug!("output is {}",state.output);
        Some(state.output)
    }

    fn get_deps_of_recurse(&self, thing: &String, state: &mut WalkState)
        -> bool
    {
        // If we find thing, we have a circular dependency:
        if state.curpath.contains(thing) {
            error!("Circular dependency detected at {}", thing);
            return false;
        }

        state.curpath.insert(thing.clone());

        match self.dependencies.find(thing) {
            None => {
                debug!("{} has no dependencies",thing);
            },

            Some(deplist) => {
                debug!("Handling the dependencies of {}",thing);
                for n in deplist.iter() {
                    // If thing was not yet visited, recurse into it
                    if !state.output.contains(n) {

                        debug!("Recursing for {}",n);
                        if ! self.get_deps_of_recurse(n, state) {
                            return false;
                        }

                        debug!("Appending {} to output",n);
                        state.output.push(n.clone());
                    }
                }
            },
        }

        state.curpath.remove(thing);

        return true;
    }
}

#[test]
fn dglr_test() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.add_dependencies("a",vec!["b","c","d"]);
    depgraph.add_dependency("b","d");
    depgraph.add_dependencies("c",vec!["e","m","g"]);
    depgraph.add_dependency("e","f");
    depgraph.add_dependency("g","h");
    depgraph.add_dependency("h","i");
    depgraph.add_dependencies("i",vec!["j","k"]);
    depgraph.add_dependencies("k",vec!["l","m"]);
    depgraph.add_dependency("m","n");

    let deps = depgraph.get_ordered_dependencies_of("a").unwrap();
    debug!("Deps of a = {}",deps);
    assert!( deps == vec![String::from_str("d"),
                          String::from_str("b"),
                          String::from_str("f"),
                          String::from_str("e"),
                          String::from_str("n"),
                          String::from_str("m"),
                          String::from_str("j"),
                          String::from_str("l"),
                          String::from_str("k"),
                          String::from_str("i"),
                          String::from_str("h"),
                          String::from_str("g"),
                          String::from_str("c")] );

    let deps2 = depgraph.get_ordered_dependencies_of("i").unwrap();
    debug!("Deps of i = {}",deps2);
    assert!( deps2 == vec![String::from_str("j"),
                           String::from_str("l"),
                           String::from_str("n"),
                           String::from_str("m"),
                           String::from_str("k")] );

    depgraph.add_dependency("i","g");
    let deps3 = depgraph.get_ordered_dependencies_of("a");
    assert!(deps3 == None);
    debug!("Circular dependency was detected.");
}
<|endoftext|>


<commit_before>use super::helpers::edits::{get_random_edit, invert_edit};
use super::helpers::fixtures::{fixtures_dir, get_language, get_test_language};
use super::helpers::random::Rand;
use super::helpers::scope_sequence::ScopeSequence;
use crate::generate;
use crate::parse::perform_edit;
use crate::test::{parse_tests, print_diff, print_diff_key, strip_sexp_fields, TestEntry};
use crate::util;
use lazy_static::lazy_static;
use std::{env, fs, time, usize};
use tree_sitter::{allocations, LogType, Node, Parser, Tree};

const EDIT_COUNT: usize = 3;
const TRIAL_COUNT: usize = 10;
const LANGUAGES: &'static [&'static str] = &[
    "bash",
    "c",
    "cpp",
    "embedded-template",
    "go",
    "html",
    "javascript",
    "json",
    "php",
    "python",
    "ruby",
    "rust",
];

lazy_static! {
    static ref LOG_ENABLED: bool = env::var("TREE_SITTER_TEST_ENABLE_LOG").is_ok();
    static ref LOG_GRAPH_ENABLED: bool = env::var("TREE_SITTER_TEST_ENABLE_LOG_GRAPHS").is_ok();
    static ref LANGUAGE_FILTER: Option<String> = env::var("TREE_SITTER_TEST_LANGUAGE_FILTER").ok();
    static ref EXAMPLE_FILTER: Option<String> = env::var("TREE_SITTER_TEST_EXAMPLE_FILTER").ok();
    static ref TRIAL_FILTER: Option<usize> = env::var("TREE_SITTER_TEST_TRIAL_FILTER")
        .map(|s| usize::from_str_radix(&s, 10).unwrap())
        .ok();
    pub static ref SEED: usize = env::var("TREE_SITTER_TEST_SEED")
        .map(|s| usize::from_str_radix(&s, 10).unwrap())
        .unwrap_or(
            time::SystemTime::now()
                .duration_since(time::UNIX_EPOCH)
                .unwrap()
                .as_secs() as usize,
        );
}

#[test]
fn test_real_language_corpus_files() {
    eprintln!("\n\nRandom seed: {}\n", *SEED);
    let grammars_dir = fixtures_dir().join("grammars");
    let error_corpus_dir = fixtures_dir().join("error_corpus");

    let mut failure_count = 0;
    for language_name in LANGUAGES.iter().cloned() {
        if let Some(filter) = LANGUAGE_FILTER.as_ref() {
            if language_name != filter.as_str() {
                continue;
            }
        }

        let language = get_language(language_name);
        let mut corpus_dir = grammars_dir.join(language_name).join("corpus");
        if !corpus_dir.is_dir() {
            corpus_dir = grammars_dir.join(language_name).join("test").join("corpus");
        }

        let error_corpus_file = error_corpus_dir.join(&format!("{}_errors.txt", language_name));
        let main_tests = parse_tests(&corpus_dir).unwrap();
        let error_tests = parse_tests(&error_corpus_file).unwrap_or(TestEntry::default());
        let mut tests = flatten_tests(main_tests);
        tests.extend(flatten_tests(error_tests));

        if !tests.is_empty() {
            eprintln!("language: {:?}", language_name);
        }

        for (example_name, input, expected_output, has_fields) in tests {
            eprintln!("  example: {:?}", example_name);

            if TRIAL_FILTER.map_or(true, |t| t == 0) {
                allocations::start_recording();
                let mut log_session = None;
                let mut parser = get_parser(&mut log_session, "log.html");
                parser.set_language(language).unwrap();
                let tree = parser.parse(&input, None).unwrap();
                let mut actual_output = tree.root_node().to_sexp();
                if !has_fields {
                    actual_output = strip_sexp_fields(actual_output);
                }
                drop(tree);
                drop(parser);
                if actual_output != expected_output {
                    print_diff_key();
                    print_diff(&actual_output, &expected_output);
                    println!("");
                    failure_count += 1;
                    continue;
                }
                allocations::stop_recording();
            }

            let mut parser = Parser::new();
            parser.set_language(language).unwrap();
            let tree = parser.parse(&input, None).unwrap();
            drop(parser);

            for trial in 1..=TRIAL_COUNT {
                if TRIAL_FILTER.map_or(true, |filter| filter == trial) {
                    let mut rand = Rand::new(*SEED + trial);

                    allocations::start_recording();
                    let mut log_session = None;
                    let mut parser = get_parser(&mut log_session, "log.html");
                    parser.set_language(language).unwrap();
                    let mut tree = tree.clone();
                    let mut input = input.clone();

                    if *LOG_GRAPH_ENABLED {
                        eprintln!("{}\n", String::from_utf8_lossy(&input));
                    }

                    // Perform a random series of edits and reparse.
                    let mut undo_stack = Vec::new();
                    for _ in 0..EDIT_COUNT {
                        let edit = get_random_edit(&mut rand, &input);
                        undo_stack.push(invert_edit(&input, &edit));
                        perform_edit(&mut tree, &mut input, &edit);
                    }
                    if *LOG_GRAPH_ENABLED {
                        eprintln!("{}\n", String::from_utf8_lossy(&input));
                    }

                    let mut tree2 = parser.parse(&input, Some(&tree)).unwrap();

                    // Check that the new tree is consistent.
                    check_consistent_sizes(&tree2, &input);
                    if let Err(message) = check_changed_ranges(&tree, &tree2, &input) {
                        println!(
                            "\nUnexpected scope change in trial {}\n{}\n\n",
                            trial, message
                        );
                        failure_count += 1;
                        break;
                    }

                    // Undo all of the edits and re-parse again.
                    while let Some(edit) = undo_stack.pop() {
                        perform_edit(&mut tree2, &mut input, &edit);
                    }
                    if *LOG_GRAPH_ENABLED {
                        eprintln!("{}\n", String::from_utf8_lossy(&input));
                    }

                    let tree3 = parser.parse(&input, Some(&tree2)).unwrap();

                    // Verify that the final tree matches the expectation from the corpus.
                    let mut actual_output = tree3.root_node().to_sexp();
                    if !has_fields {
                        actual_output = strip_sexp_fields(actual_output);
                    }

                    if actual_output != expected_output {
                        println!(
                            "Incorrect parse for {} - {} - trial {}",
                            language_name, example_name, trial
                        );
                        print_diff_key();
                        print_diff(&actual_output, &expected_output);
                        println!("");
                        failure_count += 1;
                        break;
                    }

                    // Check that the edited tree is consistent.
                    check_consistent_sizes(&tree3, &input);
                    if let Err(message) = check_changed_ranges(&tree2, &tree3, &input) {
                        eprintln!(
                            "Unexpected scope change in trial {}\n{}\n\n",
                            trial, message
                        );
                        failure_count += 1;
                        break;
                    }

                    drop(tree);
                    drop(tree2);
                    drop(tree3);
                    drop(parser);
                    allocations::stop_recording();
                }
            }
        }
    }
    if failure_count > 0 {
        panic!("{} corpus tests failed", failure_count);
    }
}

#[test]
fn test_feature_corpus_files() {
    let test_grammars_dir = fixtures_dir().join("test_grammars");

    let mut failure_count = 0;
    for entry in fs::read_dir(&test_grammars_dir).unwrap() {
        let entry = entry.unwrap();
        if !entry.metadata().unwrap().is_dir() {
            continue;
        }
        let language_name = entry.file_name();
        let language_name = language_name.to_str().unwrap();

        if let Some(filter) = LANGUAGE_FILTER.as_ref() {
            if language_name != filter.as_str() {
                continue;
            }
        }

        let test_path = entry.path();
        let grammar_path = test_path.join("grammar.json");
        let error_message_path = test_path.join("expected_error.txt");
        let grammar_json = fs::read_to_string(grammar_path).unwrap();
        let generate_result = generate::generate_parser_for_grammar(&grammar_json);

        if error_message_path.exists() {
            if EXAMPLE_FILTER.is_some() {
                continue;
            }

            eprintln!("test language: {:?}", language_name);

            let expected_message = fs::read_to_string(&error_message_path).unwrap();
            if let Err(e) = generate_result {
                let actual_message = e.to_string();
                let first_diff = expected_message
                    .lines()
                    .zip(actual_message.lines())
                    .enumerate()
                    .filter(|(_, (expected, actual))| expected != actual)
                    .next();
                if let Some((line_number, (expected_line, actual_line))) = first_diff {
                    eprintln!(
                        "Unexpected error message.\n\nExpected:\n\n{}\nActual:\n\n{}\n",
                        expected_message, actual_message
                    );
                    eprintln!(
                        "First difference on line {}; expected:\n{}\nActual:\n{}\n",
                        line_number, expected_line, actual_line
                    );
                    failure_count += 1;
                }
            } else {
                eprintln!(
                    "Expected error message but got none for test grammar '{}'",
                    language_name
                );
                failure_count += 1;
            }
        } else {
            if let Err(e) = &generate_result {
                eprintln!(
                    "Unexpected error for test grammar '{}':\n{}",
                    language_name, e
                );
                failure_count += 1;
                continue;
            }

            let corpus_path = test_path.join("corpus.txt");
            let c_code = generate_result.unwrap().1;
            let language = get_test_language(language_name, &c_code, Some(&test_path));
            let test = parse_tests(&corpus_path).unwrap();
            let tests = flatten_tests(test);

            if !tests.is_empty() {
                eprintln!("test language: {:?}", language_name);
            }

            for (name, input, expected_output, has_fields) in tests {
                eprintln!("  example: {:?}", name);

                allocations::start_recording();
                let mut log_session = None;
                let mut parser = get_parser(&mut log_session, "log.html");
                parser.set_language(language).unwrap();
                let tree = parser.parse(&input, None).unwrap();
                let mut actual_output = tree.root_node().to_sexp();
                if !has_fields {
                    actual_output = strip_sexp_fields(actual_output);
                }

                drop(tree);
                drop(parser);
                if actual_output != expected_output {
                    print_diff_key();
                    print_diff(&actual_output, &expected_output);
                    println!("");
                    failure_count += 1;
                    continue;
                }
                allocations::stop_recording();
            }
        }
    }
    if failure_count > 0 {
        panic!("{} corpus tests failed", failure_count);
    }
}

fn check_consistent_sizes(tree: &Tree, input: &Vec<u8>) {
    fn check(node: Node, line_offsets: &Vec<usize>) {
        let start_byte = node.start_byte();
        let end_byte = node.end_byte();
        let start_point = node.start_position();
        let end_point = node.end_position();

        assert!(start_byte <= end_byte);
        assert!(start_point <= end_point);
        assert_eq!(
            start_byte,
            line_offsets[start_point.row] + start_point.column
        );
        assert_eq!(end_byte, line_offsets[end_point.row] + end_point.column);

        let mut last_child_end_byte = start_byte;
        let mut last_child_end_point = start_point;
        let mut some_child_has_changes = false;
        let mut actual_named_child_count = 0;
        for i in 0..node.child_count() {
            let child = node.child(i).unwrap();
            assert!(child.start_byte() >= last_child_end_byte);
            assert!(child.start_position() >= last_child_end_point);
            check(child, line_offsets);
            if child.has_changes() {
                some_child_has_changes = true;
            }
            if child.is_named() {
                actual_named_child_count += 1;
            }
            last_child_end_byte = child.end_byte();
            last_child_end_point = child.end_position();
        }

        assert_eq!(actual_named_child_count, node.named_child_count());

        if node.child_count() > 0 {
            assert!(end_byte >= last_child_end_byte);
            assert!(end_point >= last_child_end_point);
        }

        if some_child_has_changes {
            assert!(node.has_changes());
        }
    }

    let mut line_offsets = vec![0];
    for (i, c) in input.iter().enumerate() {
        if *c == '\n' as u8 {
            line_offsets.push(i + 1);
        }
    }

    check(tree.root_node(), &line_offsets);
}

fn check_changed_ranges(old_tree: &Tree, new_tree: &Tree, input: &Vec<u8>) -> Result<(), String> {
    let changed_ranges = old_tree.changed_ranges(new_tree).collect();
    let old_scope_sequence = ScopeSequence::new(old_tree);
    let new_scope_sequence = ScopeSequence::new(new_tree);
    old_scope_sequence.check_changes(&new_scope_sequence, &input, &changed_ranges)
}

fn get_parser(session: &mut Option<util::LogSession>, log_filename: &str) -> Parser {
    let mut parser = Parser::new();

    if *LOG_ENABLED {
        parser.set_logger(Some(Box::new(|log_type, msg| {
            if log_type == LogType::Lex {
                eprintln!("  {}", msg);
            } else {
                eprintln!("{}", msg);
            }
        })));
    } else if *LOG_GRAPH_ENABLED {
        *session = Some(util::log_graphs(&mut parser, log_filename).unwrap());
    }

    parser
}

fn flatten_tests(test: TestEntry) -> Vec<(String, Vec<u8>, String, bool)> {
    fn helper(test: TestEntry, prefix: &str, result: &mut Vec<(String, Vec<u8>, String, bool)>) {
        match test {
            TestEntry::Example {
                mut name,
                input,
                output,
                has_fields,
            } => {
                if !prefix.is_empty() {
                    name.insert_str(0, " - ");
                    name.insert_str(0, prefix);
                }
                if let Some(filter) = EXAMPLE_FILTER.as_ref() {
                    if !name.contains(filter.as_str()) {
                        return;
                    }
                }
                result.push((name, input, output, has_fields));
            }
            TestEntry::Group {
                mut name, children, ..
            } => {
                if !prefix.is_empty() {
                    name.insert_str(0, " - ");
                    name.insert_str(0, prefix);
                }
                for child in children {
                    helper(child, &name, result);
                }
            }
        }
    }
    let mut result = Vec::new();
    helper(test, "", &mut result);
    result
}
<commit_msg>Simplified corpus test output comparisons<commit_after>use super::helpers::edits::{get_random_edit, invert_edit};
use super::helpers::fixtures::{fixtures_dir, get_language, get_test_language};
use super::helpers::random::Rand;
use super::helpers::scope_sequence::ScopeSequence;
use crate::generate;
use crate::parse::perform_edit;
use crate::test::{parse_tests, print_diff, print_diff_key, strip_sexp_fields, TestEntry};
use crate::util;
use lazy_static::lazy_static;
use std::{env, fs, time, usize};
use tree_sitter::{allocations, LogType, Node, Parser, Tree};

const EDIT_COUNT: usize = 3;
const TRIAL_COUNT: usize = 10;
const LANGUAGES: &'static [&'static str] = &[
    "bash",
    "c",
    "cpp",
    "embedded-template",
    "go",
    "html",
    "javascript",
    "json",
    "php",
    "python",
    "ruby",
    "rust",
];

lazy_static! {
    static ref LOG_ENABLED: bool = env::var("TREE_SITTER_TEST_ENABLE_LOG").is_ok();
    static ref LOG_GRAPH_ENABLED: bool = env::var("TREE_SITTER_TEST_ENABLE_LOG_GRAPHS").is_ok();
    static ref LANGUAGE_FILTER: Option<String> = env::var("TREE_SITTER_TEST_LANGUAGE_FILTER").ok();
    static ref EXAMPLE_FILTER: Option<String> = env::var("TREE_SITTER_TEST_EXAMPLE_FILTER").ok();
    static ref TRIAL_FILTER: Option<usize> = env::var("TREE_SITTER_TEST_TRIAL_FILTER")
        .map(|s| usize::from_str_radix(&s, 10).unwrap())
        .ok();
    pub static ref SEED: usize = env::var("TREE_SITTER_TEST_SEED")
        .map(|s| usize::from_str_radix(&s, 10).unwrap())
        .unwrap_or(
            time::SystemTime::now()
                .duration_since(time::UNIX_EPOCH)
                .unwrap()
                .as_secs() as usize,
        );
}

#[test]
fn test_real_language_corpus_files() {
    eprintln!("\n\nRandom seed: {}\n", *SEED);
    let grammars_dir = fixtures_dir().join("grammars");
    let error_corpus_dir = fixtures_dir().join("error_corpus");

    let mut failure_count = 0;
    for language_name in LANGUAGES.iter().cloned() {
        if let Some(filter) = LANGUAGE_FILTER.as_ref() {
            if language_name != filter.as_str() {
                continue;
            }
        }

        let language = get_language(language_name);
        let mut corpus_dir = grammars_dir.join(language_name).join("corpus");
        if !corpus_dir.is_dir() {
            corpus_dir = grammars_dir.join(language_name).join("test").join("corpus");
        }

        let error_corpus_file = error_corpus_dir.join(&format!("{}_errors.txt", language_name));
        let main_tests = parse_tests(&corpus_dir).unwrap();
        let error_tests = parse_tests(&error_corpus_file).unwrap_or(TestEntry::default());
        let mut tests = flatten_tests(main_tests);
        tests.extend(flatten_tests(error_tests));

        if !tests.is_empty() {
            eprintln!("language: {:?}", language_name);
        }

        for (example_name, input, expected_output, has_fields) in tests {
            eprintln!("  example: {:?}", example_name);

            if TRIAL_FILTER.map_or(true, |t| t == 0) {
                allocations::start_recording();
                let mut log_session = None;
                let mut parser = get_parser(&mut log_session, "log.html");
                parser.set_language(language).unwrap();
                let tree = parser.parse(&input, None).unwrap();
                let mut actual_output = tree.root_node().to_sexp();
                if !has_fields {
                    actual_output = strip_sexp_fields(actual_output);
                }
                drop(tree);
                drop(parser);
                if actual_output != expected_output {
                    print_diff_key();
                    print_diff(&actual_output, &expected_output);
                    println!("");
                    failure_count += 1;
                    continue;
                }
                allocations::stop_recording();
            }

            let mut parser = Parser::new();
            parser.set_language(language).unwrap();
            let tree = parser.parse(&input, None).unwrap();
            drop(parser);

            for trial in 1..=TRIAL_COUNT {
                if TRIAL_FILTER.map_or(true, |filter| filter == trial) {
                    let mut rand = Rand::new(*SEED + trial);

                    allocations::start_recording();
                    let mut log_session = None;
                    let mut parser = get_parser(&mut log_session, "log.html");
                    parser.set_language(language).unwrap();
                    let mut tree = tree.clone();
                    let mut input = input.clone();

                    if *LOG_GRAPH_ENABLED {
                        eprintln!("{}\n", String::from_utf8_lossy(&input));
                    }

                    // Perform a random series of edits and reparse.
                    let mut undo_stack = Vec::new();
                    for _ in 0..EDIT_COUNT {
                        let edit = get_random_edit(&mut rand, &input);
                        undo_stack.push(invert_edit(&input, &edit));
                        perform_edit(&mut tree, &mut input, &edit);
                    }
                    if *LOG_GRAPH_ENABLED {
                        eprintln!("{}\n", String::from_utf8_lossy(&input));
                    }

                    let mut tree2 = parser.parse(&input, Some(&tree)).unwrap();

                    // Check that the new tree is consistent.
                    check_consistent_sizes(&tree2, &input);
                    if let Err(message) = check_changed_ranges(&tree, &tree2, &input) {
                        println!(
                            "\nUnexpected scope change in trial {}\n{}\n\n",
                            trial, message
                        );
                        failure_count += 1;
                        break;
                    }

                    // Undo all of the edits and re-parse again.
                    while let Some(edit) = undo_stack.pop() {
                        perform_edit(&mut tree2, &mut input, &edit);
                    }
                    if *LOG_GRAPH_ENABLED {
                        eprintln!("{}\n", String::from_utf8_lossy(&input));
                    }

                    let tree3 = parser.parse(&input, Some(&tree2)).unwrap();

                    // Verify that the final tree matches the expectation from the corpus.
                    let mut actual_output = tree3.root_node().to_sexp();
                    if !has_fields {
                        actual_output = strip_sexp_fields(actual_output);
                    }

                    if actual_output != expected_output {
                        println!(
                            "Incorrect parse for {} - {} - trial {}",
                            language_name, example_name, trial
                        );
                        print_diff_key();
                        print_diff(&actual_output, &expected_output);
                        println!("");
                        failure_count += 1;
                        break;
                    }

                    // Check that the edited tree is consistent.
                    check_consistent_sizes(&tree3, &input);
                    if let Err(message) = check_changed_ranges(&tree2, &tree3, &input) {
                        eprintln!(
                            "Unexpected scope change in trial {}\n{}\n\n",
                            trial, message
                        );
                        failure_count += 1;
                        break;
                    }

                    drop(tree);
                    drop(tree2);
                    drop(tree3);
                    drop(parser);
                    allocations::stop_recording();
                }
            }
        }
    }
    if failure_count > 0 {
        panic!("{} corpus tests failed", failure_count);
    }
}

#[test]
fn test_feature_corpus_files() {
    let test_grammars_dir = fixtures_dir().join("test_grammars");

    let mut failure_count = 0;
    for entry in fs::read_dir(&test_grammars_dir).unwrap() {
        let entry = entry.unwrap();
        if !entry.metadata().unwrap().is_dir() {
            continue;
        }
        let language_name = entry.file_name();
        let language_name = language_name.to_str().unwrap();

        if let Some(filter) = LANGUAGE_FILTER.as_ref() {
            if language_name != filter.as_str() {
                continue;
            }
        }

        let test_path = entry.path();
        let grammar_path = test_path.join("grammar.json");
        let error_message_path = test_path.join("expected_error.txt");
        let grammar_json = fs::read_to_string(grammar_path).unwrap();
        let generate_result = generate::generate_parser_for_grammar(&grammar_json);

        if error_message_path.exists() {
            if EXAMPLE_FILTER.is_some() {
                continue;
            }

            eprintln!("test language: {:?}", language_name);

            let expected_message = fs::read_to_string(&error_message_path).unwrap().replace("\r\n", "\n");
            if let Err(e) = generate_result {
                let actual_message = e.to_string().replace("\r\n", "\n");
                if expected_message != actual_message {
                    eprintln!(
                        "Unexpected error message.\n\nExpected:\n\n{}\nActual:\n\n{}\n",
                        expected_message, actual_message
                    );
                    failure_count += 1;
                }
            } else {
                eprintln!(
                    "Expected error message but got none for test grammar '{}'",
                    language_name
                );
                failure_count += 1;
            }
        } else {
            if let Err(e) = &generate_result {
                eprintln!(
                    "Unexpected error for test grammar '{}':\n{}",
                    language_name, e
                );
                failure_count += 1;
                continue;
            }

            let corpus_path = test_path.join("corpus.txt");
            let c_code = generate_result.unwrap().1;
            let language = get_test_language(language_name, &c_code, Some(&test_path));
            let test = parse_tests(&corpus_path).unwrap();
            let tests = flatten_tests(test);

            if !tests.is_empty() {
                eprintln!("test language: {:?}", language_name);
            }

            for (name, input, expected_output, has_fields) in tests {
                eprintln!("  example: {:?}", name);

                allocations::start_recording();
                let mut log_session = None;
                let mut parser = get_parser(&mut log_session, "log.html");
                parser.set_language(language).unwrap();
                let tree = parser.parse(&input, None).unwrap();
                let mut actual_output = tree.root_node().to_sexp();
                if !has_fields {
                    actual_output = strip_sexp_fields(actual_output);
                }

                drop(tree);
                drop(parser);
                if actual_output != expected_output {
                    print_diff_key();
                    print_diff(&actual_output, &expected_output);
                    println!("");
                    failure_count += 1;
                    continue;
                }
                allocations::stop_recording();
            }
        }
    }
    if failure_count > 0 {
        panic!("{} corpus tests failed", failure_count);
    }
}

fn check_consistent_sizes(tree: &Tree, input: &Vec<u8>) {
    fn check(node: Node, line_offsets: &Vec<usize>) {
        let start_byte = node.start_byte();
        let end_byte = node.end_byte();
        let start_point = node.start_position();
        let end_point = node.end_position();

        assert!(start_byte <= end_byte);
        assert!(start_point <= end_point);
        assert_eq!(
            start_byte,
            line_offsets[start_point.row] + start_point.column
        );
        assert_eq!(end_byte, line_offsets[end_point.row] + end_point.column);

        let mut last_child_end_byte = start_byte;
        let mut last_child_end_point = start_point;
        let mut some_child_has_changes = false;
        let mut actual_named_child_count = 0;
        for i in 0..node.child_count() {
            let child = node.child(i).unwrap();
            assert!(child.start_byte() >= last_child_end_byte);
            assert!(child.start_position() >= last_child_end_point);
            check(child, line_offsets);
            if child.has_changes() {
                some_child_has_changes = true;
            }
            if child.is_named() {
                actual_named_child_count += 1;
            }
            last_child_end_byte = child.end_byte();
            last_child_end_point = child.end_position();
        }

        assert_eq!(actual_named_child_count, node.named_child_count());

        if node.child_count() > 0 {
            assert!(end_byte >= last_child_end_byte);
            assert!(end_point >= last_child_end_point);
        }

        if some_child_has_changes {
            assert!(node.has_changes());
        }
    }

    let mut line_offsets = vec![0];
    for (i, c) in input.iter().enumerate() {
        if *c == '\n' as u8 {
            line_offsets.push(i + 1);
        }
    }

    check(tree.root_node(), &line_offsets);
}

fn check_changed_ranges(old_tree: &Tree, new_tree: &Tree, input: &Vec<u8>) -> Result<(), String> {
    let changed_ranges = old_tree.changed_ranges(new_tree).collect();
    let old_scope_sequence = ScopeSequence::new(old_tree);
    let new_scope_sequence = ScopeSequence::new(new_tree);
    old_scope_sequence.check_changes(&new_scope_sequence, &input, &changed_ranges)
}

fn get_parser(session: &mut Option<util::LogSession>, log_filename: &str) -> Parser {
    let mut parser = Parser::new();

    if *LOG_ENABLED {
        parser.set_logger(Some(Box::new(|log_type, msg| {
            if log_type == LogType::Lex {
                eprintln!("  {}", msg);
            } else {
                eprintln!("{}", msg);
            }
        })));
    } else if *LOG_GRAPH_ENABLED {
        *session = Some(util::log_graphs(&mut parser, log_filename).unwrap());
    }

    parser
}

fn flatten_tests(test: TestEntry) -> Vec<(String, Vec<u8>, String, bool)> {
    fn helper(test: TestEntry, prefix: &str, result: &mut Vec<(String, Vec<u8>, String, bool)>) {
        match test {
            TestEntry::Example {
                mut name,
                input,
                output,
                has_fields,
            } => {
                if !prefix.is_empty() {
                    name.insert_str(0, " - ");
                    name.insert_str(0, prefix);
                }
                if let Some(filter) = EXAMPLE_FILTER.as_ref() {
                    if !name.contains(filter.as_str()) {
                        return;
                    }
                }
                result.push((name, input, output, has_fields));
            }
            TestEntry::Group {
                mut name, children, ..
            } => {
                if !prefix.is_empty() {
                    name.insert_str(0, " - ");
                    name.insert_str(0, prefix);
                }
                for child in children {
                    helper(child, &name, result);
                }
            }
        }
    }
    let mut result = Vec::new();
    helper(test, "", &mut result);
    result
}
<|endoftext|>