<commit_before>extern crate nalgebra;

use memoized_flat_time_steward as s;
use {TimeSteward, DeterministicRandomId, Column, ColumnId, RowId, PredictorId, Mutator,
     TimeStewardStaticMethods, Accessor, MomentaryAccessor, PredictorAccessor};
use collision_detection::inefficient as collisions;

use time_functions::QuadraticTrajectory;
use std::rc::Rc;
use rand::Rng;
use nalgebra::Vector2;
use std::thread::sleep;
use std::time::{Instant, Duration};
use glium;
use glium::{DisplayBuild, Surface};

use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

type Time = i64;
type SpaceCoordinate = i64;

const HOW_MANY_CIRCLES: i32 = 20;
const ARENA_SIZE: SpaceCoordinate = (1 << 20);
const TIME_SHIFT: i32 = 20;
const SECOND: Time = (1 << TIME_SHIFT);

#[derive(Clone)]
struct Basics;
impl ::Basics for Basics {
  type Time = Time;
  type Constants = ();
}
struct CollisionBasics {}
impl ::collision_detection::Basics for CollisionBasics {
  type StewardBasics = Basics;
  type DetectorId =();
  fn nearness_column_id() -> ColumnId {
    ColumnId(0x89ebc3ba9a24c286)
  }
}

type Nearness = ::collision_detection::Nearness<CollisionBasics>;

#[derive(Clone)]
struct Circle {
  position: QuadraticTrajectory,
  radius: SpaceCoordinate,
}
impl Column for Circle {
  type FieldType = Self;
  fn column_id() -> ColumnId {
    ColumnId(0x6422505ce8c8ce8e)
  }
}
struct Intersection {
  induced_acceleration: Vector2<SpaceCoordinate>,
}
impl Column for Intersection {
  type FieldType = Self;
  fn column_id() -> ColumnId {
    ColumnId(0x9357f021339198a1)
  }
}

type Steward = s::Steward<Basics>;

fn get_circle_id(index: i32) -> RowId {
  DeterministicRandomId::new(&(0x86ccbeb2c140cc51u64, index))
}

fn collision_predictor <PA: PredictorAccessor <Basics, <s::Steward <Basics> as TimeStewardStaticMethods < Basics>>::EventFn >> (accessor: &mut PA, id: RowId) {
  printlnerr!("Planning {}", id);
  let ids = Nearness::get_ids(accessor, id).0;
  let time;
  {

    let us = (accessor.data_and_last_change::<Circle>(ids[0])
                      .expect("a nearness exists for a circle that doesn't"),
              accessor.data_and_last_change::<Circle>(ids[0])
                      .expect("a nearness exists for a circle that doesn't"));

    let relationship = accessor.get::<Intersection>(id);
    time = QuadraticTrajectory::approximately_when_distance_passes((us.0).0.radius +
                                                                   (us.1).0.radius,
                                                                   if relationship.is_none() {
                                                                     -1
                                                                   } else {
                                                                     1
                                                                   },
                                                                   ((us.0).1.clone(),
                                                                    &(us.0).0.position),
                                                                   ((us.1).1.clone(),
                                                                    &(us.1).0.position));
    printlnerr!("At {}, {}", (us.0).1, (us.1).1);
  }
  if let Some(yes) = time {
    accessor.predict_at_time(&yes,
                             Rc::new(move |mutator| {
                               let new_relationship;
                               let mut new;
                               {
                                 let relationship = mutator.get::<Intersection>(id).clone();
                                 let us = (mutator.data_and_last_change::<Circle>(ids[0])
                                                  .expect("a nearness exists for a circle that \
                                                           doesn't (event)"),
                                           mutator.data_and_last_change::<Circle>(ids[0])
                                                  .expect("a nearness exists for a circle that \
                                                           doesn't (event)"));
                                 new = ((us.0).0.clone(), (us.1).0.clone());
                                 new.0.position.update_by(mutator.now() - (us.0).1);
                                 new.1.position.update_by(mutator.now() - (us.1).1);
                                 if let Some(intersection) = relationship {
                                   new.0
                                      .position
                                      .add_acceleration(-intersection.induced_acceleration);
                                   new.1
                                      .position
                                      .add_acceleration(intersection.induced_acceleration);
                                   new_relationship = None;
                                 } else {
                                   let acceleration = Vector2::new(ARENA_SIZE, ARENA_SIZE);
                                   new.0.position.add_acceleration(acceleration);
                                   new.1.position.add_acceleration(-acceleration);
                                   new_relationship = Some(Intersection {
                                     induced_acceleration: acceleration,
                                   });

                                 }
                               }
                               mutator.set::<Intersection>(id, new_relationship);
                               mutator.set::<Circle>(ids[0], Some(new.0));
                               mutator.set::<Circle>(ids[1], Some(new.1));
                             }));
  }
}

#[derive(Copy, Clone)]

struct Vertex {
  direction: [f32; 2],
  center: [f32; 2],
  radius: f32,
}
implement_vertex!(Vertex, direction, center, radius);

pub fn testfunc() {

  let mut stew: Steward =
    ::TimeStewardStaticMethods::new_empty((),
                                          vec![s::Predictor {
                                                 predictor_id: PredictorId(0x5375592f4da8682c),
                                                 column_id: Nearness::column_id(),
                                                 function: Rc::new(|accessor, id| {
                                                   collision_predictor(accessor, id)
                                                 }),
                                               }]); /*{
      printlnerr!("Planning {}", id);
      let me = pa.get::<Circle>(id).unwrap().clone();
      pa.predict_at_time(&me.time_when_next_initiates_handshake,
                         Rc::new(move |m| {
        let now = *m.now();
        let friend_id = get_philosopher_id(m.rng().gen_range(0, HOW_MANY_PHILOSOPHERS));
        let awaken_time_1 = now + m.rng().gen_range(-1, 4);
        let awaken_time_2 = now + m.rng().gen_range(-1, 7);
        printlnerr!("SHAKE!!! @{}. {}={}; {}={}", now, whodunnit, awaken_time_2, friend_id, awaken_time_1);
        // IF YOU SHAKE YOUR OWN HAND YOU RECOVER
        // IN THE SECOND TIME APPARENTLY
        m.set::<Philosopher>(friend_id,
                             Some(Philosopher {
                               time_when_next_initiates_handshake: awaken_time_1,
                             }));
        m.set::<Philosopher>(whodunnit,
                             Some(Philosopher {
                               time_when_next_initiates_handshake: awaken_time_2,
                             }));
      }));
    }),
                                                        }]);*/

  stew.insert_fiat_event(-1,
                         DeterministicRandomId::new(&0),
                         Rc::new(|mutator| {
                           for i in 0..HOW_MANY_CIRCLES {
                             let thingy = ARENA_SIZE / 20;
                             let radius = mutator.rng().gen_range(ARENA_SIZE / 30, ARENA_SIZE / 15);
                             let id = get_circle_id(i);

                             let position =
                               QuadraticTrajectory::new(TIME_SHIFT,
                                                        [mutator.rng().gen_range(0, ARENA_SIZE),
                                                         mutator.rng().gen_range(0, ARENA_SIZE),
                                                         mutator.rng().gen_range(-thingy, thingy),
                                                         mutator.rng().gen_range(-thingy, thingy),
                                                         0,
                                                         0]);
                             mutator.set::<Circle>(id,
                                                   Some(Circle {
                                                     position: position,
                                                     radius: radius,
                                                   }));
                             collisions::insert::<CollisionBasics, _>(mutator, id, ());
                           }
                         }));
  let vertex_shader_source = r#"
#version 140
in vec2 direction;
in vec2 center;
in float radius;
out vec2 direction_transfer;

void main() {
direction_transfer = direction*1.5;
gl_Position = vec4 ( center + direction*1.5*radius, 0.0, 1.0);
}

"#;

  let fragment_shader_source = r#"
#version 140
in vec2 direction_transfer;
out vec4 color;

void main() {
if (dot (direction_transfer,direction_transfer) <1.0) {
color = vec4 (1.0, 0.0, 0.0, 1.0);
} else {
color = vec4 (0.0, 0.0, 0.0, 0.0);

}
}

"#;

  return;
  let display = glium::glutin::WindowBuilder::new()
                  .with_dimensions(600, 600)
                  .build_glium()
                  .expect("failed to create window");
  let program = glium::Program::from_source(&display,
                                            vertex_shader_source,
                                            fragment_shader_source,
                                            None)
                  .unwrap();
  let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
  let mut snapshots = Vec::new();
  let start = Instant::now();
  loop {
    for ev in display.poll_events() {
      match ev {
        glium::glutin::Event::Closed => return,
        _ => (),
      }
    }

    let mut target = display.draw();
    target.clear_color(0.0, 0.0, 0.0, 1.0);
    let mut vertices = Vec::<Vertex>::new();

    let snapshot = stew.snapshot_before(&(((start.elapsed().as_secs() as i64*1000000000i64)+start.elapsed().subsec_nanos() as i64) * SECOND /
                                          1000000000i64))
                       .unwrap();
    for index in 0..HOW_MANY_CIRCLES {
      let (circle, time) = snapshot.data_and_last_change::<Circle>(get_circle_id(index))
                                   .expect("missing circle")
                                   .clone();
      let position = circle.position.updated_by(snapshot.now() - time).evaluate();
      let center = [position[0] as f32 / ARENA_SIZE as f32 - 0.5, position[1] as f32 / ARENA_SIZE as f32 - 0.5];
      let radius = circle.radius as f32 / ARENA_SIZE as f32;
    //printlnerr!("drawing circ at {}, {}", center[0],center[1]);
      vertices.extend(&[Vertex {
                          center: center,
                          radius: radius,
                          direction: [1.0, 0.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [-1.0, 0.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [0.0, 1.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [1.0, 0.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [-1.0, 0.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [0.0, -1.0],
                        }]);

    }
    target.draw(&glium::VertexBuffer::new(&display, &vertices).unwrap(),
                &indices,
                &program,
                &glium::uniforms::EmptyUniforms,
                &Default::default())
          .unwrap();

    target.finish().expect("failed to finish drawing");

    sleep(Duration::from_millis(10));
  }

  for increment in 1..21 {
    snapshots.push(stew.snapshot_before(&(increment * SECOND * 2)));
  }
  for snapshot in snapshots.iter_mut().map(|option| {
    option.as_mut().expect("all these snapshots should have been valid")
  }) {
    printlnerr!("snapshot for {}", snapshot.now());
    for index in 0..HOW_MANY_CIRCLES {
      // printlnerr!("{}", snapshot.get::<Circle> (get_circle_id (index)).expect("missing circle").position);
    }
  }
  // panic!("anyway")
}

#[test]
fn actuallytest() {
  testfunc();
}
<commit_msg>Better debug messages<commit_after>extern crate nalgebra;

use memoized_flat_time_steward as s;
use {TimeSteward, DeterministicRandomId, Column, ColumnId, RowId, PredictorId, Mutator,
     TimeStewardStaticMethods, Accessor, MomentaryAccessor, PredictorAccessor};
use collision_detection::inefficient as collisions;

use time_functions::QuadraticTrajectory;
use std::rc::Rc;
use rand::Rng;
use nalgebra::Vector2;
use std::thread::sleep;
use std::time::{Instant, Duration};
use glium;
use glium::{DisplayBuild, Surface};

use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

type Time = i64;
type SpaceCoordinate = i64;

const HOW_MANY_CIRCLES: i32 = 20;
const ARENA_SIZE: SpaceCoordinate = (1 << 20);
const TIME_SHIFT: i32 = 20;
const SECOND: Time = (1 << TIME_SHIFT);

#[derive(Clone)]
struct Basics;
impl ::Basics for Basics {
  type Time = Time;
  type Constants = ();
}
struct CollisionBasics {}
impl ::collision_detection::Basics for CollisionBasics {
  type StewardBasics = Basics;
  type DetectorId =();
  fn nearness_column_id() -> ColumnId {
    ColumnId(0x89ebc3ba9a24c286)
  }
}

type Nearness = ::collision_detection::Nearness<CollisionBasics>;

#[derive(Clone)]
struct Circle {
  position: QuadraticTrajectory,
  radius: SpaceCoordinate,
}
impl Column for Circle {
  type FieldType = Self;
  fn column_id() -> ColumnId {
    ColumnId(0x6422505ce8c8ce8e)
  }
}
struct Intersection {
  induced_acceleration: Vector2<SpaceCoordinate>,
}
impl Column for Intersection {
  type FieldType = Self;
  fn column_id() -> ColumnId {
    ColumnId(0x9357f021339198a1)
  }
}

type Steward = s::Steward<Basics>;

fn get_circle_id(index: i32) -> RowId {
  DeterministicRandomId::new(&(0x86ccbeb2c140cc51u64, index))
}

fn collision_predictor <PA: PredictorAccessor <Basics, <s::Steward <Basics> as TimeStewardStaticMethods < Basics>>::EventFn >> (accessor: &mut PA, id: RowId) {
  let ids = Nearness::get_ids(accessor, id).0;
  let time;
  {

    let us = (accessor.data_and_last_change::<Circle>(ids[0])
                      .expect("a nearness exists for a circle that doesn't"),
              accessor.data_and_last_change::<Circle>(ids[0])
                      .expect("a nearness exists for a circle that doesn't"));

    let relationship = accessor.get::<Intersection>(id);
    time = QuadraticTrajectory::approximately_when_distance_passes((us.0).0.radius +
                                                                   (us.1).0.radius,
                                                                   if relationship.is_none() {
                                                                     -1
                                                                   } else {
                                                                     1
                                                                   },
                                                                   ((us.0).1.clone(),
                                                                    &(us.0).0.position),
                                                                   ((us.1).1.clone(),
                                                                    &(us.1).0.position));
    printlnerr!("Planning for {} At {}, {}", id, (us.0).1, (us.1).1);
  }
  if let Some(yes) = time {
  printlnerr!(" planned for {}", & yes);
    accessor.predict_at_time(&yes,
                             Rc::new(move |mutator| {
                               let new_relationship;
                               let mut new;
                               {
                                 let relationship = mutator.get::<Intersection>(id).clone();
                                 let us = (mutator.data_and_last_change::<Circle>(ids[0])
                                                  .expect("a nearness exists for a circle that \
                                                           doesn't (event)"),
                                           mutator.data_and_last_change::<Circle>(ids[0])
                                                  .expect("a nearness exists for a circle that \
                                                           doesn't (event)"));
                                 new = ((us.0).0.clone(), (us.1).0.clone());
                                 new.0.position.update_by(mutator.now() - (us.0).1);
                                 new.1.position.update_by(mutator.now() - (us.1).1);
                                 if let Some(intersection) = relationship {
                                   new.0
                                      .position
                                      .add_acceleration(-intersection.induced_acceleration);
                                   new.1
                                      .position
                                      .add_acceleration(intersection.induced_acceleration);
                                   new_relationship = None;
                                 } else {
                                   let acceleration = Vector2::new(ARENA_SIZE, ARENA_SIZE);
                                   new.0.position.add_acceleration(acceleration);
                                   new.1.position.add_acceleration(-acceleration);
                                   new_relationship = Some(Intersection {
                                     induced_acceleration: acceleration,
                                   });

                                 }
                               }
                               mutator.set::<Intersection>(id, new_relationship);
                               mutator.set::<Circle>(ids[0], Some(new.0));
                               mutator.set::<Circle>(ids[1], Some(new.1));
                             }));
  }
}

#[derive(Copy, Clone)]

struct Vertex {
  direction: [f32; 2],
  center: [f32; 2],
  radius: f32,
}
implement_vertex!(Vertex, direction, center, radius);

pub fn testfunc() {

  let mut stew: Steward =
    ::TimeStewardStaticMethods::new_empty((),
                                          vec![s::Predictor {
                                                 predictor_id: PredictorId(0x5375592f4da8682c),
                                                 column_id: Nearness::column_id(),
                                                 function: Rc::new(|accessor, id| {
                                                   collision_predictor(accessor, id)
                                                 }),
                                               }]); /*{
      printlnerr!("Planning {}", id);
      let me = pa.get::<Circle>(id).unwrap().clone();
      pa.predict_at_time(&me.time_when_next_initiates_handshake,
                         Rc::new(move |m| {
        let now = *m.now();
        let friend_id = get_philosopher_id(m.rng().gen_range(0, HOW_MANY_PHILOSOPHERS));
        let awaken_time_1 = now + m.rng().gen_range(-1, 4);
        let awaken_time_2 = now + m.rng().gen_range(-1, 7);
        printlnerr!("SHAKE!!! @{}. {}={}; {}={}", now, whodunnit, awaken_time_2, friend_id, awaken_time_1);
        // IF YOU SHAKE YOUR OWN HAND YOU RECOVER
        // IN THE SECOND TIME APPARENTLY
        m.set::<Philosopher>(friend_id,
                             Some(Philosopher {
                               time_when_next_initiates_handshake: awaken_time_1,
                             }));
        m.set::<Philosopher>(whodunnit,
                             Some(Philosopher {
                               time_when_next_initiates_handshake: awaken_time_2,
                             }));
      }));
    }),
                                                        }]);*/

  stew.insert_fiat_event(-1,
                         DeterministicRandomId::new(&0),
                         Rc::new(|mutator| {
                           for i in 0..HOW_MANY_CIRCLES {
                             let thingy = ARENA_SIZE / 20;
                             let radius = mutator.rng().gen_range(ARENA_SIZE / 30, ARENA_SIZE / 15);
                             let id = get_circle_id(i);

                             let position =
                               QuadraticTrajectory::new(TIME_SHIFT,
                                                        [mutator.rng().gen_range(0, ARENA_SIZE),
                                                         mutator.rng().gen_range(0, ARENA_SIZE),
                                                         mutator.rng().gen_range(-thingy, thingy),
                                                         mutator.rng().gen_range(-thingy, thingy),
                                                         0,
                                                         0]);
                             mutator.set::<Circle>(id,
                                                   Some(Circle {
                                                     position: position,
                                                     radius: radius,
                                                   }));
                             collisions::insert::<CollisionBasics, _>(mutator, id, ());
                           }
                         }));
  let vertex_shader_source = r#"
#version 140
in vec2 direction;
in vec2 center;
in float radius;
out vec2 direction_transfer;

void main() {
direction_transfer = direction*1.5;
gl_Position = vec4 ( center + direction*1.5*radius, 0.0, 1.0);
}

"#;

  let fragment_shader_source = r#"
#version 140
in vec2 direction_transfer;
out vec4 color;

void main() {
if (dot (direction_transfer,direction_transfer) <1.0) {
color = vec4 (1.0, 0.0, 0.0, 1.0);
} else {
color = vec4 (0.0, 0.0, 0.0, 0.0);

}
}

"#;

  let mut snapshots = Vec::new();

if false {
  let display = glium::glutin::WindowBuilder::new()
                  .with_dimensions(600, 600)
                  .build_glium()
                  .expect("failed to create window");
  let program = glium::Program::from_source(&display,
                                            vertex_shader_source,
                                            fragment_shader_source,
                                            None)
                  .unwrap();
  let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
  let start = Instant::now();
  loop {
    for ev in display.poll_events() {
      match ev {
        glium::glutin::Event::Closed => return,
        _ => (),
      }
    }

    let mut target = display.draw();
    target.clear_color(0.0, 0.0, 0.0, 1.0);
    let mut vertices = Vec::<Vertex>::new();

    let snapshot = stew.snapshot_before(&(((start.elapsed().as_secs() as i64*1000000000i64)+start.elapsed().subsec_nanos() as i64) * SECOND /
                                          1000000000i64))
                       .unwrap();
    for index in 0..HOW_MANY_CIRCLES {
      let (circle, time) = snapshot.data_and_last_change::<Circle>(get_circle_id(index))
                                   .expect("missing circle")
                                   .clone();
      let position = circle.position.updated_by(snapshot.now() - time).evaluate();
      let center = [position[0] as f32 / ARENA_SIZE as f32 - 0.5, position[1] as f32 / ARENA_SIZE as f32 - 0.5];
      let radius = circle.radius as f32 / ARENA_SIZE as f32;
    //printlnerr!("drawing circ at {}, {}", center[0],center[1]);
      vertices.extend(&[Vertex {
                          center: center,
                          radius: radius,
                          direction: [1.0, 0.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [-1.0, 0.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [0.0, 1.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [1.0, 0.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [-1.0, 0.0],
                        },
                        Vertex {
                          center: center,
                          radius: radius,
                          direction: [0.0, -1.0],
                        }]);

    }
    target.draw(&glium::VertexBuffer::new(&display, &vertices).unwrap(),
                &indices,
                &program,
                &glium::uniforms::EmptyUniforms,
                &Default::default())
          .unwrap();

    target.finish().expect("failed to finish drawing");

}
    sleep(Duration::from_millis(10));
  }

  for increment in 1..21 {
    snapshots.push(stew.snapshot_before(&(increment * SECOND * 2)));
  }
  for snapshot in snapshots.iter_mut().map(|option| {
    option.as_mut().expect("all these snapshots should have been valid")
  }) {
    printlnerr!("snapshot for {}", snapshot.now());
    for index in 0..HOW_MANY_CIRCLES {
      // printlnerr!("{}", snapshot.get::<Circle> (get_circle_id (index)).expect("missing circle").position);
    }
  }
  // panic!("anyway")
}

#[test]
fn actuallytest() {
  testfunc();
}
<|endoftext|>


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

//! A rust helper to ease the use of Gecko's refcounted types.

use gecko_bindings::structs;
use gecko_bindings::sugar::ownership::HasArcFFI;
use servo_arc::Arc;
use std::{mem, ptr};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

/// Trait for all objects that have Addref() and Release
/// methods and can be placed inside RefPtr<T>
pub unsafe trait RefCounted {
    /// Bump the reference count.
    fn addref(&self);
    /// Decrease the reference count.
    unsafe fn release(&self);
}

/// Trait for types which can be shared across threads in RefPtr.
pub unsafe trait ThreadSafeRefCounted: RefCounted {}

/// A custom RefPtr implementation to take into account Drop semantics and
/// a bit less-painful memory management.
#[derive(Debug)]
pub struct RefPtr<T: RefCounted> {
    ptr: *mut T,
    _marker: PhantomData<T>,
}

/// A RefPtr that we know is uniquely owned.
///
/// This is basically Box<T>, with the additional guarantee that the box can be
/// safely interpreted as a RefPtr<T> (with refcount 1)
///
/// This is useful when you wish to create a refptr and mutate it temporarily,
/// while it is still uniquely owned.
pub struct UniqueRefPtr<T: RefCounted>(RefPtr<T>);

// There is no safe conversion from &T to RefPtr<T> (like Gecko has)
// because this lets you break UniqueRefPtr's guarantee

impl<T: RefCounted> RefPtr<T> {
    /// Create a new RefPtr from an already addrefed pointer obtained from FFI.
    ///
    /// The pointer must be valid, non-null and have been addrefed.
    pub unsafe fn from_addrefed(ptr: *mut T) -> Self {
        debug_assert!(!ptr.is_null());
        RefPtr {
            ptr: ptr,
            _marker: PhantomData,
        }
    }

    /// Create a new RefPtr from a pointer obtained from FFI.
    ///
    /// The pointer must be valid and non null.
    ///
    /// This method calls addref() internally
    pub unsafe fn new(ptr: *mut T) -> Self {
        debug_assert!(!ptr.is_null());
        let ret = RefPtr {
            ptr: ptr,
            _marker: PhantomData,
        };
        ret.addref();
        ret
    }

    /// Create a reference to RefPtr from a reference to pointer.
    ///
    /// The pointer must be valid and non null.
    ///
    /// This method doesn't touch refcount.
    pub unsafe fn from_ptr_ref(ptr: &*mut T) -> &Self {
        mem::transmute(ptr)
    }

    /// Produces an FFI-compatible RefPtr that can be stored in style structs.
    ///
    /// structs::RefPtr does not have a destructor, so this may leak
    pub fn forget(self) -> structs::RefPtr<T> {
        let ret = structs::RefPtr {
            mRawPtr: self.ptr,
            _phantom_0: PhantomData,
        };
        mem::forget(self);
        ret
    }

    /// Returns the raw inner pointer to be fed back into FFI.
    pub fn get(&self) -> *mut T {
        self.ptr
    }

    /// Addref the inner data, obviously leaky on its own.
    pub fn addref(&self) {
        unsafe { (*self.ptr).addref(); }
    }

    /// Release the inner data.
    ///
    /// Call only when the data actually needs releasing.
    pub unsafe fn release(&self) {
        (*self.ptr).release();
    }
}

impl<T: RefCounted> UniqueRefPtr<T> {
    /// Create a unique refptr from an already addrefed pointer obtained from
    /// FFI.
    ///
    /// The refcount must be one.
    ///
    /// The pointer must be valid and non null
    pub unsafe fn from_addrefed(ptr: *mut T) -> Self {
        UniqueRefPtr(RefPtr::from_addrefed(ptr))
    }

    /// Convert to a RefPtr so that it can be used.
    pub fn get(self) -> RefPtr<T> {
        self.0
    }
}

impl<T: RefCounted> Deref for RefPtr<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T: RefCounted> Deref for UniqueRefPtr<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.0.ptr }
    }
}

impl<T: RefCounted> DerefMut for UniqueRefPtr<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.0.ptr }
    }
}

impl<T: RefCounted> structs::RefPtr<T> {
    /// Produces a Rust-side RefPtr from an FFI RefPtr, bumping the refcount.
    ///
    /// Must be called on a valid, non-null structs::RefPtr<T>.
    pub unsafe fn to_safe(&self) -> RefPtr<T> {
        debug_assert!(!self.mRawPtr.is_null());
        let r = RefPtr {
            ptr: self.mRawPtr,
            _marker: PhantomData,
        };
        r.addref();
        r
    }
    /// Produces a Rust-side RefPtr, consuming the existing one (and not bumping
    /// the refcount).
    pub unsafe fn into_safe(self) -> RefPtr<T> {
        debug_assert!(!self.mRawPtr.is_null());
        RefPtr {
            ptr: self.mRawPtr,
            _marker: PhantomData,
        }
    }

    /// Replace a structs::RefPtr<T> with a different one, appropriately
    /// addref/releasing.
    ///
    /// Both `self` and `other` must be valid, but can be null.
    ///
    /// Safe when called on an aliased pointer because the refcount in that case
    /// needs to be at least two.
    pub unsafe fn set(&mut self, other: &Self) {
        self.clear();
        if !other.mRawPtr.is_null() {
            *self = other.to_safe().forget();
        }
    }

    /// Clear an instance of the structs::RefPtr<T>, by releasing
    /// it and setting its contents to null.
    ///
    /// `self` must be valid, but can be null.
    pub unsafe fn clear(&mut self) {
        if !self.mRawPtr.is_null() {
            (*self.mRawPtr).release();
            self.mRawPtr = ptr::null_mut();
        }
    }

    /// Replace a `structs::RefPtr<T>` with a `RefPtr<T>`,
    /// consuming the `RefPtr<T>`, and releasing the old
    /// value in `self` if necessary.
    ///
    /// `self` must be valid, possibly null.
    pub fn set_move(&mut self, other: RefPtr<T>) {
        if !self.mRawPtr.is_null() {
            unsafe { (*self.mRawPtr).release(); }
        }
        *self = other.forget();
    }
}

impl<T> structs::RefPtr<T> {
    /// Sets the contents to an Arc<T>
    /// will leak existing contents
    pub fn set_arc_leaky<U>(&mut self, other: Arc<U>) where U: HasArcFFI<FFIType = T> {
        *self = unsafe { mem::transmute(Arc::into_raw_offset(other)) };
    }
}

impl<T: RefCounted> Drop for RefPtr<T> {
    fn drop(&mut self) {
        unsafe { self.release() }
    }
}

impl<T: RefCounted> Clone for RefPtr<T> {
    fn clone(&self) -> Self {
        self.addref();
        RefPtr {
            ptr: self.ptr,
            _marker: PhantomData,
        }
    }
}

impl<T: RefCounted> PartialEq for RefPtr<T> {
    fn eq(&self, other: &Self) -> bool {
        self.ptr == other.ptr
    }
}

unsafe impl<T: ThreadSafeRefCounted> Send for RefPtr<T> {}
unsafe impl<T: ThreadSafeRefCounted> Sync for RefPtr<T> {}

macro_rules! impl_refcount {
    ($t:ty, $addref:ident, $release:ident) => (
        unsafe impl RefCounted for $t {
            fn addref(&self) {
                unsafe { ::gecko_bindings::bindings::$addref(self as *const _ as *mut _) }
            }
            unsafe fn release(&self) {
                ::gecko_bindings::bindings::$release(self as *const _ as *mut _)
            }
        }
    );
}

impl_refcount!(::gecko_bindings::structs::nsCSSFontFaceRule,
               Gecko_CSSFontFaceRule_AddRef, Gecko_CSSFontFaceRule_Release);
impl_refcount!(::gecko_bindings::structs::nsCSSCounterStyleRule,
               Gecko_CSSCounterStyleRule_AddRef, Gecko_CSSCounterStyleRule_Release);

// Companion of NS_DECL_THREADSAFE_FFI_REFCOUNTING.
//
// Gets you a free RefCounted impl implemented via FFI.
macro_rules! impl_threadsafe_refcount {
    ($t:ty, $addref:ident, $release:ident) => (
        impl_refcount!($t, $addref, $release);
        unsafe impl ThreadSafeRefCounted for $t {}
    );
}

impl_threadsafe_refcount!(::gecko_bindings::structs::RawGeckoURLExtraData,
                          Gecko_AddRefURLExtraDataArbitraryThread,
                          Gecko_ReleaseURLExtraDataArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::nsStyleQuoteValues,
                          Gecko_AddRefQuoteValuesArbitraryThread,
                          Gecko_ReleaseQuoteValuesArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::nsCSSValueSharedList,
                          Gecko_AddRefCSSValueSharedListArbitraryThread,
                          Gecko_ReleaseCSSValueSharedListArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::URLValue,
                          Gecko_AddRefCSSURLValueArbitraryThread,
                          Gecko_ReleaseCSSURLValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::GridTemplateAreasValue,
                          Gecko_AddRefGridTemplateAreasValueArbitraryThread,
                          Gecko_ReleaseGridTemplateAreasValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::ImageValue,
                          Gecko_AddRefImageValueArbitraryThread,
                          Gecko_ReleaseImageValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::SharedFontList,
                          Gecko_AddRefSharedFontListArbitraryThread,
                          Gecko_ReleaseSharedFontListArbitraryThread);

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

//! A rust helper to ease the use of Gecko's refcounted types.

use gecko_bindings::structs;
use gecko_bindings::sugar::ownership::HasArcFFI;
use servo_arc::Arc;
use std::{fmt, mem, ptr};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

/// Trait for all objects that have Addref() and Release
/// methods and can be placed inside RefPtr<T>
pub unsafe trait RefCounted {
    /// Bump the reference count.
    fn addref(&self);
    /// Decrease the reference count.
    unsafe fn release(&self);
}

/// Trait for types which can be shared across threads in RefPtr.
pub unsafe trait ThreadSafeRefCounted: RefCounted {}

/// A custom RefPtr implementation to take into account Drop semantics and
/// a bit less-painful memory management.
pub struct RefPtr<T: RefCounted> {
    ptr: *mut T,
    _marker: PhantomData<T>,
}

impl<T: RefCounted> fmt::Debug for RefPtr<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("RefPtr { ")?;
        self.ptr.fmt(f)?;
        f.write_str("}")
    }
}

/// A RefPtr that we know is uniquely owned.
///
/// This is basically Box<T>, with the additional guarantee that the box can be
/// safely interpreted as a RefPtr<T> (with refcount 1)
///
/// This is useful when you wish to create a refptr and mutate it temporarily,
/// while it is still uniquely owned.
pub struct UniqueRefPtr<T: RefCounted>(RefPtr<T>);

// There is no safe conversion from &T to RefPtr<T> (like Gecko has)
// because this lets you break UniqueRefPtr's guarantee

impl<T: RefCounted> RefPtr<T> {
    /// Create a new RefPtr from an already addrefed pointer obtained from FFI.
    ///
    /// The pointer must be valid, non-null and have been addrefed.
    pub unsafe fn from_addrefed(ptr: *mut T) -> Self {
        debug_assert!(!ptr.is_null());
        RefPtr {
            ptr: ptr,
            _marker: PhantomData,
        }
    }

    /// Create a new RefPtr from a pointer obtained from FFI.
    ///
    /// The pointer must be valid and non null.
    ///
    /// This method calls addref() internally
    pub unsafe fn new(ptr: *mut T) -> Self {
        debug_assert!(!ptr.is_null());
        let ret = RefPtr {
            ptr: ptr,
            _marker: PhantomData,
        };
        ret.addref();
        ret
    }

    /// Create a reference to RefPtr from a reference to pointer.
    ///
    /// The pointer must be valid and non null.
    ///
    /// This method doesn't touch refcount.
    pub unsafe fn from_ptr_ref(ptr: &*mut T) -> &Self {
        mem::transmute(ptr)
    }

    /// Produces an FFI-compatible RefPtr that can be stored in style structs.
    ///
    /// structs::RefPtr does not have a destructor, so this may leak
    pub fn forget(self) -> structs::RefPtr<T> {
        let ret = structs::RefPtr {
            mRawPtr: self.ptr,
            _phantom_0: PhantomData,
        };
        mem::forget(self);
        ret
    }

    /// Returns the raw inner pointer to be fed back into FFI.
    pub fn get(&self) -> *mut T {
        self.ptr
    }

    /// Addref the inner data, obviously leaky on its own.
    pub fn addref(&self) {
        unsafe { (*self.ptr).addref(); }
    }

    /// Release the inner data.
    ///
    /// Call only when the data actually needs releasing.
    pub unsafe fn release(&self) {
        (*self.ptr).release();
    }
}

impl<T: RefCounted> UniqueRefPtr<T> {
    /// Create a unique refptr from an already addrefed pointer obtained from
    /// FFI.
    ///
    /// The refcount must be one.
    ///
    /// The pointer must be valid and non null
    pub unsafe fn from_addrefed(ptr: *mut T) -> Self {
        UniqueRefPtr(RefPtr::from_addrefed(ptr))
    }

    /// Convert to a RefPtr so that it can be used.
    pub fn get(self) -> RefPtr<T> {
        self.0
    }
}

impl<T: RefCounted> Deref for RefPtr<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T: RefCounted> Deref for UniqueRefPtr<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.0.ptr }
    }
}

impl<T: RefCounted> DerefMut for UniqueRefPtr<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.0.ptr }
    }
}

impl<T: RefCounted> structs::RefPtr<T> {
    /// Produces a Rust-side RefPtr from an FFI RefPtr, bumping the refcount.
    ///
    /// Must be called on a valid, non-null structs::RefPtr<T>.
    pub unsafe fn to_safe(&self) -> RefPtr<T> {
        debug_assert!(!self.mRawPtr.is_null());
        let r = RefPtr {
            ptr: self.mRawPtr,
            _marker: PhantomData,
        };
        r.addref();
        r
    }
    /// Produces a Rust-side RefPtr, consuming the existing one (and not bumping
    /// the refcount).
    pub unsafe fn into_safe(self) -> RefPtr<T> {
        debug_assert!(!self.mRawPtr.is_null());
        RefPtr {
            ptr: self.mRawPtr,
            _marker: PhantomData,
        }
    }

    /// Replace a structs::RefPtr<T> with a different one, appropriately
    /// addref/releasing.
    ///
    /// Both `self` and `other` must be valid, but can be null.
    ///
    /// Safe when called on an aliased pointer because the refcount in that case
    /// needs to be at least two.
    pub unsafe fn set(&mut self, other: &Self) {
        self.clear();
        if !other.mRawPtr.is_null() {
            *self = other.to_safe().forget();
        }
    }

    /// Clear an instance of the structs::RefPtr<T>, by releasing
    /// it and setting its contents to null.
    ///
    /// `self` must be valid, but can be null.
    pub unsafe fn clear(&mut self) {
        if !self.mRawPtr.is_null() {
            (*self.mRawPtr).release();
            self.mRawPtr = ptr::null_mut();
        }
    }

    /// Replace a `structs::RefPtr<T>` with a `RefPtr<T>`,
    /// consuming the `RefPtr<T>`, and releasing the old
    /// value in `self` if necessary.
    ///
    /// `self` must be valid, possibly null.
    pub fn set_move(&mut self, other: RefPtr<T>) {
        if !self.mRawPtr.is_null() {
            unsafe { (*self.mRawPtr).release(); }
        }
        *self = other.forget();
    }
}

impl<T> structs::RefPtr<T> {
    /// Sets the contents to an Arc<T>
    /// will leak existing contents
    pub fn set_arc_leaky<U>(&mut self, other: Arc<U>) where U: HasArcFFI<FFIType = T> {
        *self = unsafe { mem::transmute(Arc::into_raw_offset(other)) };
    }
}

impl<T: RefCounted> Drop for RefPtr<T> {
    fn drop(&mut self) {
        unsafe { self.release() }
    }
}

impl<T: RefCounted> Clone for RefPtr<T> {
    fn clone(&self) -> Self {
        self.addref();
        RefPtr {
            ptr: self.ptr,
            _marker: PhantomData,
        }
    }
}

impl<T: RefCounted> PartialEq for RefPtr<T> {
    fn eq(&self, other: &Self) -> bool {
        self.ptr == other.ptr
    }
}

unsafe impl<T: ThreadSafeRefCounted> Send for RefPtr<T> {}
unsafe impl<T: ThreadSafeRefCounted> Sync for RefPtr<T> {}

macro_rules! impl_refcount {
    ($t:ty, $addref:ident, $release:ident) => (
        unsafe impl RefCounted for $t {
            fn addref(&self) {
                unsafe { ::gecko_bindings::bindings::$addref(self as *const _ as *mut _) }
            }
            unsafe fn release(&self) {
                ::gecko_bindings::bindings::$release(self as *const _ as *mut _)
            }
        }
    );
}

impl_refcount!(::gecko_bindings::structs::nsCSSFontFaceRule,
               Gecko_CSSFontFaceRule_AddRef, Gecko_CSSFontFaceRule_Release);
impl_refcount!(::gecko_bindings::structs::nsCSSCounterStyleRule,
               Gecko_CSSCounterStyleRule_AddRef, Gecko_CSSCounterStyleRule_Release);

// Companion of NS_DECL_THREADSAFE_FFI_REFCOUNTING.
//
// Gets you a free RefCounted impl implemented via FFI.
macro_rules! impl_threadsafe_refcount {
    ($t:ty, $addref:ident, $release:ident) => (
        impl_refcount!($t, $addref, $release);
        unsafe impl ThreadSafeRefCounted for $t {}
    );
}

impl_threadsafe_refcount!(::gecko_bindings::structs::RawGeckoURLExtraData,
                          Gecko_AddRefURLExtraDataArbitraryThread,
                          Gecko_ReleaseURLExtraDataArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::nsStyleQuoteValues,
                          Gecko_AddRefQuoteValuesArbitraryThread,
                          Gecko_ReleaseQuoteValuesArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::nsCSSValueSharedList,
                          Gecko_AddRefCSSValueSharedListArbitraryThread,
                          Gecko_ReleaseCSSValueSharedListArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::URLValue,
                          Gecko_AddRefCSSURLValueArbitraryThread,
                          Gecko_ReleaseCSSURLValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::GridTemplateAreasValue,
                          Gecko_AddRefGridTemplateAreasValueArbitraryThread,
                          Gecko_ReleaseGridTemplateAreasValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::ImageValue,
                          Gecko_AddRefImageValueArbitraryThread,
                          Gecko_ReleaseImageValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::SharedFontList,
                          Gecko_AddRefSharedFontListArbitraryThread,
                          Gecko_ReleaseSharedFontListArbitraryThread);

<|endoftext|>


<commit_before>use innovation::Innovation;
use gene::Gene;
use gene_list::GeneList;
use traits::{Distance, Genotype};
use crossover::Crossover;
use rand::Rng;
use acyclic_network::{Network, NetworkMap};
pub use acyclic_network::NodeType;
use std::collections::BTreeMap;
use std::cmp;
use std::marker::PhantomData;
use mutate::MutateMethod;
use std::fmt::Debug;

#[derive(Debug, Clone)]
pub struct NodeGene<NT: NodeType> {
    pub innovation: Innovation,
    pub node_type: NT,
}

impl<NT: NodeType> Gene for NodeGene<NT> {
    fn weight_distance(&self, _other: &Self) -> f64 {
        0.0
    }

    fn innovation(&self) -> Innovation {
        self.innovation
    }
}

// To avoid node collisions we use Innovation numbers instead of node ids.
// XXX: We could omit the `innovation` and instead use (source_node_gene, target_node_gene),
// but only if duplicate links are not allowed.
#[derive(Debug, Clone)]
pub struct LinkGene {
    // The innovation number of that LinkGene
    pub innovation: Innovation,

    // This points to the NodeGene of that innovation
    pub source_node_gene: Innovation,
    // This points to the NodeGene of that innovation
    pub target_node_gene: Innovation,
    pub weight: f64,
    pub active: bool,
}

impl Gene for LinkGene {
    fn weight_distance(&self, other: &Self) -> f64 {
        self.weight - other.weight
    }

    fn innovation(&self) -> Innovation {
        self.innovation
    }
}

impl LinkGene {
    pub fn disable(&mut self) {
        assert!(self.active);
        self.active = false;
    }
}

#[derive(Clone, Debug)]
pub struct Genome<NT: NodeType> {
    link_genes: GeneList<LinkGene>,
    node_genes: GeneList<NodeGene<NT>>,
    network: NetworkMap<Innovation, NT, f64>,
}

impl<NT: NodeType> Genotype for Genome<NT> {}

impl<NT: NodeType> Genome<NT> {
    pub fn new() -> Self {
        Genome {
            link_genes: GeneList::new(),
            node_genes: GeneList::new(),
            network: NetworkMap::new(),
        }
    }

    pub fn network(&self) -> &Network<NT, f64> {
        self.network.network()
    }

    pub fn visit_node_genes<F>(&self, mut f: F)
        where F: FnMut(&NodeGene<NT>)
    {
        for node_gene_w in self.node_genes.genes().iter() {
            f(node_gene_w.as_ref())
        }
    }

    pub fn visit_active_link_genes<F>(&self, mut f: F)
        where F: FnMut(&LinkGene)
    {
        for link_gene_w in self.link_genes.genes().iter() {
            let link_gene = link_gene_w.as_ref();
            if link_gene.active {
                f(link_gene)
            }
        }
    }

    pub fn add_link(&mut self, link_gene: LinkGene) {
        self.network.add_link(link_gene.source_node_gene,
                              link_gene.target_node_gene,
                              link_gene.weight);
        self.link_genes.insert(link_gene);
    }

    pub fn add_node(&mut self, node_gene: NodeGene<NT>) {
        self.network.add_node(node_gene.innovation(), node_gene.node_type.clone());
        self.node_genes.push(node_gene);
    }

    // Uses the crossover method C to recombine left and right.
    pub fn crossover<R: Rng, C: Crossover>(left: &Self, right: &Self, c: &C, rng: &mut R) -> Self {
        let mut new_link_genes = GeneList::new();
        let mut new_node_genes = GeneList::new();

        // At first, crossover the node genes.
        c.crossover(&left.node_genes,
                    &right.node_genes,
                    &mut |gene| {
                        new_node_genes.push(gene.clone());
                    },
                    rng);

        // As the crossover of node genes might lead out some nodes which
        // we need for connections, we have to make sure that they exist.
        c.crossover(&left.link_genes,
                    &right.link_genes,
                    &mut |gene| {
                        new_link_genes.push(gene.clone());
                    },
                    rng);

        // Additionally make sure that all link genes have a correspondant node gene.
        // We do this also for disabled links!
        for link_gene in new_link_genes.genes().iter() {
            new_node_genes.insert_from_either_or_by_innovation(link_gene.as_ref().source_node_gene,
                                                               &left.node_genes,
                                                               &right.node_genes);
            new_node_genes.insert_from_either_or_by_innovation(link_gene.as_ref().target_node_gene,
                                                               &left.node_genes,
                                                               &right.node_genes);
        }

        // now we have to check that the link genes do not introduce a cycle, and remove those that do.
        let mut net = NetworkMap::new();

        // At first, add all nodes to the graph
        for node_gene in new_node_genes.genes().iter() {
            let node = node_gene.as_ref();
            net.add_node(node.innovation(), node.node_type.clone());
        }

        // now only retain those link genes, which would not introduce a cycle
        new_link_genes.retain(|link_gene| {
            if net.link_would_cycle(link_gene.source_node_gene, link_gene.target_node_gene) {
                false
            } else {
                net.add_link(link_gene.source_node_gene,
                             link_gene.target_node_gene,
                             link_gene.weight);
                true
            }
        });
        // XXX: handle disabled links

        // we might now have some additional nodes which are unconnected. leave them
        // for now.

        Genome {
            link_genes: new_link_genes,
            node_genes: new_node_genes,
            network: net,
        }
    }

    /// Returns a random link gene innovation which is active. Or None if no such exists.
    pub fn find_random_active_link_gene<R: Rng>(&self, rng: &mut R) -> Option<Innovation> {
        let mut all_active_link_genes = Vec::with_capacity(self.link_genes.len());
        for link_gene_w in self.link_genes.genes().iter() {
            let link_gene = link_gene_w.as_ref();
            if link_gene.active {
                all_active_link_genes.push(link_gene.innovation());
            }
        }
        rng.choose(&all_active_link_genes).map(|&i| i)
    }
}

pub struct GenomeDistance {
    pub excess: f64,
    pub disjoint: f64,
    pub weight: f64,
}

impl<NT: NodeType> Distance<Genome<NT>> for GenomeDistance {
    fn distance(&self, genome_left: &Genome<NT>, genome_right: &Genome<NT>) -> f64 {
        let genes_left = &genome_left.link_genes;
        let genes_right = &genome_right.link_genes;

        let max_len = cmp::max(genes_left.len(), genes_right.len());
        if max_len == 0 {
            return 0.0;
        }

        let m = genes_left.alignment_metric(&genes_right);

        self.excess * (m.excess as f64) / (max_len as f64) +
        self.disjoint * (m.disjoint as f64) / (max_len as f64) +
        self.weight *
        if m.matching > 0 {
            m.weight_distance / (m.matching as f64)
        } else {
            0.0
        }
    }
}
/// This trait is used to specialize link weight creation and node activation function creation.
pub trait ElementStrategy<NT: NodeType>
{
    fn random_link_weight<R: Rng>(rng: &mut R) -> f64;
    fn random_node_type<R: Rng>(rng: &mut R) -> NT;
}

#[derive(Debug)]
pub struct Environment<NT, S>
    where NT: NodeType,
          S: ElementStrategy<NT>
{
    node_innovation_counter: Innovation,
    link_innovation_counter: Innovation,
    // (src_node, target_node) -> link_innovation
    link_innovation_cache: BTreeMap<(Innovation, Innovation), Innovation>,
    _marker_s: PhantomData<S>,
    _marker_nt: PhantomData<NT>,
}

impl<NT, S> Environment<NT, S>
    where NT: NodeType,
          S: ElementStrategy<NT>
{
    pub fn new() -> Self {
        Environment {
            node_innovation_counter: Innovation::new(0),
            link_innovation_counter: Innovation::new(0),
            link_innovation_cache: BTreeMap::new(),
            _marker_s: PhantomData,
            _marker_nt: PhantomData,
        }
    }

    /// Adds a link to `genome` without checking if the addition of this
    /// link would introduce a cycle or would otherwise be illegal.
    fn add_link(&mut self,
                genome: &mut Genome<NT>,
                source_node: Innovation,
                target_node: Innovation,
                weight: f64) {
        let link_innovation = self.get_link_innovation(source_node, target_node);
        let link_gene = LinkGene {
            innovation: link_innovation,
            source_node_gene: source_node,
            target_node_gene: target_node,
            weight: weight,
            active: true,
        };
        genome.add_link(link_gene)
    }

    fn get_link_innovation(&mut self,
                           source_node_gene: Innovation,
                           target_node_gene: Innovation)
                           -> Innovation {
        let key = (source_node_gene, target_node_gene);
        if let Some(&cached_innovation) = self.link_innovation_cache.get(&key) {
            return cached_innovation;
        }
        let new_innovation = self.link_innovation_counter.next().unwrap();
        self.link_innovation_cache.insert(key, new_innovation);
        new_innovation
    }

    fn new_node_innovation(&mut self) -> Innovation {
        self.node_innovation_counter.next().unwrap()
    }

    pub fn mutate<R: Rng>(&mut self,
                          genome: &Genome<NT>,
                          method: MutateMethod,
                          rng: &mut R)
                          -> Option<Genome<NT>> {
        match method {
            MutateMethod::ModifyWeight => {
                // XXX
                None
            }
            MutateMethod::AddConnection => self.mutate_add_connection(genome, rng),
            MutateMethod::AddNode => self.mutate_add_node(genome, rng),
        }
    }

    pub fn mutate_add_connection<R: Rng>(&mut self,
                                         genome: &Genome<NT>,
                                         rng: &mut R)
                                         -> Option<Genome<NT>> {
        genome.network.find_random_unconnected_link_no_cycle(rng).map(|(&src, &target)| {
            let mut offspring = genome.clone();
            // Add new link to the offspring genome
            self.add_link(&mut offspring, src, target, S::random_link_weight(rng));
            offspring
        })
    }

    pub fn add_node_to_genome(&mut self, genome: &mut Genome<NT>, node_type: NT) {
        genome.add_node(NodeGene {
            innovation: self.node_innovation_counter.next().unwrap(),
            node_type: node_type,
        });
    }

    /// choose a random link. split it in half.
    /// XXX: activate if link is inactive?
    pub fn mutate_add_node<R: Rng>(&mut self,
                                   genome: &Genome<NT>,
                                   rng: &mut R)
                                   -> Option<Genome<NT>> {
        genome.find_random_active_link_gene(rng).map(|link_innov| {
            // split link in half.
            let mut offspring = genome.clone();
            let new_node_innovation = self.new_node_innovation();
            // add new node
            offspring.add_node(NodeGene {
                innovation: new_node_innovation,
                node_type: S::random_node_type(rng),
            });

            // disable `link_innov` in offspring
            // we keep this gene (but disable it), because this allows us to have a structurally
            // compatible genome to the old one, as disabled genes are taken into account for
            // the genomic distance measure.
            let (orig_src_node, orig_target_node) = {
                let mut orig_link = offspring.link_genes
                                             .find_by_innovation_mut(link_innov)
                                             .unwrap();
                orig_link.disable();
                // add two new link innovations with the new node in the middle.
                // XXX: Choose random weights? Or split weight? We use random weights for now.
                (orig_link.source_node_gene, orig_link.target_node_gene)
            };
            // adding these two links cannot create a cycle.
            self.add_link(&mut offspring,
                          orig_src_node,
                          new_node_innovation,
                          S::random_link_weight(rng));
            self.add_link(&mut offspring,
                          new_node_innovation,
                          orig_target_node,
                          S::random_link_weight(rng));
            offspring
        })
    }
}
<commit_msg>Silence warning<commit_after>use innovation::Innovation;
use gene::Gene;
use gene_list::GeneList;
use traits::{Distance, Genotype};
use crossover::Crossover;
use rand::Rng;
use acyclic_network::{Network, NetworkMap};
pub use acyclic_network::NodeType;
use std::collections::BTreeMap;
use std::cmp;
use std::marker::PhantomData;
use mutate::MutateMethod;

#[derive(Debug, Clone)]
pub struct NodeGene<NT: NodeType> {
    pub innovation: Innovation,
    pub node_type: NT,
}

impl<NT: NodeType> Gene for NodeGene<NT> {
    fn weight_distance(&self, _other: &Self) -> f64 {
        0.0
    }

    fn innovation(&self) -> Innovation {
        self.innovation
    }
}

// To avoid node collisions we use Innovation numbers instead of node ids.
// XXX: We could omit the `innovation` and instead use (source_node_gene, target_node_gene),
// but only if duplicate links are not allowed.
#[derive(Debug, Clone)]
pub struct LinkGene {
    // The innovation number of that LinkGene
    pub innovation: Innovation,

    // This points to the NodeGene of that innovation
    pub source_node_gene: Innovation,
    // This points to the NodeGene of that innovation
    pub target_node_gene: Innovation,
    pub weight: f64,
    pub active: bool,
}

impl Gene for LinkGene {
    fn weight_distance(&self, other: &Self) -> f64 {
        self.weight - other.weight
    }

    fn innovation(&self) -> Innovation {
        self.innovation
    }
}

impl LinkGene {
    pub fn disable(&mut self) {
        assert!(self.active);
        self.active = false;
    }
}

#[derive(Clone, Debug)]
pub struct Genome<NT: NodeType> {
    link_genes: GeneList<LinkGene>,
    node_genes: GeneList<NodeGene<NT>>,
    network: NetworkMap<Innovation, NT, f64>,
}

impl<NT: NodeType> Genotype for Genome<NT> {}

impl<NT: NodeType> Genome<NT> {
    pub fn new() -> Self {
        Genome {
            link_genes: GeneList::new(),
            node_genes: GeneList::new(),
            network: NetworkMap::new(),
        }
    }

    pub fn network(&self) -> &Network<NT, f64> {
        self.network.network()
    }

    pub fn visit_node_genes<F>(&self, mut f: F)
        where F: FnMut(&NodeGene<NT>)
    {
        for node_gene_w in self.node_genes.genes().iter() {
            f(node_gene_w.as_ref())
        }
    }

    pub fn visit_active_link_genes<F>(&self, mut f: F)
        where F: FnMut(&LinkGene)
    {
        for link_gene_w in self.link_genes.genes().iter() {
            let link_gene = link_gene_w.as_ref();
            if link_gene.active {
                f(link_gene)
            }
        }
    }

    pub fn add_link(&mut self, link_gene: LinkGene) {
        self.network.add_link(link_gene.source_node_gene,
                              link_gene.target_node_gene,
                              link_gene.weight);
        self.link_genes.insert(link_gene);
    }

    pub fn add_node(&mut self, node_gene: NodeGene<NT>) {
        self.network.add_node(node_gene.innovation(), node_gene.node_type.clone());
        self.node_genes.push(node_gene);
    }

    // Uses the crossover method C to recombine left and right.
    pub fn crossover<R: Rng, C: Crossover>(left: &Self, right: &Self, c: &C, rng: &mut R) -> Self {
        let mut new_link_genes = GeneList::new();
        let mut new_node_genes = GeneList::new();

        // At first, crossover the node genes.
        c.crossover(&left.node_genes,
                    &right.node_genes,
                    &mut |gene| {
                        new_node_genes.push(gene.clone());
                    },
                    rng);

        // As the crossover of node genes might lead out some nodes which
        // we need for connections, we have to make sure that they exist.
        c.crossover(&left.link_genes,
                    &right.link_genes,
                    &mut |gene| {
                        new_link_genes.push(gene.clone());
                    },
                    rng);

        // Additionally make sure that all link genes have a correspondant node gene.
        // We do this also for disabled links!
        for link_gene in new_link_genes.genes().iter() {
            new_node_genes.insert_from_either_or_by_innovation(link_gene.as_ref().source_node_gene,
                                                               &left.node_genes,
                                                               &right.node_genes);
            new_node_genes.insert_from_either_or_by_innovation(link_gene.as_ref().target_node_gene,
                                                               &left.node_genes,
                                                               &right.node_genes);
        }

        // now we have to check that the link genes do not introduce a cycle, and remove those that do.
        let mut net = NetworkMap::new();

        // At first, add all nodes to the graph
        for node_gene in new_node_genes.genes().iter() {
            let node = node_gene.as_ref();
            net.add_node(node.innovation(), node.node_type.clone());
        }

        // now only retain those link genes, which would not introduce a cycle
        new_link_genes.retain(|link_gene| {
            if net.link_would_cycle(link_gene.source_node_gene, link_gene.target_node_gene) {
                false
            } else {
                net.add_link(link_gene.source_node_gene,
                             link_gene.target_node_gene,
                             link_gene.weight);
                true
            }
        });
        // XXX: handle disabled links

        // we might now have some additional nodes which are unconnected. leave them
        // for now.

        Genome {
            link_genes: new_link_genes,
            node_genes: new_node_genes,
            network: net,
        }
    }

    /// Returns a random link gene innovation which is active. Or None if no such exists.
    pub fn find_random_active_link_gene<R: Rng>(&self, rng: &mut R) -> Option<Innovation> {
        let mut all_active_link_genes = Vec::with_capacity(self.link_genes.len());
        for link_gene_w in self.link_genes.genes().iter() {
            let link_gene = link_gene_w.as_ref();
            if link_gene.active {
                all_active_link_genes.push(link_gene.innovation());
            }
        }
        rng.choose(&all_active_link_genes).map(|&i| i)
    }
}

pub struct GenomeDistance {
    pub excess: f64,
    pub disjoint: f64,
    pub weight: f64,
}

impl<NT: NodeType> Distance<Genome<NT>> for GenomeDistance {
    fn distance(&self, genome_left: &Genome<NT>, genome_right: &Genome<NT>) -> f64 {
        let genes_left = &genome_left.link_genes;
        let genes_right = &genome_right.link_genes;

        let max_len = cmp::max(genes_left.len(), genes_right.len());
        if max_len == 0 {
            return 0.0;
        }

        let m = genes_left.alignment_metric(&genes_right);

        self.excess * (m.excess as f64) / (max_len as f64) +
        self.disjoint * (m.disjoint as f64) / (max_len as f64) +
        self.weight *
        if m.matching > 0 {
            m.weight_distance / (m.matching as f64)
        } else {
            0.0
        }
    }
}
/// This trait is used to specialize link weight creation and node activation function creation.
pub trait ElementStrategy<NT: NodeType>
{
    fn random_link_weight<R: Rng>(rng: &mut R) -> f64;
    fn random_node_type<R: Rng>(rng: &mut R) -> NT;
}

#[derive(Debug)]
pub struct Environment<NT, S>
    where NT: NodeType,
          S: ElementStrategy<NT>
{
    node_innovation_counter: Innovation,
    link_innovation_counter: Innovation,
    // (src_node, target_node) -> link_innovation
    link_innovation_cache: BTreeMap<(Innovation, Innovation), Innovation>,
    _marker_s: PhantomData<S>,
    _marker_nt: PhantomData<NT>,
}

impl<NT, S> Environment<NT, S>
    where NT: NodeType,
          S: ElementStrategy<NT>
{
    pub fn new() -> Self {
        Environment {
            node_innovation_counter: Innovation::new(0),
            link_innovation_counter: Innovation::new(0),
            link_innovation_cache: BTreeMap::new(),
            _marker_s: PhantomData,
            _marker_nt: PhantomData,
        }
    }

    /// Adds a link to `genome` without checking if the addition of this
    /// link would introduce a cycle or would otherwise be illegal.
    fn add_link(&mut self,
                genome: &mut Genome<NT>,
                source_node: Innovation,
                target_node: Innovation,
                weight: f64) {
        let link_innovation = self.get_link_innovation(source_node, target_node);
        let link_gene = LinkGene {
            innovation: link_innovation,
            source_node_gene: source_node,
            target_node_gene: target_node,
            weight: weight,
            active: true,
        };
        genome.add_link(link_gene)
    }

    fn get_link_innovation(&mut self,
                           source_node_gene: Innovation,
                           target_node_gene: Innovation)
                           -> Innovation {
        let key = (source_node_gene, target_node_gene);
        if let Some(&cached_innovation) = self.link_innovation_cache.get(&key) {
            return cached_innovation;
        }
        let new_innovation = self.link_innovation_counter.next().unwrap();
        self.link_innovation_cache.insert(key, new_innovation);
        new_innovation
    }

    fn new_node_innovation(&mut self) -> Innovation {
        self.node_innovation_counter.next().unwrap()
    }

    pub fn mutate<R: Rng>(&mut self,
                          genome: &Genome<NT>,
                          method: MutateMethod,
                          rng: &mut R)
                          -> Option<Genome<NT>> {
        match method {
            MutateMethod::ModifyWeight => {
                // XXX
                None
            }
            MutateMethod::AddConnection => self.mutate_add_connection(genome, rng),
            MutateMethod::AddNode => self.mutate_add_node(genome, rng),
        }
    }

    pub fn mutate_add_connection<R: Rng>(&mut self,
                                         genome: &Genome<NT>,
                                         rng: &mut R)
                                         -> Option<Genome<NT>> {
        genome.network.find_random_unconnected_link_no_cycle(rng).map(|(&src, &target)| {
            let mut offspring = genome.clone();
            // Add new link to the offspring genome
            self.add_link(&mut offspring, src, target, S::random_link_weight(rng));
            offspring
        })
    }

    pub fn add_node_to_genome(&mut self, genome: &mut Genome<NT>, node_type: NT) {
        genome.add_node(NodeGene {
            innovation: self.node_innovation_counter.next().unwrap(),
            node_type: node_type,
        });
    }

    /// choose a random link. split it in half.
    /// XXX: activate if link is inactive?
    pub fn mutate_add_node<R: Rng>(&mut self,
                                   genome: &Genome<NT>,
                                   rng: &mut R)
                                   -> Option<Genome<NT>> {
        genome.find_random_active_link_gene(rng).map(|link_innov| {
            // split link in half.
            let mut offspring = genome.clone();
            let new_node_innovation = self.new_node_innovation();
            // add new node
            offspring.add_node(NodeGene {
                innovation: new_node_innovation,
                node_type: S::random_node_type(rng),
            });

            // disable `link_innov` in offspring
            // we keep this gene (but disable it), because this allows us to have a structurally
            // compatible genome to the old one, as disabled genes are taken into account for
            // the genomic distance measure.
            let (orig_src_node, orig_target_node) = {
                let mut orig_link = offspring.link_genes
                                             .find_by_innovation_mut(link_innov)
                                             .unwrap();
                orig_link.disable();
                // add two new link innovations with the new node in the middle.
                // XXX: Choose random weights? Or split weight? We use random weights for now.
                (orig_link.source_node_gene, orig_link.target_node_gene)
            };
            // adding these two links cannot create a cycle.
            self.add_link(&mut offspring,
                          orig_src_node,
                          new_node_innovation,
                          S::random_link_weight(rng));
            self.add_link(&mut offspring,
                          new_node_innovation,
                          orig_target_node,
                          S::random_link_weight(rng));
            offspring
        })
    }
}
<|endoftext|>


<commit_before>extern crate challenges;
extern crate failure;
use challenges::errors::run_exercise;
use failure::Error;
use std::env;

fn main() {
    let mut challenges = Vec::<fn() -> Result<(), Error>>::new();
    challenges::set1::add_challenges(&mut challenges);
    challenges::set2::add_challenges(&mut challenges);
    challenges::set3::add_challenges(&mut challenges);
    challenges::set4::add_challenges(&mut challenges);
    challenges::set5::add_challenges(&mut challenges);
    challenges::set6::add_challenges(&mut challenges);

    let challenges_count = challenges.len();
    assert!(challenges_count <= std::u8::MAX as usize);

    match challenge_indices(challenges_count) {
        Ok(indices) => {
            for i in indices {
                run_exercise(challenges[i - 1], i as u8);
            }
        }
        Err(arg) => {
            println!(
                "Provided argument \"{}\" is invalid. Expected a number between 1 and {} ",
                arg, challenges_count
            );
        }
    }
}

fn challenge_indices(challenges_count: usize) -> Result<Vec<usize>, String> {
    let args = env::args();
    if args.len() <= 1 {
        return Ok((1..=challenges_count).collect());
    }

    let mut indices = Vec::new();
    for arg in args.into_iter().skip(1) {
        if let Ok(index) = arg.parse::<usize>() {
            if index >= 1 && index <= challenges_count {
                indices.push(index);
                continue;
            }
        }
        println!("{}", arg);
        return Err(arg);
    }
    Ok(indices)
}
<commit_msg>Remove debug output<commit_after>extern crate challenges;
extern crate failure;
use challenges::errors::run_exercise;
use failure::Error;
use std::env;

fn main() {
    let mut challenges = Vec::<fn() -> Result<(), Error>>::new();
    challenges::set1::add_challenges(&mut challenges);
    challenges::set2::add_challenges(&mut challenges);
    challenges::set3::add_challenges(&mut challenges);
    challenges::set4::add_challenges(&mut challenges);
    challenges::set5::add_challenges(&mut challenges);
    challenges::set6::add_challenges(&mut challenges);

    let challenges_count = challenges.len();
    assert!(challenges_count <= std::u8::MAX as usize);

    match challenge_indices(challenges_count) {
        Ok(indices) => {
            for i in indices {
                run_exercise(challenges[i - 1], i as u8);
            }
        }
        Err(arg) => {
            println!(
                "Provided argument \"{}\" is invalid. Expected a number between 1 and {} ",
                arg, challenges_count
            );
        }
    }
}

fn challenge_indices(challenges_count: usize) -> Result<Vec<usize>, String> {
    let args = env::args();
    if args.len() <= 1 {
        return Ok((1..=challenges_count).collect());
    }

    let mut indices = Vec::new();
    for arg in args.into_iter().skip(1) {
        if let Ok(index) = arg.parse::<usize>() {
            if index >= 1 && index <= challenges_count {
                indices.push(index);
                continue;
            }
        }
        return Err(arg);
    }
    Ok(indices)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use session::config::Options;

use std::fs;
use std::io::{self, StdoutLock, Write};
use std::time::Instant;

macro_rules! define_categories {
    ($($name:ident,)*) => {
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        pub enum ProfileCategory {
            $($name),*
        }

        #[allow(nonstandard_style)]
        struct Categories<T> {
            $($name: T),*
        }

        impl<T: Default> Categories<T> {
            fn new() -> Categories<T> {
                Categories {
                    $($name: T::default()),*
                }
            }
        }

        impl<T> Categories<T> {
            fn get(&self, category: ProfileCategory) -> &T {
                match category {
                    $(ProfileCategory::$name => &self.$name),*
                }
            }

            fn set(&mut self, category: ProfileCategory, value: T) {
                match category {
                    $(ProfileCategory::$name => self.$name = value),*
                }
            }
        }

        struct CategoryData {
            times: Categories<u64>,
            query_counts: Categories<(u64, u64)>,
        }

        impl CategoryData {
            fn new() -> CategoryData {
                CategoryData {
                    times: Categories::new(),
                    query_counts: Categories::new(),
                }
            }

            fn print(&self, lock: &mut StdoutLock<'_>) {
                writeln!(lock, "| Phase            | Time (ms)      | Queries        | Hits (%) |")
                    .unwrap();
                writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
                    .unwrap();

                $(
                    let (hits, total) = self.query_counts.$name;
                    let (hits, total) = if total > 0 {
                        (format!("{:.2}",
                        (((hits as f32) / (total as f32)) * 100.0)), total.to_string())
                    } else {
                        (String::new(), String::new())
                    };

                    writeln!(
                        lock,
                        "| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        hits
                    ).unwrap();
                )*
            }

            fn json(&self) -> String {
                let mut json = String::from("[");

                $(
                    let (hits, total) = self.query_counts.$name;

                    json.push_str(&format!(
                        "{{ \"category\": {}, \"time_ms\": {},
                            \"query_count\": {}, \"query_hits\": {} }}",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        format!("{:.2}", (((hits as f32) / (total as f32)) * 100.0))
                    ));
                )*

                json.push(']');

                json
            }
        }
    }
}

define_categories! {
    Parsing,
    Expansion,
    TypeChecking,
    BorrowChecking,
    Codegen,
    Linking,
    Other,
}

pub struct SelfProfiler {
    timer_stack: Vec<ProfileCategory>,
    data: CategoryData,
    current_timer: Instant,
}

impl SelfProfiler {
    pub fn new() -> SelfProfiler {
        let mut profiler = SelfProfiler {
            timer_stack: Vec::new(),
            data: CategoryData::new(),
            current_timer: Instant::now(),
        };

        profiler.start_activity(ProfileCategory::Other);

        profiler
    }

    pub fn start_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.last().cloned() {
            None => {
                self.current_timer = Instant::now();
            },
            Some(current_category) if current_category == category => {
                //since the current category is the same as the new activity's category,
                //we don't need to do anything with the timer, we just need to push it on the stack
            }
            Some(current_category) => {
                let elapsed = self.stop_timer();

                //record the current category's time
                let new_time = self.data.times.get(current_category) + elapsed;
                self.data.times.set(current_category, new_time);
            }
        }

        //push the new category
        self.timer_stack.push(category);
    }

    pub fn record_query(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits, total + 1));
    }

    pub fn record_query_hit(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits + 1, total));
    }

    pub fn end_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.pop() {
            None => bug!("end_activity() was called but there was no running activity"),
            Some(c) =>
                assert!(
                    c == category,
                    "end_activity() was called but a different activity was running"),
        }

        //check if the new running timer is in the same category as this one
        //if it is, we don't need to do anything
        if let Some(c) = self.timer_stack.last() {
            if *c == category {
                return;
            }
        }

        //the new timer is different than the previous,
        //so record the elapsed time and start a new timer
        let elapsed = self.stop_timer();
        let new_time = self.data.times.get(category) + elapsed;
        self.data.times.set(category, new_time);
    }

    fn stop_timer(&mut self) -> u64 {
        let elapsed = self.current_timer.elapsed();

        self.current_timer = Instant::now();

        (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64)
    }

    pub fn print_results(&mut self, opts: &Options) {
        self.end_activity(ProfileCategory::Other);

        assert!(
            self.timer_stack.is_empty(),
            "there were timers running when print_results() was called");

        let out = io::stdout();
        let mut lock = out.lock();

        let crate_name =
            opts.crate_name
            .as_ref()
            .map(|n| format!(" for {}", n))
            .unwrap_or_default();

        writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
        writeln!(lock).unwrap();

        self.data.print(&mut lock);

        writeln!(lock).unwrap();
        writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();

        let incremental = if opts.incremental.is_some() { "on" } else { "off" };
        writeln!(lock, "Incremental: {}", incremental).unwrap();
    }

    pub fn save_results(&self, opts: &Options) {
        let category_data = self.data.json();
        let compilation_options =
            format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
                    opts.optimize,
                    if opts.incremental.is_some() { "true" } else { "false" });

        let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
                        category_data,
                        compilation_options);

        fs::write("self_profiler_results.json", json).unwrap();
    }
}
<commit_msg>Rollup merge of #56091 - wesleywiser:fix_self_profiler_json, r=petrochenkov<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use session::config::Options;

use std::fs;
use std::io::{self, StdoutLock, Write};
use std::time::Instant;

macro_rules! define_categories {
    ($($name:ident,)*) => {
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        pub enum ProfileCategory {
            $($name),*
        }

        #[allow(nonstandard_style)]
        struct Categories<T> {
            $($name: T),*
        }

        impl<T: Default> Categories<T> {
            fn new() -> Categories<T> {
                Categories {
                    $($name: T::default()),*
                }
            }
        }

        impl<T> Categories<T> {
            fn get(&self, category: ProfileCategory) -> &T {
                match category {
                    $(ProfileCategory::$name => &self.$name),*
                }
            }

            fn set(&mut self, category: ProfileCategory, value: T) {
                match category {
                    $(ProfileCategory::$name => self.$name = value),*
                }
            }
        }

        struct CategoryData {
            times: Categories<u64>,
            query_counts: Categories<(u64, u64)>,
        }

        impl CategoryData {
            fn new() -> CategoryData {
                CategoryData {
                    times: Categories::new(),
                    query_counts: Categories::new(),
                }
            }

            fn print(&self, lock: &mut StdoutLock<'_>) {
                writeln!(lock, "| Phase            | Time (ms)      | Queries        | Hits (%) |")
                    .unwrap();
                writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
                    .unwrap();

                $(
                    let (hits, total) = self.query_counts.$name;
                    let (hits, total) = if total > 0 {
                        (format!("{:.2}",
                        (((hits as f32) / (total as f32)) * 100.0)), total.to_string())
                    } else {
                        (String::new(), String::new())
                    };

                    writeln!(
                        lock,
                        "| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        hits
                    ).unwrap();
                )*
            }

            fn json(&self) -> String {
                let mut json = String::from("[");

                $(
                    let (hits, total) = self.query_counts.$name;

                    //normalize hits to 0%
                    let hit_percent =
                        if total > 0 {
                            ((hits as f32) / (total as f32)) * 100.0
                        } else {
                            0.0
                        };

                    json.push_str(&format!(
                        "{{ \"category\": {}, \"time_ms\": {},
                            \"query_count\": {}, \"query_hits\": {} }},",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        format!("{:.2}", hit_percent)
                    ));
                )*

                //remove the trailing ',' character
                json.pop();

                json.push(']');

                json
            }
        }
    }
}

define_categories! {
    Parsing,
    Expansion,
    TypeChecking,
    BorrowChecking,
    Codegen,
    Linking,
    Other,
}

pub struct SelfProfiler {
    timer_stack: Vec<ProfileCategory>,
    data: CategoryData,
    current_timer: Instant,
}

impl SelfProfiler {
    pub fn new() -> SelfProfiler {
        let mut profiler = SelfProfiler {
            timer_stack: Vec::new(),
            data: CategoryData::new(),
            current_timer: Instant::now(),
        };

        profiler.start_activity(ProfileCategory::Other);

        profiler
    }

    pub fn start_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.last().cloned() {
            None => {
                self.current_timer = Instant::now();
            },
            Some(current_category) if current_category == category => {
                //since the current category is the same as the new activity's category,
                //we don't need to do anything with the timer, we just need to push it on the stack
            }
            Some(current_category) => {
                let elapsed = self.stop_timer();

                //record the current category's time
                let new_time = self.data.times.get(current_category) + elapsed;
                self.data.times.set(current_category, new_time);
            }
        }

        //push the new category
        self.timer_stack.push(category);
    }

    pub fn record_query(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits, total + 1));
    }

    pub fn record_query_hit(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits + 1, total));
    }

    pub fn end_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.pop() {
            None => bug!("end_activity() was called but there was no running activity"),
            Some(c) =>
                assert!(
                    c == category,
                    "end_activity() was called but a different activity was running"),
        }

        //check if the new running timer is in the same category as this one
        //if it is, we don't need to do anything
        if let Some(c) = self.timer_stack.last() {
            if *c == category {
                return;
            }
        }

        //the new timer is different than the previous,
        //so record the elapsed time and start a new timer
        let elapsed = self.stop_timer();
        let new_time = self.data.times.get(category) + elapsed;
        self.data.times.set(category, new_time);
    }

    fn stop_timer(&mut self) -> u64 {
        let elapsed = self.current_timer.elapsed();

        self.current_timer = Instant::now();

        (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64)
    }

    pub fn print_results(&mut self, opts: &Options) {
        self.end_activity(ProfileCategory::Other);

        assert!(
            self.timer_stack.is_empty(),
            "there were timers running when print_results() was called");

        let out = io::stdout();
        let mut lock = out.lock();

        let crate_name =
            opts.crate_name
            .as_ref()
            .map(|n| format!(" for {}", n))
            .unwrap_or_default();

        writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
        writeln!(lock).unwrap();

        self.data.print(&mut lock);

        writeln!(lock).unwrap();
        writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();

        let incremental = if opts.incremental.is_some() { "on" } else { "off" };
        writeln!(lock, "Incremental: {}", incremental).unwrap();
    }

    pub fn save_results(&self, opts: &Options) {
        let category_data = self.data.json();
        let compilation_options =
            format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
                    opts.optimize,
                    if opts.incremental.is_some() { "true" } else { "false" });

        let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
                        category_data,
                        compilation_options);

        fs::write("self_profiler_results.json", json).unwrap();
    }
}
<|endoftext|>