<commit_before>use codespan::{CodeMap, LineIndex, RawIndex};
use std::io;
use termcolor::{Color, ColorSpec, WriteColor};

use crate::{Diagnostic, LabelStyle, Severity};

pub fn emit<W, S>(mut writer: W, codemap: &CodeMap<S>, diagnostic: &Diagnostic) -> io::Result<()>
where
    W: WriteColor,
    S: AsRef<str>,
{
    let severity_color = severity_color(diagnostic.severity);
    let gutter_spec = ColorSpec::new().set_fg(Some(gutter_color())).clone();
    let primary_spec = ColorSpec::new().set_fg(Some(severity_color)).clone();
    let secondary_spec = ColorSpec::new().set_fg(Some(secondary_color())).clone();
    let header_message_spec = ColorSpec::new().set_bold(true).set_intense(true).clone();
    let header_primary_spec = header_message_spec.clone().set_fg(Some(severity_color)).clone();

    // Diagnostic header

    writer.set_color(&header_primary_spec)?;

    // Severity
    //
    // ```
    // error
    // ```
    write!(writer, "{}", severity_name(diagnostic.severity))?;

    // Error code
    //
    // ```
    // [E0001]
    // ```
    if let Some(code) = &diagnostic.code {
        write!(writer, "[{}]", code)?;
    }

    // Diagnostic message
    //
    // ```
    // : Unexpected type in `+` application
    // ```
    writer.set_color(&header_message_spec)?;
    writeln!(writer, ": {}", diagnostic.message)?;
    writer.reset()?;

    // Diagnostic Labels

    for label in &diagnostic.labels {
        match codemap.find_file(label.span.start()) {
            None => {
                if !label.message.is_empty() {
                    writeln!(writer, "- {}", label.message)?
                }
            },
            Some(file) => {
                let (start_line, column) =
                    file.location(label.span.start()).expect("location_start");
                let (end_line, _) = file.location(label.span.end()).expect("location_end");
                // Use the length of the last line number as the gutter padding
                let gutter_padding = format!("{}", end_line.number()).len();

                // File name
                //
                // ```
                // - <test>:2:9
                // ```

                writeln!(
                    writer,
                    "{: >width$} - {file}:{line}:{column}",
                    "",
                    width = gutter_padding,
                    file = file.name(),
                    line = start_line.number(),
                    column = column.number(),
                )?;

                // Source code snippet
                //
                // ```
                //   │
                // 2 │ (+ test "")
                //   │         ^^ Expected integer but got string
                //   │
                // ```

                let start_line_span = file.line_span(start_line).expect("line_span");
                let end_line_span = file.line_span(end_line).expect("line_span");

                let label_spec = match label.style {
                    LabelStyle::Primary => &primary_spec,
                    LabelStyle::Secondary => &secondary_spec,
                };

                // Write prefix to marked section

                writer.set_color(&gutter_spec)?;
                writeln!(writer, "{: >width$} │ ", "", width = gutter_padding)?;
                write!(
                    writer,
                    "{: >width$} │ ",
                    start_line.number(),
                    width = gutter_padding,
                )?;

                let prefix = file
                    .src_slice(start_line_span.with_end(label.span.start()))
                    .expect("prefix");
                writer.reset()?;
                write!(writer, "{}", prefix)?;

                // Write marked section
                let mark_len = if start_line == end_line {
                    // Single line

                    let marked = file.src_slice(label.span).expect("marked");
                    writer.set_color(&label_spec)?;
                    write!(writer, "{}", marked)?;
                    marked.len()
                } else {
                    // Multiple lines

                    let marked = file
                        .src_slice(start_line_span.with_start(label.span.start()))
                        .expect("start_of_marked");
                    writer.set_color(&label_spec)?;
                    write!(writer, "{}", marked)?;

                    for line_index in ((start_line.to_usize() + 1)..end_line.to_usize())
                        .map(|i| LineIndex::from(i as RawIndex))
                    {
                        writer.set_color(&gutter_spec)?;
                        write!(
                            writer,
                            "{: >width$} │ ",
                            line_index.number(),
                            width = gutter_padding,
                        )?;

                        let line_span = file.line_span(line_index).expect("marked_line_span");
                        let line = file
                            .src_slice(line_span)
                            .expect("line")
                            .trim_end_matches(|ch: char| ch == '\r' || ch == '\n');
                        writer.set_color(&label_spec)?;
                        writeln!(writer, "{}", line)?;
                    }

                    writer.set_color(&gutter_spec)?;
                    write!(
                        writer,
                        "{: >width$} │ ",
                        end_line.number(),
                        width = gutter_padding,
                    )?;
                    let line = file
                        .src_slice(end_line_span.with_end(label.span.end()))
                        .expect("line");
                    writer.set_color(&label_spec)?;
                    write!(writer, "{}", line)?;
                    line.len()
                };

                // Write suffix to marked section

                let suffix = file
                    .src_slice(end_line_span.with_start(label.span.end()))
                    .expect("suffix")
                    .trim_end_matches(|ch: char| ch == '\r' || ch == '\n');
                writer.reset()?;
                writeln!(writer, "{}", suffix)?;

                // Write mark and label

                writer.set_color(&gutter_spec)?;
                write!(writer, "{: >width$} │ ", "", width = gutter_padding)?;
                writer.reset()?;

                writer.set_color(&label_spec)?;
                write!(writer, "{: >width$}", "", width = prefix.len())?;
                for _ in 0..mark_len {
                    write!(writer, "{}", underline_mark(label.style))?;
                }
                writer.reset()?;

                if !label.message.is_empty() {
                    writer.set_color(&label_spec)?;
                    writeln!(writer, " {}", label.message)?;
                    writer.reset()?;
                }
                writer.set_color(&gutter_spec)?;
                writeln!(writer, "{: >width$} │", "", width = gutter_padding)?;
                writer.reset()?;
            },
        }
    }
    Ok(())
}

// Blue is really difficult to see on the standard windows command line
// FIXME: Make colors configurable
#[cfg(windows)]
const BLUE: Color = Color::Cyan;
#[cfg(not(windows))]
const BLUE: Color = Color::Blue;

/// Return the termcolor to use when rendering messages of this diagnostic severity.
fn severity_color(severity: Severity) -> Color {
    match severity {
        Severity::Bug | Severity::Error => Color::Red,
        Severity::Warning => Color::Yellow,
        Severity::Note => Color::Green,
        Severity::Help => Color::Cyan,
    }
}

/// The color to use for secondary highlights.
fn secondary_color() -> Color {
    BLUE
}

/// The color to use for gutters highlights.
fn gutter_color() -> Color {
    BLUE
}

/// A string that explains this diagnostic severity.
fn severity_name(severity: Severity) -> &'static str {
    match severity {
        Severity::Bug => "bug",
        Severity::Error => "error",
        Severity::Warning => "warning",
        Severity::Note => "note",
        Severity::Help => "help",
    }
}

/// The mark used for the underlined section of code.
fn underline_mark(label_style: LabelStyle) -> char {
    match label_style {
        LabelStyle::Primary => '^',
        LabelStyle::Secondary => '-',
    }
}
<commit_msg>Consistently use write macro<commit_after>use codespan::{CodeMap, LineIndex, RawIndex};
use std::io;
use termcolor::{Color, ColorSpec, WriteColor};

use crate::{Diagnostic, LabelStyle, Severity};

pub fn emit<W, S>(mut writer: W, codemap: &CodeMap<S>, diagnostic: &Diagnostic) -> io::Result<()>
where
    W: WriteColor,
    S: AsRef<str>,
{
    let severity_color = severity_color(diagnostic.severity);
    let gutter_spec = ColorSpec::new().set_fg(Some(gutter_color())).clone();
    let primary_spec = ColorSpec::new().set_fg(Some(severity_color)).clone();
    let secondary_spec = ColorSpec::new().set_fg(Some(secondary_color())).clone();
    let header_message_spec = ColorSpec::new().set_bold(true).set_intense(true).clone();
    let header_primary_spec = header_message_spec.clone().set_fg(Some(severity_color)).clone();

    // Diagnostic header

    writer.set_color(&header_primary_spec)?;

    // Severity
    //
    // ```
    // error
    // ```
    write!(writer, "{}", severity_name(diagnostic.severity))?;

    // Error code
    //
    // ```
    // [E0001]
    // ```
    if let Some(code) = &diagnostic.code {
        write!(writer, "[{}]", code)?;
    }

    // Diagnostic message
    //
    // ```
    // : Unexpected type in `+` application
    // ```
    writer.set_color(&header_message_spec)?;
    write!(writer, ": {}", diagnostic.message)?;
    write!(writer, "\n")?;
    writer.reset()?;

    // Diagnostic Labels

    for label in &diagnostic.labels {
        match codemap.find_file(label.span.start()) {
            None => {
                if !label.message.is_empty() {
                    write!(writer, "- {}", label.message)?;
                    write!(writer, "\n")?;
                }
            },
            Some(file) => {
                let (start_line, column) =
                    file.location(label.span.start()).expect("location_start");
                let (end_line, _) = file.location(label.span.end()).expect("location_end");
                // Use the length of the last line number as the gutter padding
                let gutter_padding = format!("{}", end_line.number()).len();

                // File name
                //
                // ```
                // - <test>:2:9
                // ```

                write!(
                    writer,
                    "{: >width$} - {file}:{line}:{column}",
                    "",
                    width = gutter_padding,
                    file = file.name(),
                    line = start_line.number(),
                    column = column.number(),
                )?;
                write!(writer, "\n")?;

                // Source code snippet
                //
                // ```
                //   │
                // 2 │ (+ test "")
                //   │         ^^ Expected integer but got string
                //   │
                // ```

                let start_line_span = file.line_span(start_line).expect("line_span");
                let end_line_span = file.line_span(end_line).expect("line_span");

                let label_spec = match label.style {
                    LabelStyle::Primary => &primary_spec,
                    LabelStyle::Secondary => &secondary_spec,
                };

                // Write prefix to marked section

                writer.set_color(&gutter_spec)?;
                write!(writer, "{: >width$} │ ", "", width = gutter_padding)?;
                write!(writer, "\n")?;
                write!(
                    writer,
                    "{: >width$} │ ",
                    start_line.number(),
                    width = gutter_padding,
                )?;

                let prefix = file
                    .src_slice(start_line_span.with_end(label.span.start()))
                    .expect("prefix");
                writer.reset()?;
                write!(writer, "{}", prefix)?;

                // Write marked section
                let mark_len = if start_line == end_line {
                    // Single line

                    let marked = file.src_slice(label.span).expect("marked");
                    writer.set_color(&label_spec)?;
                    write!(writer, "{}", marked)?;
                    marked.len()
                } else {
                    // Multiple lines

                    let marked = file
                        .src_slice(start_line_span.with_start(label.span.start()))
                        .expect("start_of_marked");
                    writer.set_color(&label_spec)?;
                    write!(writer, "{}", marked)?;

                    for line_index in ((start_line.to_usize() + 1)..end_line.to_usize())
                        .map(|i| LineIndex::from(i as RawIndex))
                    {
                        writer.set_color(&gutter_spec)?;
                        write!(
                            writer,
                            "{: >width$} │ ",
                            line_index.number(),
                            width = gutter_padding,
                        )?;

                        let line_span = file.line_span(line_index).expect("marked_line_span");
                        let line = file
                            .src_slice(line_span)
                            .expect("line")
                            .trim_end_matches(|ch: char| ch == '\r' || ch == '\n');
                        writer.set_color(&label_spec)?;
                        write!(writer, "{}", line)?;
                        write!(writer, "\n")?;
                    }

                    writer.set_color(&gutter_spec)?;
                    write!(
                        writer,
                        "{: >width$} │ ",
                        end_line.number(),
                        width = gutter_padding,
                    )?;
                    let line = file
                        .src_slice(end_line_span.with_end(label.span.end()))
                        .expect("line");
                    writer.set_color(&label_spec)?;
                    write!(writer, "{}", line)?;
                    line.len()
                };

                // Write suffix to marked section

                let suffix = file
                    .src_slice(end_line_span.with_start(label.span.end()))
                    .expect("suffix")
                    .trim_end_matches(|ch: char| ch == '\r' || ch == '\n');
                writer.reset()?;
                write!(writer, "{}", suffix)?;
                write!(writer, "\n")?;

                // Write mark and label

                writer.set_color(&gutter_spec)?;
                write!(writer, "{: >width$} │ ", "", width = gutter_padding)?;
                writer.reset()?;

                writer.set_color(&label_spec)?;
                write!(writer, "{: >width$}", "", width = prefix.len())?;
                for _ in 0..mark_len {
                    write!(writer, "{}", underline_mark(label.style))?;
                }
                writer.reset()?;

                if !label.message.is_empty() {
                    writer.set_color(&label_spec)?;
                    write!(writer, " {}", label.message)?;
                    write!(writer, "\n")?;
                    writer.reset()?;
                }
                writer.set_color(&gutter_spec)?;
                write!(writer, "{: >width$} │", "", width = gutter_padding)?;
                write!(writer, "\n")?;
                writer.reset()?;
            },
        }
    }
    Ok(())
}

// Blue is really difficult to see on the standard windows command line
// FIXME: Make colors configurable
#[cfg(windows)]
const BLUE: Color = Color::Cyan;
#[cfg(not(windows))]
const BLUE: Color = Color::Blue;

/// Return the termcolor to use when rendering messages of this diagnostic severity.
fn severity_color(severity: Severity) -> Color {
    match severity {
        Severity::Bug | Severity::Error => Color::Red,
        Severity::Warning => Color::Yellow,
        Severity::Note => Color::Green,
        Severity::Help => Color::Cyan,
    }
}

/// The color to use for secondary highlights.
fn secondary_color() -> Color {
    BLUE
}

/// The color to use for gutters highlights.
fn gutter_color() -> Color {
    BLUE
}

/// A string that explains this diagnostic severity.
fn severity_name(severity: Severity) -> &'static str {
    match severity {
        Severity::Bug => "bug",
        Severity::Error => "error",
        Severity::Warning => "warning",
        Severity::Note => "note",
        Severity::Help => "help",
    }
}

/// The mark used for the underlined section of code.
fn underline_mark(label_style: LabelStyle) -> char {
    match label_style {
        LabelStyle::Primary => '^',
        LabelStyle::Secondary => '-',
    }
}
<|endoftext|>


<commit_before>use super::VulkanoRenderer;

use game_state::winit;
use game_state::input::events::{
    InputEvent,
    MouseButton,
};

use game_state::input::screen::{
    ScreenPoint,
    ScreenRect,
    DeltaVector,
};

use std::collections::VecDeque;
use game_state::input::InputSource;

// TODO: probably extract this to game_state

impl VulkanoRenderer {
    fn toggle_fullscreen(&mut self) {
        let is_fullscreen = !self.fullscreen;
        println!("toggle_fullscreen {} -> {}", self.fullscreen, is_fullscreen);
        if is_fullscreen {
            let current = self.window.get_current_monitor();
            println!("current monitor {:?}", current);
            self.window.set_fullscreen( Some(current) );
        } else {
            self.window.set_fullscreen(None);
        }
        self.fullscreen = is_fullscreen;
        self.window.hide_cursor(is_fullscreen);
        self.cursor_hidden = is_fullscreen;
        match self.window.grab_cursor(is_fullscreen) {
            Ok(_) => {
                println!("{}", if is_fullscreen {"grabbed cursor"} else {"released cursor"});
                self.cursor_grabbed = is_fullscreen;
            },
            Err(e) => println!("unable to grab or release cursor {:?}", e)
        }

    }

}

impl InputSource for VulkanoRenderer {

    fn get_input_events(&mut self) -> VecDeque<InputEvent> {

        //println!("get_input_events");
        let mut events = VecDeque::new();
        {
            let event_loop = &mut self.events_loop.lock().unwrap();
            event_loop.poll_events(|e| events.push_back(e.clone()));
        }

        let this_window_id = self.id as u64;
        //test chg

        let mut converted_events = VecDeque::with_capacity(events.len());

        for e in events {

            match e {
                winit::Event::DeviceEvent{device_id, ref event} => {
                    match event {
                        &winit::DeviceEvent::Added => {
                            println!("device added");
                        },
                        &winit::DeviceEvent::Removed => {
                            println!("device removed")
                        },
                        &winit::DeviceEvent::MouseMotion { delta } => { },
                        &winit::DeviceEvent::MouseWheel {delta} => {},
                        &winit::DeviceEvent::Motion { axis, value } => {
                        },
                        &winit::DeviceEvent::Button { button, state } => {},
                        &winit::DeviceEvent::Key(input) => {},
                        &winit::DeviceEvent::Text{codepoint} => {}
                    }
                },
                winit::Event::WindowEvent{ window_id, ref event } => {
                    let maybe_converted_event = match event {
                        // Keyboard Events
                        &winit::WindowEvent::KeyboardInput{device_id, input} => {
                            let e = match input.state {
                                winit::ElementState::Pressed => InputEvent::KeyDown(self.id, input.scancode),
                                winit::ElementState::Released => InputEvent::KeyUp(self.id, input.scancode)
                            };

                            // within the renderer itself we want to listen for input events
                            // directly, so we read what's been copied
                            if let &InputEvent::KeyDown(ref id, ref scan) = &e {
                                let c = *scan as u8;
                                match c {
                                    33 => {
                                        self.toggle_fullscreen();
                                    }
                                    _ => {}
                                }
                            }

                            Some(e)
                        }

                        // Mouse Events
                        &winit::WindowEvent::CursorMoved{device_id, position, modifiers} => {
                            let winit::dpi::LogicalPosition{x,y} = position;
                            let old_pos: ScreenPoint = self.get_mouse_pos().clone();
                            // TODO: resolve f64 truncation to i32 here
                            let new_pos = ScreenPoint::new(x as i32, y as i32);
                            let moved =
                                InputEvent::MouseMove(self.id, new_pos.clone(), DeltaVector::from_points(&old_pos, &new_pos));
                            self.set_mouse_pos(new_pos);
                            Some(moved)
                        },
                        &winit::WindowEvent::MouseInput{device_id, state, button, modifiers} => {
                            let b = match button {
                                winit::MouseButton::Left => MouseButton::Left,
                                winit::MouseButton::Right => MouseButton::Right,
                                winit::MouseButton::Middle => MouseButton::Middle,
                                winit::MouseButton::Other(n) => MouseButton::Other(n)
                            };
                            let e = match state {
                                winit::ElementState::Pressed => InputEvent::MouseDown(self.id, b, self.get_mouse_pos().clone()),
                                winit::ElementState::Released => InputEvent::MouseUp(self.id, b, self.get_mouse_pos().clone())
                            };
                            Some(e)
                        },

                        &winit::WindowEvent::MouseWheel{device_id, delta, phase, modifiers} => {
                            let e = match delta {
                                winit::MouseScrollDelta::LineDelta(x,y) => {
                                    InputEvent::MouseWheel(
                                        self.id, self.get_mouse_pos().clone(),
                                        DeltaVector::new(x as i32, y as i32)
                                    )
                                },
                                winit::MouseScrollDelta::PixelDelta(winit::dpi::LogicalPosition{x,y}) => {
                                    InputEvent::MouseWheel(
                                        self.id, self.get_mouse_pos().clone(),
                                        DeltaVector::new(x as i32, y as i32)
                                    )
                                }
                            };

                            Some(e)
                        },

                        // Window Manager events
                        &winit::WindowEvent::CloseRequested => Some(InputEvent::CloseRequested(self.id)),
                        &winit::WindowEvent::Destroyed => Some(InputEvent::Destroyed(self.id)),
                        &winit::WindowEvent::Focused(f) => Some(if f { InputEvent::GainedFocus(self.id) } else { InputEvent::LostFocus(self.id) }),
                        &winit::WindowEvent::Moved(winit::dpi::LogicalPosition{x,y}) => {
                            let new_rect = ScreenRect::new(x as i32, y as i32, self.rect.w, self.rect.h);
                            let e = InputEvent::Moved(self.id, ScreenPoint::new(x as i32, y as i32));
                            self.set_rect(new_rect);
                            Some(e)
                        }
                        &winit::WindowEvent::Resized(winit::dpi::LogicalSize{width, height}) => {
                            let new_rect = ScreenRect::new(self.rect.x, self.rect.y, width as i32, height as i32);
                            let e = InputEvent::Resized(self.id, new_rect.clone());
                            self.set_rect(new_rect);
                            Some(e)
                        },
                        _ => None

                    };
                    if maybe_converted_event.is_some() {
                        converted_events.push_back(maybe_converted_event.unwrap());
                    }

                }
                _ => {}
            };
        }
        converted_events
    }
    // FIXME Ruby
}

<commit_msg>fix fullscreen and cursor grab/hide<commit_after>use super::VulkanoRenderer;

use game_state::winit;
use game_state::input::events::{
    InputEvent,
    MouseButton,
};

use game_state::input::screen::{
    ScreenPoint,
    ScreenRect,
    DeltaVector,
};

use std::collections::VecDeque;
use game_state::input::InputSource;

// TODO: probably extract this to game_state

impl VulkanoRenderer {
    fn toggle_fullscreen(&mut self) {
        let is_fullscreen = !self.fullscreen;
        println!("toggle_fullscreen {} -> {}", self.fullscreen, is_fullscreen);

        self.window.hide_cursor(is_fullscreen);
        self.cursor_hidden = is_fullscreen;
        match self.window.grab_cursor(is_fullscreen) {
            Ok(_) => {
               println!("{}", if is_fullscreen {"grabbed cursor"} else {"released cursor"});
               self.cursor_grabbed = is_fullscreen;
           },
           Err(e) => println!("unable to grab or release cursor {:?}", e)
        }

        // WIN32 WARNING grabbing the cursor and hiding it MUST be done before the set_fullscreen call
        // due to a deadlock in the win32 implementation
        // https://github.com/tomaka/winit/issues/574

        if is_fullscreen {
            let current = self.window.get_current_monitor();
            println!("current monitor {:?}", current);
            self.window.set_fullscreen( Some(current) );
        } else {
            self.window.set_fullscreen(None);
        }
        self.fullscreen = is_fullscreen;
    }

}

impl InputSource for VulkanoRenderer {

    fn get_input_events(&mut self) -> VecDeque<InputEvent> {

        //println!("get_input_events");
        let mut events = VecDeque::new();
        {
            let event_loop = &mut self.events_loop.lock().unwrap();
            event_loop.poll_events(|e| events.push_back(e.clone()));
        }

        let this_window_id = self.id as u64;
        //test chg

        let mut converted_events = VecDeque::with_capacity(events.len());

        for e in events {

            match e {
                winit::Event::DeviceEvent{device_id, ref event} => {
                    match event {
                        &winit::DeviceEvent::Added => {
                            println!("device added");
                        },
                        &winit::DeviceEvent::Removed => {
                            println!("device removed")
                        },
                        &winit::DeviceEvent::MouseMotion { delta } => { },
                        &winit::DeviceEvent::MouseWheel {delta} => {},
                        &winit::DeviceEvent::Motion { axis, value } => {
                        },
                        &winit::DeviceEvent::Button { button, state } => {},
                        &winit::DeviceEvent::Key(input) => {},
                        &winit::DeviceEvent::Text{codepoint} => {}
                    }
                },
                winit::Event::WindowEvent{ window_id, ref event } => {
                    let maybe_converted_event = match event {
                        // Keyboard Events
                        &winit::WindowEvent::KeyboardInput{device_id, input} => {
                            let e = match input.state {
                                winit::ElementState::Pressed => InputEvent::KeyDown(self.id, input.scancode),
                                winit::ElementState::Released => InputEvent::KeyUp(self.id, input.scancode)
                            };

                            // within the renderer itself we want to listen for input events
                            // directly, so we read what's been copied
                            if let &InputEvent::KeyDown(ref id, ref scan) = &e {
                                let c = *scan as u8;
                                match c {
                                    33 => {
                                        self.toggle_fullscreen();
                                    }
                                    _ => {}
                                }
                            }

                            Some(e)
                        }

                        // Mouse Events
                        &winit::WindowEvent::CursorMoved{device_id, position, modifiers} => {
                            let winit::dpi::LogicalPosition{x,y} = position;
                            let old_pos: ScreenPoint = self.get_mouse_pos().clone();
                            // TODO: resolve f64 truncation to i32 here
                            let new_pos = ScreenPoint::new(x as i32, y as i32);
                            let moved =
                                InputEvent::MouseMove(self.id, new_pos.clone(), DeltaVector::from_points(&old_pos, &new_pos));
                            self.set_mouse_pos(new_pos);
                            Some(moved)
                        },
                        &winit::WindowEvent::MouseInput{device_id, state, button, modifiers} => {
                            let b = match button {
                                winit::MouseButton::Left => MouseButton::Left,
                                winit::MouseButton::Right => MouseButton::Right,
                                winit::MouseButton::Middle => MouseButton::Middle,
                                winit::MouseButton::Other(n) => MouseButton::Other(n)
                            };
                            let e = match state {
                                winit::ElementState::Pressed => InputEvent::MouseDown(self.id, b, self.get_mouse_pos().clone()),
                                winit::ElementState::Released => InputEvent::MouseUp(self.id, b, self.get_mouse_pos().clone())
                            };
                            Some(e)
                        },

                        &winit::WindowEvent::MouseWheel{device_id, delta, phase, modifiers} => {
                            let e = match delta {
                                winit::MouseScrollDelta::LineDelta(x,y) => {
                                    InputEvent::MouseWheel(
                                        self.id, self.get_mouse_pos().clone(),
                                        DeltaVector::new(x as i32, y as i32)
                                    )
                                },
                                winit::MouseScrollDelta::PixelDelta(winit::dpi::LogicalPosition{x,y}) => {
                                    InputEvent::MouseWheel(
                                        self.id, self.get_mouse_pos().clone(),
                                        DeltaVector::new(x as i32, y as i32)
                                    )
                                }
                            };

                            Some(e)
                        },

                        // Window Manager events
                        &winit::WindowEvent::CloseRequested => Some(InputEvent::CloseRequested(self.id)),
                        &winit::WindowEvent::Destroyed => Some(InputEvent::Destroyed(self.id)),
                        &winit::WindowEvent::Focused(f) => Some(if f { InputEvent::GainedFocus(self.id) } else { InputEvent::LostFocus(self.id) }),
                        &winit::WindowEvent::Moved(winit::dpi::LogicalPosition{x,y}) => {
                            let new_rect = ScreenRect::new(x as i32, y as i32, self.rect.w, self.rect.h);
                            let e = InputEvent::Moved(self.id, ScreenPoint::new(x as i32, y as i32));
                            self.set_rect(new_rect);
                            Some(e)
                        }
                        &winit::WindowEvent::Resized(winit::dpi::LogicalSize{width, height}) => {
                            let new_rect = ScreenRect::new(self.rect.x, self.rect.y, width as i32, height as i32);
                            let e = InputEvent::Resized(self.id, new_rect.clone());
                            self.set_rect(new_rect);
                            Some(e)
                        },
                        _ => None

                    };
                    if maybe_converted_event.is_some() {
                        converted_events.push_back(maybe_converted_event.unwrap());
                    }

                }
                _ => {}
            };
        }
        converted_events
    }
    // FIXME Ruby
}

<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::ops::Deref;
use std::ops::DerefMut;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::MutexGuard;
use std::sync::TryLockError;

use memory::ChunkProperties;
use memory::CpuAccessible;
use memory::CpuWriteAccessible;
use memory::MemorySource;
use memory::MemorySourceChunk;
use memory::DeviceMemory;
use memory::MappedDeviceMemory;
use sync::Fence;
use sync::Semaphore;

use device::Device;
use device::Queue;

use VulkanObject;
use VulkanPointers;
use vk;

/// Dummy marker whose strategy is to allocate a new chunk of memory for each allocation.
///
/// The memory will not be accessible since it is not necessarily in host-visible memory.
///
/// This is good for large buffers, but inefficient is you use a lot of small buffers.
///
/// The memory is locked globally. That means that it doesn't matter whether you access the buffer
/// for reading or writing (like a `Mutex`).
#[derive(Debug, Copy, Clone)]
pub struct DeviceLocal;

unsafe impl MemorySource for DeviceLocal {
    type Chunk = DeviceLocalChunk;

    #[inline]
    fn is_sparse(&self) -> bool {
        false
    }

    #[inline]
    fn allocate(self, device: &Arc<Device>, size: usize, alignment: usize, memory_type_bits: u32)
                -> Result<DeviceLocalChunk, ()>
    {
        let mem_ty = device.physical_device().memory_types()
                           .skip(memory_type_bits.trailing_zeros() as usize).next().unwrap();
        let mem = try!(DeviceMemory::alloc(device, &mem_ty, size).map_err(|_| ()));

        // note: alignment doesn't need to be checked because allocating memory is guaranteed to
        //       fulfill any alignment requirement
        Ok(DeviceLocalChunk {
            mem: mem,
            semaphore: Mutex::new(None),
        })
    }
}

/// A chunk allocated from a `DeviceLocal`.
pub struct DeviceLocalChunk {
    mem: DeviceMemory,
    semaphore: Mutex<Option<Arc<Semaphore>>>,
}

unsafe impl MemorySourceChunk for DeviceLocalChunk {
    #[inline]
    fn size(&self) -> usize {
        self.mem.size()
    }

    #[inline]
    fn gpu_access(&self, _write: bool, _offset: usize, _size: usize, _: &mut Queue,
                  _: Option<Arc<Fence>>, mut semaphore: Option<Arc<Semaphore>>)
                  -> Option<Arc<Semaphore>>
    {
        assert!(semaphore.is_some());

        let mut self_semaphore = self.semaphore.lock().unwrap();
        mem::swap(&mut *self_semaphore, &mut semaphore);

        semaphore
    }

    #[inline]
    fn requires_fence(&self) -> bool {
        false
    }

    #[inline]
    fn properties(&self) -> ChunkProperties {
        ChunkProperties::Regular {
            memory: &self.mem,
            offset: 0,
            size: self.mem.size(),
        }
    }

    #[inline]
    fn may_alias(&self) -> bool {
        false
    }
}

/// Dummy marker whose strategy is to allocate a new chunk of memory for each allocation.
///
/// Guaranteed to allocate from a host-visible memory type.
///
/// This is good for large buffers, but inefficient is you use a lot of small buffers.
///
/// The memory is locked globally. That means that it doesn't matter whether you access the buffer
/// for reading or writing (like a `Mutex`).
#[derive(Debug, Copy, Clone)]
pub struct HostVisible;

unsafe impl MemorySource for HostVisible {
    type Chunk = HostVisibleChunk;

    #[inline]
    fn is_sparse(&self) -> bool {
        false
    }

    #[inline]
    fn allocate(self, device: &Arc<Device>, size: usize, alignment: usize, memory_type_bits: u32)
                -> Result<HostVisibleChunk, ()>
    {
        let mem_ty = device.physical_device().memory_types()
                           .filter(|t| (memory_type_bits & (1 << t.id())) != 0)
                           .filter(|t| t.is_host_visible())
                           .next().unwrap();
        let mem = try!(DeviceMemory::alloc_and_map(device, &mem_ty, size).map_err(|_| ()));

        // note: alignment doesn't need to be checked because allocating memory is guaranteed to
        //       fulfill any alignment requirement
        Ok(HostVisibleChunk {
            mem: mem,
            lock: Mutex::new((None, None)),
        })
    }
}

/// A chunk allocated from a `HostVisible`.
pub struct HostVisibleChunk {
    mem: MappedDeviceMemory,
    lock: Mutex<(Option<Arc<Semaphore>>, Option<Arc<Fence>>)>,
}

unsafe impl MemorySourceChunk for HostVisibleChunk {
    #[inline]
    fn size(&self) -> usize {
        self.mem.memory().size()
    }

    #[inline]
    fn gpu_access(&self, _write: bool, _offset: usize, _size: usize, _: &mut Queue,
                  fence: Option<Arc<Fence>>, mut semaphore: Option<Arc<Semaphore>>)
                  -> Option<Arc<Semaphore>>
    {
        assert!(fence.is_some());
        assert!(semaphore.is_some());

        let mut self_lock = self.lock.lock().unwrap();
        mem::swap(&mut self_lock.0, &mut semaphore);
        self_lock.1 = fence;

        semaphore
    }

    #[inline]
    fn properties(&self) -> ChunkProperties {
        ChunkProperties::Regular {
            memory: &self.mem.memory(),
            offset: 0,
            size: self.mem.memory().size(),
        }
    }

    #[inline]
    fn may_alias(&self) -> bool {
        false
    }
}

unsafe impl<'a, T: 'a> CpuAccessible<'a, T> for HostVisibleChunk {       // TODO: ?Sized
    type Read = GpuAccess<'a, T>;

    #[inline]
    fn read(&'a self, timeout_ns: u64) -> GpuAccess<'a, T> {
        self.write(timeout_ns)
    }

    #[inline]
    fn try_read(&'a self) -> Option<GpuAccess<'a, T>> {
        self.try_write()
    }
}

unsafe impl<'a, T: 'a> CpuWriteAccessible<'a, T> for HostVisibleChunk {       // TODO: ?Sized
    type Write = GpuAccess<'a, T>;

    #[inline]
    fn write(&'a self, timeout_ns: u64) -> GpuAccess<'a, T> {
        let pointer = self.mem.mapping_pointer() as *mut T;

        let mut lock = self.lock.lock().unwrap();
        if let Some(ref fence) = lock.1 {
            fence.wait(timeout_ns).unwrap();        // FIXME: error
        }
        lock.1 = None;

        // TODO: invalidate

        GpuAccess {
            mem: &self.mem,
            guard: lock,
            pointer: pointer,
        }
    }

    #[inline]
    fn try_write(&'a self) -> Option<GpuAccess<'a, T>> {
        let pointer = self.mem.mapping_pointer() as *mut T;

        let mut lock = match self.lock.try_lock() {
            Ok(l) => l,
            Err(TryLockError::Poisoned(_)) => panic!(),
            Err(TryLockError::WouldBlock) => return None,
        };

        if let Some(ref fence) = lock.1 {
            if fence.ready() != Ok(true) {      // TODO: we ignore ready()'s error here?
                return None;
            }
        }

        lock.1 = None;

        // TODO: invalidate

        Some(GpuAccess {
            mem: &self.mem,
            guard: lock,
            pointer: pointer,
        })
    }
}

/// Object that can be used to read or write the content of a `HostVisibleChunk`.
///
/// Note that this object holds a mutex guard on the chunk. If another thread tries to access
/// this memory's content or tries to submit a GPU command that uses this memory, it will block.
pub struct GpuAccess<'a, T: ?Sized + 'a> {
    mem: &'a MappedDeviceMemory,
    guard: MutexGuard<'a, (Option<Arc<Semaphore>>, Option<Arc<Fence>>)>,
    pointer: *mut T,
}

impl<'a, T: ?Sized + 'a> Deref for GpuAccess<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.pointer }
    }
}

impl<'a, T: ?Sized + 'a> DerefMut for GpuAccess<'a, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.pointer }
    }
}

impl<'a, T: ?Sized + 'a> Drop for GpuAccess<'a, T> {
    #[inline]
    fn drop(&mut self) {
        // TODO: only flush if necessary

        let vk = self.mem.memory().device().pointers();

        let range = vk::MappedMemoryRange {
            sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
            pNext: ptr::null(),
            memory: self.mem.memory().internal_object(),
            offset: 0,
            size: vk::WHOLE_SIZE,
        };

        // TODO: check result?
        unsafe {
            vk.FlushMappedMemoryRanges(self.mem.memory().device().internal_object(), 1, &range);
        }
    }
}
<commit_msg>Invalidate mapping when reading buffer<commit_after>use std::mem;
use std::ptr;
use std::ops::Deref;
use std::ops::DerefMut;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::MutexGuard;
use std::sync::TryLockError;

use memory::ChunkProperties;
use memory::CpuAccessible;
use memory::CpuWriteAccessible;
use memory::MemorySource;
use memory::MemorySourceChunk;
use memory::DeviceMemory;
use memory::MappedDeviceMemory;
use sync::Fence;
use sync::Semaphore;

use device::Device;
use device::Queue;

use VulkanObject;
use VulkanPointers;
use vk;

/// Dummy marker whose strategy is to allocate a new chunk of memory for each allocation.
///
/// The memory will not be accessible since it is not necessarily in host-visible memory.
///
/// This is good for large buffers, but inefficient is you use a lot of small buffers.
///
/// The memory is locked globally. That means that it doesn't matter whether you access the buffer
/// for reading or writing (like a `Mutex`).
#[derive(Debug, Copy, Clone)]
pub struct DeviceLocal;

unsafe impl MemorySource for DeviceLocal {
    type Chunk = DeviceLocalChunk;

    #[inline]
    fn is_sparse(&self) -> bool {
        false
    }

    #[inline]
    fn allocate(self, device: &Arc<Device>, size: usize, alignment: usize, memory_type_bits: u32)
                -> Result<DeviceLocalChunk, ()>
    {
        let mem_ty = device.physical_device().memory_types()
                           .skip(memory_type_bits.trailing_zeros() as usize).next().unwrap();
        let mem = try!(DeviceMemory::alloc(device, &mem_ty, size).map_err(|_| ()));

        // note: alignment doesn't need to be checked because allocating memory is guaranteed to
        //       fulfill any alignment requirement
        Ok(DeviceLocalChunk {
            mem: mem,
            semaphore: Mutex::new(None),
        })
    }
}

/// A chunk allocated from a `DeviceLocal`.
pub struct DeviceLocalChunk {
    mem: DeviceMemory,
    semaphore: Mutex<Option<Arc<Semaphore>>>,
}

unsafe impl MemorySourceChunk for DeviceLocalChunk {
    #[inline]
    fn size(&self) -> usize {
        self.mem.size()
    }

    #[inline]
    fn gpu_access(&self, _write: bool, _offset: usize, _size: usize, _: &mut Queue,
                  _: Option<Arc<Fence>>, mut semaphore: Option<Arc<Semaphore>>)
                  -> Option<Arc<Semaphore>>
    {
        assert!(semaphore.is_some());

        let mut self_semaphore = self.semaphore.lock().unwrap();
        mem::swap(&mut *self_semaphore, &mut semaphore);

        semaphore
    }

    #[inline]
    fn requires_fence(&self) -> bool {
        false
    }

    #[inline]
    fn properties(&self) -> ChunkProperties {
        ChunkProperties::Regular {
            memory: &self.mem,
            offset: 0,
            size: self.mem.size(),
        }
    }

    #[inline]
    fn may_alias(&self) -> bool {
        false
    }
}

/// Dummy marker whose strategy is to allocate a new chunk of memory for each allocation.
///
/// Guaranteed to allocate from a host-visible memory type.
///
/// This is good for large buffers, but inefficient is you use a lot of small buffers.
///
/// The memory is locked globally. That means that it doesn't matter whether you access the buffer
/// for reading or writing (like a `Mutex`).
#[derive(Debug, Copy, Clone)]
pub struct HostVisible;

unsafe impl MemorySource for HostVisible {
    type Chunk = HostVisibleChunk;

    #[inline]
    fn is_sparse(&self) -> bool {
        false
    }

    #[inline]
    fn allocate(self, device: &Arc<Device>, size: usize, alignment: usize, memory_type_bits: u32)
                -> Result<HostVisibleChunk, ()>
    {
        let mem_ty = device.physical_device().memory_types()
                           .filter(|t| (memory_type_bits & (1 << t.id())) != 0)
                           .filter(|t| t.is_host_visible())
                           .next().unwrap();
        let mem = try!(DeviceMemory::alloc_and_map(device, &mem_ty, size).map_err(|_| ()));

        // note: alignment doesn't need to be checked because allocating memory is guaranteed to
        //       fulfill any alignment requirement
        Ok(HostVisibleChunk {
            mem: mem,
            lock: Mutex::new((None, None)),
        })
    }
}

/// A chunk allocated from a `HostVisible`.
pub struct HostVisibleChunk {
    mem: MappedDeviceMemory,
    lock: Mutex<(Option<Arc<Semaphore>>, Option<Arc<Fence>>)>,
}

unsafe impl MemorySourceChunk for HostVisibleChunk {
    #[inline]
    fn size(&self) -> usize {
        self.mem.memory().size()
    }

    #[inline]
    fn gpu_access(&self, _write: bool, _offset: usize, _size: usize, _: &mut Queue,
                  fence: Option<Arc<Fence>>, mut semaphore: Option<Arc<Semaphore>>)
                  -> Option<Arc<Semaphore>>
    {
        assert!(fence.is_some());
        assert!(semaphore.is_some());

        let mut self_lock = self.lock.lock().unwrap();
        mem::swap(&mut self_lock.0, &mut semaphore);
        self_lock.1 = fence;

        semaphore
    }

    #[inline]
    fn properties(&self) -> ChunkProperties {
        ChunkProperties::Regular {
            memory: &self.mem.memory(),
            offset: 0,
            size: self.mem.memory().size(),
        }
    }

    #[inline]
    fn may_alias(&self) -> bool {
        false
    }
}

unsafe impl<'a, T: 'a> CpuAccessible<'a, T> for HostVisibleChunk {       // TODO: ?Sized
    type Read = GpuAccess<'a, T>;

    #[inline]
    fn read(&'a self, timeout_ns: u64) -> GpuAccess<'a, T> {
        self.write(timeout_ns)
    }

    #[inline]
    fn try_read(&'a self) -> Option<GpuAccess<'a, T>> {
        self.try_write()
    }
}

unsafe impl<'a, T: 'a> CpuWriteAccessible<'a, T> for HostVisibleChunk {       // TODO: ?Sized
    type Write = GpuAccess<'a, T>;

    #[inline]
    fn write(&'a self, timeout_ns: u64) -> GpuAccess<'a, T> {
        let vk = self.mem.memory().device().pointers();
        let pointer = self.mem.mapping_pointer() as *mut T;

        let mut lock = self.lock.lock().unwrap();
        if let Some(ref fence) = lock.1 {
            fence.wait(timeout_ns).unwrap();        // FIXME: error
        }
        lock.1 = None;

        // TODO: only invalidate if necessary
        let range = vk::MappedMemoryRange {
            sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
            pNext: ptr::null(),
            memory: self.mem.memory().internal_object(),
            offset: 0,
            size: vk::WHOLE_SIZE,
        };

        // TODO: check result?
        unsafe {
            vk.InvalidateMappedMemoryRanges(self.mem.memory().device().internal_object(),
                                            1, &range);
        }

        GpuAccess {
            mem: &self.mem,
            guard: lock,
            pointer: pointer,
        }
    }

    #[inline]
    fn try_write(&'a self) -> Option<GpuAccess<'a, T>> {
        let vk = self.mem.memory().device().pointers();
        let pointer = self.mem.mapping_pointer() as *mut T;

        let mut lock = match self.lock.try_lock() {
            Ok(l) => l,
            Err(TryLockError::Poisoned(_)) => panic!(),
            Err(TryLockError::WouldBlock) => return None,
        };

        if let Some(ref fence) = lock.1 {
            if fence.ready() != Ok(true) {      // TODO: we ignore ready()'s error here?
                return None;
            }
        }

        lock.1 = None;

        // TODO: only invalidate if necessary
        let range = vk::MappedMemoryRange {
            sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
            pNext: ptr::null(),
            memory: self.mem.memory().internal_object(),
            offset: 0,
            size: vk::WHOLE_SIZE,
        };

        // TODO: check result?
        unsafe {
            vk.InvalidateMappedMemoryRanges(self.mem.memory().device().internal_object(),
                                            1, &range);
        }

        Some(GpuAccess {
            mem: &self.mem,
            guard: lock,
            pointer: pointer,
        })
    }
}

/// Object that can be used to read or write the content of a `HostVisibleChunk`.
///
/// Note that this object holds a mutex guard on the chunk. If another thread tries to access
/// this memory's content or tries to submit a GPU command that uses this memory, it will block.
pub struct GpuAccess<'a, T: ?Sized + 'a> {
    mem: &'a MappedDeviceMemory,
    guard: MutexGuard<'a, (Option<Arc<Semaphore>>, Option<Arc<Fence>>)>,
    pointer: *mut T,
}

impl<'a, T: ?Sized + 'a> Deref for GpuAccess<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.pointer }
    }
}

impl<'a, T: ?Sized + 'a> DerefMut for GpuAccess<'a, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.pointer }
    }
}

impl<'a, T: ?Sized + 'a> Drop for GpuAccess<'a, T> {
    #[inline]
    fn drop(&mut self) {
        // TODO: only flush if necessary

        let vk = self.mem.memory().device().pointers();

        let range = vk::MappedMemoryRange {
            sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
            pNext: ptr::null(),
            memory: self.mem.memory().internal_object(),
            offset: 0,
            size: vk::WHOLE_SIZE,
        };

        // TODO: check result?
        unsafe {
            vk.FlushMappedMemoryRanges(self.mem.memory().device().internal_object(), 1, &range);
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp;

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// The iterator **Zip\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::Zip;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in Zip::new((0i32..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct Zip<T> {
    t: T
}

impl<T> Zip<T> where Zip<T>: Iterator
{
    /// Create a new **Zip** from a tuple of iterators.
    pub fn new(t: T) -> Zip<T>
    {
        Zip{t: t}
    }
}

// Macro to turn `t.$idx`, where $idx:tt, into an expression.
macro_rules! e(
    ($e:expr) => { $e }
);

macro_rules! impl_zip_iter(
    ($($idx:tt is $B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for Zip<($($B,)*)>
            where
            $(
                $B: Iterator,
            )*
        {
            type Item = ($(<$B as Iterator>::Item,)*);

            fn next(&mut self) -> Option<
                    ($(<$B as Iterator>::Item,)*)
                >
            {
                $(
                    let $B = match e!(self.t. $idx).next() {
                        None => return None,
                        Some(elt) => elt
                    };
                )*
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (usize, Option<usize>)
            {
                let mut low = ::std::usize::MAX;
                let mut high = None;
                $(
                    // update estimate
                    let (l, h) = e!(self.t. $idx).size_hint();
                    low = cmp::min(low, l);
                    high = match (high, h) {
                        (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
                        _ => high.or(h)
                    };
                )*
                (low, high)
            }
        }
    );
);

impl_zip_iter!(0 is A);
impl_zip_iter!(0 is A, 1 is B);
impl_zip_iter!(0 is A, 1 is B, 2 is C);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G, 7 is H);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G, 7 is H, 8 is I);
<commit_msg>refactor tuple zip macros and traits<commit_after>use std::cmp;

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// The iterator **Zip\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::Zip;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in Zip::new((0i32..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct Zip<T> {
    t: T
}

impl<T> Zip<T> where Zip<T>: Iterator
{
    /// Create a new **Zip** from a tuple of iterators.
    pub fn new(t: T) -> Zip<T>
    {
        Zip{t: t}
    }
}

macro_rules! impl_zip_iter(
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for Zip<($($B,)*)>
            where
            $(
                $B: Iterator,
            )*
        {
            type Item = ($(<$B as Iterator>::Item,)*);

            fn next(&mut self) -> Option<
                    ($(<$B as Iterator>::Item,)*)
                >
            {
                let &mut Zip { t : ($(ref mut $B,)*)} = self;
                // WARNING: partial consume possible
                // Zip worked the same.
                $(
                    let $B = match $B.next() {
                        None => return None,
                        Some(elt) => elt
                    };
                )*
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (usize, Option<usize>)
            {
                let low = ::std::usize::MAX;
                let high = None;
                let &Zip { t : ($(ref $B,)*) } = self;
                $(
                    // update estimate
                    let (l, h) = $B.size_hint();
                    let low = cmp::min(low, l);
                    let high = match (high, h) {
                        (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
                        _ => high.or(h)
                    };
                )*
                (low, high)
            }
        }
    );
);

impl_zip_iter!(A);
impl_zip_iter!(A, B);
impl_zip_iter!(A, B, C);
impl_zip_iter!(A, B, C, D);
impl_zip_iter!(A, B, C, D, E);
impl_zip_iter!(A, B, C, D, E, F);
impl_zip_iter!(A, B, C, D, E, F, G);
impl_zip_iter!(A, B, C, D, E, F, G, H);
impl_zip_iter!(A, B, C, D, E, F, G, H, I);
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd and Justin Ingram jci5kb
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::os::getcwd;
use extra::getopts;
use std::run::Process;
use std::run::ProcessOutput;
use std::run::ProcessOptions;
use std::option::{Option, None, Some};

struct Shell {
    cmd_prompt: ~str,
    cwd: Path,
    cwdopt: Option<Path>,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cwd: getcwd(),
            cwdopt: Some(getcwd()),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
	    // Old stuff
            // run::process_status(program, argv);

            let mut whichprocop = ProcessOptions::new();
	    whichprocop.dir = self.cwdopt.as_ref();

	    let mut whichproc = Process::new(program, argv, whichprocop);
	    let mut process = whichproc.unwrap();
	    let mut procout = process.finish_with_output();
	    println(std::str::from_utf8(procout.output));

        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        //let ret = run::process_output("which", [cmd_path.to_owned()]);
        //return ret.expect("exit code error.").status.success();

        let mut whichprocop = ProcessOptions::new();
        whichprocop.dir = self.cwdopt.as_ref();

        let mut whichproc = Process::new("which", [cmd_path.to_owned()], whichprocop);
        let mut process = whichproc.unwrap();
	let mut procout = process.finish();
        procout.success()
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);

            //println!("You want to change cwd to {:s}", pstring);

            let npath = Path::new(pstring);

            let mut cpath = self.cwd.clone();
            cpath.push(npath);

            if cpath.exists() {
		let mut cpathforopt = cpath.clone();
		self.cwd = cpath;
		self.cwdopt = Some(cpathforopt);
            } else {
		println("Path does not exist!");
            }

        }
        match self.cwd.as_str() {
	    Some(path_str) => {println!("{:s}", path_str); }
	    None	=> {println("Path not representable as string!"); }
        }
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>Got detecting a trailing & working<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd and Justin Ingram jci5kb
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::os::getcwd;
use extra::getopts;
use std::run::Process;
use std::run::ProcessOutput;
use std::run::ProcessOptions;
use std::option::{Option, None, Some};

struct Shell {
    cmd_prompt: ~str,
    cwd: Path,
    cwdopt: Option<Path>,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cwd: getcwd(),
            cwdopt: Some(getcwd()),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);

            //Let's process the argv

            let endopt = argv.pop_opt();
            let end = match endopt {
		Some(stringy) => { stringy }
		None => { ~"" }
            };

            if end.eq(&~"&") {
		println("Start in a new process" + end);
            } else {
		println("No new process");
		if !end.eq(&~"") {
		    argv.push(end.to_owned());
		}
            }

            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
	    // Old stuff
            // run::process_status(program, argv);

            //println("Run command hit");
            //println(program);

            let mut whichprocop = ProcessOptions::new();
	    whichprocop.dir = self.cwdopt.as_ref();

	    let mut whichproc = Process::new(program, argv, whichprocop);
	    let mut process = whichproc.unwrap();
	    let mut procout = process.finish_with_output();
	    println(std::str::from_utf8(procout.output));

        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        //let ret = run::process_output("which", [cmd_path.to_owned()]);
        //return ret.expect("exit code error.").status.success();
        println("cmd_exists hit");
        let mut whichprocop = ProcessOptions::new();
        whichprocop.dir = self.cwdopt.as_ref();

        let mut whichproc = Process::new("which", [cmd_path.to_owned()], whichprocop);
        let mut process = whichproc.unwrap();
	let mut procout = process.finish();
        procout.success()
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);

            //println!("You want to change cwd to {:s}", pstring);

            let npath = Path::new(pstring);

            let mut cpath = self.cwd.clone();
            cpath.push(npath);

            if cpath.exists() {
		let mut cpathforopt = cpath.clone();
		self.cwd = cpath;
		self.cwdopt = Some(cpathforopt);
            } else {
		println("Path does not exist!");
            }

        }
        match self.cwd.as_str() {
	    Some(path_str) => {println!("{:s}", path_str); }
	    None	=> {println("Path not representable as string!"); }
        }
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

use std::sync::{mpsc, Arc};
use std::thread;
use std::time::Duration;

use grpcio::{ChannelBuilder, Environment};
use kvproto::kvrpcpb::*;
use kvproto::metapb::{Peer, Region};
use kvproto::tikvpb::TikvClient;

use test_raftstore::*;
use tikv_util::HandyRwLock;

fn must_deadlock(client: &TikvClient, ctx: Context, key1: &[u8], ts: u64) {
    let key1 = key1.to_vec();
    let mut key2 = key1.clone();
    key2.push(0);
    must_kv_pessimistic_lock(client, ctx.clone(), key1.clone(), ts);
    must_kv_pessimistic_lock(client, ctx.clone(), key2.clone(), ts + 1);

    let (client_clone, ctx_clone, key1_clone) = (client.clone(), ctx.clone(), key1.clone());
    let (tx, rx) = mpsc::sync_channel(1);
    thread::spawn(move || {
        let _ = kv_pessimistic_lock(
            &client_clone,
            ctx_clone,
            vec![key1_clone],
            ts + 1,
            ts + 1,
            false,
        );
        tx.send(1).unwrap();
    });
    // Sleep to make sure txn(ts+1) is waiting for txn(ts)
    thread::sleep(Duration::from_millis(500));
    let resp = kv_pessimistic_lock(client, ctx.clone(), vec![key2.clone()], ts, ts, false);
    assert_eq!(resp.errors.len(), 1);
    assert!(resp.errors[0].has_deadlock(), "{:?}", resp.get_errors());
    rx.recv().unwrap();

    // Clean up
    must_kv_pessimistic_rollback(client, ctx.clone(), key1, ts);
    must_kv_pessimistic_rollback(client, ctx, key2, ts);
}

fn build_leader_client(cluster: &mut Cluster<ServerCluster>, key: &[u8]) -> (TikvClient, Context) {
    let region_id = cluster.get_region_id(key);
    let leader = cluster.leader_of_region(region_id).unwrap();
    let epoch = cluster.get_region_epoch(region_id);

    let env = Arc::new(Environment::new(1));
    let channel =
        ChannelBuilder::new(env).connect(&cluster.sim.rl().get_addr(leader.get_store_id()));
    let client = TikvClient::new(channel);

    let mut ctx = Context::default();
    ctx.set_region_id(region_id);
    ctx.set_peer(leader);
    ctx.set_region_epoch(epoch);

    (client, ctx)
}

/// Creates a deadlock on the store containing key.
fn must_detect_deadlock(cluster: &mut Cluster<ServerCluster>, key: &[u8], ts: u64) {
    let (client, ctx) = build_leader_client(cluster, key);
    must_deadlock(&client, ctx, key, ts);
}

fn deadlock_detector_leader_must_be(cluster: &mut Cluster<ServerCluster>, store_id: u64) {
    let leader_region = cluster.get_region(b"");
    assert_eq!(
        cluster
            .leader_of_region(leader_region.get_id())
            .unwrap()
            .get_store_id(),
        store_id
    );
    let leader_peer = find_peer_of_store(&leader_region, store_id);
    cluster
        .pd_client
        .region_leader_must_be(leader_region.get_id(), leader_peer);
}

fn must_transfer_leader(cluster: &mut Cluster<ServerCluster>, region_key: &[u8], store_id: u64) {
    let region = cluster.get_region(region_key);
    let target_peer = find_peer_of_store(&region, store_id);
    cluster.must_transfer_leader(region.get_id(), target_peer.clone());
    cluster
        .pd_client
        .region_leader_must_be(region.get_id(), target_peer);
    // Make sure the new leader can get snapshot locally.
    cluster.must_get(region_key);
}

/// Transfers the region containing region_key from source store to target peer.
///
/// REQUIRE: The source store must be the leader the region and the target store must not have
/// this region.
fn must_transfer_region(
    cluster: &mut Cluster<ServerCluster>,
    region_key: &[u8],
    source_store_id: u64,
    target_store_id: u64,
    target_peer_id: u64,
) {
    let target_peer = new_peer(target_store_id, target_peer_id);
    let region = cluster.get_region(region_key);
    cluster
        .pd_client
        .must_add_peer(region.get_id(), target_peer);
    must_transfer_leader(cluster, region_key, target_store_id);
    let source_peer = find_peer_of_store(&region, source_store_id);
    cluster
        .pd_client
        .must_remove_peer(region.get_id(), source_peer);
}

fn must_merge_region(
    cluster: &mut Cluster<ServerCluster>,
    source_region_key: &[u8],
    target_region_key: &[u8],
) {
    let (source_id, target_id) = (
        cluster.get_region(source_region_key).get_id(),
        cluster.get_region(target_region_key).get_id(),
    );
    cluster.pd_client.must_merge(source_id, target_id);
}

fn find_peer_of_store(region: &Region, store_id: u64) -> Peer {
    region
        .get_peers()
        .iter()
        .find(|p| p.get_store_id() == store_id)
        .unwrap()
        .clone()
}

/// Creates a cluster with only one region and store(1) is the leader of the region.
fn new_cluster_for_deadlock_test(count: usize) -> Cluster<ServerCluster> {
    let mut cluster = new_server_cluster(0, count);
    let pd_client = Arc::clone(&cluster.pd_client);
    // Disable default max peer count check.
    pd_client.disable_default_operator();
    // Region 1 has 3 peers. And peer(1, 1) is the leader of region 1.
    let region_id = cluster.run_conf_change();
    pd_client.must_add_peer(region_id, new_peer(2, 2));
    pd_client.must_add_peer(region_id, new_peer(3, 3));
    cluster.must_transfer_leader(region_id, new_peer(1, 1));
    deadlock_detector_leader_must_be(&mut cluster, 1);
    must_detect_deadlock(&mut cluster, b"k", 10);
    cluster
}

#[test]
fn test_detect_deadlock_when_transfer_leader() {
    let mut cluster = new_cluster_for_deadlock_test(3);
    // Transfer the leader of region 1 to store(2).
    // The leader of deadlock detector should also be transfered to store(2).
    must_transfer_leader(&mut cluster, b"", 2);
    deadlock_detector_leader_must_be(&mut cluster, 2);
    must_detect_deadlock(&mut cluster, b"k", 10);
}

#[test]
fn test_detect_deadlock_when_split_region() {
    let mut cluster = new_cluster_for_deadlock_test(3);
    let region = cluster.get_region(b"");
    cluster.must_split(&region, b"k1");
    // After split, the leader is still store(1).
    deadlock_detector_leader_must_be(&mut cluster, 1);
    must_detect_deadlock(&mut cluster, b"k", 10);
    // Transfer the new region's leader to store(2) and deadlock occours on it.
    must_transfer_leader(&mut cluster, b"k1", 2);
    deadlock_detector_leader_must_be(&mut cluster, 1);
    must_detect_deadlock(&mut cluster, b"k1", 10);
}

#[test]
fn test_detect_deadlock_when_transfer_region() {
    let mut cluster = new_cluster_for_deadlock_test(4);
    // Transfer the leader region to store(4) and the leader of deadlock detector should be
    // also transfered.
    must_transfer_region(&mut cluster, b"k", 1, 4, 4);
    deadlock_detector_leader_must_be(&mut cluster, 4);
    must_detect_deadlock(&mut cluster, b"k", 10);

    let region = cluster.get_region(b"");
    cluster.must_split(&region, b"k1");
    // Transfer the new region to store(1). It shouldn't affect deadlock detector.
    must_transfer_region(&mut cluster, b"k1", 4, 1, 5);
    deadlock_detector_leader_must_be(&mut cluster, 4);
    must_detect_deadlock(&mut cluster, b"k", 10);
    must_detect_deadlock(&mut cluster, b"k1", 10);

    // Transfer the new region back to store(4) which will send a role change message with empty
    // key range. It shouldn't affect deadlock detector.
    must_transfer_region(&mut cluster, b"k1", 1, 4, 6);
    deadlock_detector_leader_must_be(&mut cluster, 4);
    must_detect_deadlock(&mut cluster, b"k", 10);
    must_detect_deadlock(&mut cluster, b"k1", 10);
}

#[test]
fn test_detect_deadlock_when_merge_region() {
    let mut cluster = new_cluster_for_deadlock_test(3);

    // Source region will be destroyed.
    for as_target in &[false, true] {
        let region = cluster.get_region(b"");
        cluster.must_split(&region, b"k1");
        if *as_target {
            must_merge_region(&mut cluster, b"k1", b"");
        } else {
            must_merge_region(&mut cluster, b"", b"k1");
        }
        deadlock_detector_leader_must_be(&mut cluster, 1);
        must_detect_deadlock(&mut cluster, b"k", 10);
    }

    // Leaders of two regions are on different store.
    for as_target in &[false, true] {
        let region = cluster.get_region(b"");
        cluster.must_split(&region, b"k1");
        must_transfer_leader(&mut cluster, b"k1", 2);
        if *as_target {
            must_merge_region(&mut cluster, b"k1", b"");
            deadlock_detector_leader_must_be(&mut cluster, 1);
        } else {
            must_merge_region(&mut cluster, b"", b"k1");
            deadlock_detector_leader_must_be(&mut cluster, 2);
        }
        must_detect_deadlock(&mut cluster, b"k", 10);
        must_transfer_leader(&mut cluster, b"", 1);
    }
}
<commit_msg>test: stabilize deadlock tests (#9007)<commit_after>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

use std::sync::Arc;
use std::thread;
use std::time::Duration;

use grpcio::{ChannelBuilder, Environment};
use kvproto::kvrpcpb::*;
use kvproto::metapb::{Peer, Region};
use kvproto::tikvpb::TikvClient;

use test_raftstore::*;
use tikv_util::{config::ReadableDuration, HandyRwLock};

fn deadlock(client: &TikvClient, ctx: Context, key1: &[u8], ts: u64) -> bool {
    let key1 = key1.to_vec();
    let mut key2 = key1.clone();
    key2.push(0);
    must_kv_pessimistic_lock(client, ctx.clone(), key1.clone(), ts);
    must_kv_pessimistic_lock(client, ctx.clone(), key2.clone(), ts + 1);

    let (client_clone, ctx_clone, key1_clone) = (client.clone(), ctx.clone(), key1.clone());
    let handle = thread::spawn(move || {
        let resp = kv_pessimistic_lock(
            &client_clone,
            ctx_clone,
            vec![key1_clone],
            ts + 1,
            ts + 1,
            false,
        );
        assert_eq!(resp.errors.len(), 1);
        assert!(resp.errors[0].has_locked(), "{:?}", resp.errors[0]);
    });
    // Sleep to make sure txn(ts+1) is waiting for txn(ts)
    thread::sleep(Duration::from_millis(100));
    let resp = kv_pessimistic_lock(client, ctx.clone(), vec![key2.clone()], ts, ts, false);
    handle.join().unwrap();

    // Clean up
    must_kv_pessimistic_rollback(client, ctx.clone(), key1, ts);
    must_kv_pessimistic_rollback(client, ctx, key2, ts + 1);

    assert_eq!(resp.errors.len(), 1);
    resp.errors[0].has_deadlock()
}

fn build_leader_client(cluster: &mut Cluster<ServerCluster>, key: &[u8]) -> (TikvClient, Context) {
    let region_id = cluster.get_region_id(key);
    let leader = cluster.leader_of_region(region_id).unwrap();
    let epoch = cluster.get_region_epoch(region_id);

    let env = Arc::new(Environment::new(1));
    let channel =
        ChannelBuilder::new(env).connect(&cluster.sim.rl().get_addr(leader.get_store_id()));
    let client = TikvClient::new(channel);

    let mut ctx = Context::default();
    ctx.set_region_id(region_id);
    ctx.set_peer(leader);
    ctx.set_region_epoch(epoch);

    (client, ctx)
}

/// Creates a deadlock on the store containing key.
fn must_detect_deadlock(cluster: &mut Cluster<ServerCluster>, key: &[u8], ts: u64) {
    // Sometimes, deadlocks can't be detected at once due to leader change, but it will be
    // detected.
    for _ in 0..3 {
        let (client, ctx) = build_leader_client(cluster, key);
        if deadlock(&client, ctx, key, ts) {
            return;
        }
    }
    panic!("failed to detect deadlock");
}

fn deadlock_detector_leader_must_be(cluster: &mut Cluster<ServerCluster>, store_id: u64) {
    let leader_region = cluster.get_region(b"");
    assert_eq!(
        cluster
            .leader_of_region(leader_region.get_id())
            .unwrap()
            .get_store_id(),
        store_id
    );
    let leader_peer = find_peer_of_store(&leader_region, store_id);
    cluster
        .pd_client
        .region_leader_must_be(leader_region.get_id(), leader_peer);
}

fn must_transfer_leader(cluster: &mut Cluster<ServerCluster>, region_key: &[u8], store_id: u64) {
    let region = cluster.get_region(region_key);
    let target_peer = find_peer_of_store(&region, store_id);
    cluster.must_transfer_leader(region.get_id(), target_peer.clone());
    cluster
        .pd_client
        .region_leader_must_be(region.get_id(), target_peer);
    cluster.must_put(region_key, b"v");
}

/// Transfers the region containing region_key from source store to target peer.
///
/// REQUIRE: The source store must be the leader the region and the target store must not have
/// this region.
fn must_transfer_region(
    cluster: &mut Cluster<ServerCluster>,
    region_key: &[u8],
    source_store_id: u64,
    target_store_id: u64,
    target_peer_id: u64,
) {
    let target_peer = new_peer(target_store_id, target_peer_id);
    let region = cluster.get_region(region_key);
    cluster
        .pd_client
        .must_add_peer(region.get_id(), target_peer);
    must_transfer_leader(cluster, region_key, target_store_id);
    let source_peer = find_peer_of_store(&region, source_store_id);
    cluster
        .pd_client
        .must_remove_peer(region.get_id(), source_peer);
    cluster.must_put(region_key, b"v");
}

fn must_split_region(cluster: &mut Cluster<ServerCluster>, region_key: &[u8], split_key: &[u8]) {
    let region = cluster.get_region(region_key);
    cluster.must_split(&region, split_key);
    cluster.must_put(split_key, b"v");
}

fn must_merge_region(
    cluster: &mut Cluster<ServerCluster>,
    source_region_key: &[u8],
    target_region_key: &[u8],
) {
    let (source_id, target_id) = (
        cluster.get_region(source_region_key).get_id(),
        cluster.get_region(target_region_key).get_id(),
    );
    cluster.pd_client.must_merge(source_id, target_id);
    cluster.must_put(target_region_key, b"v");
}

fn find_peer_of_store(region: &Region, store_id: u64) -> Peer {
    region
        .get_peers()
        .iter()
        .find(|p| p.get_store_id() == store_id)
        .unwrap()
        .clone()
}

/// Creates a cluster with only one region and store(1) is the leader of the region.
fn new_cluster_for_deadlock_test(count: usize) -> Cluster<ServerCluster> {
    let mut cluster = new_server_cluster(0, count);
    cluster.cfg.pessimistic_txn.wait_for_lock_timeout = ReadableDuration::millis(500);
    cluster.cfg.pessimistic_txn.pipelined = false;
    let pd_client = Arc::clone(&cluster.pd_client);
    // Disable default max peer count check.
    pd_client.disable_default_operator();
    // Region 1 has 3 peers. And peer(1, 1) is the leader of region 1.
    let region_id = cluster.run_conf_change();
    pd_client.must_add_peer(region_id, new_peer(2, 2));
    pd_client.must_add_peer(region_id, new_peer(3, 3));
    cluster.must_transfer_leader(region_id, new_peer(1, 1));
    cluster.must_put(b"a", b"a");
    deadlock_detector_leader_must_be(&mut cluster, 1);
    must_detect_deadlock(&mut cluster, b"k", 10);
    cluster
}

#[test]
fn test_detect_deadlock_when_transfer_leader() {
    let mut cluster = new_cluster_for_deadlock_test(3);
    // Transfer the leader of region 1 to store(2).
    // The leader of deadlock detector should also be transfered to store(2).
    must_transfer_leader(&mut cluster, b"", 2);
    deadlock_detector_leader_must_be(&mut cluster, 2);
    must_detect_deadlock(&mut cluster, b"k", 10);
}

#[test]
fn test_detect_deadlock_when_split_region() {
    let mut cluster = new_cluster_for_deadlock_test(3);
    must_split_region(&mut cluster, b"", b"k1");
    // After split, the leader is still store(1).
    deadlock_detector_leader_must_be(&mut cluster, 1);
    must_detect_deadlock(&mut cluster, b"k", 10);
    // Transfer the new region's leader to store(2) and deadlock occours on it.
    must_transfer_leader(&mut cluster, b"k1", 2);
    deadlock_detector_leader_must_be(&mut cluster, 1);
    must_detect_deadlock(&mut cluster, b"k1", 10);
}

#[test]
fn test_detect_deadlock_when_transfer_region() {
    let mut cluster = new_cluster_for_deadlock_test(4);
    // Transfer the leader region to store(4) and the leader of deadlock detector should be
    // also transfered.
    must_transfer_region(&mut cluster, b"k", 1, 4, 4);
    deadlock_detector_leader_must_be(&mut cluster, 4);
    must_detect_deadlock(&mut cluster, b"k", 10);

    must_split_region(&mut cluster, b"", b"k1");
    // Transfer the new region to store(1). It shouldn't affect deadlock detector.
    must_transfer_region(&mut cluster, b"k1", 4, 1, 5);
    deadlock_detector_leader_must_be(&mut cluster, 4);
    must_detect_deadlock(&mut cluster, b"k", 10);
    must_detect_deadlock(&mut cluster, b"k1", 10);

    // Transfer the new region back to store(4) which will send a role change message with empty
    // key range. It shouldn't affect deadlock detector.
    must_transfer_region(&mut cluster, b"k1", 1, 4, 6);
    deadlock_detector_leader_must_be(&mut cluster, 4);
    must_detect_deadlock(&mut cluster, b"k", 10);
    must_detect_deadlock(&mut cluster, b"k1", 10);
}

#[test]
fn test_detect_deadlock_when_merge_region() {
    let mut cluster = new_cluster_for_deadlock_test(3);

    // Source region will be destroyed.
    for as_target in &[false, true] {
        must_split_region(&mut cluster, b"", b"k1");
        if *as_target {
            must_merge_region(&mut cluster, b"k1", b"");
        } else {
            must_merge_region(&mut cluster, b"", b"k1");
        }
        deadlock_detector_leader_must_be(&mut cluster, 1);
        must_detect_deadlock(&mut cluster, b"k", 10);
    }

    // Leaders of two regions are on different store.
    for as_target in &[false, true] {
        must_split_region(&mut cluster, b"", b"k1");
        must_transfer_leader(&mut cluster, b"k1", 2);
        if *as_target {
            must_merge_region(&mut cluster, b"k1", b"");
            deadlock_detector_leader_must_be(&mut cluster, 1);
        } else {
            must_merge_region(&mut cluster, b"", b"k1");
            deadlock_detector_leader_must_be(&mut cluster, 2);
        }
        must_detect_deadlock(&mut cluster, b"k", 10);
        must_transfer_leader(&mut cluster, b"", 1);
    }
}
<|endoftext|>