<commit_before>mod draw_batch;

use std::path::Path;
use cgmath;
use cgmath::Vector2;
use glium::{DisplayBuild, Surface, Program, Frame};
use glium::glutin::{WindowBuilder, Event, ElementState, VirtualKeyCode};
use glium::backend::glutin_backend::GlutinFacade;
use glium::texture::RawImage2d;
use glium::texture::srgb_texture2d::SrgbTexture2d;
use image;
use warp_horizon::Grid;
use warp_horizon_client::{FrontendEvent, GameButton, ClientState};
use frontend::draw_batch::DrawBatch;

#[derive(Copy, Clone)]
struct SimpleVertex {
    position: [f32; 2],
    tex_coords: [f32; 2],
}

implement_vertex!(SimpleVertex, position, tex_coords);

impl SimpleVertex {
    fn new(position: [f32; 2], tex_coords: [f32; 2]) -> Self {
        SimpleVertex {
            position: position,
            tex_coords: tex_coords,
        }
    }
}

struct DrawResources {
    pub display: GlutinFacade,
    pub program: Program,
    pub texture: SrgbTexture2d,
}

struct FrameResources<'a> {
    pub target: &'a mut Frame,
    pub matrix: &'a [[f32; 4]; 4],
}

pub struct Frontend {
    resources: DrawResources,
    should_exit: bool,
}

impl Frontend {
    pub fn init() -> Self {
        // Set up our frontend
        let display = WindowBuilder::new()
            .with_dimensions(1280, 720)
            .build_glium()
            .unwrap();

        // Load in the shaders
        let program = Program::from_source(
                &display,
                include_str!("vert.glsl"),
                include_str!("frag.glsl"),
                None
            )
            .unwrap();

        // Load in the tileset
        let image = image::open(&Path::new("./assets/tiles.png")).unwrap().to_rgba();
        let image_dimensions = image.dimensions();
        let image = RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions);
        let texture = SrgbTexture2d::new(&display, image).unwrap();

        // Create the frontend struct
        Frontend {
            resources: DrawResources {
                display: display,
                program: program,
                texture: texture,
            },
            should_exit: false,
        }
    }

    pub fn process_events(&mut self) -> Vec<FrontendEvent> {
        let mut events = Vec::new();

        // Poll all glutin events
        for ev in self.resources.display.poll_events() {
            match ev {
                Event::Closed => self.should_exit = true,
                Event::KeyboardInput(state, _scan_code, key_code) =>
                    Self::process_key(&mut events, state, key_code),
                _ => {},
            }
        }

        events
    }

    fn process_key(
        events: &mut Vec<FrontendEvent>,
        state: ElementState, key: Option<VirtualKeyCode>
    ) {
        let key = match key.unwrap() {
            VirtualKeyCode::Right => GameButton::MoveCameraRight,
            VirtualKeyCode::Left => GameButton::MoveCameraLeft,
            VirtualKeyCode::Up => GameButton::MoveCameraUp,
            VirtualKeyCode::Down => GameButton::MoveCameraDown,
            _ => return // We don't know about this key, so just do nothing
        };
        let event = match state {
            ElementState::Pressed => FrontendEvent::Press(key),
            ElementState::Released => FrontendEvent::Release(key),
        };

        events.push(event);
    }

    pub fn render(&self, state: &ClientState) {
        // Create our projection matrix
        // Our camera is a window onto an infinite plane, one pixel in graphics is one pixel on the
        // plane. We change the window defined in the matrix rather than changing the position of
        // vertices. The matrix however doesn't do the world-to-screen conversion, that's still
        // done when putting together the vertices, we just take away the worry of having to move
        // around depending on camera position away from those.
        let cam_pos = state.main_camera().position();
        let cam_scale = state.main_camera().zoom();
        let cam_half_res = Vector2::new((1280 / cam_scale) as f32, (720 / cam_scale) as f32) * 0.5;
        let matrix = cgmath::ortho(
            cam_pos.x - cam_half_res.x, cam_pos.x + cam_half_res.x,
            cam_pos.y - cam_half_res.y, cam_pos.y + cam_half_res.y,
            -10.0, 10.0
        );

        // Begin drawing
        let mut target = self.resources.display.draw();
        let mut brightness = 10.0 / 255.0;
        brightness = (((brightness+0.055)/1.055) as f32).powf(2.4); // sRGB to Linear
        target.clear_color(brightness, brightness, brightness, 1.0);

        {
            // Create the container struct for the frame's resources
            let mut frame = FrameResources {
                target: &mut target,
                matrix: &matrix.into()
            };

            // Draw the grid
            self.draw_grid(&mut frame, state.main_grid());
        }

        // Finish drawing
        target.finish().unwrap();
    }

    pub fn should_exit(&self) -> bool {
        self.should_exit
    }

    fn draw_grid(&self, frame: &mut FrameResources, grid: &Grid) {
        // Set up the tile batch we can use to draw
        let mut batch = DrawBatch::new();

        // Actually send over the tile data
        for y in 0..grid.height() {
            for x in 0..grid.width() {
                // If the tile is 0, there's nothing here
                if grid.get(x, y).unwrap() == 0 {
                    continue;
                }

                // Calculate some misc data about our tiles
                let tile = Vector2::new(32.0, 15.0);
                let uv_per = Vector2::new(1.0 / (256.0 / tile.x), 1.0 / (120.0 / tile.y));

                // Calculate the start of the grid cell this tile is in and where we have to draw
                // the "+ 1.0" bit is a hack to get it working, I don't know where the actual problem is
                let offset_from_x = Vector2::new(tile.x * 0.5, -(tile.y + 1.0) * 0.5) * (x as f32);
                let offset_from_y = Vector2::new(-tile.x * 0.5, -(tile.y + 1.0) * 0.5) * (y as f32);
                let cell_start_pos = offset_from_x + offset_from_y; // The start of the cell in world on screen
                let pos = cell_start_pos - Vector2::new(tile.x * 0.5, tile.y);

                // Add the tile to the batch
                batch.push_tile(
                    pos, tile,
                    Vector2::new(uv_per.x * 0.0, uv_per.y * 7.0),
                    Vector2::new(uv_per.x * 1.0, uv_per.y * 8.0)
                );
            }
        }

        // Finally, draw
        batch.draw(&self.resources, frame);
    }
}
<commit_msg>Hook mouse movement into the frontend<commit_after>mod draw_batch;

use std::path::Path;
use cgmath;
use cgmath::Vector2;
use glium::{DisplayBuild, Surface, Program, Frame};
use glium::glutin::{WindowBuilder, Event, ElementState, VirtualKeyCode};
use glium::backend::glutin_backend::GlutinFacade;
use glium::texture::RawImage2d;
use glium::texture::srgb_texture2d::SrgbTexture2d;
use image;
use warp_horizon::Grid;
use warp_horizon_client::{FrontendEvent, GameButton, ClientState};
use frontend::draw_batch::DrawBatch;

#[derive(Copy, Clone)]
struct SimpleVertex {
    position: [f32; 2],
    tex_coords: [f32; 2],
}

implement_vertex!(SimpleVertex, position, tex_coords);

impl SimpleVertex {
    fn new(position: [f32; 2], tex_coords: [f32; 2]) -> Self {
        SimpleVertex {
            position: position,
            tex_coords: tex_coords,
        }
    }
}

struct DrawResources {
    pub display: GlutinFacade,
    pub program: Program,
    pub texture: SrgbTexture2d,
}

struct FrameResources<'a> {
    pub target: &'a mut Frame,
    pub matrix: &'a [[f32; 4]; 4],
}

pub struct Frontend {
    resources: DrawResources,
    should_exit: bool,
}

impl Frontend {
    pub fn init() -> Self {
        // Set up our frontend
        let display = WindowBuilder::new()
            .with_dimensions(1280, 720)
            .build_glium()
            .unwrap();

        // Load in the shaders
        let program = Program::from_source(
                &display,
                include_str!("vert.glsl"),
                include_str!("frag.glsl"),
                None
            )
            .unwrap();

        // Load in the tileset
        let image = image::open(&Path::new("./assets/tiles.png")).unwrap().to_rgba();
        let image_dimensions = image.dimensions();
        let image = RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions);
        let texture = SrgbTexture2d::new(&display, image).unwrap();

        // Create the frontend struct
        Frontend {
            resources: DrawResources {
                display: display,
                program: program,
                texture: texture,
            },
            should_exit: false,
        }
    }

    pub fn process_events(&mut self) -> Vec<FrontendEvent> {
        let mut events = Vec::new();

        // Poll all glutin events
        for ev in self.resources.display.poll_events() {
            match ev {
                Event::Closed => self.should_exit = true,
                Event::KeyboardInput(state, _scan_code, key_code) =>
                    Self::process_key(&mut events, state, key_code),
                Event::MouseMoved((x, y)) =>
                    events.push(FrontendEvent::MouseMove(Vector2::new(x, y))),
                _ => {},
            }
        }

        events
    }

    fn process_key(
        events: &mut Vec<FrontendEvent>,
        state: ElementState, key: Option<VirtualKeyCode>
    ) {
        let key = match key.unwrap() {
            VirtualKeyCode::Right => GameButton::MoveCameraRight,
            VirtualKeyCode::Left => GameButton::MoveCameraLeft,
            VirtualKeyCode::Up => GameButton::MoveCameraUp,
            VirtualKeyCode::Down => GameButton::MoveCameraDown,
            _ => return // We don't know about this key, so just do nothing
        };
        let event = match state {
            ElementState::Pressed => FrontendEvent::Press(key),
            ElementState::Released => FrontendEvent::Release(key),
        };

        events.push(event);
    }

    pub fn render(&self, state: &ClientState) {
        // Create our projection matrix
        // Our camera is a window onto an infinite plane, one pixel in graphics is one pixel on the
        // plane. We change the window defined in the matrix rather than changing the position of
        // vertices. The matrix however doesn't do the world-to-screen conversion, that's still
        // done when putting together the vertices, we just take away the worry of having to move
        // around depending on camera position away from those.
        let cam_pos = state.main_camera().position();
        let cam_scale = state.main_camera().zoom();
        let cam_half_res = Vector2::new((1280 / cam_scale) as f32, (720 / cam_scale) as f32) * 0.5;
        let matrix = cgmath::ortho(
            cam_pos.x - cam_half_res.x, cam_pos.x + cam_half_res.x,
            cam_pos.y - cam_half_res.y, cam_pos.y + cam_half_res.y,
            -10.0, 10.0
        );

        // Begin drawing
        let mut target = self.resources.display.draw();
        let mut brightness = 10.0 / 255.0;
        brightness = (((brightness+0.055)/1.055) as f32).powf(2.4); // sRGB to Linear
        target.clear_color(brightness, brightness, brightness, 1.0);

        {
            // Create the container struct for the frame's resources
            let mut frame = FrameResources {
                target: &mut target,
                matrix: &matrix.into()
            };

            // Draw the grid
            self.draw_grid(&mut frame, state.main_grid());
        }

        // Finish drawing
        target.finish().unwrap();
    }

    pub fn should_exit(&self) -> bool {
        self.should_exit
    }

    fn draw_grid(&self, frame: &mut FrameResources, grid: &Grid) {
        // Set up the tile batch we can use to draw
        let mut batch = DrawBatch::new();

        // Actually send over the tile data
        for y in 0..grid.height() {
            for x in 0..grid.width() {
                // If the tile is 0, there's nothing here
                if grid.get(x, y).unwrap() == 0 {
                    continue;
                }

                // Calculate some misc data about our tiles
                let tile = Vector2::new(32.0, 15.0);
                let uv_per = Vector2::new(1.0 / (256.0 / tile.x), 1.0 / (120.0 / tile.y));

                // Calculate the start of the grid cell this tile is in and where we have to draw
                // the "+ 1.0" bit is a hack to get it working, I don't know where the actual problem is
                let offset_from_x = Vector2::new(tile.x * 0.5, -(tile.y + 1.0) * 0.5) * (x as f32);
                let offset_from_y = Vector2::new(-tile.x * 0.5, -(tile.y + 1.0) * 0.5) * (y as f32);
                let cell_start_pos = offset_from_x + offset_from_y; // The start of the cell in world on screen
                let pos = cell_start_pos - Vector2::new(tile.x * 0.5, tile.y);

                // Add the tile to the batch
                batch.push_tile(
                    pos, tile,
                    Vector2::new(uv_per.x * 0.0, uv_per.y * 7.0),
                    Vector2::new(uv_per.x * 1.0, uv_per.y * 8.0)
                );
            }
        }

        // Finally, draw
        batch.draw(&self.resources, frame);
    }
}
<|endoftext|>


<commit_before>extern crate react;

use react::*;

#[test]
fn input_cells_have_a_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(10);
    assert_eq!(reactor.value(input), Some(10));
}

#[test]
#[ignore]
fn an_input_cells_value_can_be_set() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(4);
    assert!(reactor.set_value(input, 20).is_ok());
    assert_eq!(reactor.value(input), Some(20));
}

#[test]
#[ignore]
fn error_setting_a_nonexistent_input_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(Reactor::new().set_value(input, 0).is_err());
}

#[test]
#[ignore]
fn compute_cells_calculate_initial_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert_eq!(reactor.value(output), Some(2));
}

#[test]
#[ignore]
fn compute_cells_take_inputs_in_the_right_order() {
    let mut reactor = Reactor::new();
    let one = reactor.create_input(1);
    let two = reactor.create_input(2);
    let output = reactor.create_compute(&[one, two], |v| v[0] + v[1] * 10).unwrap();
    assert_eq!(reactor.value(output), Some(21));
}

#[test]
#[ignore]
fn error_creating_compute_cell_if_input_doesnt_exist() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(Reactor::new().create_compute(&[input], |_| 0).is_err());
}

#[test]
#[ignore]
fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() {
    let mut dummy_reactor = Reactor::new();
    let _ = dummy_reactor.create_input(1);
    let dummy_cell = dummy_reactor.create_input(2);
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    assert!(reactor.create_compute(&[input, dummy_cell], |_| 0).is_err());
    assert!(reactor.set_value(input, 5).is_ok());
    assert_eq!(reactor.value(input), Some(5));
}

#[test]
#[ignore]
fn compute_cells_update_value_when_dependencies_are_changed() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert_eq!(reactor.value(output), Some(2));
    assert!(reactor.set_value(input, 3).is_ok());
    assert_eq!(reactor.value(output), Some(4));
}

#[test]
#[ignore]
fn compute_cells_can_depend_on_other_compute_cells() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let times_two = reactor.create_compute(&[input], |v| v[0] * 2).unwrap();
    let times_thirty = reactor.create_compute(&[input], |v| v[0] * 30).unwrap();
    let output = reactor.create_compute(&[times_two, times_thirty], |v| v[0] + v[1]).unwrap();
    assert_eq!(reactor.value(output), Some(32));
    assert!(reactor.set_value(input, 3).is_ok());
    assert_eq!(reactor.value(output), Some(96));
}

#[test]
#[ignore]
fn error_setting_a_compute_cell() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |_| 0).unwrap();
    assert!(reactor.set_value(output, 3).is_err());
}

#[test]
#[ignore]
fn compute_cells_fire_callbacks() {
    // This is a bit awkward, but the closure mutably borrows `values`.
    // So we have to end its borrow by taking reactor out of scope.
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 3).is_ok());
    }
    assert_eq!(values, vec![4]);
}

#[test]
#[ignore]
fn error_adding_callback_to_nonexistent_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    let output = dummy_reactor.create_compute(&[input], |_| 0).unwrap();
    assert!(Reactor::new().add_callback(output, |_: usize| println!("hi")).is_err());
}

#[test]
#[ignore]
fn callbacks_only_fire_on_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| if v[0] < 3 { 111 } else { 222 }).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 2).is_ok());
        assert!(reactor.set_value(input, 4).is_ok());
    }
    assert_eq!(values, vec![222]);
}

#[test]
#[ignore]
fn callbacks_can_be_added_and_removed() {
    let mut values1 = Vec::new();
    let mut values2 = Vec::new();
    let mut values3 = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(11);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let callback = reactor.add_callback(output, |v| values1.push(v)).unwrap();
        assert!(reactor.add_callback(output, |v| values2.push(v)).is_ok());
        assert!(reactor.set_value(input, 31).is_ok());
        assert!(reactor.remove_callback(output, callback).is_ok());
        assert!(reactor.add_callback(output, |v| values3.push(v)).is_ok());
        assert!(reactor.set_value(input, 41).is_ok());
    }
    assert_eq!(values1, vec![32]);
    assert_eq!(values2, vec![32, 42]);
    assert_eq!(values3, vec![42]);
}

#[test]
#[ignore]
fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() {
    let mut values1 = Vec::new();
    let mut values2 = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let callback = reactor.add_callback(output, |v| values1.push(v)).unwrap();
        assert!(reactor.add_callback(output, |v| values2.push(v)).is_ok());
        // We want the first remove to be Ok, but we don't care about the others.
        assert!(reactor.remove_callback(output, callback).is_ok());
        for _ in 1..5 {
            assert!(reactor.remove_callback(output, callback).is_err());
        }
        assert!(reactor.set_value(input, 2).is_ok());
    }
    assert_eq!(values1, Vec::new());
    assert_eq!(values2, vec![3]);
}

#[test]
#[ignore]
fn callbacks_should_only_be_called_once_even_if_multiple_dependencies_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let minus_one1 = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
        let minus_one2 = reactor.create_compute(&[minus_one1], |v| v[0] - 1).unwrap();
        let output = reactor.create_compute(&[plus_one, minus_one2], |v| v[0] * v[1]).unwrap();
        assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
        assert!(reactor.set_value(input, 4).is_ok());
    }
    assert_eq!(values, vec![10]);
}

#[test]
#[ignore]
fn callbacks_should_not_be_called_if_dependencies_change_but_output_value_doesnt_change() {
    let mut values = Vec::new();
    {
        let mut reactor = Reactor::new();
        let input = reactor.create_input(1);
        let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
        let minus_one = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
        let always_two = reactor.create_compute(&[plus_one, minus_one], |v| v[0] - v[1]).unwrap();
        assert!(reactor.add_callback(always_two, |v| values.push(v)).is_ok());
        for i in 2..5 {
            assert!(reactor.set_value(input, i).is_ok());
        }
    }
    assert_eq!(values, Vec::new());
}

#[test]
#[ignore]
fn test_adder_with_boolean_values() {
    // This is a digital logic circuit called an adder:
    // https://en.wikipedia.org/wiki/Adder_(electronics)
    let mut reactor = Reactor::new();
    let a = reactor.create_input(false);
    let b = reactor.create_input(false);
    let carry_in = reactor.create_input(false);

    let a_xor_b = reactor.create_compute(&[a, b], |v| v[0] ^ v[1]).unwrap();
    let sum = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] ^ v[1]).unwrap();

    let a_xor_b_and_cin = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] && v[1]).unwrap();
    let a_and_b = reactor.create_compute(&[a, b], |v| v[0] && v[1]).unwrap();
    let carry_out = reactor.create_compute(&[a_xor_b_and_cin, a_and_b], |v| v[0] || v[1]).unwrap();

    let tests = &[
        (false, false, false, false, false),
        (false, false, true, false, true),
        (false, true, false, false, true),
        (false, true, true, true, false),
        (true, false, false, false, true),
        (true, false, true, true, false),
        (true, true, false, true, false),
        (true, true, true, true, true),
    ];

    for &(aval, bval, cinval, expected_cout, expected_sum) in tests {
        assert!(reactor.set_value(a, aval).is_ok());
        assert!(reactor.set_value(b, bval).is_ok());
        assert!(reactor.set_value(carry_in, cinval).is_ok());

        assert_eq!(reactor.value(sum), Some(expected_sum));
        assert_eq!(reactor.value(carry_out), Some(expected_cout));
    }
}
<commit_msg>react: Express callback expectations precisely after each `set_value` (#434)<commit_after>extern crate react;

use react::*;

#[test]
fn input_cells_have_a_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(10);
    assert_eq!(reactor.value(input), Some(10));
}

#[test]
#[ignore]
fn an_input_cells_value_can_be_set() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(4);
    assert!(reactor.set_value(input, 20).is_ok());
    assert_eq!(reactor.value(input), Some(20));
}

#[test]
#[ignore]
fn error_setting_a_nonexistent_input_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(Reactor::new().set_value(input, 0).is_err());
}

#[test]
#[ignore]
fn compute_cells_calculate_initial_value() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert_eq!(reactor.value(output), Some(2));
}

#[test]
#[ignore]
fn compute_cells_take_inputs_in_the_right_order() {
    let mut reactor = Reactor::new();
    let one = reactor.create_input(1);
    let two = reactor.create_input(2);
    let output = reactor.create_compute(&[one, two], |v| v[0] + v[1] * 10).unwrap();
    assert_eq!(reactor.value(output), Some(21));
}

#[test]
#[ignore]
fn error_creating_compute_cell_if_input_doesnt_exist() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    assert!(Reactor::new().create_compute(&[input], |_| 0).is_err());
}

#[test]
#[ignore]
fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() {
    let mut dummy_reactor = Reactor::new();
    let _ = dummy_reactor.create_input(1);
    let dummy_cell = dummy_reactor.create_input(2);
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    assert!(reactor.create_compute(&[input, dummy_cell], |_| 0).is_err());
    assert!(reactor.set_value(input, 5).is_ok());
    assert_eq!(reactor.value(input), Some(5));
}

#[test]
#[ignore]
fn compute_cells_update_value_when_dependencies_are_changed() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert_eq!(reactor.value(output), Some(2));
    assert!(reactor.set_value(input, 3).is_ok());
    assert_eq!(reactor.value(output), Some(4));
}

#[test]
#[ignore]
fn compute_cells_can_depend_on_other_compute_cells() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let times_two = reactor.create_compute(&[input], |v| v[0] * 2).unwrap();
    let times_thirty = reactor.create_compute(&[input], |v| v[0] * 30).unwrap();
    let output = reactor.create_compute(&[times_two, times_thirty], |v| v[0] + v[1]).unwrap();
    assert_eq!(reactor.value(output), Some(32));
    assert!(reactor.set_value(input, 3).is_ok());
    assert_eq!(reactor.value(output), Some(96));
}

#[test]
#[ignore]
fn error_setting_a_compute_cell() {
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |_| 0).unwrap();
    assert!(reactor.set_value(output, 3).is_err());
}

/// A CallbackRecorder helps tests whether callbacks get called correctly.
/// You'll see it used in tests that deal with callbacks.
/// The names should be descriptive enough so that the tests make sense,
/// so it's not necessary to fully understand the implementation,
/// though you are welcome to.
struct CallbackRecorder {
    // Note that this `Cell` is https://doc.rust-lang.org/std/cell/
    // a mechanism to allow internal mutability,
    // distinct from the cells (input cells, compute cells) in the reactor
    value: std::cell::Cell<Option<isize>>,
}

impl CallbackRecorder {
    fn new() -> Self {
        CallbackRecorder {
            value: std::cell::Cell::new(None),
        }
    }

    fn expect_to_have_been_called_with(&self, v: isize) {
        assert_ne!(self.value.get(), None, "Callback was not called, but should have been");
        assert_eq!(self.value.replace(None), Some(v), "Callback was called with incorrect value");
    }

    fn expect_not_to_have_been_called(&self) {
        assert_eq!(self.value.get(), None, "Callback was called, but should not have been");
    }

    fn callback_called(&self, v: isize) {
        assert_eq!(self.value.replace(Some(v)), None, "Callback was called too many times; can't be called with {}", v);
    }
}

#[test]
#[ignore]
fn compute_cells_fire_callbacks() {
    let cb = CallbackRecorder::new();
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_ok());
    assert!(reactor.set_value(input, 3).is_ok());
    cb.expect_to_have_been_called_with(4);
}

#[test]
#[ignore]
fn error_adding_callback_to_nonexistent_cell() {
    let mut dummy_reactor = Reactor::new();
    let input = dummy_reactor.create_input(1);
    let output = dummy_reactor.create_compute(&[input], |_| 0).unwrap();
    assert!(Reactor::new().add_callback(output, |_: usize| println!("hi")).is_err());
}

#[test]
#[ignore]
fn callbacks_only_fire_on_change() {
    let cb = CallbackRecorder::new();
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| if v[0] < 3 { 111 } else { 222 }).unwrap();
    assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_ok());

    assert!(reactor.set_value(input, 2).is_ok());
    cb.expect_not_to_have_been_called();
    assert!(reactor.set_value(input, 4).is_ok());
    cb.expect_to_have_been_called_with(222);
}

#[test]
#[ignore]
fn callbacks_can_be_added_and_removed() {
    let cb1 = CallbackRecorder::new();
    let cb2 = CallbackRecorder::new();
    let cb3 = CallbackRecorder::new();

    let mut reactor = Reactor::new();
    let input = reactor.create_input(11);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();

    let callback = reactor.add_callback(output, |v| cb1.callback_called(v)).unwrap();
    assert!(reactor.add_callback(output, |v| cb2.callback_called(v)).is_ok());

    assert!(reactor.set_value(input, 31).is_ok());
    cb1.expect_to_have_been_called_with(32);
    cb2.expect_to_have_been_called_with(32);

    assert!(reactor.remove_callback(output, callback).is_ok());
    assert!(reactor.add_callback(output, |v| cb3.callback_called(v)).is_ok());

    assert!(reactor.set_value(input, 41).is_ok());
    cb1.expect_not_to_have_been_called();
    cb2.expect_to_have_been_called_with(42);
    cb3.expect_to_have_been_called_with(42);
}

#[test]
#[ignore]
fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() {
    let cb1 = CallbackRecorder::new();
    let cb2 = CallbackRecorder::new();

    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    let callback = reactor.add_callback(output, |v| cb1.callback_called(v)).unwrap();
    assert!(reactor.add_callback(output, |v| cb2.callback_called(v)).is_ok());
    // We want the first remove to be Ok, but we don't care about the others.
    assert!(reactor.remove_callback(output, callback).is_ok());
    for _ in 1..5 {
        assert!(reactor.remove_callback(output, callback).is_err());
    }

    assert!(reactor.set_value(input, 2).is_ok());
    cb1.expect_not_to_have_been_called();
    cb2.expect_to_have_been_called_with(3);
}

#[test]
#[ignore]
fn callbacks_should_only_be_called_once_even_if_multiple_dependencies_change() {
    let cb = CallbackRecorder::new();
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    let minus_one1 = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
    let minus_one2 = reactor.create_compute(&[minus_one1], |v| v[0] - 1).unwrap();
    let output = reactor.create_compute(&[plus_one, minus_one2], |v| v[0] * v[1]).unwrap();
    assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_ok());
    assert!(reactor.set_value(input, 4).is_ok());
    cb.expect_to_have_been_called_with(10);
}

#[test]
#[ignore]
fn callbacks_should_not_be_called_if_dependencies_change_but_output_value_doesnt_change() {
    let cb = CallbackRecorder::new();
    let mut reactor = Reactor::new();
    let input = reactor.create_input(1);
    let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
    let minus_one = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
    let always_two = reactor.create_compute(&[plus_one, minus_one], |v| v[0] - v[1]).unwrap();
    assert!(reactor.add_callback(always_two, |v| cb.callback_called(v)).is_ok());
    for i in 2..5 {
        assert!(reactor.set_value(input, i).is_ok());
        cb.expect_not_to_have_been_called();
    }
}

#[test]
#[ignore]
fn test_adder_with_boolean_values() {
    // This is a digital logic circuit called an adder:
    // https://en.wikipedia.org/wiki/Adder_(electronics)
    let mut reactor = Reactor::new();
    let a = reactor.create_input(false);
    let b = reactor.create_input(false);
    let carry_in = reactor.create_input(false);

    let a_xor_b = reactor.create_compute(&[a, b], |v| v[0] ^ v[1]).unwrap();
    let sum = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] ^ v[1]).unwrap();

    let a_xor_b_and_cin = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] && v[1]).unwrap();
    let a_and_b = reactor.create_compute(&[a, b], |v| v[0] && v[1]).unwrap();
    let carry_out = reactor.create_compute(&[a_xor_b_and_cin, a_and_b], |v| v[0] || v[1]).unwrap();

    let tests = &[
        (false, false, false, false, false),
        (false, false, true, false, true),
        (false, true, false, false, true),
        (false, true, true, true, false),
        (true, false, false, false, true),
        (true, false, true, true, false),
        (true, true, false, true, false),
        (true, true, true, true, true),
    ];

    for &(aval, bval, cinval, expected_cout, expected_sum) in tests {
        assert!(reactor.set_value(a, aval).is_ok());
        assert!(reactor.set_value(b, bval).is_ok());
        assert!(reactor.set_value(carry_in, cinval).is_ok());

        assert_eq!(reactor.value(sum), Some(expected_sum));
        assert_eq!(reactor.value(carry_out), Some(expected_cout));
    }
}
<|endoftext|>


<commit_before>extern crate file_dialog;
extern crate glfw_window;
extern crate shader_version;
extern crate opengl_graphics;

use file_dialog::FileDialog;
use glfw_window::GlfwWindow;
use opengl_graphics::glyph_cache::GlyphCache as Font;
use shader_version::opengl::OpenGL;

fn main() {
    let font = Font::new(&Path::new("./assets/Dense-Regular.otf")).unwrap();

    let promise = FileDialog::new("File Dialog Test", font)
        .show(GlfwWindow::new, OpenGL::OpenGL_3_2);

    promise.unwrap();
}
<commit_msg>Print selected file in test<commit_after>extern crate file_dialog;
extern crate glfw_window;
extern crate shader_version;
extern crate opengl_graphics;

use file_dialog::FileDialog;
use glfw_window::GlfwWindow;
use opengl_graphics::glyph_cache::GlyphCache as Font;
use shader_version::opengl::OpenGL;

use std::io::fs::PathExtensions;

fn main() {
    let font = Font::new(&Path::new("./assets/Dense-Regular.otf")).unwrap();

    let promise = FileDialog::new("File Dialog Test", font)
        .show(GlfwWindow::new, OpenGL::OpenGL_3_2);

    println!("Selected file: {}", promise.unwrap().display());
}
<|endoftext|>


<commit_before>use std::env;

use serenity::async_trait;
use serenity::model::channel::Message;
use serenity::model::gateway::Ready;
use serenity::prelude::*;

// Serenity implements transparent sharding in a way that you do not need to
// manually handle separate processes or connections manually.
//
// Transparent sharding is useful for a shared cache. Instead of having caches
// with duplicated data, a shared cache means all your data can be easily
// accessible across all shards.
//
// If your bot is on many guilds - or over the maximum of 2500 - then you
// should/must use guild sharding.
//
// This is an example file showing how guild sharding works. For this to
// properly be able to be seen in effect, your bot should be in at least 2
// guilds.
//
// Taking a scenario of 2 guilds, try saying "!ping" in one guild. It should
// print either "0" or "1" in the console. Saying "!ping" in the other guild,
// it should cache the other number in the console. This confirms that guild
// sharding works.
struct Handler;

#[async_trait]
impl EventHandler for Handler {
    async fn message(&self, ctx: Context, msg: Message) {
        if msg.content == "!ping" {
            println!("Shard {}", ctx.shard_id);

            if let Err(why) = msg.channel_id.say(&ctx.http, "Pong!").await {
                println!("Error sending message: {:?}", why);
            }
        }
    }

    async fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

#[tokio::main]
async fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");
    let intents = GatewayIntents::GUILD_MESSAGES
        | GatewayIntents::DIRECT_MESSAGES
        | GatewayIntents::MESSAGE_CONTENT;
    let mut client =
        Client::builder(&token, intents).event_handler(Handler).await.expect("Err creating client");

    // The total number of shards to use. The "current shard number" of a
    // shard - that is, the shard it is assigned to - is indexed at 0,
    // while the total shard count is indexed at 1.
    //
    // This means if you have 5 shards, your total shard count will be 5, while
    // each shard will be assigned numbers 0 through 4.
    if let Err(why) = client.start_shards(2).await {
        println!("Client error: {:?}", why);
    }
}
<commit_msg>Fix a typo in example 02 (#1971)<commit_after>use std::env;

use serenity::async_trait;
use serenity::model::channel::Message;
use serenity::model::gateway::Ready;
use serenity::prelude::*;

// Serenity implements transparent sharding in a way that you do not need to
// handle separate processes or connections manually.
//
// Transparent sharding is useful for a shared cache. Instead of having caches
// with duplicated data, a shared cache means all your data can be easily
// accessible across all shards.
//
// If your bot is on many guilds - or over the maximum of 2500 - then you
// should/must use guild sharding.
//
// This is an example file showing how guild sharding works. For this to
// properly be able to be seen in effect, your bot should be in at least 2
// guilds.
//
// Taking a scenario of 2 guilds, try saying "!ping" in one guild. It should
// print either "0" or "1" in the console. Saying "!ping" in the other guild,
// it should cache the other number in the console. This confirms that guild
// sharding works.
struct Handler;

#[async_trait]
impl EventHandler for Handler {
    async fn message(&self, ctx: Context, msg: Message) {
        if msg.content == "!ping" {
            println!("Shard {}", ctx.shard_id);

            if let Err(why) = msg.channel_id.say(&ctx.http, "Pong!").await {
                println!("Error sending message: {:?}", why);
            }
        }
    }

    async fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

#[tokio::main]
async fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");
    let intents = GatewayIntents::GUILD_MESSAGES
        | GatewayIntents::DIRECT_MESSAGES
        | GatewayIntents::MESSAGE_CONTENT;
    let mut client =
        Client::builder(&token, intents).event_handler(Handler).await.expect("Err creating client");

    // The total number of shards to use. The "current shard number" of a
    // shard - that is, the shard it is assigned to - is indexed at 0,
    // while the total shard count is indexed at 1.
    //
    // This means if you have 5 shards, your total shard count will be 5, while
    // each shard will be assigned numbers 0 through 4.
    if let Err(why) = client.start_shards(2).await {
        println!("Client error: {:?}", why);
    }
}
<|endoftext|>


<commit_before>
extern crate cpython;
extern crate numpy;

use numpy::*;

#[test]
fn array_shapes() {
    let py = cpython::Python::acquire_gil();
    let n = 3;
    let m = 5;
    let arr = PyArray::zeros(py.python(),
                             &[n, m],
                             NPY_TYPES::NPY_DOUBLE,
                             NPY_ORDER::NPY_CORDER);
    assert!(arr.ndim() == 2);
    assert!(arr.dims() == [n, m]);
    assert!(arr.strides() == [m as isize * 8, 8]);

    let arr = PyArray::zeros(py.python(),
                             &[n, m],
                             NPY_TYPES::NPY_DOUBLE,
                             NPY_ORDER::NPY_FORTRANORDER);
    assert!(arr.ndim() == 2);
    assert!(arr.dims() == [n, m]);
    assert!(arr.strides() == [8, n as isize * 8]);
}

#[test]
fn arange() {
    let gil = cpython::Python::acquire_gil();
    let arr = PyArray::arange(gil.python(), 0.0, 1.0, 0.1, NPY_TYPES::NPY_DOUBLE);
    println!("ndim = {:?}", arr.ndim());
    println!("dims = {:?}", arr.dims());
    println!("array = {:?}", arr.as_slice::<f64>());
}
<commit_msg>Add test of new<commit_after>
extern crate cpython;
extern crate numpy;

use numpy::*;

#[test]
fn new() {
    let gil = cpython::Python::acquire_gil();
    let n = 3;
    let m = 5;
    let arr = PyArray::new(gil.python(), &[n, m], NPY_TYPES::NPY_DOUBLE);
    assert!(arr.ndim() == 2);
    assert!(arr.dims() == [n, m]);
    assert!(arr.strides() == [m as isize * 8, 8]);
}

#[test]
fn zeros() {
    let gil = cpython::Python::acquire_gil();
    let n = 3;
    let m = 5;
    let arr = PyArray::zeros(gil.python(),
                             &[n, m],
                             NPY_TYPES::NPY_DOUBLE,
                             NPY_ORDER::NPY_CORDER);
    assert!(arr.ndim() == 2);
    assert!(arr.dims() == [n, m]);
    assert!(arr.strides() == [m as isize * 8, 8]);

    let arr = PyArray::zeros(gil.python(),
                             &[n, m],
                             NPY_TYPES::NPY_DOUBLE,
                             NPY_ORDER::NPY_FORTRANORDER);
    assert!(arr.ndim() == 2);
    assert!(arr.dims() == [n, m]);
    assert!(arr.strides() == [8, n as isize * 8]);
}

#[test]
fn arange() {
    let gil = cpython::Python::acquire_gil();
    let arr = PyArray::arange(gil.python(), 0.0, 1.0, 0.1, NPY_TYPES::NPY_DOUBLE);
    println!("ndim = {:?}", arr.ndim());
    println!("dims = {:?}", arr.dims());
    println!("array = {:?}", arr.as_slice::<f64>());
}
<|endoftext|>


<commit_before>extern crate ucd_raw;

use std::fs::File;
use std::io::Write;
use std::time::Instant;
use ucd_raw::CHARACTERS;

#[derive(Debug)]
struct Entry {
    index: usize,
    codepoint: u32,
}

#[derive(Debug)]
struct TempSuffix<'a> {
    suffix: &'a str,
    entry: Entry,
}

fn suffixes<'a>(string: &'a str) -> impl Iterator<Item = (usize, &'a str)> {
    (0..string.len()).map(move |i| &string[i..]).enumerate()
}

fn main() {
    let start = Instant::now();

    let mut combined = Vec::new();
    let mut temp_suffixes = Vec::new();

    let mut out = File::create("src/generated.rs").unwrap();

    for character in CHARACTERS.iter() {
        let start = combined.len();

        for byte in character.name.bytes() {
            combined.push(byte);
        }
        combined.push(b'\n');

        for (offset, suffix) in suffixes(character.name) {
            temp_suffixes.push(TempSuffix {
                suffix,
                entry: Entry {
                    index: start + offset,
                    codepoint: character.codepoint,
                },
            });
        }
    }

    temp_suffixes.sort_by_key(|temp_suffix| temp_suffix.suffix);

    writeln!(out, "use table::Entry;").unwrap();

    writeln!(
        out,
        "pub const ENTRIES: &[Entry] = &{:#?};",
        temp_suffixes
            .into_iter()
            .map(|temp_suffix| temp_suffix.entry)
            .collect::<Vec<_>>()
    ).unwrap();

    writeln!(
        out,
        "pub static COMBINED: &[u8] = b\"{}\";",
        String::from_utf8(combined).unwrap()
    ).unwrap();

    println!("Generated in {:?}", start.elapsed());
}
<commit_msg>filter out unified CJK characters<commit_after>extern crate ucd_raw;

use std::fs::File;
use std::io::Write;
use std::time::Instant;
use ucd_raw::Character;
use ucd_raw::CHARACTERS;

#[derive(Debug)]
struct Entry {
    index: usize,
    codepoint: u32,
}

#[derive(Debug)]
struct TempSuffix<'a> {
    suffix: &'a str,
    entry: Entry,
}

fn suffixes<'a>(string: &'a str) -> impl Iterator<Item = (usize, &'a str)> {
    (0..string.len()).map(move |i| &string[i..]).enumerate()
}

fn main() {
    let start = Instant::now();

    let mut combined = Vec::new();
    let mut temp_suffixes = Vec::new();

    let mut out = File::create("src/generated.rs").unwrap();

    for character in char_iter() {
        let start = combined.len();

        for byte in character.name.bytes() {
            combined.push(byte);
        }
        combined.push(b'\n');

        for (offset, suffix) in suffixes(character.name) {
            temp_suffixes.push(TempSuffix {
                suffix,
                entry: Entry {
                    index: start + offset,
                    codepoint: character.codepoint,
                },
            });
        }
    }

    temp_suffixes.sort_by_key(|temp_suffix| temp_suffix.suffix);

    writeln!(out, "use table::Entry;").unwrap();

    writeln!(
        out,
        "pub const ENTRIES: &[Entry] = &{:#?};",
        temp_suffixes
            .into_iter()
            .map(|temp_suffix| temp_suffix.entry)
            .collect::<Vec<_>>()
    ).unwrap();

    writeln!(
        out,
        "pub static COMBINED: &[u8] = b\"{}\";",
        String::from_utf8(combined).unwrap()
    ).unwrap();

    println!("Generated in {:?}", start.elapsed());
}

fn char_iter() -> impl Iterator<Item = &'static Character> {
    CHARACTERS
        .iter()
        .filter(|character| match character.codepoint {
            0x03400...0x04DB5 => false,
            0x04E00...0x09FEA => false,
            0x20000...0x2A6D6 => false,
            0x2A700...0x2B734 => false,
            0x2B740...0x2B81D => false,
            0x2B820...0x2CEA1 => false,
            0x2CEB0...0x2EBE0 => false,
            0x17000...0x187EC => false,
            0x1B170...0x1B2FB => false,
            0x0F900...0x0FA6D => false,
            0x0FA70...0x0FAD9 => false,
            0x2F800...0x2FA1D => false,
            _ => true,
        })
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! version management

use std::str::FromStr;

use super::ContractCallExt;
use contracts::tools::method as method_tools;
use libexecutor::executor::Executor;

use cita_types::Address;
use cita_types::H256;
use ethabi::{decode, ParamType};
use types::ids::BlockId;
use types::reserved_addresses;

lazy_static! {
    static ref VERSION_HASH: Vec<u8> = method_tools::encode_to_vec(b"getVersion()");
    static ref CONTRACT_ADDRESS: Address =
        Address::from_str(reserved_addresses::VERSION_MANAGEMENT).unwrap();
}

pub struct VersionManager<'a> {
    executor: &'a Executor,
}

impl<'a> VersionManager<'a> {
    pub fn new(executor: &'a Executor) -> Self {
        VersionManager { executor }
    }

    pub fn get_version(&self, block_id: BlockId) -> Option<u32> {
        self.executor
            .call_method(
                &*CONTRACT_ADDRESS,
                &*VERSION_HASH.as_slice(),
                None,
                block_id,
            )
            .and_then(|output| {
                decode(&[ParamType::Uint(64)], &output)
                    .map_err(|_| "decode value error".to_string())
            })
            .ok()
            .and_then(|mut x| x.remove(0).to_uint())
            .map(|x| H256::from(x).low_u64() as u32)
    }

    pub fn default_version() -> u32 {
        error!("Use default emergency break state.");
        0
    }
}
<commit_msg>:pencil: Fix wrong log.<commit_after>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! version management

use std::str::FromStr;

use super::ContractCallExt;
use contracts::tools::method as method_tools;
use libexecutor::executor::Executor;

use cita_types::Address;
use cita_types::H256;
use ethabi::{decode, ParamType};
use types::ids::BlockId;
use types::reserved_addresses;

lazy_static! {
    static ref VERSION_HASH: Vec<u8> = method_tools::encode_to_vec(b"getVersion()");
    static ref CONTRACT_ADDRESS: Address =
        Address::from_str(reserved_addresses::VERSION_MANAGEMENT).unwrap();
}

pub struct VersionManager<'a> {
    executor: &'a Executor,
}

impl<'a> VersionManager<'a> {
    pub fn new(executor: &'a Executor) -> Self {
        VersionManager { executor }
    }

    pub fn get_version(&self, block_id: BlockId) -> Option<u32> {
        self.executor
            .call_method(
                &*CONTRACT_ADDRESS,
                &*VERSION_HASH.as_slice(),
                None,
                block_id,
            )
            .and_then(|output| {
                decode(&[ParamType::Uint(64)], &output)
                    .map_err(|_| "decode value error".to_string())
            })
            .ok()
            .and_then(|mut x| x.remove(0).to_uint())
            .map(|x| H256::from(x).low_u64() as u32)
    }

    pub fn default_version() -> u32 {
        error!("Use default version.");
        0
    }
}
<|endoftext|>


<commit_before>//! `GET /_matrix/media/*/download/{serverName}/{mediaId}/{fileName}`

pub mod v3 {
    //! `/v3/` ([spec])
    //!
    //! [spec]: https://spec.matrix.org/v1.2/client-server-api/#get_matrixmediav3downloadservernamemediaidfilename

    use ruma_common::api::ruma_api;
    use ruma_identifiers::{Error, MxcUri, ServerName};

    ruma_api! {
        metadata: {
            description: "Retrieve content from the media store, specifying a filename to return.",
            method: GET,
            name: "get_media_content_as_filename",
            r0_path: "/_matrix/media/r0/download/:server_name/:media_id/:filename",
            stable_path: "/_matrix/media/v3/download/:server_name/:media_id/:filename",
            rate_limited: false,
            authentication: None,
            added: 1.0,
        }

        request: {
            /// The media ID from the mxc:// URI (the path component).
            #[ruma_api(path)]
            pub media_id: &'a str,

            /// The server name from the mxc:// URI (the authoritory component).
            #[ruma_api(path)]
            pub server_name: &'a ServerName,

            /// The filename to return in the `Content-Disposition` header.
            #[ruma_api(path)]
            pub filename: &'a str,

            /// Whether to fetch media deemed remote.
            ///
            /// Used to prevent routing loops. Defaults to `true`.
            #[ruma_api(query)]
            #[serde(default = "ruma_serde::default_true", skip_serializing_if = "ruma_serde::is_true")]
            pub allow_remote: bool,
        }

        response: {
            /// The content that was previously uploaded.
            #[ruma_api(raw_body)]
            pub file: Vec<u8>,

            /// The content type of the file that was previously uploaded.
            #[ruma_api(header = CONTENT_TYPE)]
            // Potentially not actually optional – https://github.com/matrix-org/matrix-spec-proposals/pull/2818
            pub content_type: Option<String>,

            /// The value of the `Content-Disposition` HTTP header, possibly containing the name of the
            /// file that was previously uploaded.
            ///
            /// See [MDN] for the syntax.
            ///
            /// [MDN]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#Syntax
            #[ruma_api(header = CONTENT_DISPOSITION)]
            pub content_disposition: Option<String>,
        }

        error: crate::Error
    }

    impl<'a> Request<'a> {
        /// Creates a new `Request` with the given media ID, server name and filename.
        pub fn new(media_id: &'a str, server_name: &'a ServerName, filename: &'a str) -> Self {
            Self { media_id, server_name, filename, allow_remote: true }
        }

        /// Creates a new `Request` with the given url and filename.
        pub fn from_url(url: &'a MxcUri, filename: &'a str) -> Result<Self, Error> {
            let (server_name, media_id) = url.parts()?;

            Ok(Self { media_id, server_name, filename, allow_remote: true })
        }
    }

    impl Response {
        /// Creates a new `Response` with the given file.
        pub fn new(file: Vec<u8>) -> Self {
            Self { file, content_type: None, content_disposition: None }
        }
    }
}
<commit_msg>client-api: Remove outdated comment<commit_after>//! `GET /_matrix/media/*/download/{serverName}/{mediaId}/{fileName}`

pub mod v3 {
    //! `/v3/` ([spec])
    //!
    //! [spec]: https://spec.matrix.org/v1.2/client-server-api/#get_matrixmediav3downloadservernamemediaidfilename

    use ruma_common::api::ruma_api;
    use ruma_identifiers::{Error, MxcUri, ServerName};

    ruma_api! {
        metadata: {
            description: "Retrieve content from the media store, specifying a filename to return.",
            method: GET,
            name: "get_media_content_as_filename",
            r0_path: "/_matrix/media/r0/download/:server_name/:media_id/:filename",
            stable_path: "/_matrix/media/v3/download/:server_name/:media_id/:filename",
            rate_limited: false,
            authentication: None,
            added: 1.0,
        }

        request: {
            /// The media ID from the mxc:// URI (the path component).
            #[ruma_api(path)]
            pub media_id: &'a str,

            /// The server name from the mxc:// URI (the authoritory component).
            #[ruma_api(path)]
            pub server_name: &'a ServerName,

            /// The filename to return in the `Content-Disposition` header.
            #[ruma_api(path)]
            pub filename: &'a str,

            /// Whether to fetch media deemed remote.
            ///
            /// Used to prevent routing loops. Defaults to `true`.
            #[ruma_api(query)]
            #[serde(default = "ruma_serde::default_true", skip_serializing_if = "ruma_serde::is_true")]
            pub allow_remote: bool,
        }

        response: {
            /// The content that was previously uploaded.
            #[ruma_api(raw_body)]
            pub file: Vec<u8>,

            /// The content type of the file that was previously uploaded.
            #[ruma_api(header = CONTENT_TYPE)]
            pub content_type: Option<String>,

            /// The value of the `Content-Disposition` HTTP header, possibly containing the name of the
            /// file that was previously uploaded.
            ///
            /// See [MDN] for the syntax.
            ///
            /// [MDN]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#Syntax
            #[ruma_api(header = CONTENT_DISPOSITION)]
            pub content_disposition: Option<String>,
        }

        error: crate::Error
    }

    impl<'a> Request<'a> {
        /// Creates a new `Request` with the given media ID, server name and filename.
        pub fn new(media_id: &'a str, server_name: &'a ServerName, filename: &'a str) -> Self {
            Self { media_id, server_name, filename, allow_remote: true }
        }

        /// Creates a new `Request` with the given url and filename.
        pub fn from_url(url: &'a MxcUri, filename: &'a str) -> Result<Self, Error> {
            let (server_name, media_id) = url.parts()?;

            Ok(Self { media_id, server_name, filename, allow_remote: true })
        }
    }

    impl Response {
        /// Creates a new `Response` with the given file.
        pub fn new(file: Vec<u8>) -> Self {
            Self { file, content_type: None, content_disposition: None }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::{
    collections::{HashMap, HashSet},
    sync::{atomic::AtomicI8, atomic::Ordering, Arc, RwLock},
};

use common::{PerfLogEvent, PerfLogger};
use crossbeam::Sender;
use graphql_ir::Program;
use interner::StringKey;
use log::debug;
use lsp_server::Message;
use relay_compiler::{
    compiler::Compiler, compiler_state::CompilerState, config::Config, errors::BuildProjectError,
    FileSource, FileSourceResult, FileSourceSubscription, FileSourceSubscriptionNextChange,
};
use schema::SDLSchema;
use tokio::{sync::Notify, task, task::JoinHandle};

use crate::{
    lsp::set_initializing_status,
    lsp_process_error::{LSPProcessError, LSPProcessResult},
};

#[derive(Clone, Default)]
/// This structure is representing the state of the current source control update
/// Watchman subscription will trigger updates here
struct SourceControlUpdateStatus {
    // default - no updates
    // 1 - update started
    // 2 - update completed
    value: Arc<AtomicI8>,
}

impl SourceControlUpdateStatus {
    fn mark_as_started(&self) {
        debug!("SourceControlUpdateStatus: source control update started!");
        self.value.store(1, Ordering::Relaxed);
    }
    fn is_started(&self) -> bool {
        self.value.load(Ordering::Relaxed) == 1
    }
    fn mark_as_completed(&self) {
        debug!("SourceControlUpdateStatus: source control update completed!");
        self.value.store(2, Ordering::Relaxed);
    }
    fn is_completed(&self) -> bool {
        self.value.load(Ordering::Relaxed) == 2
    }
}

/// This structure is responsible for keeping schemas/programs in sync with the current state of the world
pub(crate) struct LSPStateResources<TPerfLogger: PerfLogger + 'static> {
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
    schemas: Arc<RwLock<HashMap<StringKey, Arc<SDLSchema>>>>,
    source_programs: Arc<RwLock<HashMap<StringKey, Program>>>,
    compiler: Compiler<TPerfLogger>,
    errors: Arc<RwLock<Vec<String>>>,
    source_code_update_status: SourceControlUpdateStatus,
    notify_sender: Arc<Notify>,
    notify_receiver: Arc<Notify>,
    sender: Sender<Message>,
}

impl<TPerfLogger: PerfLogger + 'static> LSPStateResources<TPerfLogger> {
    pub(crate) fn new(
        config: Arc<Config>,
        perf_logger: Arc<TPerfLogger>,
        schemas: Arc<RwLock<HashMap<StringKey, Arc<SDLSchema>>>>,
        source_programs: Arc<RwLock<HashMap<StringKey, Program>>>,
        sender: Sender<Message>,
    ) -> Self {
        let compiler = Compiler::new(Arc::clone(&config), Arc::clone(&perf_logger));
        let notify_sender = Arc::new(Notify::new());
        let notify_receiver = notify_sender.clone();
        Self {
            config,
            perf_logger,
            schemas,
            source_programs,
            compiler,
            errors: Default::default(),
            sender,
            source_code_update_status: Default::default(),
            notify_sender,
            notify_receiver,
        }
    }

    /// Create an end-less loop of keeping the resources up-to-date with the source control changes
    pub(crate) async fn watch(&self) -> LSPProcessResult<()> {
        'outer: loop {
            set_initializing_status(&self.sender);

            let setup_event = self
                .perf_logger
                .create_event("lsp_state_initialize_resources");

            let file_source = FileSource::connect(&self.config, &setup_event)
                .await
                .map_err(LSPProcessError::CompilerError)?;
            let (mut compiler_state, file_source_subscription) = file_source
                .subscribe(&setup_event, self.perf_logger.as_ref())
                .await
                .map_err(LSPProcessError::CompilerError)?;

            let pending_file_source_changes =
                Arc::clone(&compiler_state.pending_file_source_changes);

            // Start a separate task to receive watchman subscription updates
            // this process will notify, when the change is detected.
            // If watchman detects the source control update, it will update the state
            // of the source_control_update_status, so we can cancel building schemas/
            // and programs earlier
            let subscription_handle = self.watchman_subscription_handler(
                file_source_subscription,
                pending_file_source_changes,
            );

            // Run initial build, before entering the watch changes loop
            self.initial_build(&compiler_state, &setup_event)?;
            compiler_state.complete_compilation();
            self.perf_logger.complete_event(setup_event);

            self.log_errors("lsp_state_error");
            self.clear_errors();

            // Here we will wait for changes from watchman
            'inner: loop {
                self.notify_receiver.notified().await;

                // Source control update started, we can ignore all pending changes, and wait for it to complete,
                // we may change the status bar to `Source Control Update...`
                if self.source_code_update_status.is_started() {
                    break 'inner;
                }

                // SC Update completed, we need to abort current subscription, and re-initialize resource for LSP
                if self.source_code_update_status.is_completed() {
                    debug!("Watchman indicated the the source control update has completed!");
                    subscription_handle.abort();
                    continue 'outer;
                }

                let log_event = self.perf_logger.create_event("lsp_state_watchman_event");
                let log_time = log_event.start("lsp_state_watchman_event_time");

                let has_new_changes = compiler_state
                    .merge_file_source_changes(
                        &self.config,
                        &log_event,
                        self.perf_logger.as_ref(),
                        false,
                    )
                    .unwrap();

                // If changes contains schema files we need to rebuild schemas
                if has_new_changes {
                    if compiler_state.has_schema_changes() {
                        self.build_schemas(&compiler_state, &log_event)?;
                    }

                    self.build_source_programs(
                        &compiler_state,
                        Some(self.get_affected_projects(&compiler_state)),
                        &log_event,
                    )?;

                    compiler_state.complete_compilation();

                    self.log_errors("lsp_state_user_error");
                    self.clear_errors();
                }

                log_event.stop(log_time);
                self.perf_logger.complete_event(log_event);
                self.perf_logger.flush();
            }
        }
    }

    fn initial_build(
        &self,
        compiler_state: &CompilerState,
        log_event: &impl PerfLogEvent,
    ) -> LSPProcessResult<()> {
        debug!("Initial build started...");
        // TODO: (from https://fburl.com/diff/m8jg14sy) - pass source code update status to
        // `compiler.build_schemas` and `compiler.build_source_programs` to cancel build earlier,
        // if update detected
        self.build_schemas(compiler_state, log_event)?;
        self.build_source_programs(compiler_state, None, log_event)?;

        Ok(())
    }

    fn build_schemas(
        &self,
        compiler_state: &CompilerState,
        log_event: &impl PerfLogEvent,
    ) -> LSPProcessResult<()> {
        debug!("Building schemas");

        // Stop building programs if we detect source code update
        if self.source_code_update_status.is_started() {
            return Ok(());
        }

        let (next_schemas, build_errors) = self.compiler.build_schemas(&compiler_state, log_event);
        self.schemas
            .write()
            .expect("LSPState::watch_and_update_schemas: expect to acquire write lock on schemas")
            .clone_from(&next_schemas);

        if !build_errors.is_empty() {
            self.write_errors(vec![BuildProjectError::ValidationErrors {
                errors: build_errors,
            }]);
        }

        Ok(())
    }

    fn build_source_programs(
        &self,
        compiler_state: &CompilerState,
        affected_projects: Option<HashSet<&StringKey>>,
        log_event: &impl PerfLogEvent,
    ) -> LSPProcessResult<()> {
        debug!("Building source programs");

        // Stop building programs if we detect source code update
        if self.source_code_update_status.is_started() {
            return Ok(());
        }

        // This will build programs, but won't apply any transformations to them
        // that should be enough for LSP to start showing fragments information
        let (programs, build_errors) = self.compiler.build_raw_programs(
            compiler_state,
            &self
                .schemas
                .read()
                .expect("LSPState::build_in_watch_mode: expect to acquire read lock on schemas"),
            affected_projects,
            log_event,
        )?;

        if !build_errors.is_empty() {
            self.write_errors(build_errors);
        }

        let mut source_programs_write_lock = self.source_programs.write().expect(
            "LSPState::build_in_watch_mode: expect to acquire write lock on source_programs",
        );

        for (program_name, program) in programs {
            // NOTE: Currently, we rely on the fact that `build_raw_programs`
            // will always return a full program, so we can safely replace it in the current
            // list of source_programs
            source_programs_write_lock.insert(program_name, program);
        }

        Ok(())
    }

    fn watchman_subscription_handler(
        &self,
        mut file_source_subscription: FileSourceSubscription,
        pending_file_source_changes: Arc<RwLock<Vec<FileSourceResult>>>,
    ) -> JoinHandle<()> {
        let source_code_update_status = self.source_code_update_status.clone();
        let notify_sender = self.notify_sender.clone();
        task::spawn(async move {
            loop {
                match file_source_subscription.next_change().await {
                    Err(_) => {
                        // do nothing? compiler should panic, and restart the lsp
                    }
                    Ok(FileSourceSubscriptionNextChange::None) => {}
                    Ok(FileSourceSubscriptionNextChange::SourceControlUpdateEnter) => {
                        source_code_update_status.mark_as_started();
                        notify_sender.notify_one();
                    }
                    Ok(FileSourceSubscriptionNextChange::SourceControlUpdateLeave) => {
                        source_code_update_status.mark_as_completed();
                        notify_sender.notify_one();
                    }
                    Ok(FileSourceSubscriptionNextChange::Result(file_source_changes)) => {
                        pending_file_source_changes
                            .write()
                            .expect("LSPState::watch_and_update_schemas: expect to acquire write lock on pending_file_source_changes")
                            .push(file_source_changes);

                        notify_sender.notify_one();
                    }
                }
            }
        })
    }

    fn get_affected_projects(&self, compiler_state: &CompilerState) -> HashSet<&StringKey> {
        self.config
            .projects
            .keys()
            .filter(|project_name| compiler_state.project_has_pending_changes(**project_name))
            .collect::<HashSet<_>>()
    }

    fn write_errors(&self, errors: Vec<BuildProjectError>) {
        let mut write_lock = self.errors.write().unwrap();
        for error in errors {
            write_lock.push(error.to_string());
        }
    }

    fn log_errors(&self, log_event_name: &str) {
        if let Ok(read_lock) = self.errors.try_read() {
            if !read_lock.is_empty() {
                let error_message = read_lock
                    .iter()
                    .map(|err| format!("{:?}", err))
                    .collect::<Vec<String>>()
                    .join("\n");
                let error_event = self.perf_logger.create_event(log_event_name);
                error_event.string("error", error_message);
                self.perf_logger.complete_event(error_event);
                self.perf_logger.flush();
            }
        }
    }

    fn clear_errors(&self) {
        if let Ok(mut write_lock) = self.errors.try_write() {
            write_lock.clear();
        }
    }
}
<commit_msg>Update status bar messaging<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::{
    collections::{HashMap, HashSet},
    sync::{atomic::AtomicI8, atomic::Ordering, Arc, RwLock},
};

use common::{PerfLogEvent, PerfLogger};
use crossbeam::Sender;
use graphql_ir::Program;
use interner::StringKey;
use log::{debug, info};
use lsp_server::Message;
use relay_compiler::{
    compiler::Compiler, compiler_state::CompilerState, config::Config, errors::BuildProjectError,
    FileSource, FileSourceResult, FileSourceSubscription, FileSourceSubscriptionNextChange,
};
use schema::SDLSchema;
use tokio::{sync::Notify, task, task::JoinHandle};

use crate::{
    lsp::set_ready_status,
    lsp::update_in_progress_status,
    lsp_process_error::{LSPProcessError, LSPProcessResult},
};

#[derive(Clone, Default)]
/// This structure is representing the state of the current source control update
/// Watchman subscription will trigger updates here
struct SourceControlUpdateStatus {
    // default - no updates
    // 1 - update started
    // 2 - update completed
    value: Arc<AtomicI8>,
}

impl SourceControlUpdateStatus {
    fn mark_as_started(&self) {
        debug!("SourceControlUpdateStatus: source control update started!");
        self.value.store(1, Ordering::Relaxed);
    }
    fn is_started(&self) -> bool {
        self.value.load(Ordering::Relaxed) == 1
    }
    fn mark_as_completed(&self) {
        debug!("SourceControlUpdateStatus: source control update completed!");
        self.value.store(2, Ordering::Relaxed);
    }
    fn is_completed(&self) -> bool {
        self.value.load(Ordering::Relaxed) == 2
    }
}

/// This structure is responsible for keeping schemas/programs in sync with the current state of the world
pub(crate) struct LSPStateResources<TPerfLogger: PerfLogger + 'static> {
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
    schemas: Arc<RwLock<HashMap<StringKey, Arc<SDLSchema>>>>,
    source_programs: Arc<RwLock<HashMap<StringKey, Program>>>,
    compiler: Compiler<TPerfLogger>,
    errors: Arc<RwLock<Vec<String>>>,
    source_code_update_status: SourceControlUpdateStatus,
    notify_sender: Arc<Notify>,
    notify_receiver: Arc<Notify>,
    sender: Sender<Message>,
}

impl<TPerfLogger: PerfLogger + 'static> LSPStateResources<TPerfLogger> {
    pub(crate) fn new(
        config: Arc<Config>,
        perf_logger: Arc<TPerfLogger>,
        schemas: Arc<RwLock<HashMap<StringKey, Arc<SDLSchema>>>>,
        source_programs: Arc<RwLock<HashMap<StringKey, Program>>>,
        sender: Sender<Message>,
    ) -> Self {
        let compiler = Compiler::new(Arc::clone(&config), Arc::clone(&perf_logger));
        let notify_sender = Arc::new(Notify::new());
        let notify_receiver = notify_sender.clone();
        Self {
            config,
            perf_logger,
            schemas,
            source_programs,
            compiler,
            errors: Default::default(),
            sender,
            source_code_update_status: Default::default(),
            notify_sender,
            notify_receiver,
        }
    }

    /// Create an end-less loop of keeping the resources up-to-date with the source control changes
    pub(crate) async fn watch(&self) -> LSPProcessResult<()> {
        'outer: loop {
            info!("Initializing resources for LSP server");

            update_in_progress_status(
                "Relay: watchman...",
                Some("Sending watchman query to get source files and possible saved state"),
                &self.sender,
            );
            let setup_event = self
                .perf_logger
                .create_event("lsp_state_initialize_resources");

            let file_source = FileSource::connect(&self.config, &setup_event)
                .await
                .map_err(LSPProcessError::CompilerError)?;
            let (mut compiler_state, file_source_subscription) = file_source
                .subscribe(&setup_event, self.perf_logger.as_ref())
                .await
                .map_err(LSPProcessError::CompilerError)?;

            let pending_file_source_changes =
                Arc::clone(&compiler_state.pending_file_source_changes);

            // Start a separate task to receive watchman subscription updates
            // this process will notify, when the change is detected.
            // If watchman detects the source control update, it will update the state
            // of the source_control_update_status, so we can cancel building schemas/
            // and programs earlier
            let subscription_handle = self.watchman_subscription_handler(
                file_source_subscription,
                pending_file_source_changes,
            );
            update_in_progress_status(
                "Relay: creating state...",
                Some("Building schemas and source programs for LSP"),
                &self.sender,
            );

            // Run initial build, before entering the watch changes loop
            self.initial_build(&compiler_state, &setup_event)?;
            compiler_state.complete_compilation();
            self.perf_logger.complete_event(setup_event);

            self.log_errors("lsp_state_error");
            self.clear_errors();

            info!("LSP server initialization completed!");

            set_ready_status(&self.sender);

            // Here we will wait for changes from watchman
            'inner: loop {
                self.notify_receiver.notified().await;

                // Source control update started, we can ignore all pending changes, and wait for it to complete,
                // we may change the status bar to `Source Control Update...`
                if self.source_code_update_status.is_started() {
                    update_in_progress_status(
                        "Relay: hg update...",
                        Some("Waiting for source control update"),
                        &self.sender,
                    );
                    break 'inner;
                }

                // SC Update completed, we need to abort current subscription, and re-initialize resource for LSP
                if self.source_code_update_status.is_completed() {
                    debug!("Watchman indicated the the source control update has completed!");
                    subscription_handle.abort();
                    continue 'outer;
                }

                let log_event = self.perf_logger.create_event("lsp_state_watchman_event");
                let log_time = log_event.start("lsp_state_watchman_event_time");

                let has_new_changes = compiler_state
                    .merge_file_source_changes(
                        &self.config,
                        &log_event,
                        self.perf_logger.as_ref(),
                        false,
                    )
                    .unwrap();

                // If changes contains schema files we need to rebuild schemas
                if has_new_changes {
                    update_in_progress_status(
                        "Relay: updating state...",
                        Some("Updating source programs with the latest changes."),
                        &self.sender,
                    );

                    if compiler_state.has_schema_changes() {
                        self.build_schemas(&compiler_state, &log_event)?;
                    }

                    self.build_source_programs(
                        &compiler_state,
                        Some(self.get_affected_projects(&compiler_state)),
                        &log_event,
                    )?;

                    compiler_state.complete_compilation();

                    self.log_errors("lsp_state_user_error");
                    self.clear_errors();

                    set_ready_status(&self.sender);
                }

                log_event.stop(log_time);
                self.perf_logger.complete_event(log_event);
                self.perf_logger.flush();
            }
        }
    }

    fn initial_build(
        &self,
        compiler_state: &CompilerState,
        log_event: &impl PerfLogEvent,
    ) -> LSPProcessResult<()> {
        debug!("Initial build started...");
        // TODO: (from https://fburl.com/diff/m8jg14sy) - pass source code update status to
        // `compiler.build_schemas` and `compiler.build_source_programs` to cancel build earlier,
        // if update detected
        self.build_schemas(compiler_state, log_event)?;
        self.build_source_programs(compiler_state, None, log_event)?;

        Ok(())
    }

    fn build_schemas(
        &self,
        compiler_state: &CompilerState,
        log_event: &impl PerfLogEvent,
    ) -> LSPProcessResult<()> {
        debug!("Building schemas");

        // Stop building programs if we detect source code update
        if self.source_code_update_status.is_started() {
            return Ok(());
        }

        let (next_schemas, build_errors) = self.compiler.build_schemas(&compiler_state, log_event);
        self.schemas
            .write()
            .expect("LSPState::watch_and_update_schemas: expect to acquire write lock on schemas")
            .clone_from(&next_schemas);

        if !build_errors.is_empty() {
            self.write_errors(vec![BuildProjectError::ValidationErrors {
                errors: build_errors,
            }]);
        }

        Ok(())
    }

    fn build_source_programs(
        &self,
        compiler_state: &CompilerState,
        affected_projects: Option<HashSet<&StringKey>>,
        log_event: &impl PerfLogEvent,
    ) -> LSPProcessResult<()> {
        debug!("Building source programs");

        // Stop building programs if we detect source code update
        if self.source_code_update_status.is_started() {
            return Ok(());
        }

        // This will build programs, but won't apply any transformations to them
        // that should be enough for LSP to start showing fragments information
        let (programs, build_errors) = self.compiler.build_raw_programs(
            compiler_state,
            &self
                .schemas
                .read()
                .expect("LSPState::build_in_watch_mode: expect to acquire read lock on schemas"),
            affected_projects,
            log_event,
        )?;

        if !build_errors.is_empty() {
            self.write_errors(build_errors);
        }

        let mut source_programs_write_lock = self.source_programs.write().expect(
            "LSPState::build_in_watch_mode: expect to acquire write lock on source_programs",
        );

        for (program_name, program) in programs {
            // NOTE: Currently, we rely on the fact that `build_raw_programs`
            // will always return a full program, so we can safely replace it in the current
            // list of source_programs
            source_programs_write_lock.insert(program_name, program);
        }

        Ok(())
    }

    fn watchman_subscription_handler(
        &self,
        mut file_source_subscription: FileSourceSubscription,
        pending_file_source_changes: Arc<RwLock<Vec<FileSourceResult>>>,
    ) -> JoinHandle<()> {
        let source_code_update_status = self.source_code_update_status.clone();
        let notify_sender = self.notify_sender.clone();
        task::spawn(async move {
            loop {
                match file_source_subscription.next_change().await {
                    Err(_) => {
                        // do nothing? compiler should panic, and restart the lsp
                    }
                    Ok(FileSourceSubscriptionNextChange::None) => {}
                    Ok(FileSourceSubscriptionNextChange::SourceControlUpdateEnter) => {
                        source_code_update_status.mark_as_started();
                        notify_sender.notify_one();
                    }
                    Ok(FileSourceSubscriptionNextChange::SourceControlUpdateLeave) => {
                        source_code_update_status.mark_as_completed();
                        notify_sender.notify_one();
                    }
                    Ok(FileSourceSubscriptionNextChange::Result(file_source_changes)) => {
                        pending_file_source_changes
                            .write()
                            .expect("LSPState::watch_and_update_schemas: expect to acquire write lock on pending_file_source_changes")
                            .push(file_source_changes);

                        notify_sender.notify_one();
                    }
                }
            }
        })
    }

    fn get_affected_projects(&self, compiler_state: &CompilerState) -> HashSet<&StringKey> {
        self.config
            .projects
            .keys()
            .filter(|project_name| compiler_state.project_has_pending_changes(**project_name))
            .collect::<HashSet<_>>()
    }

    fn write_errors(&self, errors: Vec<BuildProjectError>) {
        let mut write_lock = self.errors.write().unwrap();
        for error in errors {
            write_lock.push(error.to_string());
        }
    }

    fn log_errors(&self, log_event_name: &str) {
        if let Ok(read_lock) = self.errors.try_read() {
            if !read_lock.is_empty() {
                let error_message = read_lock
                    .iter()
                    .map(|err| format!("{:?}", err))
                    .collect::<Vec<String>>()
                    .join("\n");
                let error_event = self.perf_logger.create_event(log_event_name);
                error_event.string("error", error_message);
                self.perf_logger.complete_event(error_event);
                self.perf_logger.flush();
            }
        }
    }

    fn clear_errors(&self) {
        if let Ok(mut write_lock) = self.errors.try_write() {
            write_lock.clear();
        }
    }
}
<|endoftext|>


<commit_before>//! Create new `Streams` connected to external inputs.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::frontier::{MutableAntichain, Antichain};
use progress::{Operate, Timestamp};
use progress::nested::subgraph::Source;
use progress::count_map::CountMap;
use progress::timestamp::RootTimestamp;
use progress::nested::product::Product;

use timely_communication::Allocate;
use {Data, Push};
use dataflow::channels::Content;
use dataflow::channels::pushers::{Tee, Counter};

use dataflow::{Stream, Scope};
use dataflow::scopes::{Child, Root};

// TODO : This is an exogenous input, but it would be nice to wrap a Subgraph in something
// TODO : more like a harness, with direct access to its inputs.

// NOTE : This only takes a &self, not a &mut self, which works but is a bit weird.
// NOTE : Experiments with &mut indicate that the borrow of 'a lives for too long.
// NOTE : Might be able to fix with another lifetime parameter, say 'c: 'a.

/// Create a new `Stream` and `Handle` through which to supply input.
pub trait Input<A: Allocate, T: Timestamp+Ord> {
    /// Create a new `Stream` and `Handle` through which to supply input.
    ///
    /// The `new_input` method returns a pair `(Handle, Stream)` where the `Stream` can be used
    /// immediately for timely dataflow construction, and the `Handle` is later used to introduce
    /// data into the timely dataflow computation.
    ///
    /// The `Handle` also provides a means to indicate
    /// to timely dataflow that the input has advanced beyond certain timestamps, allowing timely
    /// to issue progress notifications.
    ///
    /// #Examples
    /// ```
    /// use timely::*;
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{Input, Inspect};
    ///
    /// // construct and execute a timely dataflow
    /// timely::execute(Configuration::Thread, |root| {
    ///
    ///     // add an input and base computation off of it
    ///     let mut input = root.scoped(|scope| {
    ///         let (input, stream) = scope.new_input();
    ///         stream.inspect(|x| println!("hello {:?}", x));
    ///         input
    ///     });
    ///
    ///     // introduce input, advance computation
    ///     for round in 0..10 {
    ///         input.send(round);
    ///         input.advance_to(round + 1);
    ///         root.step();
    ///     }
    /// });
    /// ```
    fn new_input<D:Data>(&mut self) -> (Handle<T, D>, Stream<Child<Root<A>, T>, D>);
}

impl<A: Allocate, T: Timestamp+Ord> Input<A, T> for Child<Root<A>, T> {
    fn new_input<D:Data>(&mut self) -> (Handle<T, D>, Stream<Child<Root<A>, T>, D>) {

        let (output, registrar) = Tee::<Product<RootTimestamp, T>, D>::new();
        let produced = Rc::new(RefCell::new(CountMap::new()));
        let helper = Handle::new(Counter::new(output, produced.clone()));
        let copies = self.peers();

        let index = self.add_operator(Operator {
            frontier: helper.frontier.clone(),
            progress: helper.progress.clone(),
            messages: produced.clone(),
            copies:   copies,
        });

        (helper, Stream::new(Source { index: index, port: 0 }, registrar, self.clone()))
    }
}

struct Operator<T:Timestamp+Ord> {
    frontier:   Rc<RefCell<MutableAntichain<Product<RootTimestamp, T>>>>,   // times available for sending
    progress:   Rc<RefCell<CountMap<Product<RootTimestamp, T>>>>,           // times closed since last asked
    messages:   Rc<RefCell<CountMap<Product<RootTimestamp, T>>>>,           // messages sent since last asked
    copies:     usize,
}

impl<T:Timestamp+Ord> Operate<Product<RootTimestamp, T>> for Operator<T> {
    fn name(&self) -> String { "Input".to_owned() }
    fn inputs(&self) -> usize { 0 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<<Product<RootTimestamp, T> as Timestamp>::Summary>>>,
                                           Vec<CountMap<Product<RootTimestamp, T>>>) {
        let mut map = CountMap::new();
        for x in self.frontier.borrow().elements().iter() {
            map.update(x, self.copies as i64);
        }
        (Vec::new(), vec![map])
    }

    fn pull_internal_progress(&mut self,_messages_consumed: &mut [CountMap<Product<RootTimestamp, T>>],
                                         frontier_progress: &mut [CountMap<Product<RootTimestamp, T>>],
                                         messages_produced: &mut [CountMap<Product<RootTimestamp, T>>]) -> bool
    {
        self.messages.borrow_mut().drain_into(&mut messages_produced[0]);
        self.progress.borrow_mut().drain_into(&mut frontier_progress[0]);
        false
    }

    fn notify_me(&self) -> bool { false }
}

/// A handle to an input `Stream`, used to introduce data to a timely dataflow computation.
pub struct Handle<T: Timestamp+Ord, D: Data> {
    frontier: Rc<RefCell<MutableAntichain<Product<RootTimestamp, T>>>>,   // times available for sending
    progress: Rc<RefCell<CountMap<Product<RootTimestamp, T>>>>,           // times closed since last asked
    pusher: Counter<Product<RootTimestamp, T>, D, Tee<Product<RootTimestamp, T>, D>>,
    buffer: Vec<D>,
    now_at: Product<RootTimestamp, T>,
}

// an input helper's state is either uninitialized, with now_at == None, or at some specific time.
// if now_at == None it has a hold on Default::default(), else it has a hold on the specific time.
// if now_at == None the pusher has not been opened, else it is open with the specific time.

impl<T:Timestamp+Ord, D: Data> Handle<T, D> {
    fn new(pusher: Counter<Product<RootTimestamp, T>, D, Tee<Product<RootTimestamp, T>, D>>) -> Handle<T, D> {
        Handle {
            frontier: Rc::new(RefCell::new(MutableAntichain::new_bottom(Default::default()))),
            progress: Rc::new(RefCell::new(CountMap::new())),
            pusher: pusher,
            buffer: Vec::with_capacity(Content::<D>::default_length()),
            now_at: Default::default(),
        }
    }

    // flushes any data we are sitting on. may need to initialize self.now_at if no one has yet.
    fn flush(&mut self) {
        Content::push_at(&mut self.buffer, self.now_at, &mut self.pusher);
    }

    // closes the current epoch, flushing if needed, shutting if needed, and updating the frontier.
    fn close_epoch(&mut self) {
        if !self.buffer.is_empty() { self.flush(); }
        self.pusher.done();
        self.frontier.borrow_mut().update_weight(&self.now_at, -1, &mut (*self.progress.borrow_mut()));
    }

    #[inline(always)]
    /// Sends one record into the corresponding timely dataflow `Stream`, at the current epoch.
    pub fn send(&mut self, data: D) {
        // assert!(self.buffer.capacity() == Content::<D>::default_length());
        self.buffer.push(data);
        if self.buffer.len() == self.buffer.capacity() {
            self.flush();
        }
    }

    /// Advances the current epoch to `next`.
    ///
    /// This method allows timely dataflow to issue progress notifications as it can now determine
    /// that this input can no longer produce data at earlier timestamps.
    pub fn advance_to(&mut self, next: T) {
        assert!(next > self.now_at.inner);
        self.close_epoch();
        self.now_at = RootTimestamp::new(next);
        self.frontier.borrow_mut().update_weight(&self.now_at,  1, &mut (*self.progress.borrow_mut()));
    }

    /// Closes the input.
    ///
    /// This method allows timely dataflow to issue all progress notifications blocked by this input
    /// and to begin to shut down operators, as this input can no longer produce data.
    pub fn close(self) { }

    /// Reports the current epoch.
    pub fn epoch(&self) -> &T {
        &self.now_at.inner
    }

    /// Reports the current timestamp.
    pub fn time(&self) -> &Product<RootTimestamp, T> {
        &self.now_at
    }
}

impl<T:Timestamp+Ord, D: Data> Drop for Handle<T, D> {
    fn drop(&mut self) {
        self.close_epoch();
    }
}
<commit_msg>removed frontier, which seemed to be unused<commit_after>//! Create new `Streams` connected to external inputs.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::frontier::{MutableAntichain, Antichain};
use progress::{Operate, Timestamp};
use progress::nested::subgraph::Source;
use progress::count_map::CountMap;
use progress::timestamp::RootTimestamp;
use progress::nested::product::Product;

use timely_communication::Allocate;
use {Data, Push};
use dataflow::channels::Content;
use dataflow::channels::pushers::{Tee, Counter};

use dataflow::{Stream, Scope};
use dataflow::scopes::{Child, Root};

// TODO : This is an exogenous input, but it would be nice to wrap a Subgraph in something
// TODO : more like a harness, with direct access to its inputs.

// NOTE : This only takes a &self, not a &mut self, which works but is a bit weird.
// NOTE : Experiments with &mut indicate that the borrow of 'a lives for too long.
// NOTE : Might be able to fix with another lifetime parameter, say 'c: 'a.

/// Create a new `Stream` and `Handle` through which to supply input.
pub trait Input<A: Allocate, T: Timestamp+Ord> {
    /// Create a new `Stream` and `Handle` through which to supply input.
    ///
    /// The `new_input` method returns a pair `(Handle, Stream)` where the `Stream` can be used
    /// immediately for timely dataflow construction, and the `Handle` is later used to introduce
    /// data into the timely dataflow computation.
    ///
    /// The `Handle` also provides a means to indicate
    /// to timely dataflow that the input has advanced beyond certain timestamps, allowing timely
    /// to issue progress notifications.
    ///
    /// #Examples
    /// ```
    /// use timely::*;
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{Input, Inspect};
    ///
    /// // construct and execute a timely dataflow
    /// timely::execute(Configuration::Thread, |root| {
    ///
    ///     // add an input and base computation off of it
    ///     let mut input = root.scoped(|scope| {
    ///         let (input, stream) = scope.new_input();
    ///         stream.inspect(|x| println!("hello {:?}", x));
    ///         input
    ///     });
    ///
    ///     // introduce input, advance computation
    ///     for round in 0..10 {
    ///         input.send(round);
    ///         input.advance_to(round + 1);
    ///         root.step();
    ///     }
    /// });
    /// ```
    fn new_input<D:Data>(&mut self) -> (Handle<T, D>, Stream<Child<Root<A>, T>, D>);
}

impl<A: Allocate, T: Timestamp+Ord> Input<A, T> for Child<Root<A>, T> {
    fn new_input<D:Data>(&mut self) -> (Handle<T, D>, Stream<Child<Root<A>, T>, D>) {

        let (output, registrar) = Tee::<Product<RootTimestamp, T>, D>::new();
        let produced = Rc::new(RefCell::new(CountMap::new()));
        let helper = Handle::new(Counter::new(output, produced.clone()));
        let copies = self.peers();

        let index = self.add_operator(Operator {
            progress: helper.progress.clone(),
            messages: produced.clone(),
            copies:   copies,
        });

        (helper, Stream::new(Source { index: index, port: 0 }, registrar, self.clone()))
    }
}

struct Operator<T:Timestamp+Ord> {
    progress:   Rc<RefCell<CountMap<Product<RootTimestamp, T>>>>,           // times closed since last asked
    messages:   Rc<RefCell<CountMap<Product<RootTimestamp, T>>>>,           // messages sent since last asked
    copies:     usize,
}

impl<T:Timestamp+Ord> Operate<Product<RootTimestamp, T>> for Operator<T> {
    fn name(&self) -> String { "Input".to_owned() }
    fn inputs(&self) -> usize { 0 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<<Product<RootTimestamp, T> as Timestamp>::Summary>>>,
                                           Vec<CountMap<Product<RootTimestamp, T>>>) {
        let mut map = CountMap::new();
        map.update(&Default::default(), self.copies as i64);
        (Vec::new(), vec![map])
    }

    fn pull_internal_progress(&mut self,_messages_consumed: &mut [CountMap<Product<RootTimestamp, T>>],
                                         frontier_progress: &mut [CountMap<Product<RootTimestamp, T>>],
                                         messages_produced: &mut [CountMap<Product<RootTimestamp, T>>]) -> bool
    {
        self.messages.borrow_mut().drain_into(&mut messages_produced[0]);
        self.progress.borrow_mut().drain_into(&mut frontier_progress[0]);
        false
    }

    fn notify_me(&self) -> bool { false }
}

/// A handle to an input `Stream`, used to introduce data to a timely dataflow computation.
pub struct Handle<T: Timestamp+Ord, D: Data> {
    // frontier: Rc<RefCell<MutableAntichain<Product<RootTimestamp, T>>>>,   // times available for sending
    progress: Rc<RefCell<CountMap<Product<RootTimestamp, T>>>>,           // times closed since last asked
    pusher: Counter<Product<RootTimestamp, T>, D, Tee<Product<RootTimestamp, T>, D>>,
    buffer: Vec<D>,
    now_at: Product<RootTimestamp, T>,
}

// an input helper's state is either uninitialized, with now_at == None, or at some specific time.
// if now_at == None it has a hold on Default::default(), else it has a hold on the specific time.
// if now_at == None the pusher has not been opened, else it is open with the specific time.

impl<T:Timestamp+Ord, D: Data> Handle<T, D> {
    fn new(pusher: Counter<Product<RootTimestamp, T>, D, Tee<Product<RootTimestamp, T>, D>>) -> Handle<T, D> {
        Handle {
            // frontier: Rc::new(RefCell::new(MutableAntichain::new_bottom(Default::default()))),
            progress: Rc::new(RefCell::new(CountMap::new())),
            pusher: pusher,
            buffer: Vec::with_capacity(Content::<D>::default_length()),
            now_at: Default::default(),
        }
    }

    // flushes any data we are sitting on. may need to initialize self.now_at if no one has yet.
    fn flush(&mut self) {
        Content::push_at(&mut self.buffer, self.now_at, &mut self.pusher);
    }

    // closes the current epoch, flushing if needed, shutting if needed, and updating the frontier.
    fn close_epoch(&mut self) {
        if !self.buffer.is_empty() { self.flush(); }
        self.pusher.done();
        self.progress.borrow_mut().update(&self.now_at, -1);
    }

    #[inline(always)]
    /// Sends one record into the corresponding timely dataflow `Stream`, at the current epoch.
    pub fn send(&mut self, data: D) {
        // assert!(self.buffer.capacity() == Content::<D>::default_length());
        self.buffer.push(data);
        if self.buffer.len() == self.buffer.capacity() {
            self.flush();
        }
    }

    /// Advances the current epoch to `next`.
    ///
    /// This method allows timely dataflow to issue progress notifications as it can now determine
    /// that this input can no longer produce data at earlier timestamps.
    pub fn advance_to(&mut self, next: T) {
        assert!(next > self.now_at.inner);
        self.close_epoch();
        self.now_at = RootTimestamp::new(next);
        self.progress.borrow_mut().update(&self.now_at, 1);
    }

    /// Closes the input.
    ///
    /// This method allows timely dataflow to issue all progress notifications blocked by this input
    /// and to begin to shut down operators, as this input can no longer produce data.
    pub fn close(self) { }

    /// Reports the current epoch.
    pub fn epoch(&self) -> &T {
        &self.now_at.inner
    }

    /// Reports the current timestamp.
    pub fn time(&self) -> &Product<RootTimestamp, T> {
        &self.now_at
    }
}

impl<T:Timestamp+Ord, D: Data> Drop for Handle<T, D> {
    fn drop(&mut self) {
        self.close_epoch();
    }
}
<|endoftext|>