<commit_before>use reqwest;
use std::error::Error as StdError;
use std::io;
use std::string::FromUtf8Error;
use toml::de::Error as TomlDeserializeError;

/// The error type for the program's every operations, such as TOML Parsing
/// or IO-related errors. Wherever there's an error, it _should_ be wrapped
/// into this type.
#[derive(Debug)]
pub enum PackageError {
    Download(String),
    Parsing(String),
    Utf8(String),
    IO(String),
}

impl From<io::Error> for PackageError {
    /// Converts an `io::Error` into this type.
    fn from(err: io::Error) -> Self {
        PackageError::IO(String::from("An IO error occured:") + err.description())
    }
}

impl From<TomlDeserializeError> for PackageError {
    /// Converts a `toml::de:Error` into this type.
    fn from(err: TomlDeserializeError) -> Self {
        let err_location =
            err
                // Get the position of the error
                .line_col()
                // If it's not available, return a empty string.
                // If it is, then convert the position into a string.
                .map_or(String::from(""), |(line, col)| {
                    format!("in Line: {}, Col: {}",
                        line,
                        col
                    )
                });

        let err_description = err.description();

        PackageError::Parsing(
            format!(
                "An error occured while parsing a TOML, {} due to: {}.",
                err_location,
                err_description
            )
        )
    }
}

impl From<reqwest::Error> for PackageError {
    fn from(err: reqwest::Error) -> PackageError {
        let related_url =
            err
                // Try to retrieve the final stop if an error occured.
                .url()
                // If there's none, return "none"
                .map_or("none", |url| {
                    url.as_str()
                });

        let status_code =
            &err
                // Try to retrieve the status code if the error was generated
                // from an response.
                .status()
                // If there's none, return "none"
                .map_or(String::from("none"), |code| {
                    code.as_u16().to_string()
                });

        PackageError::Download(
            String::new() +
            "related url:           " + related_url +
            "http related:          " + &err.is_http().to_string() +
            "serialization related: " + &err.is_serialization().to_string() +
            "redirect related:      " + &err.is_redirect().to_string() +
            "client related:        " + &err.is_client_error().to_string() +
            "server related:        " + &err.is_server_error().to_string() +
            "status code:           " + status_code +
            "other messages:        " + err.description()
        )
    }
}

impl From<FromUtf8Error> for PackageError {
    fn from(err: FromUtf8Error) -> Self {
        let utf8_error = err.utf8_error();
        let errored_bytes =
            err
            // Gets the invalid bytes of the string
            .as_bytes()
            // Convert the bytes into an iterator.
            .iter()
            // Reduce the array of bytes into a string.
            // Example output: `152, 84, 156, 78`
            .fold(String::from(""), |acc, cur| {
                acc + ", " + &cur.to_string()
            });

        PackageError::Utf8(
            String::new() +
            "description:         " + err.description() +
            "further description: " + utf8_error.description() +
            "bytes valid up to:   " + &utf8_error.valid_up_to().to_string() +
            "invalid bytes:       " + &errored_bytes
        )
    }
}<commit_msg>Error handling for TOML serialize errors<commit_after>use reqwest;
use std::error::Error as StdError;
use std::io;
use std::string::FromUtf8Error;
use toml::de::Error as TomlDeserializeError;
use toml::ser::Error as TomlSerializeError;

/// The error type for the program's every operations, such as TOML Parsing
/// or IO-related errors. Wherever there's an error, it _should_ be wrapped
/// into this type.
#[derive(Debug)]
pub enum PackageError {
    Download(String),
    Parsing(String),
    Utf8(String),
    IO(String),
}

impl From<io::Error> for PackageError {
    /// Converts an `io::Error` into this type.
    fn from(err: io::Error) -> Self {
        PackageError::IO(String::from("An IO error occured:") + err.description())
    }
}

impl From<TomlDeserializeError> for PackageError {
    /// Converts a `toml::de:Error` into this type.
    fn from(err: TomlDeserializeError) -> Self {
        let err_location =
            err
                // Get the position of the error
                .line_col()
                // If it's not available, return a empty string.
                // If it is, then convert the position into a string.
                .map_or(String::from(""), |(line, col)| {
                    format!("in Line: {}, Col: {}",
                        line,
                        col
                    )
                });

        let err_description = err.description();

        PackageError::Parsing(
            format!(
                "An error occured while parsing a TOML, {} due to: {}.",
                err_location,
                err_description
            )
        )
    }
}

impl From<TomlSerializeError> for PackageError {
    /// Converts a `toml::de:Error` into this type.
    fn from(err: TomlSerializeError) -> Self {
        PackageError::Parsing(
            String::from("TOML serialize error:") +
            err.description()
        )
    }
}

impl From<reqwest::Error> for PackageError {
    fn from(err: reqwest::Error) -> PackageError {
        let related_url =
            err
                // Try to retrieve the final stop if an error occured.
                .url()
                // If there's none, return "none"
                .map_or("none", |url| {
                    url.as_str()
                });

        let status_code =
            &err
                // Try to retrieve the status code if the error was generated
                // from an response.
                .status()
                // If there's none, return "none"
                .map_or(String::from("none"), |code| {
                    code.as_u16().to_string()
                });

        PackageError::Download(
            String::new() +
            "related url:           " + related_url +
            "http related:          " + &err.is_http().to_string() +
            "serialization related: " + &err.is_serialization().to_string() +
            "redirect related:      " + &err.is_redirect().to_string() +
            "client related:        " + &err.is_client_error().to_string() +
            "server related:        " + &err.is_server_error().to_string() +
            "status code:           " + status_code +
            "other messages:        " + err.description()
        )
    }
}

impl From<FromUtf8Error> for PackageError {
    fn from(err: FromUtf8Error) -> Self {
        let utf8_error = err.utf8_error();
        let errored_bytes =
            err
            // Gets the invalid bytes of the string
            .as_bytes()
            // Convert the bytes into an iterator.
            .iter()
            // Reduce the array of bytes into a string.
            // Example output: `152, 84, 156, 78`
            .fold(String::from(""), |acc, cur| {
                acc + ", " + &cur.to_string()
            });

        PackageError::Utf8(
            String::new() +
            "description:         " + err.description() +
            "further description: " + utf8_error.description() +
            "bytes valid up to:   " + &utf8_error.valid_up_to().to_string() +
            "invalid bytes:       " + &errored_bytes
        )
    }
}<|endoftext|>


<commit_before>//! The `event` module contains traits and structs to actually run your game mainloop
//! and handle top-level state, as well as handle input events such as keyboard
//! and mouse.
//!
//! If you don't want to use `ggez`'s built in event loop, you can
//! write your own mainloop and check for events on your own.  This is
//! not particularly hard, there's nothing special about the
//! `EventHandler` trait.  It just tries to simplify the process a
//! little.  For examples of how to write your own main loop, see the
//! source code for this module, or the [`eventloop`
//! example](https://github.com/ggez/ggez/blob/master/examples/eventloop.rs).

use winit::{self, dpi};

/// A mouse button.
pub use winit::event::MouseButton;

/// An analog axis of some device (gamepad thumbstick, joystick...).
pub use gilrs::Axis;
/// A button of some device (gamepad, joystick...).
pub use gilrs::Button;

/// `winit` events; nested in a module for re-export neatness.
pub mod winit_event {
    pub use super::winit::event::{
        DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, MouseScrollDelta,
        TouchPhase, WindowEvent,
    };
}
pub use crate::input::gamepad::GamepadId;
pub use crate::input::keyboard::{KeyCode, KeyMods};

use self::winit_event::*;
/// `winit` event loop.
pub use winit::event_loop::{ControlFlow, EventLoop};

use crate::context::Context;
use crate::error::GameResult;

/// A trait defining event callbacks.  This is your primary interface with
/// `ggez`'s event loop.  Implement this trait for a type and
/// override at least the [`update()`](#tymethod.update) and
/// [`draw()`](#tymethod.draw) methods, then pass it to
/// [`event::run()`](fn.run.html) to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// [`key_down_event()`](#tymethod.key_down_event), which will by
/// default exit the game if the escape key is pressed.  Just
/// override the methods you want to use.
pub trait EventHandler {
    /// Called upon each logic update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self, _ctx: &mut Context) -> GameResult;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// [`graphics::clear()`](../graphics/fn.clear.html) and end it
    /// with [`graphics::present()`](../graphics/fn.present.html) and
    /// maybe [`timer::yield_now()`](../timer/fn.yield_now.html).
    fn draw(&mut self, _ctx: &mut Context) -> GameResult;

    /// A mouse button was pressed
    fn mouse_button_down_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// A mouse button was released
    fn mouse_button_up_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// The mouse was moved; it provides both absolute x and y coordinates in the window,
    /// and relative x and y coordinates compared to its last position.
    fn mouse_motion_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32, _dx: f32, _dy: f32) {}

    /// mouse entered or left window area
    fn mouse_enter_or_leave(&mut self, _ctx: &mut Context, _entered: bool) {}

    /// The mousewheel was scrolled, vertically (y, positive away from and negative toward the user)
    /// or horizontally (x, positive to the right and negative to the left).
    fn mouse_wheel_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32) {}

    /// A keyboard button was pressed.
    ///
    /// The default implementation of this will call `ggez::event::quit()`
    /// when the escape key is pressed.  If you override this with
    /// your own event handler you have to re-implment that
    /// functionality yourself.
    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: KeyCode,
        _keymods: KeyMods,
        _repeat: bool,
    ) {
        if keycode == KeyCode::Escape {
            quit(ctx);
        }
    }

    /// A keyboard button was released.
    fn key_up_event(&mut self, _ctx: &mut Context, _keycode: KeyCode, _keymods: KeyMods) {}

    /// A unicode character was received, usually from keyboard input.
    /// This is the intended way of facilitating text input.
    fn text_input_event(&mut self, _ctx: &mut Context, _character: char) {}

    /// A gamepad button was pressed; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_button_down_event(&mut self, _ctx: &mut Context, _btn: Button, _id: GamepadId) {}

    /// A gamepad button was released; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_button_up_event(&mut self, _ctx: &mut Context, _btn: Button, _id: GamepadId) {}

    /// A gamepad axis moved; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_axis_event(&mut self, _ctx: &mut Context, _axis: Axis, _value: f32, _id: GamepadId) {
    }

    /// Called when the window is shown or hidden.
    fn focus_event(&mut self, _ctx: &mut Context, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit (the quit event is cancelled).
    fn quit_event(&mut self, _ctx: &mut Context) -> bool {
        debug!("quit_event() callback called, quitting...");
        false
    }

    /// Called when the user resizes the window, or when it is resized
    /// via [`graphics::set_mode()`](../graphics/fn.set_mode.html).
    fn resize_event(&mut self, _ctx: &mut Context, _width: f32, _height: f32) {}
}

/// Terminates the [`ggez::event::run()`](fn.run.html) loop by setting
/// [`Context.continuing`](struct.Context.html#structfield.continuing)
/// to `false`.
pub fn quit(ctx: &mut Context) {
    ctx.continuing = false;
}

/// Runs the game's main loop, calling event callbacks on the given state
/// object as events occur.
///
/// It does not try to do any type of framerate limiting.  See the
/// documentation for the [`timer`](../timer/index.html) module for more info.
pub fn run<S: 'static>(mut ctx: Context, event_loop: EventLoop<()>, mut state: S) -> !
where
    S: EventHandler,
{
    use crate::input::{keyboard, mouse};

    event_loop.run(move |mut event, _, control_flow| {
        if !ctx.continuing {
            *control_flow = ControlFlow::Exit;
            return;
        }

        *control_flow = ControlFlow::Poll;

        let ctx = &mut ctx;
        let state = &mut state;

        process_event(ctx, &mut event);
        match event {
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::Resized(logical_size) => {
                    // let actual_size = logical_size;
                    state.resize_event(ctx, logical_size.width as f32, logical_size.height as f32);
                }
                WindowEvent::CloseRequested => {
                    if !state.quit_event(ctx) {
                        quit(ctx);
                    }
                }
                WindowEvent::Focused(gained) => {
                    state.focus_event(ctx, gained);
                }
                WindowEvent::ReceivedCharacter(ch) => {
                    state.text_input_event(ctx, ch);
                }
                WindowEvent::ModifiersChanged(mods) => {
                    ctx.keyboard_context.set_modifiers(KeyMods::from(mods))
                }
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            state: ElementState::Pressed,
                            virtual_keycode: Some(keycode),
                            ..
                        },
                    ..
                } => {
                    let repeat = keyboard::is_key_repeated(ctx);
                    state.key_down_event(ctx, keycode, ctx.keyboard_context.active_mods(), repeat);
                }
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            state: ElementState::Released,
                            virtual_keycode: Some(keycode),
                            ..
                        },
                    ..
                } => {
                    state.key_up_event(ctx, keycode, ctx.keyboard_context.active_mods());
                }
                WindowEvent::MouseWheel { delta, .. } => {
                    let (x, y) = match delta {
                        MouseScrollDelta::LineDelta(x, y) => (x, y),
                        MouseScrollDelta::PixelDelta(pos) => {
                            let scale_factor = ctx.gfx_context.window.window().scale_factor();
                            let dpi::LogicalPosition { x, y } = pos.to_logical::<f32>(scale_factor);
                            (x, y)
                        }
                    };
                    state.mouse_wheel_event(ctx, x, y);
                }
                WindowEvent::MouseInput {
                    state: element_state,
                    button,
                    ..
                } => {
                    let position = mouse::position(ctx);
                    match element_state {
                        ElementState::Pressed => {
                            state.mouse_button_down_event(ctx, button, position.x, position.y)
                        }
                        ElementState::Released => {
                            state.mouse_button_up_event(ctx, button, position.x, position.y)
                        }
                    }
                }
                WindowEvent::CursorMoved { .. } => {
                    let position = mouse::position(ctx);
                    let delta = mouse::delta(ctx);
                    state.mouse_motion_event(ctx, position.x, position.y, delta.x, delta.y);
                }
                _x => {
                    // trace!("ignoring window event {:?}", x);
                }
            },
            Event::DeviceEvent { .. } => (),
            Event::Resumed => (),
            Event::Suspended => (),
            Event::NewEvents(_) => (),
            Event::UserEvent(_) => (),
            Event::MainEventsCleared => {
                // If you are writing your own event loop, make sure
                // you include `timer_context.tick()` and
                // `ctx.process_event()` calls.  These update ggez's
                // internal state however necessary.
                ctx.timer_context.tick();

                // Handle gamepad events if necessary.
                if ctx.conf.modules.gamepad {
                    while let Some(gilrs::Event { id, event, .. }) =
                        ctx.gamepad_context.next_event()
                    {
                        match event {
                            gilrs::EventType::ButtonPressed(button, _) => {
                                state.gamepad_button_down_event(ctx, button, GamepadId(id));
                            }
                            gilrs::EventType::ButtonReleased(button, _) => {
                                state.gamepad_button_up_event(ctx, button, GamepadId(id));
                            }
                            gilrs::EventType::AxisChanged(axis, value, _) => {
                                state.gamepad_axis_event(ctx, axis, value, GamepadId(id));
                            }
                            _ => {}
                        }
                    }
                }

                if let Err(e) = state.update(ctx) {
                    error!("Error on EventHandler::update(): {:?}", e);
                    eprintln!("Error on EventHandler::update(): {:?}", e);
                    *control_flow = ControlFlow::Exit;
                    return;
                }

                if let Err(e) = state.draw(ctx) {
                    error!("Error on EventHandler::draw(): {:?}", e);
                    eprintln!("Error on EventHandler::draw(): {:?}", e);
                    *control_flow = ControlFlow::Exit;
                    return;
                }
            }
            Event::RedrawRequested(_) => (),
            Event::RedrawEventsCleared => (),
            Event::LoopDestroyed => (),
        }
    })
}

/// Feeds an `Event` into the `Context` so it can update any internal
/// state it needs to, such as detecting window resizes.  If you are
/// rolling your own event loop, you should call this on the events
/// you receive before processing them yourself.
pub fn process_event(ctx: &mut Context, event: &mut winit::event::Event<()>) {
    match event {
        winit_event::Event::WindowEvent { event, .. } => match event {
            winit_event::WindowEvent::Resized(physical_size) => {
                ctx.gfx_context.window.resize(*physical_size);
                ctx.gfx_context.resize_viewport();
            }
            winit_event::WindowEvent::CursorMoved {
                position: logical_position,
                ..
            } => {
                ctx.mouse_context
                    .set_last_position(crate::graphics::Point2::new(
                        logical_position.x as f32,
                        logical_position.y as f32,
                    ));
            }
            winit_event::WindowEvent::MouseInput { button, state, .. } => {
                let pressed = match state {
                    winit_event::ElementState::Pressed => true,
                    winit_event::ElementState::Released => false,
                };
                ctx.mouse_context.set_button(*button, pressed);
            }
            winit_event::WindowEvent::ModifiersChanged(mods) => ctx
                .keyboard_context
                .set_modifiers(crate::input::keyboard::KeyMods::from(*mods)),
            winit_event::WindowEvent::KeyboardInput {
                input:
                    winit::event::KeyboardInput {
                        state,
                        virtual_keycode: Some(keycode),
                        ..
                    },
                ..
            } => {
                let pressed = match state {
                    winit_event::ElementState::Pressed => true,
                    winit_event::ElementState::Released => false,
                };
                ctx.keyboard_context.set_key(*keycode, pressed);
            }
            winit_event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
                // actively set the new_inner_size to be the current inner size
                // to stop winit from resizing our window
                **new_inner_size = ctx.gfx_context.window.window().inner_size();
            }
            _ => (),
        },
        winit_event::Event::DeviceEvent {
            event: winit_event::DeviceEvent::MouseMotion { delta: (x, y) },
            ..
        } => ctx
            .mouse_context
            .set_last_delta(crate::graphics::Point2::new(*x as f32, *y as f32)),

        _ => (),
    };
}
<commit_msg>set new_inner_size to the value provided my the current window_mode;<commit_after>//! The `event` module contains traits and structs to actually run your game mainloop
//! and handle top-level state, as well as handle input events such as keyboard
//! and mouse.
//!
//! If you don't want to use `ggez`'s built in event loop, you can
//! write your own mainloop and check for events on your own.  This is
//! not particularly hard, there's nothing special about the
//! `EventHandler` trait.  It just tries to simplify the process a
//! little.  For examples of how to write your own main loop, see the
//! source code for this module, or the [`eventloop`
//! example](https://github.com/ggez/ggez/blob/master/examples/eventloop.rs).

use winit::{self, dpi};

/// A mouse button.
pub use winit::event::MouseButton;

/// An analog axis of some device (gamepad thumbstick, joystick...).
pub use gilrs::Axis;
/// A button of some device (gamepad, joystick...).
pub use gilrs::Button;

/// `winit` events; nested in a module for re-export neatness.
pub mod winit_event {
    pub use super::winit::event::{
        DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, MouseScrollDelta,
        TouchPhase, WindowEvent,
    };
}
pub use crate::input::gamepad::GamepadId;
pub use crate::input::keyboard::{KeyCode, KeyMods};

use self::winit_event::*;
/// `winit` event loop.
pub use winit::event_loop::{ControlFlow, EventLoop};

use crate::context::Context;
use crate::error::GameResult;

/// A trait defining event callbacks.  This is your primary interface with
/// `ggez`'s event loop.  Implement this trait for a type and
/// override at least the [`update()`](#tymethod.update) and
/// [`draw()`](#tymethod.draw) methods, then pass it to
/// [`event::run()`](fn.run.html) to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// [`key_down_event()`](#tymethod.key_down_event), which will by
/// default exit the game if the escape key is pressed.  Just
/// override the methods you want to use.
pub trait EventHandler {
    /// Called upon each logic update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self, _ctx: &mut Context) -> GameResult;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// [`graphics::clear()`](../graphics/fn.clear.html) and end it
    /// with [`graphics::present()`](../graphics/fn.present.html) and
    /// maybe [`timer::yield_now()`](../timer/fn.yield_now.html).
    fn draw(&mut self, _ctx: &mut Context) -> GameResult;

    /// A mouse button was pressed
    fn mouse_button_down_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// A mouse button was released
    fn mouse_button_up_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// The mouse was moved; it provides both absolute x and y coordinates in the window,
    /// and relative x and y coordinates compared to its last position.
    fn mouse_motion_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32, _dx: f32, _dy: f32) {}

    /// mouse entered or left window area
    fn mouse_enter_or_leave(&mut self, _ctx: &mut Context, _entered: bool) {}

    /// The mousewheel was scrolled, vertically (y, positive away from and negative toward the user)
    /// or horizontally (x, positive to the right and negative to the left).
    fn mouse_wheel_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32) {}

    /// A keyboard button was pressed.
    ///
    /// The default implementation of this will call `ggez::event::quit()`
    /// when the escape key is pressed.  If you override this with
    /// your own event handler you have to re-implment that
    /// functionality yourself.
    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: KeyCode,
        _keymods: KeyMods,
        _repeat: bool,
    ) {
        if keycode == KeyCode::Escape {
            quit(ctx);
        }
    }

    /// A keyboard button was released.
    fn key_up_event(&mut self, _ctx: &mut Context, _keycode: KeyCode, _keymods: KeyMods) {}

    /// A unicode character was received, usually from keyboard input.
    /// This is the intended way of facilitating text input.
    fn text_input_event(&mut self, _ctx: &mut Context, _character: char) {}

    /// A gamepad button was pressed; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_button_down_event(&mut self, _ctx: &mut Context, _btn: Button, _id: GamepadId) {}

    /// A gamepad button was released; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_button_up_event(&mut self, _ctx: &mut Context, _btn: Button, _id: GamepadId) {}

    /// A gamepad axis moved; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_axis_event(&mut self, _ctx: &mut Context, _axis: Axis, _value: f32, _id: GamepadId) {
    }

    /// Called when the window is shown or hidden.
    fn focus_event(&mut self, _ctx: &mut Context, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit (the quit event is cancelled).
    fn quit_event(&mut self, _ctx: &mut Context) -> bool {
        debug!("quit_event() callback called, quitting...");
        false
    }

    /// Called when the user resizes the window, or when it is resized
    /// via [`graphics::set_mode()`](../graphics/fn.set_mode.html).
    fn resize_event(&mut self, _ctx: &mut Context, _width: f32, _height: f32) {}
}

/// Terminates the [`ggez::event::run()`](fn.run.html) loop by setting
/// [`Context.continuing`](struct.Context.html#structfield.continuing)
/// to `false`.
pub fn quit(ctx: &mut Context) {
    ctx.continuing = false;
}

/// Runs the game's main loop, calling event callbacks on the given state
/// object as events occur.
///
/// It does not try to do any type of framerate limiting.  See the
/// documentation for the [`timer`](../timer/index.html) module for more info.
pub fn run<S: 'static>(mut ctx: Context, event_loop: EventLoop<()>, mut state: S) -> !
where
    S: EventHandler,
{
    use crate::input::{keyboard, mouse};

    event_loop.run(move |mut event, _, control_flow| {
        if !ctx.continuing {
            *control_flow = ControlFlow::Exit;
            return;
        }

        *control_flow = ControlFlow::Poll;

        let ctx = &mut ctx;
        let state = &mut state;

        process_event(ctx, &mut event);
        match event {
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::Resized(logical_size) => {
                    // let actual_size = logical_size;
                    state.resize_event(ctx, logical_size.width as f32, logical_size.height as f32);
                }
                WindowEvent::CloseRequested => {
                    if !state.quit_event(ctx) {
                        quit(ctx);
                    }
                }
                WindowEvent::Focused(gained) => {
                    state.focus_event(ctx, gained);
                }
                WindowEvent::ReceivedCharacter(ch) => {
                    state.text_input_event(ctx, ch);
                }
                WindowEvent::ModifiersChanged(mods) => {
                    ctx.keyboard_context.set_modifiers(KeyMods::from(mods))
                }
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            state: ElementState::Pressed,
                            virtual_keycode: Some(keycode),
                            ..
                        },
                    ..
                } => {
                    let repeat = keyboard::is_key_repeated(ctx);
                    state.key_down_event(ctx, keycode, ctx.keyboard_context.active_mods(), repeat);
                }
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            state: ElementState::Released,
                            virtual_keycode: Some(keycode),
                            ..
                        },
                    ..
                } => {
                    state.key_up_event(ctx, keycode, ctx.keyboard_context.active_mods());
                }
                WindowEvent::MouseWheel { delta, .. } => {
                    let (x, y) = match delta {
                        MouseScrollDelta::LineDelta(x, y) => (x, y),
                        MouseScrollDelta::PixelDelta(pos) => {
                            let scale_factor = ctx.gfx_context.window.window().scale_factor();
                            let dpi::LogicalPosition { x, y } = pos.to_logical::<f32>(scale_factor);
                            (x, y)
                        }
                    };
                    state.mouse_wheel_event(ctx, x, y);
                }
                WindowEvent::MouseInput {
                    state: element_state,
                    button,
                    ..
                } => {
                    let position = mouse::position(ctx);
                    match element_state {
                        ElementState::Pressed => {
                            state.mouse_button_down_event(ctx, button, position.x, position.y)
                        }
                        ElementState::Released => {
                            state.mouse_button_up_event(ctx, button, position.x, position.y)
                        }
                    }
                }
                WindowEvent::CursorMoved { .. } => {
                    let position = mouse::position(ctx);
                    let delta = mouse::delta(ctx);
                    state.mouse_motion_event(ctx, position.x, position.y, delta.x, delta.y);
                }
                _x => {
                    // trace!("ignoring window event {:?}", x);
                }
            },
            Event::DeviceEvent { .. } => (),
            Event::Resumed => (),
            Event::Suspended => (),
            Event::NewEvents(_) => (),
            Event::UserEvent(_) => (),
            Event::MainEventsCleared => {
                // If you are writing your own event loop, make sure
                // you include `timer_context.tick()` and
                // `ctx.process_event()` calls.  These update ggez's
                // internal state however necessary.
                ctx.timer_context.tick();

                // Handle gamepad events if necessary.
                if ctx.conf.modules.gamepad {
                    while let Some(gilrs::Event { id, event, .. }) =
                        ctx.gamepad_context.next_event()
                    {
                        match event {
                            gilrs::EventType::ButtonPressed(button, _) => {
                                state.gamepad_button_down_event(ctx, button, GamepadId(id));
                            }
                            gilrs::EventType::ButtonReleased(button, _) => {
                                state.gamepad_button_up_event(ctx, button, GamepadId(id));
                            }
                            gilrs::EventType::AxisChanged(axis, value, _) => {
                                state.gamepad_axis_event(ctx, axis, value, GamepadId(id));
                            }
                            _ => {}
                        }
                    }
                }

                if let Err(e) = state.update(ctx) {
                    error!("Error on EventHandler::update(): {:?}", e);
                    eprintln!("Error on EventHandler::update(): {:?}", e);
                    *control_flow = ControlFlow::Exit;
                    return;
                }

                if let Err(e) = state.draw(ctx) {
                    error!("Error on EventHandler::draw(): {:?}", e);
                    eprintln!("Error on EventHandler::draw(): {:?}", e);
                    *control_flow = ControlFlow::Exit;
                    return;
                }
            }
            Event::RedrawRequested(_) => (),
            Event::RedrawEventsCleared => (),
            Event::LoopDestroyed => (),
        }
    })
}

/// Feeds an `Event` into the `Context` so it can update any internal
/// state it needs to, such as detecting window resizes.  If you are
/// rolling your own event loop, you should call this on the events
/// you receive before processing them yourself.
pub fn process_event(ctx: &mut Context, event: &mut winit::event::Event<()>) {
    match event {
        winit_event::Event::WindowEvent { event, .. } => match event {
            winit_event::WindowEvent::Resized(physical_size) => {
                ctx.gfx_context.window.resize(*physical_size);
                ctx.gfx_context.resize_viewport();
            }
            winit_event::WindowEvent::CursorMoved {
                position: logical_position,
                ..
            } => {
                ctx.mouse_context
                    .set_last_position(crate::graphics::Point2::new(
                        logical_position.x as f32,
                        logical_position.y as f32,
                    ));
            }
            winit_event::WindowEvent::MouseInput { button, state, .. } => {
                let pressed = match state {
                    winit_event::ElementState::Pressed => true,
                    winit_event::ElementState::Released => false,
                };
                ctx.mouse_context.set_button(*button, pressed);
            }
            winit_event::WindowEvent::ModifiersChanged(mods) => ctx
                .keyboard_context
                .set_modifiers(crate::input::keyboard::KeyMods::from(*mods)),
            winit_event::WindowEvent::KeyboardInput {
                input:
                    winit::event::KeyboardInput {
                        state,
                        virtual_keycode: Some(keycode),
                        ..
                    },
                ..
            } => {
                let pressed = match state {
                    winit_event::ElementState::Pressed => true,
                    winit_event::ElementState::Released => false,
                };
                ctx.keyboard_context.set_key(*keycode, pressed);
            }
            winit_event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
                // actively set the new_inner_size to be the desired size
                // to stop winit from resizing our window
                **new_inner_size = winit::dpi::PhysicalSize::<u32>::from([
                    ctx.conf.window_mode.width,
                    ctx.conf.window_mode.height,
                ]);
            }
            _ => (),
        },
        winit_event::Event::DeviceEvent {
            event: winit_event::DeviceEvent::MouseMotion { delta: (x, y) },
            ..
        } => ctx
            .mouse_context
            .set_last_delta(crate::graphics::Point2::new(*x as f32, *y as f32)),

        _ => (),
    };
}
<|endoftext|>


<commit_before>use crate::algorithm::AlgorithmType;
use base64::DecodeError;
use crypto_mac::MacError;
use serde_json::Error as JsonError;
use std::fmt;
use std::string::FromUtf8Error;

#[derive(Debug)]
pub enum Error {
    AlgorithmMismatch(AlgorithmType, AlgorithmType),
    NoKeyId,
    NoKeyWithKeyId(String),
    Format,
    Base64(DecodeError),
    Json(JsonError),
    Utf8(FromUtf8Error),
    RustCryptoMac(MacError),
    #[cfg(feature = "openssl")]
    OpenSsl(openssl::error::ErrorStack),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::AlgorithmMismatch(a, b) => {
                write!(f, "Expected algorithm type {:?} but found {:?}", a, b)
            }
            Error::NoKeyId => write!(f, "No key id found"),
            Error::NoKeyWithKeyId(ref kid) => write!(f, "Key with key id {} not found", kid),
            Error::Format => write!(f, "Format"),
            Error::Base64(ref x) => write!(f, "{}", x),
            Error::Json(ref x) => write!(f, "{}", x),
            Error::Utf8(ref x) => write!(f, "{}", x),
            Error::RustCryptoMac(ref x) => write!(f, "{}", x),
            #[cfg(feature = "openssl")]
            Error::OpenSsl(ref x) => write!(f, "{}", x),
        }
    }
}

macro_rules! error_wrap {
    ($f: ty, $e: expr) => {
        impl From<$f> for Error {
            fn from(f: $f) -> Error {
                $e(f)
            }
        }
    };
}

error_wrap!(DecodeError, Error::Base64);
error_wrap!(JsonError, Error::Json);
error_wrap!(FromUtf8Error, Error::Utf8);
error_wrap!(MacError, Error::RustCryptoMac);
#[cfg(feature = "openssl")]
error_wrap!(openssl::error::ErrorStack, Error::OpenSsl);

#[cfg(test)]
pub(crate) mod tests {
    #[derive(Debug)]
    pub enum TestError {
        LibError(super::Error),
        KeyError(crypto_mac::InvalidKeyLength),
    }

    impl<T> From<T> for TestError
    where
        T: Into<super::Error>,
    {
        fn from(error: T) -> Self {
            TestError::LibError(error.into())
        }
    }

    impl From<crypto_mac::InvalidKeyLength> for TestError {
        fn from(error: crypto_mac::InvalidKeyLength) -> Self {
            TestError::KeyError(error)
        }
    }

    pub type TestResult = Result<(), TestError>;
}
<commit_msg>Just use regular error type<commit_after>use crate::algorithm::AlgorithmType;
use base64::DecodeError;
use crypto_mac::{InvalidKeyLength, MacError};
use serde_json::Error as JsonError;
use std::fmt;
use std::string::FromUtf8Error;

#[derive(Debug)]
pub enum Error {
    AlgorithmMismatch(AlgorithmType, AlgorithmType),
    NoKeyId,
    NoKeyWithKeyId(String),
    Format,
    Base64(DecodeError),
    Json(JsonError),
    Utf8(FromUtf8Error),
    RustCryptoMac(MacError),
    RustCryptoMacKeyLength(InvalidKeyLength),
    #[cfg(feature = "openssl")]
    OpenSsl(openssl::error::ErrorStack),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::AlgorithmMismatch(a, b) => {
                write!(f, "Expected algorithm type {:?} but found {:?}", a, b)
            }
            Error::NoKeyId => write!(f, "No key id found"),
            Error::NoKeyWithKeyId(ref kid) => write!(f, "Key with key id {} not found", kid),
            Error::Format => write!(f, "Format"),
            Error::Base64(ref x) => write!(f, "{}", x),
            Error::Json(ref x) => write!(f, "{}", x),
            Error::Utf8(ref x) => write!(f, "{}", x),
            Error::RustCryptoMac(ref x) => write!(f, "{}", x),
            Error::RustCryptoMacKeyLength(ref x) => write!(f, "{}", x),
            #[cfg(feature = "openssl")]
            Error::OpenSsl(ref x) => write!(f, "{}", x),
        }
    }
}

macro_rules! error_wrap {
    ($f: ty, $e: expr) => {
        impl From<$f> for Error {
            fn from(f: $f) -> Error {
                $e(f)
            }
        }
    };
}

error_wrap!(DecodeError, Error::Base64);
error_wrap!(JsonError, Error::Json);
error_wrap!(FromUtf8Error, Error::Utf8);
error_wrap!(MacError, Error::RustCryptoMac);
error_wrap!(InvalidKeyLength, Error::RustCryptoMacKeyLength);
#[cfg(feature = "openssl")]
error_wrap!(openssl::error::ErrorStack, Error::OpenSsl);

#[cfg(test)]
pub(crate) mod tests {
    pub type TestResult = Result<(), super::Error>;
}
<|endoftext|>


<commit_before>use std::borrow;
use std::error;
use std::fmt;
use std::result;

/// Convenience type alias for Liquid compiler errors
pub type Result<T> = result::Result<T, Error>;

/// `Result` extension methods for adapting third party errors to `Error`.
pub trait ResultLiquidChainExt<T, E> {
    /// Create an `Error` with `E` as the cause.
    fn chain(self, msg: &'static str) -> Result<T>;
    /// Create an `Error` with `E` as the cause.
    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String;
}

/// `Result` convenience extension methods for working with `Error`.
impl<T, E> ResultLiquidChainExt<T, E> for result::Result<T, E>
where
    E: error::Error + 'static + Send,
{
    fn chain(self, msg: &'static str) -> Result<T> {
        self.map_err(|err| Error::with_msg(msg).cause(err))
    }

    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| Error::with_msg(msg()).cause(err))
    }
}

pub trait ResultLiquidExt<T> {
    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> Trace;
    fn context<S>(self, key: &'static str, value: &S) -> Result<T>
    where
        S: ToString;
    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (borrow::Cow<'static, str>, String);
}

impl<T> ResultLiquidExt<T> for Result<T> {
    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> Trace,
    {
        self.map_err(|err| err.trace(trace()))
    }

    fn context<S>(self, key: &'static str, value: &S) -> Result<T>
    where
        S: ToString,
    {
        self.map_err(|err| err.context(key, value))
    }

    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (borrow::Cow<'static, str>, String),
    {
        let (key, value) = context();
        self.map_err(|err| err.context(key, &value))
    }
}

/// Compiler error
#[derive(Clone, Debug)]
pub struct Error {
    inner: Box<InnerError>,
}

// Guts of `Error` here to keep `Error` small to avoid bloating the size of `Result<T>` in the
// success case.  There are already enough memory allocations below, one more shouldn't hurt.
#[derive(Clone, Debug)]
struct InnerError {
    msg: borrow::Cow<'static, str>,
    user_backtrace: Vec<Trace>,
    cause: Option<ErrorCause>,
}

impl Error {
    /// Create a new compiler error with the given message
    pub fn with_msg<S: Into<borrow::Cow<'static, str>>>(msg: S) -> Self {
        Self::with_msg_cow(msg.into())
    }

    fn with_msg_cow(msg: borrow::Cow<'static, str>) -> Self {
        let error = InnerError {
            msg: msg,
            user_backtrace: vec![Trace::empty()],
            cause: None,
        };
        Self {
            inner: Box::new(error),
        }
    }

    /// Add a new call to the user-visible backtrace
    pub fn trace<T: Into<Trace>>(self, trace: T) -> Self {
        self.trace_trace(trace.into())
    }

    fn trace_trace(mut self, trace: Trace) -> Self {
        self.inner.user_backtrace.push(trace);
        self
    }

    /// Add context to the last traced call.
    ///
    /// Example context: Value that parameters from ehe `trace` evaluate to.
    pub fn context<C, S>(self, key: C, value: &S) -> Self
    where
        C: Into<borrow::Cow<'static, str>>,
        S: ToString,
    {
        self.context_cow_string(key.into(), value.to_string())
    }

    fn context_cow_string(mut self, key: borrow::Cow<'static, str>, value: String) -> Self {
        self.inner
            .user_backtrace
            .last_mut()
            .expect("always a trace available")
            .append_context(key, value);
        self
    }

    /// Add an external cause to the error for debugging purposes.
    pub fn cause<E: error::Error + 'static + Send>(self, cause: E) -> Self {
        let cause = Box::new(cause);
        self.cause_error(cause)
    }

    fn cause_error(mut self, cause: Box<error::Error + 'static + Send>) -> Self {
        let cause = Some(ErrorCause::Generic(GenericError(cause)));
        self.inner.cause = cause;
        self
    }
}

const ERROR_DESCRIPTION: &str = "liquid";

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}: {}", ERROR_DESCRIPTION, self.inner.msg)?;
        if let Some(ref cause) = self.inner.cause {
            writeln!(f, "cause: {}", cause)?;
        }
        for trace in &self.inner.user_backtrace {
            if let Some(trace) = trace.get_trace() {
                writeln!(f, "from: {}", trace)?;
            }
            if !trace.get_context().is_empty() {
                writeln!(f, "  with:")?;
            }
            for &(ref key, ref value) in trace.get_context() {
                writeln!(f, "    {}={}", key, value)?;
            }
        }
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        ERROR_DESCRIPTION
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.inner.cause {
            Some(ErrorCause::Generic(ref e)) => Some(e.0.as_ref()),
            _ => None,
        }
    }
}

/// User-visible call trace
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct Trace {
    trace: Option<String>,
    context: Vec<(borrow::Cow<'static, str>, String)>,
}

impl Trace {
    /// User-visible call trace.
    pub fn new(trace: String) -> Self {
        Self {
            trace: Some(trace),
            context: vec![],
        }
    }

    /// Add context to the traced call.
    ///
    /// Example context: Value that parameters from ehe `trace` evaluate to.
    pub fn context(mut self, key: borrow::Cow<'static, str>, value: String) -> Self {
        self.context.push((key, value));
        self
    }

    pub(self) fn empty() -> Self {
        Self {
            trace: None,
            context: vec![],
        }
    }

    pub(self) fn append_context(&mut self, key: borrow::Cow<'static, str>, value: String) {
        self.context.push((key, value));
    }

    pub fn get_trace(&self) -> Option<&str> {
        self.trace.as_ref().map(|s| s.as_ref())
    }

    pub fn get_context(&self) -> &[(borrow::Cow<'static, str>, String)] {
        self.context.as_ref()
    }
}

impl From<String> for Trace {
    fn from(trace: String) -> Self {
        Self::new(trace)
    }
}

#[derive(Debug)]
enum ErrorCause {
    Generic(GenericError),
    Missing,
}

impl Clone for ErrorCause {
    fn clone(&self) -> Self {
        match *self {
            ErrorCause::Generic(_) | ErrorCause::Missing => ErrorCause::Missing,
        }
    }
}

impl fmt::Display for ErrorCause {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCause::Generic(ref e) => fmt::Display::fmt(e, f),
            ErrorCause::Missing => write!(f, "Unknown error"),
        }
    }
}

struct GenericError(Box<error::Error + Send>);

impl fmt::Debug for GenericError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl fmt::Display for GenericError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}
<commit_msg>fix(error): Make API consumable by failure<commit_after>use std::borrow;
use std::error;
use std::fmt;
use std::result;

/// Convenience type alias for Liquid compiler errors
pub type Result<T> = result::Result<T, Error>;

/// `Result` extension methods for adapting third party errors to `Error`.
pub trait ResultLiquidChainExt<T, E> {
    /// Create an `Error` with `E` as the cause.
    fn chain(self, msg: &'static str) -> Result<T>;
    /// Create an `Error` with `E` as the cause.
    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String;
}

/// `Result` convenience extension methods for working with `Error`.
impl<T, E> ResultLiquidChainExt<T, E> for result::Result<T, E>
where
    E: error::Error + Send + Sync + 'static,
{
    fn chain(self, msg: &'static str) -> Result<T> {
        self.map_err(|err| Error::with_msg(msg).cause(err))
    }

    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| Error::with_msg(msg()).cause(err))
    }
}

pub trait ResultLiquidExt<T> {
    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> Trace;
    fn context<S>(self, key: &'static str, value: &S) -> Result<T>
    where
        S: ToString;
    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (borrow::Cow<'static, str>, String);
}

impl<T> ResultLiquidExt<T> for Result<T> {
    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> Trace,
    {
        self.map_err(|err| err.trace(trace()))
    }

    fn context<S>(self, key: &'static str, value: &S) -> Result<T>
    where
        S: ToString,
    {
        self.map_err(|err| err.context(key, value))
    }

    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (borrow::Cow<'static, str>, String),
    {
        let (key, value) = context();
        self.map_err(|err| err.context(key, &value))
    }
}

/// Compiler error
#[derive(Clone, Debug)]
pub struct Error {
    inner: Box<InnerError>,
}

// Guts of `Error` here to keep `Error` small to avoid bloating the size of `Result<T>` in the
// success case.  There are already enough memory allocations below, one more shouldn't hurt.
#[derive(Clone, Debug)]
struct InnerError {
    msg: borrow::Cow<'static, str>,
    user_backtrace: Vec<Trace>,
    cause: Option<ErrorCause>,
}

impl Error {
    /// Create a new compiler error with the given message
    pub fn with_msg<S: Into<borrow::Cow<'static, str>>>(msg: S) -> Self {
        Self::with_msg_cow(msg.into())
    }

    fn with_msg_cow(msg: borrow::Cow<'static, str>) -> Self {
        let error = InnerError {
            msg: msg,
            user_backtrace: vec![Trace::empty()],
            cause: None,
        };
        Self {
            inner: Box::new(error),
        }
    }

    /// Add a new call to the user-visible backtrace
    pub fn trace<T: Into<Trace>>(self, trace: T) -> Self {
        self.trace_trace(trace.into())
    }

    fn trace_trace(mut self, trace: Trace) -> Self {
        self.inner.user_backtrace.push(trace);
        self
    }

    /// Add context to the last traced call.
    ///
    /// Example context: Value that parameters from ehe `trace` evaluate to.
    pub fn context<C, S>(self, key: C, value: &S) -> Self
    where
        C: Into<borrow::Cow<'static, str>>,
        S: ToString,
    {
        self.context_cow_string(key.into(), value.to_string())
    }

    fn context_cow_string(mut self, key: borrow::Cow<'static, str>, value: String) -> Self {
        self.inner
            .user_backtrace
            .last_mut()
            .expect("always a trace available")
            .append_context(key, value);
        self
    }

    /// Add an external cause to the error for debugging purposes.
    pub fn cause<E: error::Error + Send + Sync + 'static>(self, cause: E) -> Self {
        let cause = Box::new(cause);
        self.cause_error(cause)
    }

    fn cause_error(mut self, cause: Box<error::Error + Send + Sync + 'static>) -> Self {
        let cause = Some(ErrorCause::Generic(GenericError(cause)));
        self.inner.cause = cause;
        self
    }
}

const ERROR_DESCRIPTION: &str = "liquid";

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}: {}", ERROR_DESCRIPTION, self.inner.msg)?;
        if let Some(ref cause) = self.inner.cause {
            writeln!(f, "cause: {}", cause)?;
        }
        for trace in &self.inner.user_backtrace {
            if let Some(trace) = trace.get_trace() {
                writeln!(f, "from: {}", trace)?;
            }
            if !trace.get_context().is_empty() {
                writeln!(f, "  with:")?;
            }
            for &(ref key, ref value) in trace.get_context() {
                writeln!(f, "    {}={}", key, value)?;
            }
        }
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        ERROR_DESCRIPTION
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.inner.cause {
            Some(ErrorCause::Generic(ref e)) => Some(e.0.as_ref()),
            _ => None,
        }
    }
}

/// User-visible call trace
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct Trace {
    trace: Option<String>,
    context: Vec<(borrow::Cow<'static, str>, String)>,
}

impl Trace {
    /// User-visible call trace.
    pub fn new(trace: String) -> Self {
        Self {
            trace: Some(trace),
            context: vec![],
        }
    }

    /// Add context to the traced call.
    ///
    /// Example context: Value that parameters from ehe `trace` evaluate to.
    pub fn context(mut self, key: borrow::Cow<'static, str>, value: String) -> Self {
        self.context.push((key, value));
        self
    }

    pub(self) fn empty() -> Self {
        Self {
            trace: None,
            context: vec![],
        }
    }

    pub(self) fn append_context(&mut self, key: borrow::Cow<'static, str>, value: String) {
        self.context.push((key, value));
    }

    pub fn get_trace(&self) -> Option<&str> {
        self.trace.as_ref().map(|s| s.as_ref())
    }

    pub fn get_context(&self) -> &[(borrow::Cow<'static, str>, String)] {
        self.context.as_ref()
    }
}

impl From<String> for Trace {
    fn from(trace: String) -> Self {
        Self::new(trace)
    }
}

#[derive(Debug)]
enum ErrorCause {
    Generic(GenericError),
    Missing,
}

impl Clone for ErrorCause {
    fn clone(&self) -> Self {
        match *self {
            ErrorCause::Generic(_) | ErrorCause::Missing => ErrorCause::Missing,
        }
    }
}

impl fmt::Display for ErrorCause {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCause::Generic(ref e) => fmt::Display::fmt(e, f),
            ErrorCause::Missing => write!(f, "Unknown error"),
        }
    }
}

struct GenericError(Box<error::Error + Send + Sync + 'static>);

impl fmt::Debug for GenericError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl fmt::Display for GenericError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}
<|endoftext|>


<commit_before>use std;
use std::fmt::{self, Display};
use std::iter::FromIterator;

use proc_macro2::{
    Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
#[cfg(feature = "printing")]
use quote::ToTokens;

#[cfg(feature = "parsing")]
use buffer::Cursor;
#[cfg(all(procmacro2_semver_exempt, feature = "parsing"))]
use private;
use thread::ThreadBound;

/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;

/// Error returned when a Syn parser cannot parse the input tokens.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Debug)]
pub struct Error {
    // Span is implemented as an index into a thread-local interner to keep the
    // size small. It is not safe to access from a different thread. We want
    // errors to be Send and Sync to play nicely with the Failure crate, so pin
    // the span we're given to its original thread and assume it is
    // Span::call_site if accessed from any other thread.
    start_span: ThreadBound<Span>,
    end_span: ThreadBound<Span>,
    message: String,
}

#[cfg(test)]
struct _Test
where
    Error: Send + Sync;

impl Error {
    /// Usually the [`ParseStream::error`] method will be used instead, which
    /// automatically uses the correct span from the current position of the
    /// parse stream.
    ///
    /// Use `Error::new` when the error needs to be triggered on some span other
    /// than where the parse stream is currently positioned.
    ///
    /// [`ParseStream::error`]: struct.ParseBuffer.html#method.error
    ///
    /// # Example
    ///
    /// ```edition2018
    /// use syn::{Error, Ident, LitStr, Result, Token};
    /// use syn::parse::ParseStream;
    ///
    /// // Parses input that looks like `name = "string"` where the key must be
    /// // the identifier `name` and the value may be any string literal.
    /// // Returns the string literal.
    /// fn parse_name(input: ParseStream) -> Result<LitStr> {
    ///     let name_token: Ident = input.parse()?;
    ///     if name_token != "name" {
    ///         // Trigger an error not on the current position of the stream,
    ///         // but on the position of the unexpected identifier.
    ///         return Err(Error::new(name_token.span(), "expected `name`"));
    ///     }
    ///     input.parse::<Token![=]>()?;
    ///     let s: LitStr = input.parse()?;
    ///     Ok(s)
    /// }
    /// ```
    pub fn new<T: Display>(span: Span, message: T) -> Self {
        Error {
            start_span: ThreadBound::new(span),
            end_span: ThreadBound::new(span),
            message: message.to_string(),
        }
    }

    /// Creates an error with the specified message spanning the given syntax
    /// tree node.
    ///
    /// Unlike the `Error::new` constructor, this constructor takes an argument
    /// `tokens` which is a syntax tree node. This allows the resulting `Error`
    /// to attempt to span all tokens inside of `tokens`. While you would
    /// typically be able to use the `Spanned` trait with the above `Error::new`
    /// constructor, implementation limitations today mean that
    /// `Error::new_spanned` may provide a higher-quality error message on
    /// stable Rust.
    ///
    /// When in doubt it's recommended to stick to `Error::new` (or
    /// `ParseStream::error`)!
    #[cfg(feature = "printing")]
    pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
        let mut iter = tokens.into_token_stream().into_iter();
        let start = iter.next().map_or_else(Span::call_site, |t| t.span());
        let end = iter.last().map_or(start, |t| t.span());
        Error {
            start_span: ThreadBound::new(start),
            end_span: ThreadBound::new(end),
            message: message.to_string(),
        }
    }

    /// The source location of the error.
    ///
    /// Spans are not thread-safe so this function returns `Span::call_site()`
    /// if called from a different thread than the one on which the `Error` was
    /// originally created.
    pub fn span(&self) -> Span {
        let start = match self.start_span.get() {
            Some(span) => *span,
            None => return Span::call_site(),
        };

        #[cfg(procmacro2_semver_exempt)]
        {
            let end = match self.end_span.get() {
                Some(span) => *span,
                None => return Span::call_site(),
            };
            start.join(end).unwrap_or(start)
        }
        #[cfg(not(procmacro2_semver_exempt))]
        {
            start
        }
    }

    /// Render the error as an invocation of [`compile_error!`].
    ///
    /// The [`parse_macro_input!`] macro provides a convenient way to invoke
    /// this method correctly in a procedural macro.
    ///
    /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
    /// [`parse_macro_input!`]: ../macro.parse_macro_input.html
    pub fn to_compile_error(&self) -> TokenStream {
        let start = self
            .start_span
            .get()
            .cloned()
            .unwrap_or_else(Span::call_site);
        let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);

        // compile_error!($message)
        TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("compile_error", start)),
            TokenTree::Punct({
                let mut punct = Punct::new('!', Spacing::Alone);
                punct.set_span(start);
                punct
            }),
            TokenTree::Group({
                let mut group = Group::new(Delimiter::Brace, {
                    TokenStream::from_iter(vec![TokenTree::Literal({
                        let mut string = Literal::string(&self.message);
                        string.set_span(end);
                        string
                    })])
                });
                group.set_span(end);
                group
            }),
        ])
    }
}

#[cfg(feature = "parsing")]
pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
    if cursor.eof() {
        Error::new(scope, format!("unexpected end of input, {}", message))
    } else {
        #[cfg(procmacro2_semver_exempt)]
        let span = private::open_span_of_group(cursor);
        #[cfg(not(procmacro2_semver_exempt))]
        let span = cursor.span();
        Error::new(span, message)
    }
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&self.message)
    }
}

impl Clone for Error {
    fn clone(&self) -> Self {
        let start = self
            .start_span
            .get()
            .cloned()
            .unwrap_or_else(Span::call_site);
        let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
        Error {
            start_span: ThreadBound::new(start),
            end_span: ThreadBound::new(end),
            message: self.message.clone(),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        "parse error"
    }
}

impl From<LexError> for Error {
    fn from(err: LexError) -> Self {
        Error::new(Span::call_site(), format!("{:?}", err))
    }
}
<commit_msg>Condense the Debug representation for Error<commit_after>use std;
use std::fmt::{self, Debug, Display};
use std::iter::FromIterator;

use proc_macro2::{
    Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
#[cfg(feature = "printing")]
use quote::ToTokens;

#[cfg(feature = "parsing")]
use buffer::Cursor;
#[cfg(all(procmacro2_semver_exempt, feature = "parsing"))]
use private;
use thread::ThreadBound;

/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;

/// Error returned when a Syn parser cannot parse the input tokens.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
pub struct Error {
    // Span is implemented as an index into a thread-local interner to keep the
    // size small. It is not safe to access from a different thread. We want
    // errors to be Send and Sync to play nicely with the Failure crate, so pin
    // the span we're given to its original thread and assume it is
    // Span::call_site if accessed from any other thread.
    start_span: ThreadBound<Span>,
    end_span: ThreadBound<Span>,
    message: String,
}

#[cfg(test)]
struct _Test
where
    Error: Send + Sync;

impl Error {
    /// Usually the [`ParseStream::error`] method will be used instead, which
    /// automatically uses the correct span from the current position of the
    /// parse stream.
    ///
    /// Use `Error::new` when the error needs to be triggered on some span other
    /// than where the parse stream is currently positioned.
    ///
    /// [`ParseStream::error`]: struct.ParseBuffer.html#method.error
    ///
    /// # Example
    ///
    /// ```edition2018
    /// use syn::{Error, Ident, LitStr, Result, Token};
    /// use syn::parse::ParseStream;
    ///
    /// // Parses input that looks like `name = "string"` where the key must be
    /// // the identifier `name` and the value may be any string literal.
    /// // Returns the string literal.
    /// fn parse_name(input: ParseStream) -> Result<LitStr> {
    ///     let name_token: Ident = input.parse()?;
    ///     if name_token != "name" {
    ///         // Trigger an error not on the current position of the stream,
    ///         // but on the position of the unexpected identifier.
    ///         return Err(Error::new(name_token.span(), "expected `name`"));
    ///     }
    ///     input.parse::<Token![=]>()?;
    ///     let s: LitStr = input.parse()?;
    ///     Ok(s)
    /// }
    /// ```
    pub fn new<T: Display>(span: Span, message: T) -> Self {
        Error {
            start_span: ThreadBound::new(span),
            end_span: ThreadBound::new(span),
            message: message.to_string(),
        }
    }

    /// Creates an error with the specified message spanning the given syntax
    /// tree node.
    ///
    /// Unlike the `Error::new` constructor, this constructor takes an argument
    /// `tokens` which is a syntax tree node. This allows the resulting `Error`
    /// to attempt to span all tokens inside of `tokens`. While you would
    /// typically be able to use the `Spanned` trait with the above `Error::new`
    /// constructor, implementation limitations today mean that
    /// `Error::new_spanned` may provide a higher-quality error message on
    /// stable Rust.
    ///
    /// When in doubt it's recommended to stick to `Error::new` (or
    /// `ParseStream::error`)!
    #[cfg(feature = "printing")]
    pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
        let mut iter = tokens.into_token_stream().into_iter();
        let start = iter.next().map_or_else(Span::call_site, |t| t.span());
        let end = iter.last().map_or(start, |t| t.span());
        Error {
            start_span: ThreadBound::new(start),
            end_span: ThreadBound::new(end),
            message: message.to_string(),
        }
    }

    /// The source location of the error.
    ///
    /// Spans are not thread-safe so this function returns `Span::call_site()`
    /// if called from a different thread than the one on which the `Error` was
    /// originally created.
    pub fn span(&self) -> Span {
        let start = match self.start_span.get() {
            Some(span) => *span,
            None => return Span::call_site(),
        };

        #[cfg(procmacro2_semver_exempt)]
        {
            let end = match self.end_span.get() {
                Some(span) => *span,
                None => return Span::call_site(),
            };
            start.join(end).unwrap_or(start)
        }
        #[cfg(not(procmacro2_semver_exempt))]
        {
            start
        }
    }

    /// Render the error as an invocation of [`compile_error!`].
    ///
    /// The [`parse_macro_input!`] macro provides a convenient way to invoke
    /// this method correctly in a procedural macro.
    ///
    /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
    /// [`parse_macro_input!`]: ../macro.parse_macro_input.html
    pub fn to_compile_error(&self) -> TokenStream {
        let start = self
            .start_span
            .get()
            .cloned()
            .unwrap_or_else(Span::call_site);
        let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);

        // compile_error!($message)
        TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("compile_error", start)),
            TokenTree::Punct({
                let mut punct = Punct::new('!', Spacing::Alone);
                punct.set_span(start);
                punct
            }),
            TokenTree::Group({
                let mut group = Group::new(Delimiter::Brace, {
                    TokenStream::from_iter(vec![TokenTree::Literal({
                        let mut string = Literal::string(&self.message);
                        string.set_span(end);
                        string
                    })])
                });
                group.set_span(end);
                group
            }),
        ])
    }
}

#[cfg(feature = "parsing")]
pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
    if cursor.eof() {
        Error::new(scope, format!("unexpected end of input, {}", message))
    } else {
        #[cfg(procmacro2_semver_exempt)]
        let span = private::open_span_of_group(cursor);
        #[cfg(not(procmacro2_semver_exempt))]
        let span = cursor.span();
        Error::new(span, message)
    }
}

impl Debug for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_tuple("Error").field(&self.message).finish()
    }
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&self.message)
    }
}

impl Clone for Error {
    fn clone(&self) -> Self {
        let start = self
            .start_span
            .get()
            .cloned()
            .unwrap_or_else(Span::call_site);
        let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
        Error {
            start_span: ThreadBound::new(start),
            end_span: ThreadBound::new(end),
            message: self.message.clone(),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        "parse error"
    }
}

impl From<LexError> for Error {
    fn from(err: LexError) -> Self {
        Error::new(Span::call_site(), format!("{:?}", err))
    }
}
<|endoftext|>


<commit_before>/// Error types

error_chain! {
    types {
        Error, ErrorKind, ResultExt, Result;
    }

    errors {

        // Errors for tokenizer

        QueryParsingError(query: String) {
            description("parsing the query failed")
            display("Parsing the query '{}' failed", query)
        }

        EmptyQueryError {
            description("the query is empty")
            display("The query on the TOML is empty")
        }

        EmptyIdentifier {
            description("Query an empty identifier: ''")
            display("The passed query has an empty identifier")
        }

        ArrayAccessWithoutIndex {
            description("trying to access array without index")
            display("The passed query tries to access an array but does not specify the index")
        }

        ArrayAccessWithInvalidIndex {
            description("trying to pass an invalid index")
            display("The passed query tries to access an array but does not specify a valid index")
        }

        // Errors for Resolver

        IdentifierNotFoundInDocument(ident: String) {
            description("Identifier missing in document")
            display("The identfier '{}' is not present in the document", ident)
        }

        NoIndexInTable(i: usize) {
            description("Cannot deref index from table")
            display("Got an index query '[{}]' but have table", i)
        }

        NoIdentifierInArray(s: String) {
            description("Cannot query identifier in array")
            display("Got an identifier query '{}' but have array", s)
        }

        QueryingValueAsTable(s: String) {
            description("Querying a table where a value is")
            display("Got an identifier query '{}' but have value", s)
        }

        QueryingValueAsArray(i: usize) {
            description("Querying a table where a value is")
            display("Got an index query '{}' but have value", i)
        }

    }
}
<commit_msg>Add error types for deleting non-empty data structures<commit_after>/// Error types

error_chain! {
    types {
        Error, ErrorKind, ResultExt, Result;
    }

    errors {

        // Errors for tokenizer

        QueryParsingError(query: String) {
            description("parsing the query failed")
            display("Parsing the query '{}' failed", query)
        }

        EmptyQueryError {
            description("the query is empty")
            display("The query on the TOML is empty")
        }

        EmptyIdentifier {
            description("Query an empty identifier: ''")
            display("The passed query has an empty identifier")
        }

        ArrayAccessWithoutIndex {
            description("trying to access array without index")
            display("The passed query tries to access an array but does not specify the index")
        }

        ArrayAccessWithInvalidIndex {
            description("trying to pass an invalid index")
            display("The passed query tries to access an array but does not specify a valid index")
        }

        // Errors for Resolver

        IdentifierNotFoundInDocument(ident: String) {
            description("Identifier missing in document")
            display("The identfier '{}' is not present in the document", ident)
        }

        NoIndexInTable(i: usize) {
            description("Cannot deref index from table")
            display("Got an index query '[{}]' but have table", i)
        }

        NoIdentifierInArray(s: String) {
            description("Cannot query identifier in array")
            display("Got an identifier query '{}' but have array", s)
        }

        QueryingValueAsTable(s: String) {
            description("Querying a table where a value is")
            display("Got an identifier query '{}' but have value", s)
        }

        QueryingValueAsArray(i: usize) {
            description("Querying a table where a value is")
            display("Got an index query '{}' but have value", i)
        }

        CannotDeleteNonEmptyTable(tabname: String) {
            description("Cannot delete Table that is not empty")
            display("Cannot delete table '{}' which is not empty", tabname)
        }

        CannotDeleteNonEmptyArray(arrname: String) {
            description("Cannot delete Array that is not empty")
            display("Cannot delete array '{}' which is not empty", arrname)
        }

    }
}
<|endoftext|>


<commit_before>//! Error handling.

use std::{io, result, str, string};

use crate::protocol::{frame::coding::Data, Message};
use http::Response;
use thiserror::Error;

/// Result type of all Tungstenite library calls.
pub type Result<T> = result::Result<T, Error>;

/// Possible WebSocket errors.
#[derive(Error, Debug)]
pub enum Error {
    /// WebSocket connection closed normally. This informs you of the close.
    /// It's not an error as such and nothing wrong happened.
    ///
    /// This is returned as soon as the close handshake is finished (we have both sent and
    /// received a close frame) on the server end and as soon as the server has closed the
    /// underlying connection if this endpoint is a client.
    ///
    /// Thus when you receive this, it is safe to drop the underlying connection.
    ///
    /// Receiving this error means that the WebSocket object is not usable anymore and the
    /// only meaningful action with it is dropping it.
    #[error("Connection closed normally")]
    ConnectionClosed,
    /// Trying to work with already closed connection.
    ///
    /// Trying to read or write after receiving `ConnectionClosed` causes this.
    ///
    /// As opposed to `ConnectionClosed`, this indicates your code tries to operate on the
    /// connection when it really shouldn't anymore, so this really indicates a programmer
    /// error on your part.
    #[error("Trying to work with closed connection")]
    AlreadyClosed,
    /// Input-output error. Apart from WouldBlock, these are generally errors with the
    /// underlying connection and you should probably consider them fatal.
    #[error("IO error: {0}")]
    Io(#[from] io::Error),
    /// TLS error.
    ///
    /// Note that this error variant is enabled unconditionally even if no TLS feature is enabled,
    /// to provide a feature-agnostic API surface.
    #[error("TLS error: {0}")]
    Tls(#[from] TlsError),
    /// - When reading: buffer capacity exhausted.
    /// - When writing: your message is bigger than the configured max message size
    ///   (64MB by default).
    #[error("Space limit exceeded: {0}")]
    Capacity(CapacityError),
    /// Protocol violation.
    #[error("WebSocket protocol error: {0}")]
    Protocol(ProtocolError),
    /// Message send queue full.
    #[error("Send queue is full")]
    SendQueueFull(Message),
    /// UTF coding error.
    #[error("UTF-8 encoding error")]
    Utf8,
    /// Invalid URL.
    #[error("URL error: {0}")]
    Url(UrlError),
    /// HTTP error.
    #[error("HTTP error: {}", .0.status())]
    Http(Response<Option<String>>),
    /// HTTP format error.
    #[error("HTTP format error: {0}")]
    HttpFormat(#[from] http::Error),
}

impl From<str::Utf8Error> for Error {
    fn from(_: str::Utf8Error) -> Self {
        Error::Utf8
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(_: string::FromUtf8Error) -> Self {
        Error::Utf8
    }
}

impl From<http::header::InvalidHeaderValue> for Error {
    fn from(err: http::header::InvalidHeaderValue) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::header::InvalidHeaderName> for Error {
    fn from(err: http::header::InvalidHeaderName) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::header::ToStrError> for Error {
    fn from(_: http::header::ToStrError) -> Self {
        Error::Utf8
    }
}

impl From<http::uri::InvalidUri> for Error {
    fn from(err: http::uri::InvalidUri) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::status::InvalidStatusCode> for Error {
    fn from(err: http::status::InvalidStatusCode) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Self {
        match err {
            httparse::Error::TooManyHeaders => Error::Capacity(CapacityError::TooManyHeaders),
            e => Error::Protocol(ProtocolError::HttparseError(e)),
        }
    }
}

/// Indicates the specific type/cause of a capacity error.
#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
pub enum CapacityError {
    /// Too many headers provided (see [`httparse::Error::TooManyHeaders`]).
    #[error("Too many headers")]
    TooManyHeaders,
    /// Received header is too long.
    #[error("Header too long")]
    HeaderTooLong,
    /// Message is bigger than the maximum allowed size.
    #[error("Message too long: {size} > {max_size}")]
    MessageTooLong {
        /// The size of the message.
        size: usize,
        /// The maximum allowed message size.
        max_size: usize,
    },
    /// TCP buffer is full.
    #[error("Incoming TCP buffer is full")]
    TcpBufferFull,
}

/// Indicates the specific type/cause of a protocol error.
#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
pub enum ProtocolError {
    /// Use of the wrong HTTP method (the WebSocket protocol requires the GET method be used).
    #[error("Unsupported HTTP method used - only GET is allowed")]
    WrongHttpMethod,
    /// Wrong HTTP version used (the WebSocket protocol requires version 1.1 or higher).
    #[error("HTTP version must be 1.1 or higher")]
    WrongHttpVersion,
    /// Missing `Connection: upgrade` HTTP header.
    #[error("No \"Connection: upgrade\" header")]
    MissingConnectionUpgradeHeader,
    /// Missing `Upgrade: websocket` HTTP header.
    #[error("No \"Upgrade: websocket\" header")]
    MissingUpgradeWebSocketHeader,
    /// Missing `Sec-WebSocket-Version: 13` HTTP header.
    #[error("No \"Sec-WebSocket-Version: 13\" header")]
    MissingSecWebSocketVersionHeader,
    /// Missing `Sec-WebSocket-Key` HTTP header.
    #[error("No \"Sec-WebSocket-Key\" header")]
    MissingSecWebSocketKey,
    /// The `Sec-WebSocket-Accept` header is either not present or does not specify the correct key value.
    #[error("Key mismatch in \"Sec-WebSocket-Accept\" header")]
    SecWebSocketAcceptKeyMismatch,
    /// Garbage data encountered after client request.
    #[error("Junk after client request")]
    JunkAfterRequest,
    /// Custom responses must be unsuccessful.
    #[error("Custom response must not be successful")]
    CustomResponseSuccessful,
    /// No more data while still performing handshake.
    #[error("Handshake not finished")]
    HandshakeIncomplete,
    /// Wrapper around a [`httparse::Error`] value.
    #[error("httparse error: {0}")]
    HttparseError(#[from] httparse::Error),
    /// Not allowed to send after having sent a closing frame.
    #[error("Sending after closing is not allowed")]
    SendAfterClosing,
    /// Remote sent data after sending a closing frame.
    #[error("Remote sent after having closed")]
    ReceivedAfterClosing,
    /// Reserved bits in frame header are non-zero.
    #[error("Reserved bits are non-zero")]
    NonZeroReservedBits,
    /// The server must close the connection when an unmasked frame is received.
    #[error("Received an unmasked frame from client")]
    UnmaskedFrameFromClient,
    /// The client must close the connection when a masked frame is received.
    #[error("Received a masked frame from server")]
    MaskedFrameFromServer,
    /// Control frames must not be fragmented.
    #[error("Fragmented control frame")]
    FragmentedControlFrame,
    /// Control frames must have a payload of 125 bytes or less.
    #[error("Control frame too big (payload must be 125 bytes or less)")]
    ControlFrameTooBig,
    /// Type of control frame not recognised.
    #[error("Unknown control frame type: {0}")]
    UnknownControlFrameType(u8),
    /// Type of data frame not recognised.
    #[error("Unknown data frame type: {0}")]
    UnknownDataFrameType(u8),
    /// Received a continue frame despite there being nothing to continue.
    #[error("Continue frame but nothing to continue")]
    UnexpectedContinueFrame,
    /// Received data while waiting for more fragments.
    #[error("While waiting for more fragments received: {0}")]
    ExpectedFragment(Data),
    /// Connection closed without performing the closing handshake.
    #[error("Connection reset without closing handshake")]
    ResetWithoutClosingHandshake,
    /// Encountered an invalid opcode.
    #[error("Encountered invalid opcode: {0}")]
    InvalidOpcode(u8),
    /// The payload for the closing frame is invalid.
    #[error("Invalid close sequence")]
    InvalidCloseSequence,
}

/// Indicates the specific type/cause of URL error.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum UrlError {
    /// TLS is used despite not being compiled with the TLS feature enabled.
    #[error("TLS support not compiled in")]
    TlsFeatureNotEnabled,
    /// The URL does not include a host name.
    #[error("No host name in the URL")]
    NoHostName,
    /// Failed to connect with this URL.
    #[error("Unable to connect to {0}")]
    UnableToConnect(String),
    /// Unsupported URL scheme used (only `ws://` or `wss://` may be used).
    #[error("URL scheme not supported")]
    UnsupportedUrlScheme,
    /// The URL host name, though included, is empty.
    #[error("URL contains empty host name")]
    EmptyHostName,
    /// The URL does not include a path/query.
    #[error("No path/query in URL")]
    NoPathOrQuery,
}

/// TLS errors.
///
/// Note that even if you enable only the rustls-based TLS support, the error at runtime could still
/// be `Native`, as another crate in the dependency graph may enable native TLS support.
#[allow(missing_copy_implementations)]
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum TlsError {
    /// Native TLS error.
    #[cfg(feature = "native-tls")]
    #[error("native-tls error: {0}")]
    Native(#[from] native_tls_crate::Error),
    /// Rustls error.
    #[cfg(feature = "rustls-tls")]
    #[error("rustls error: {0}")]
    Rustls(#[from] rustls::TLSError),
    /// DNS name resolution error.
    #[cfg(feature = "rustls-tls")]
    #[error("Invalid DNS name: {0}")]
    Dns(#[from] webpki::InvalidDNSNameError),
}
<commit_msg>Add `From<ProtocolError>` impl for `Error`<commit_after>//! Error handling.

use std::{io, result, str, string};

use crate::protocol::{frame::coding::Data, Message};
use http::Response;
use thiserror::Error;

/// Result type of all Tungstenite library calls.
pub type Result<T> = result::Result<T, Error>;

/// Possible WebSocket errors.
#[derive(Error, Debug)]
pub enum Error {
    /// WebSocket connection closed normally. This informs you of the close.
    /// It's not an error as such and nothing wrong happened.
    ///
    /// This is returned as soon as the close handshake is finished (we have both sent and
    /// received a close frame) on the server end and as soon as the server has closed the
    /// underlying connection if this endpoint is a client.
    ///
    /// Thus when you receive this, it is safe to drop the underlying connection.
    ///
    /// Receiving this error means that the WebSocket object is not usable anymore and the
    /// only meaningful action with it is dropping it.
    #[error("Connection closed normally")]
    ConnectionClosed,
    /// Trying to work with already closed connection.
    ///
    /// Trying to read or write after receiving `ConnectionClosed` causes this.
    ///
    /// As opposed to `ConnectionClosed`, this indicates your code tries to operate on the
    /// connection when it really shouldn't anymore, so this really indicates a programmer
    /// error on your part.
    #[error("Trying to work with closed connection")]
    AlreadyClosed,
    /// Input-output error. Apart from WouldBlock, these are generally errors with the
    /// underlying connection and you should probably consider them fatal.
    #[error("IO error: {0}")]
    Io(#[from] io::Error),
    /// TLS error.
    ///
    /// Note that this error variant is enabled unconditionally even if no TLS feature is enabled,
    /// to provide a feature-agnostic API surface.
    #[error("TLS error: {0}")]
    Tls(#[from] TlsError),
    /// - When reading: buffer capacity exhausted.
    /// - When writing: your message is bigger than the configured max message size
    ///   (64MB by default).
    #[error("Space limit exceeded: {0}")]
    Capacity(CapacityError),
    /// Protocol violation.
    #[error("WebSocket protocol error: {0}")]
    Protocol(#[from] ProtocolError),
    /// Message send queue full.
    #[error("Send queue is full")]
    SendQueueFull(Message),
    /// UTF coding error.
    #[error("UTF-8 encoding error")]
    Utf8,
    /// Invalid URL.
    #[error("URL error: {0}")]
    Url(UrlError),
    /// HTTP error.
    #[error("HTTP error: {}", .0.status())]
    Http(Response<Option<String>>),
    /// HTTP format error.
    #[error("HTTP format error: {0}")]
    HttpFormat(#[from] http::Error),
}

impl From<str::Utf8Error> for Error {
    fn from(_: str::Utf8Error) -> Self {
        Error::Utf8
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(_: string::FromUtf8Error) -> Self {
        Error::Utf8
    }
}

impl From<http::header::InvalidHeaderValue> for Error {
    fn from(err: http::header::InvalidHeaderValue) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::header::InvalidHeaderName> for Error {
    fn from(err: http::header::InvalidHeaderName) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::header::ToStrError> for Error {
    fn from(_: http::header::ToStrError) -> Self {
        Error::Utf8
    }
}

impl From<http::uri::InvalidUri> for Error {
    fn from(err: http::uri::InvalidUri) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::status::InvalidStatusCode> for Error {
    fn from(err: http::status::InvalidStatusCode) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Self {
        match err {
            httparse::Error::TooManyHeaders => Error::Capacity(CapacityError::TooManyHeaders),
            e => Error::Protocol(ProtocolError::HttparseError(e)),
        }
    }
}

/// Indicates the specific type/cause of a capacity error.
#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
pub enum CapacityError {
    /// Too many headers provided (see [`httparse::Error::TooManyHeaders`]).
    #[error("Too many headers")]
    TooManyHeaders,
    /// Received header is too long.
    #[error("Header too long")]
    HeaderTooLong,
    /// Message is bigger than the maximum allowed size.
    #[error("Message too long: {size} > {max_size}")]
    MessageTooLong {
        /// The size of the message.
        size: usize,
        /// The maximum allowed message size.
        max_size: usize,
    },
    /// TCP buffer is full.
    #[error("Incoming TCP buffer is full")]
    TcpBufferFull,
}

/// Indicates the specific type/cause of a protocol error.
#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
pub enum ProtocolError {
    /// Use of the wrong HTTP method (the WebSocket protocol requires the GET method be used).
    #[error("Unsupported HTTP method used - only GET is allowed")]
    WrongHttpMethod,
    /// Wrong HTTP version used (the WebSocket protocol requires version 1.1 or higher).
    #[error("HTTP version must be 1.1 or higher")]
    WrongHttpVersion,
    /// Missing `Connection: upgrade` HTTP header.
    #[error("No \"Connection: upgrade\" header")]
    MissingConnectionUpgradeHeader,
    /// Missing `Upgrade: websocket` HTTP header.
    #[error("No \"Upgrade: websocket\" header")]
    MissingUpgradeWebSocketHeader,
    /// Missing `Sec-WebSocket-Version: 13` HTTP header.
    #[error("No \"Sec-WebSocket-Version: 13\" header")]
    MissingSecWebSocketVersionHeader,
    /// Missing `Sec-WebSocket-Key` HTTP header.
    #[error("No \"Sec-WebSocket-Key\" header")]
    MissingSecWebSocketKey,
    /// The `Sec-WebSocket-Accept` header is either not present or does not specify the correct key value.
    #[error("Key mismatch in \"Sec-WebSocket-Accept\" header")]
    SecWebSocketAcceptKeyMismatch,
    /// Garbage data encountered after client request.
    #[error("Junk after client request")]
    JunkAfterRequest,
    /// Custom responses must be unsuccessful.
    #[error("Custom response must not be successful")]
    CustomResponseSuccessful,
    /// No more data while still performing handshake.
    #[error("Handshake not finished")]
    HandshakeIncomplete,
    /// Wrapper around a [`httparse::Error`] value.
    #[error("httparse error: {0}")]
    HttparseError(#[from] httparse::Error),
    /// Not allowed to send after having sent a closing frame.
    #[error("Sending after closing is not allowed")]
    SendAfterClosing,
    /// Remote sent data after sending a closing frame.
    #[error("Remote sent after having closed")]
    ReceivedAfterClosing,
    /// Reserved bits in frame header are non-zero.
    #[error("Reserved bits are non-zero")]
    NonZeroReservedBits,
    /// The server must close the connection when an unmasked frame is received.
    #[error("Received an unmasked frame from client")]
    UnmaskedFrameFromClient,
    /// The client must close the connection when a masked frame is received.
    #[error("Received a masked frame from server")]
    MaskedFrameFromServer,
    /// Control frames must not be fragmented.
    #[error("Fragmented control frame")]
    FragmentedControlFrame,
    /// Control frames must have a payload of 125 bytes or less.
    #[error("Control frame too big (payload must be 125 bytes or less)")]
    ControlFrameTooBig,
    /// Type of control frame not recognised.
    #[error("Unknown control frame type: {0}")]
    UnknownControlFrameType(u8),
    /// Type of data frame not recognised.
    #[error("Unknown data frame type: {0}")]
    UnknownDataFrameType(u8),
    /// Received a continue frame despite there being nothing to continue.
    #[error("Continue frame but nothing to continue")]
    UnexpectedContinueFrame,
    /// Received data while waiting for more fragments.
    #[error("While waiting for more fragments received: {0}")]
    ExpectedFragment(Data),
    /// Connection closed without performing the closing handshake.
    #[error("Connection reset without closing handshake")]
    ResetWithoutClosingHandshake,
    /// Encountered an invalid opcode.
    #[error("Encountered invalid opcode: {0}")]
    InvalidOpcode(u8),
    /// The payload for the closing frame is invalid.
    #[error("Invalid close sequence")]
    InvalidCloseSequence,
}

/// Indicates the specific type/cause of URL error.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum UrlError {
    /// TLS is used despite not being compiled with the TLS feature enabled.
    #[error("TLS support not compiled in")]
    TlsFeatureNotEnabled,
    /// The URL does not include a host name.
    #[error("No host name in the URL")]
    NoHostName,
    /// Failed to connect with this URL.
    #[error("Unable to connect to {0}")]
    UnableToConnect(String),
    /// Unsupported URL scheme used (only `ws://` or `wss://` may be used).
    #[error("URL scheme not supported")]
    UnsupportedUrlScheme,
    /// The URL host name, though included, is empty.
    #[error("URL contains empty host name")]
    EmptyHostName,
    /// The URL does not include a path/query.
    #[error("No path/query in URL")]
    NoPathOrQuery,
}

/// TLS errors.
///
/// Note that even if you enable only the rustls-based TLS support, the error at runtime could still
/// be `Native`, as another crate in the dependency graph may enable native TLS support.
#[allow(missing_copy_implementations)]
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum TlsError {
    /// Native TLS error.
    #[cfg(feature = "native-tls")]
    #[error("native-tls error: {0}")]
    Native(#[from] native_tls_crate::Error),
    /// Rustls error.
    #[cfg(feature = "rustls-tls")]
    #[error("rustls error: {0}")]
    Rustls(#[from] rustls::TLSError),
    /// DNS name resolution error.
    #[cfg(feature = "rustls-tls")]
    #[error("Invalid DNS name: {0}")]
    Dns(#[from] webpki::InvalidDNSNameError),
}
<|endoftext|>