<commit_before>use std::thread;
use std::time;

use chrono;
use float_duration::{FloatDuration, TimePoint};

use framerate::FrameCount;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TimeProgression {
    FixedStep,
    VariableStep,
}

/// A specific point of time in a simulation.
///
/// `GameTime` knows both the wall time and game time of the simulation at a
/// fixed time. A `GameTime` object is usually created by calling
/// [`tick`](./struct.GameClock.html#method.tick) on a [`GameClock`](./struct.GameClock.html)
/// object.
#[derive(Debug, Clone)]
pub struct GameTime {
    frame_wall_time: chrono::DateTime<chrono::Local>,
    frame_game_time: time::Duration,
    elapsed_game_time: FloatDuration,
    elapsed_wall_time: FloatDuration,
    frame_number: u64,
}

/// Time-tracking for use in real-time simulations.
///
/// `GameClock` provides time tracking for simulations. It
/// tracks total time the simulation has run for as well as
/// the elapsed time between individual frames.
///
/// In addition to tracking wall time, it tracks "game time"
/// which is the time used by the simulation itself. This game time
/// can be coupled directly to wall time, or can be changed by a fixed
/// time step per frame.
///
/// `GameClock` uses [`GameTime`](./struct.GameTime.html) objects
/// to report the time at each frame to the program. The [`tick`](./fn.tick.html)
/// tells `GameClock` when a new frame is started, and returns
/// the `GameTime` object for that frame. This object can then be passed
/// to the rest of the simulation independently of `GameClock`.
#[derive(Debug, Clone)]
pub struct GameClock {
    last_frame_time: GameTime,
    start_wall_time: chrono::DateTime<chrono::Local>,
    total_game_time: time::Duration,
    current_frame: u64,
    clock_multiplier: f64,
    time_progression: TimeProgression,
}

impl GameClock {
    /// Construct a new `GameClock` object, initialized to start at
    /// zero game time and a wall time of `chrono::Local::now()`.
    pub fn new() -> GameClock {
        let now = chrono::Local::now();
        let start_game_time = GameTime {
            frame_wall_time: now,
            frame_game_time: time::Duration::new(0, 0),
            elapsed_game_time: FloatDuration::zero(),
            elapsed_wall_time: FloatDuration::zero(),
            frame_number: 0,
        };

        GameClock {
            last_frame_time: start_game_time,
            start_wall_time: now,
            total_game_time: time::Duration::new(0, 0),
            current_frame: 0,
            clock_multiplier: 1.0,
            time_progression: TimeProgression::VariableStep,
        }
    }

    /// Return the current frame number.
    ///
    /// The frame number starts at `0` for "before the first frame"
    /// and increases by 1 every time `tick` is called.
    pub fn current_frame_number(&self) -> u64 {
        self.current_frame
    }
    /// Return the wall time when the `GameClock` was created.
    pub fn start_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.start_wall_time
    }
    /// Return the wall time at the start of the current frame.
    ///
    /// This is equivalent to the value returned by
    /// `last_frame_time().frame_wall_time()`
    pub fn frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.last_frame_time.frame_wall_time
    }

    /// Return the amount of wall time elapsed since the start of the current frame.
    pub fn frame_elapsed_time(&self) -> FloatDuration {
        chrono::Local::now()
            .float_duration_since(self.frame_wall_time())
            .unwrap()
    }
    /// Return the [`GameTime`](./struct.GameTime.html) for the current frame.
    pub fn last_frame_time(&self) -> &GameTime {
        &self.last_frame_time
    }
    /// Return the rate at which game time is increasing.
    pub fn clock_multiplier(&self) -> f64 {
        self.clock_multiplier
    }
    /// Set the rate at which game time is increasing.
    pub fn with_clock_multiplier(&mut self, val: f64) -> &mut GameClock {
        self.clock_multiplier = val;
        self
    }

    /// Mark the start of a new frame, updating time statistics.
    ///
    /// The `GameTime` for the new frame is returned. This gives the time
    /// statistics for the entirety of the current frame. It is cached and
    /// can be later obtained by calling `last_frame_time`.
    pub fn tick<C>(&mut self, counter: &mut C) -> GameTime
        where C: FrameCount + ?Sized
    {
        let frame_start = chrono::Local::now();

        self.current_frame += 1;

        let elapsed_wall_time = frame_start
            .float_duration_since(self.frame_wall_time())
            .unwrap();

        let elapsed_game_time = self.elapsed_game_time_from_wall_time(counter, elapsed_wall_time);
        let total_game_time = self.total_game_time + elapsed_game_time.to_std().unwrap();

        self.total_game_time = total_game_time;

        let time = GameTime {
            frame_wall_time: frame_start,
            frame_game_time: total_game_time,
            elapsed_game_time,
            elapsed_wall_time,
            frame_number: self.current_frame,
        };

        self.last_frame_time = time.clone();

        counter.tick(&time);

        time
    }

    /// Map from wall time elapsed to game time elapsed.
    fn elapsed_game_time_from_wall_time<C>(&self,
                                           counter: &mut C,
                                           elapsed_wall_time: FloatDuration)
                                           -> FloatDuration
        where C: FrameCount + ?Sized
    {
        match self.time_progression {
            TimeProgression::FixedStep => counter.target_time_per_frame() * self.clock_multiplier,
            TimeProgression::VariableStep => elapsed_wall_time * self.clock_multiplier,
        }
    }

    /// Put the current thread to sleep if necessary in order to maintain the target frame rate.
    ///
    /// If the current frame has taken more time than the target frame rate allows, then the
    /// thread will not sleep. Otherwise it will sleep for
    /// `counter.target_time_per_frame() - self.frame_elapsed_time()`
    ///
    /// This method relies on the passed function `f` to actually perform the sleep.
    /// `f` receives the amount of sleep time requested and it is up to itself to
    /// sleep for that amount of time. If you don't care how the sleep is performed,
    /// use the [`sleep_remaining`](./struct.GameClock.html#method.sleep_remaining)
    /// method instead.
    pub fn sleep_remaining_via<C, F>(&mut self, counter: &C, f: F)
        where C: FrameCount + ?Sized,
              F: FnOnce(FloatDuration)
    {
        let remaining_time = counter.target_time_per_frame() -
                             chrono::Local::now()
                                 .float_duration_since(self.frame_wall_time())
                                 .unwrap();
        if !remaining_time.is_negative() {
            f(remaining_time)
        }
    }

    /// Put the current thread to sleep if necessary in order to maintain the target frame rate.
    ///
    /// If the current frame has taken more time than the target frame rate allows, then the
    /// thread will not sleep. Otherwise it will sleep for
    /// `counter.target_time_per_frame() - self.frame_elapsed_time()`
    ///
    /// This method uses [`std::thread::sleep`](https://doc.rust-lang.org/std/thread/fn.sleep.html)
    /// to put the thread to sleep. If a different sleep function is desired, use
    /// the [`sleep_remaining_via`](./struct.GameClock.html#method.sleep_remaining_via)
    /// method instead.
    pub fn sleep_remaining<C>(&mut self, counter: &C)
        where C: FrameCount + ?Sized
    {
        self.sleep_remaining_via(counter, |rem| thread::sleep(rem.to_std().unwrap()))
    }
}

impl Default for GameClock {
    fn default() -> GameClock {
        GameClock::new()
    }
}

impl GameTime {
    /// Construct a `GameTime` object directly.
    ///
    /// This is useful primarily for writing tests or for constructing a
    /// `GameTime` without using a `GameClock`.
    pub fn new(frame_wall_time: chrono::DateTime<chrono::Local>,
               frame_game_time: time::Duration,
               elapsed_game_time: FloatDuration,
               elapsed_wall_time: FloatDuration,
               frame_number: u64)
               -> GameTime {
        GameTime {
            frame_wall_time,
            frame_game_time,
            elapsed_game_time,
            elapsed_wall_time,
            frame_number,
        }
    }

    /// The game time at the time of creation of this `GameTime` object.
    pub fn frame_game_time(&self) -> time::Duration {
        self.frame_game_time
    }
    /// The wall time at the time of creation of this `GameTime` object.
    pub fn frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.frame_wall_time
    }
    /// The amount of game time that passed since the previous frame.
    pub fn elapsed_game_time(&self) -> FloatDuration {
        self.elapsed_game_time
    }
    /// The amount of wall time that passed since the previous frame.
    pub fn elapsed_wall_time(&self) -> FloatDuration {
        self.elapsed_wall_time
    }
    /// The amount of elapsed wall time since the start of the current frame.
    ///
    /// This value is computed from the current instant when called, based
    /// on the frame start time. This can be used for intra-frame profiling.
    pub fn elapsed_time_since_frame_start(&self) -> FloatDuration {
        chrono::Local::now()
            .float_duration_since(self.frame_wall_time)
            .unwrap()
    }
    /// The index of the current frame.
    ///
    /// This value increases by 1 for each frame created, and represents the total
    /// number of frames executed in the simulation.
    pub fn frame_number(&self) -> u64 {
        self.frame_number
    }
    /// Return the instantaneous frame rate between the last and current frames.
    ///
    /// The "instantaneous" frame rate is computed from the last frame's elapsed
    /// time, and takes no previous frames into account.
    ///
    /// For a more stable frame rate, use a [`FrameCount`](../framerate/counter/trait.FrameCount.html)
    /// object.
    pub fn instantaneous_frame_rate(&self) -> f64 {
        1.0 / self.elapsed_game_time.as_seconds()
    }
}
<commit_msg>Documented the `clock` module.<commit_after>//! Types for counting and recording time in a simulation.
//!
//! `clock` is the primary module for time tracking in `game_time`. It
//! provides two primary types: `GameClock`, a "clock" for tracking frames
//! and time progression within the simulation and `GameTime`, a specific
//! point in time within the simulation.
use std::thread;
use std::time;

use chrono;
use float_duration::{FloatDuration, TimePoint};

use framerate::FrameCount;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TimeProgression {
    FixedStep,
    VariableStep,
}

/// A specific point of time in a simulation.
///
/// `GameTime` knows both the wall time and game time of the simulation at a
/// fixed time. A `GameTime` object is usually created by calling
/// [`tick`](./struct.GameClock.html#method.tick) on a [`GameClock`](./struct.GameClock.html)
/// object.
#[derive(Debug, Clone)]
pub struct GameTime {
    frame_wall_time: chrono::DateTime<chrono::Local>,
    frame_game_time: time::Duration,
    elapsed_game_time: FloatDuration,
    elapsed_wall_time: FloatDuration,
    frame_number: u64,
}

/// Time-tracking for use in real-time simulations.
///
/// `GameClock` provides time tracking for simulations. It
/// tracks total time the simulation has run for as well as
/// the elapsed time between individual frames.
///
/// In addition to tracking wall time, it tracks "game time"
/// which is the time used by the simulation itself. This game time
/// can be coupled directly to wall time, or can be changed by a fixed
/// time step per frame.
///
/// `GameClock` uses [`GameTime`](./struct.GameTime.html) objects
/// to report the time at each frame to the program. The [`tick`](./fn.tick.html)
/// tells `GameClock` when a new frame is started, and returns
/// the `GameTime` object for that frame. This object can then be passed
/// to the rest of the simulation independently of `GameClock`.
#[derive(Debug, Clone)]
pub struct GameClock {
    last_frame_time: GameTime,
    start_wall_time: chrono::DateTime<chrono::Local>,
    total_game_time: time::Duration,
    current_frame: u64,
    clock_multiplier: f64,
    time_progression: TimeProgression,
}

impl GameClock {
    /// Construct a new `GameClock` object, initialized to start at
    /// zero game time and a wall time of `chrono::Local::now()`.
    pub fn new() -> GameClock {
        let now = chrono::Local::now();
        let start_game_time = GameTime {
            frame_wall_time: now,
            frame_game_time: time::Duration::new(0, 0),
            elapsed_game_time: FloatDuration::zero(),
            elapsed_wall_time: FloatDuration::zero(),
            frame_number: 0,
        };

        GameClock {
            last_frame_time: start_game_time,
            start_wall_time: now,
            total_game_time: time::Duration::new(0, 0),
            current_frame: 0,
            clock_multiplier: 1.0,
            time_progression: TimeProgression::VariableStep,
        }
    }

    /// Return the current frame number.
    ///
    /// The frame number starts at `0` for "before the first frame"
    /// and increases by 1 every time `tick` is called.
    pub fn current_frame_number(&self) -> u64 {
        self.current_frame
    }
    /// Return the wall time when the `GameClock` was created.
    pub fn start_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.start_wall_time
    }
    /// Return the wall time at the start of the current frame.
    ///
    /// This is equivalent to the value returned by
    /// `last_frame_time().frame_wall_time()`
    pub fn frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.last_frame_time.frame_wall_time
    }

    /// Return the amount of wall time elapsed since the start of the current frame.
    pub fn frame_elapsed_time(&self) -> FloatDuration {
        chrono::Local::now()
            .float_duration_since(self.frame_wall_time())
            .unwrap()
    }
    /// Return the [`GameTime`](./struct.GameTime.html) for the current frame.
    pub fn last_frame_time(&self) -> &GameTime {
        &self.last_frame_time
    }
    /// Return the rate at which game time is increasing.
    pub fn clock_multiplier(&self) -> f64 {
        self.clock_multiplier
    }
    /// Set the rate at which game time is increasing.
    pub fn with_clock_multiplier(&mut self, val: f64) -> &mut GameClock {
        self.clock_multiplier = val;
        self
    }

    /// Mark the start of a new frame, updating time statistics.
    ///
    /// The `GameTime` for the new frame is returned. This gives the time
    /// statistics for the entirety of the current frame. It is cached and
    /// can be later obtained by calling `last_frame_time`.
    pub fn tick<C>(&mut self, counter: &mut C) -> GameTime
        where C: FrameCount + ?Sized
    {
        let frame_start = chrono::Local::now();

        self.current_frame += 1;

        let elapsed_wall_time = frame_start
            .float_duration_since(self.frame_wall_time())
            .unwrap();

        let elapsed_game_time = self.elapsed_game_time_from_wall_time(counter, elapsed_wall_time);
        let total_game_time = self.total_game_time + elapsed_game_time.to_std().unwrap();

        self.total_game_time = total_game_time;

        let time = GameTime {
            frame_wall_time: frame_start,
            frame_game_time: total_game_time,
            elapsed_game_time,
            elapsed_wall_time,
            frame_number: self.current_frame,
        };

        self.last_frame_time = time.clone();

        counter.tick(&time);

        time
    }

    /// Map from wall time elapsed to game time elapsed.
    fn elapsed_game_time_from_wall_time<C>(&self,
                                           counter: &mut C,
                                           elapsed_wall_time: FloatDuration)
                                           -> FloatDuration
        where C: FrameCount + ?Sized
    {
        match self.time_progression {
            TimeProgression::FixedStep => counter.target_time_per_frame() * self.clock_multiplier,
            TimeProgression::VariableStep => elapsed_wall_time * self.clock_multiplier,
        }
    }

    /// Put the current thread to sleep if necessary in order to maintain the target frame rate.
    ///
    /// If the current frame has taken more time than the target frame rate allows, then the
    /// thread will not sleep. Otherwise it will sleep for
    /// `counter.target_time_per_frame() - self.frame_elapsed_time()`
    ///
    /// This method relies on the passed function `f` to actually perform the sleep.
    /// `f` receives the amount of sleep time requested and it is up to itself to
    /// sleep for that amount of time. If you don't care how the sleep is performed,
    /// use the [`sleep_remaining`](./struct.GameClock.html#method.sleep_remaining)
    /// method instead.
    pub fn sleep_remaining_via<C, F>(&mut self, counter: &C, f: F)
        where C: FrameCount + ?Sized,
              F: FnOnce(FloatDuration)
    {
        let remaining_time = counter.target_time_per_frame() -
                             chrono::Local::now()
                                 .float_duration_since(self.frame_wall_time())
                                 .unwrap();
        if !remaining_time.is_negative() {
            f(remaining_time)
        }
    }

    /// Put the current thread to sleep if necessary in order to maintain the target frame rate.
    ///
    /// If the current frame has taken more time than the target frame rate allows, then the
    /// thread will not sleep. Otherwise it will sleep for
    /// `counter.target_time_per_frame() - self.frame_elapsed_time()`
    ///
    /// This method uses [`std::thread::sleep`](https://doc.rust-lang.org/std/thread/fn.sleep.html)
    /// to put the thread to sleep. If a different sleep function is desired, use
    /// the [`sleep_remaining_via`](./struct.GameClock.html#method.sleep_remaining_via)
    /// method instead.
    pub fn sleep_remaining<C>(&mut self, counter: &C)
        where C: FrameCount + ?Sized
    {
        self.sleep_remaining_via(counter, |rem| thread::sleep(rem.to_std().unwrap()))
    }
}

impl Default for GameClock {
    fn default() -> GameClock {
        GameClock::new()
    }
}

impl GameTime {
    /// Construct a `GameTime` object directly.
    ///
    /// This is useful primarily for writing tests or for constructing a
    /// `GameTime` without using a `GameClock`.
    pub fn new(frame_wall_time: chrono::DateTime<chrono::Local>,
               frame_game_time: time::Duration,
               elapsed_game_time: FloatDuration,
               elapsed_wall_time: FloatDuration,
               frame_number: u64)
               -> GameTime {
        GameTime {
            frame_wall_time,
            frame_game_time,
            elapsed_game_time,
            elapsed_wall_time,
            frame_number,
        }
    }

    /// The game time at the time of creation of this `GameTime` object.
    pub fn frame_game_time(&self) -> time::Duration {
        self.frame_game_time
    }
    /// The wall time at the time of creation of this `GameTime` object.
    pub fn frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.frame_wall_time
    }
    /// The amount of game time that passed since the previous frame.
    pub fn elapsed_game_time(&self) -> FloatDuration {
        self.elapsed_game_time
    }
    /// The amount of wall time that passed since the previous frame.
    pub fn elapsed_wall_time(&self) -> FloatDuration {
        self.elapsed_wall_time
    }
    /// The amount of elapsed wall time since the start of the current frame.
    ///
    /// This value is computed from the current instant when called, based
    /// on the frame start time. This can be used for intra-frame profiling.
    pub fn elapsed_time_since_frame_start(&self) -> FloatDuration {
        chrono::Local::now()
            .float_duration_since(self.frame_wall_time)
            .unwrap()
    }
    /// The index of the current frame.
    ///
    /// This value increases by 1 for each frame created, and represents the total
    /// number of frames executed in the simulation.
    pub fn frame_number(&self) -> u64 {
        self.frame_number
    }
    /// Return the instantaneous frame rate between the last and current frames.
    ///
    /// The "instantaneous" frame rate is computed from the last frame's elapsed
    /// time, and takes no previous frames into account.
    ///
    /// For a more stable frame rate, use a [`FrameCount`](../framerate/counter/trait.FrameCount.html)
    /// object.
    pub fn instantaneous_frame_rate(&self) -> f64 {
        1.0 / self.elapsed_game_time.as_seconds()
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use chrono::Utc;
use serde_json::map::Map;
use serde_json::{from_value, Value};

use crypto::Algorithm;
use errors::{new_error, ErrorKind, Result};

/// Contains the various validations that are applied after decoding a token.
///
/// All time validation happen on UTC timestamps.
///
/// ```rust
/// use jsonwebtoken::Validation;
///
/// // Default value
/// let validation = Validation::default();
///
/// // Changing one parameter
/// let mut validation = Validation {leeway: 60, ..Default::default()};
///
/// // Setting audience
/// let mut validation = Validation::default();
/// validation.set_audience(&["Me"]); // a single string
/// validation.set_audience(&["Me", "You"]); // array of strings
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Validation {
    /// Add some leeway (in seconds) to the `exp`, `iat` and `nbf` validation to
    /// account for clock skew.
    ///
    /// Defaults to `0`.
    pub leeway: i64,
    /// Whether to validate the `exp` field.
    ///
    /// It will return an error if the time in the `exp` field is past.
    ///
    /// Defaults to `true`.
    pub validate_exp: bool,
    /// Whether to validate the `nbf` field.
    ///
    /// It will return an error if the current timestamp is before the time in the `nbf` field.
    ///
    /// Defaults to `false`.
    pub validate_nbf: bool,
    /// If it contains a value, the validation will check that the `aud` field is a member of the
    /// audience provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub aud: Option<HashSet<String>>,
    /// If it contains a value, the validation will check that the `iss` field is the same as the
    /// one provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub iss: Option<String>,
    /// If it contains a value, the validation will check that the `sub` field is the same as the
    /// one provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub sub: Option<String>,
    /// If it contains a value, the validation will check that the `alg` of the header is contained
    /// in the ones provided and will error otherwise.
    ///
    /// Defaults to `vec![Algorithm::HS256]`.
    pub algorithms: Vec<Algorithm>,
}

impl Validation {
    /// Create a default validation setup allowing the given alg
    pub fn new(alg: Algorithm) -> Validation {
        let mut validation = Validation::default();
        validation.algorithms = vec![alg];
        validation
    }

    /// `aud` is a collection of one or more acceptable audience members
    pub fn set_audience<T: ToString>(&mut self, items: &[T]) {
        self.aud = Some(items.iter().map(|x| x.to_string()).collect())
    }
}

impl Default for Validation {
    fn default() -> Validation {
        Validation {
            leeway: 0,

            validate_exp: true,
            validate_nbf: false,

            iss: None,
            sub: None,
            aud: None,

            algorithms: vec![Algorithm::HS256],
        }
    }
}

pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()> {
    let now = Utc::now().timestamp();

    if options.validate_exp {
        if let Some(exp) = claims.get("exp") {
            if from_value::<i64>(exp.clone())? < now - options.leeway {
                return Err(new_error(ErrorKind::ExpiredSignature));
            }
        } else {
            return Err(new_error(ErrorKind::ExpiredSignature));
        }
    }

    if options.validate_nbf {
        if let Some(nbf) = claims.get("nbf") {
            if from_value::<i64>(nbf.clone())? > now + options.leeway {
                return Err(new_error(ErrorKind::ImmatureSignature));
            }
        } else {
            return Err(new_error(ErrorKind::ImmatureSignature));
        }
    }

    if let Some(ref correct_iss) = options.iss {
        if let Some(iss) = claims.get("iss") {
            if from_value::<String>(iss.clone())? != *correct_iss {
                return Err(new_error(ErrorKind::InvalidIssuer));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidIssuer));
        }
    }

    if let Some(ref correct_sub) = options.sub {
        if let Some(sub) = claims.get("sub") {
            if from_value::<String>(sub.clone())? != *correct_sub {
                return Err(new_error(ErrorKind::InvalidSubject));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidSubject));
        }
    }

    if let Some(ref correct_aud) = options.aud {
        if let Some(aud) = claims.get("aud") {
			let provided_aud: HashSet<String> = from_value(aud.clone())?;
			if provided_aud.intersection(correct_aud).count() == 0 {
                return Err(new_error(ErrorKind::InvalidAudience));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidAudience));
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use chrono::Utc;
    use serde_json::map::Map;
    use serde_json::to_value;

    use super::{validate, Validation};

    use errors::ErrorKind;

    #[test]
    fn exp_in_future_ok() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() + 10000).unwrap());
        let res = validate(&claims, &Validation::default());
        assert!(res.is_ok());
    }

    #[test]
    fn exp_in_past_fails() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 100000).unwrap());
        let res = validate(&claims, &Validation::default());
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::ExpiredSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn exp_in_past_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 500).unwrap());
        let validation = Validation { leeway: 1000 * 60, ..Default::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    // https://github.com/Keats/jsonwebtoken/issues/51
    #[test]
    fn validation_called_even_if_field_is_empty() {
        let claims = Map::new();
        let res = validate(&claims, &Validation::default());
        assert!(res.is_err());
        match res.unwrap_err().kind() {
            &ErrorKind::ExpiredSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn nbf_in_past_ok() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_nbf: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn nbf_in_future_fails() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_nbf: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::ImmatureSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn nbf_in_future_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 500).unwrap());
        let validation = Validation {
            leeway: 1000 * 60,
            validate_nbf: true,
            validate_exp: false,
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iss_ok() {
        let mut claims = Map::new();
        claims.insert("iss".to_string(), to_value("Keats").unwrap());
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iss_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("iss".to_string(), to_value("Hacked").unwrap());
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuer => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn iss_missing_fails() {
        let claims = Map::new();
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuer => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn sub_ok() {
        let mut claims = Map::new();
        claims.insert("sub".to_string(), to_value("Keats").unwrap());
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn sub_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("sub".to_string(), to_value("Hacked").unwrap());
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidSubject => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn sub_missing_fails() {
        let claims = Map::new();
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidSubject => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_string_ok() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["Everyone"]);
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn aud_array_of_string_ok() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["UserA", "UserB"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["UserA", "UserB"]);
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn aud_type_mismatch_fails() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["UserA", "UserB"]);
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_correct_type_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["None"]);
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_missing_fails() {
        let claims = Map::new();
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["None"]);
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }
}
<commit_msg>updated imports in validation.rs<commit_after>use std::collections::HashSet;
use chrono::Utc;
use serde_json::map::Map;
use serde_json::{from_value, Value};

use crate::algorithms::Algorithm;
use crate::errors::{new_error, ErrorKind, Result};

/// Contains the various validations that are applied after decoding a token.
///
/// All time validation happen on UTC timestamps.
///
/// ```rust
/// use jsonwebtoken::Validation;
///
/// // Default value
/// let validation = Validation::default();
///
/// // Changing one parameter
/// let mut validation = Validation {leeway: 60, ..Default::default()};
///
/// // Setting audience
/// let mut validation = Validation::default();
/// validation.set_audience(&["Me"]); // a single string
/// validation.set_audience(&["Me", "You"]); // array of strings
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Validation {
    /// Add some leeway (in seconds) to the `exp`, `iat` and `nbf` validation to
    /// account for clock skew.
    ///
    /// Defaults to `0`.
    pub leeway: i64,
    /// Whether to validate the `exp` field.
    ///
    /// It will return an error if the time in the `exp` field is past.
    ///
    /// Defaults to `true`.
    pub validate_exp: bool,
    /// Whether to validate the `nbf` field.
    ///
    /// It will return an error if the current timestamp is before the time in the `nbf` field.
    ///
    /// Defaults to `false`.
    pub validate_nbf: bool,
    /// If it contains a value, the validation will check that the `aud` field is a member of the
    /// audience provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub aud: Option<HashSet<String>>,
    /// If it contains a value, the validation will check that the `iss` field is the same as the
    /// one provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub iss: Option<String>,
    /// If it contains a value, the validation will check that the `sub` field is the same as the
    /// one provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub sub: Option<String>,
    /// If it contains a value, the validation will check that the `alg` of the header is contained
    /// in the ones provided and will error otherwise.
    ///
    /// Defaults to `vec![Algorithm::HS256]`.
    pub algorithms: Vec<Algorithm>,
}

impl Validation {
    /// Create a default validation setup allowing the given alg
    pub fn new(alg: Algorithm) -> Validation {
        let mut validation = Validation::default();
        validation.algorithms = vec![alg];
        validation
    }

    /// `aud` is a collection of one or more acceptable audience members
    pub fn set_audience<T: ToString>(&mut self, items: &[T]) {
        self.aud = Some(items.iter().map(|x| x.to_string()).collect())
    }
}

impl Default for Validation {
    fn default() -> Validation {
        Validation {
            leeway: 0,

            validate_exp: true,
            validate_nbf: false,

            iss: None,
            sub: None,
            aud: None,

            algorithms: vec![Algorithm::HS256],
        }
    }
}

pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()> {
    let now = Utc::now().timestamp();

    if options.validate_exp {
        if let Some(exp) = claims.get("exp") {
            if from_value::<i64>(exp.clone())? < now - options.leeway {
                return Err(new_error(ErrorKind::ExpiredSignature));
            }
        } else {
            return Err(new_error(ErrorKind::ExpiredSignature));
        }
    }

    if options.validate_nbf {
        if let Some(nbf) = claims.get("nbf") {
            if from_value::<i64>(nbf.clone())? > now + options.leeway {
                return Err(new_error(ErrorKind::ImmatureSignature));
            }
        } else {
            return Err(new_error(ErrorKind::ImmatureSignature));
        }
    }

    if let Some(ref correct_iss) = options.iss {
        if let Some(iss) = claims.get("iss") {
            if from_value::<String>(iss.clone())? != *correct_iss {
                return Err(new_error(ErrorKind::InvalidIssuer));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidIssuer));
        }
    }

    if let Some(ref correct_sub) = options.sub {
        if let Some(sub) = claims.get("sub") {
            if from_value::<String>(sub.clone())? != *correct_sub {
                return Err(new_error(ErrorKind::InvalidSubject));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidSubject));
        }
    }

    if let Some(ref correct_aud) = options.aud {
        if let Some(aud) = claims.get("aud") {
			let provided_aud: HashSet<String> = from_value(aud.clone())?;
			if provided_aud.intersection(correct_aud).count() == 0 {
                return Err(new_error(ErrorKind::InvalidAudience));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidAudience));
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use chrono::Utc;
    use serde_json::map::Map;
    use serde_json::to_value;

    use super::{validate, Validation};

    use crate::errors::ErrorKind;

    #[test]
    fn exp_in_future_ok() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() + 10000).unwrap());
        let res = validate(&claims, &Validation::default());
        assert!(res.is_ok());
    }

    #[test]
    fn exp_in_past_fails() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 100000).unwrap());
        let res = validate(&claims, &Validation::default());
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::ExpiredSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn exp_in_past_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 500).unwrap());
        let validation = Validation { leeway: 1000 * 60, ..Default::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    // https://github.com/Keats/jsonwebtoken/issues/51
    #[test]
    fn validation_called_even_if_field_is_empty() {
        let claims = Map::new();
        let res = validate(&claims, &Validation::default());
        assert!(res.is_err());
        match res.unwrap_err().kind() {
            &ErrorKind::ExpiredSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn nbf_in_past_ok() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_nbf: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn nbf_in_future_fails() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_nbf: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::ImmatureSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn nbf_in_future_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 500).unwrap());
        let validation = Validation {
            leeway: 1000 * 60,
            validate_nbf: true,
            validate_exp: false,
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iss_ok() {
        let mut claims = Map::new();
        claims.insert("iss".to_string(), to_value("Keats").unwrap());
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iss_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("iss".to_string(), to_value("Hacked").unwrap());
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuer => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn iss_missing_fails() {
        let claims = Map::new();
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuer => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn sub_ok() {
        let mut claims = Map::new();
        claims.insert("sub".to_string(), to_value("Keats").unwrap());
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn sub_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("sub".to_string(), to_value("Hacked").unwrap());
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidSubject => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn sub_missing_fails() {
        let claims = Map::new();
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidSubject => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_string_ok() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["Everyone"]);
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn aud_array_of_string_ok() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["UserA", "UserB"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["UserA", "UserB"]);
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn aud_type_mismatch_fails() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["UserA", "UserB"]);
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_correct_type_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["None"]);
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_missing_fails() {
        let claims = Map::new();
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["None"]);
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }
}
<|endoftext|>


<commit_before>extern crate nalgebra;

use std::f64::consts::FRAC_PI_2;
use nalgebra::{Mat2, Pnt2, Rot2, Vec1, Vec2, Vec3};

fn main() {
    println!("24 days of Rust - nalgebra (day 14)");
    let v = Vec2::new(0.0f64, 1.0);
    // 90 degrees clockwise
    //  0, 1
    // -1, 0
    let rot = Mat2::new(0.0f64, -1.0, 1.0, 0.0);
    println!("{}", rot * v);
    let angle = FRAC_PI_2;
    let rot = Rot2::new(Vec1::new(angle));
    println!("{}", rot * v);
    let point = Pnt2::new(4.0f64, 4.0);
    println!("Translate from {} to {}", point, nalgebra::translate(&v, &point));

    let v1 = Vec3::new(2.0f64, 2.0, 0.0);
    let v2 = Vec3::new(2.0f64, -2.0, 0.0);
    if nalgebra::approx_eq(&0.0f64, &nalgebra::dot(&v1, &v2)) {
        println!("v1 is orthogonal to v2");
    }
}
<commit_msg>Cross product.<commit_after>extern crate nalgebra;

use std::f64::consts::FRAC_PI_2;
use nalgebra::{Mat2, Pnt2, Rot2, Vec1, Vec2, Vec3};

fn main() {
    println!("24 days of Rust - nalgebra (day 14)");
    let v = Vec2::new(0.0f64, 1.0);
    // 90 degrees clockwise
    //  0, 1
    // -1, 0
    let rot = Mat2::new(0.0f64, -1.0, 1.0, 0.0);
    println!("{}", rot * v);
    let angle = FRAC_PI_2;
    let rot = Rot2::new(Vec1::new(angle));
    println!("{}", rot * v);
    let point = Pnt2::new(4.0f64, 4.0);
    println!("Translate from {} to {}", point, nalgebra::translate(&v, &point));

    let v1 = Vec3::new(2.0f64, 2.0, 0.0);
    let v2 = Vec3::new(2.0f64, -2.0, 0.0);
    if nalgebra::approx_eq(&0.0f64, &nalgebra::dot(&v1, &v2)) {
        println!("v1 is orthogonal to v2");
    }

    println!("{}", nalgebra::cross(&v1, &v2));
    println!("{}", nalgebra::cross(&v2, &v1));
}
<|endoftext|>


<commit_before>//! Encapsulates error types.

use std::result;
use std::fmt;

pub type Result<T> = result::Result<T, Error>;

/// Possible errors produced by syscall collector.
pub enum Error {
    RingBufferMapping,
    TooManyCollectors,
    DeviceError
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::RingBufferMapping => write!(f, "Unable to map ring buffer device"),
            Error::TooManyCollectors => write!(f, "Too many collectors attached to device"),
            Error::DeviceError => write!(f, "Insufficient privileges to open device or device not loaded")
        }
    }
}<commit_msg>added configuration reading/parsing exceptions<commit_after>//! Encapsulates error types.

use std::result;
use std::fmt;

pub type Result<T> = result::Result<T, Error>;

/// Possible errors produced by syscall collector.
#[derive(Deserialize, Debug)]
pub enum Error {
    RingBufferMapping,
    TooManyCollectors,
    DeviceError,
    UnknownConfigPathError,
    ConfigParseError(String)
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::RingBufferMapping => write!(f, "Unable to map ring buffer device"),
            Error::TooManyCollectors => write!(f, "Too many collectors attached to device"),
            Error::DeviceError => write!(f, "Insufficient privileges to open device \
                                        or device not loaded"),
            Error::UnknownConfigPathError => write!(f, "Unable to resolve \
                                                configuration file path"),
            Error::ConfigParseError(ref e) => write!(f, "Invalid configuration descriptor. \
                                               Reason: {}", e)
        }
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;
use alloc::string::String;
use alloc::fmt;
use core::result;
use std::error::Error as StdError;
use std::io::Error as IoError;

pub type Result<T> = result::Result<T, Error>;

/// An enumeration over JPEG features (currently) unsupported by this library.
///
/// Support for features listed here may be included in future versions of this library.
#[derive(Debug)]
pub enum UnsupportedFeature {
    /// Hierarchical JPEG.
    Hierarchical,
    /// JPEG using arithmetic entropy coding instead of Huffman coding.
    ArithmeticEntropyCoding,
    /// Sample precision in bits. 8 bit sample precision is what is currently supported in non-lossless coding process.
    SamplePrecision(u8),
    /// Number of components in an image. 1, 3 and 4 components are currently supported.
    ComponentCount(u8),
    /// An image can specify a zero height in the frame header and use the DNL (Define Number of
    /// Lines) marker at the end of the first scan to define the number of lines in the frame.
    DNL,
    /// Subsampling ratio.
    SubsamplingRatio,
    /// A subsampling ratio not representable as an integer.
    NonIntegerSubsamplingRatio,
    /// Colour transform
    ColorTransform(ColorTransform),
}

/// Errors that can occur while decoding a JPEG image.
#[derive(Debug)]
pub enum Error {
    /// The image is not formatted properly. The string contains detailed information about the
    /// error.
    Format(String),
    /// The image makes use of a JPEG feature not (currently) supported by this library.
    Unsupported(UnsupportedFeature),
    /// An I/O error occurred while decoding the image.
    Io(IoError),
    /// An internal error occurred while decoding the image.
    Internal(Box<dyn StdError + Send + Sync + 'static>), //TODO: not used, can be removed with the next version bump
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Format(ref desc)      => write!(f, "invalid JPEG format: {}", desc),
            Error::Unsupported(ref feat) => write!(f, "unsupported JPEG feature: {:?}", feat),
            Error::Io(ref err)           => err.fmt(f),
            Error::Internal(ref err)     => err.fmt(f),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Internal(ref err) => Some(&**err),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
<commit_msg>Add missing `use` for `ColorTransform`<commit_after>use alloc::boxed::Box;
use alloc::string::String;
use alloc::fmt;
use core::result;
use std::error::Error as StdError;
use std::io::Error as IoError;

use crate::ColorTransform;

pub type Result<T> = result::Result<T, Error>;

/// An enumeration over JPEG features (currently) unsupported by this library.
///
/// Support for features listed here may be included in future versions of this library.
#[derive(Debug)]
pub enum UnsupportedFeature {
    /// Hierarchical JPEG.
    Hierarchical,
    /// JPEG using arithmetic entropy coding instead of Huffman coding.
    ArithmeticEntropyCoding,
    /// Sample precision in bits. 8 bit sample precision is what is currently supported in non-lossless coding process.
    SamplePrecision(u8),
    /// Number of components in an image. 1, 3 and 4 components are currently supported.
    ComponentCount(u8),
    /// An image can specify a zero height in the frame header and use the DNL (Define Number of
    /// Lines) marker at the end of the first scan to define the number of lines in the frame.
    DNL,
    /// Subsampling ratio.
    SubsamplingRatio,
    /// A subsampling ratio not representable as an integer.
    NonIntegerSubsamplingRatio,
    /// Colour transform
    ColorTransform(ColorTransform),
}

/// Errors that can occur while decoding a JPEG image.
#[derive(Debug)]
pub enum Error {
    /// The image is not formatted properly. The string contains detailed information about the
    /// error.
    Format(String),
    /// The image makes use of a JPEG feature not (currently) supported by this library.
    Unsupported(UnsupportedFeature),
    /// An I/O error occurred while decoding the image.
    Io(IoError),
    /// An internal error occurred while decoding the image.
    Internal(Box<dyn StdError + Send + Sync + 'static>), //TODO: not used, can be removed with the next version bump
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Format(ref desc)      => write!(f, "invalid JPEG format: {}", desc),
            Error::Unsupported(ref feat) => write!(f, "unsupported JPEG feature: {:?}", feat),
            Error::Io(ref err)           => err.fmt(f),
            Error::Internal(ref err)     => err.fmt(f),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Internal(ref err) => Some(&**err),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
<|endoftext|>


<commit_before>use crate::types::FromSqlError;
use crate::types::Type;
use crate::{errmsg_to_string, ffi};
use std::error;
use std::fmt;
use std::os::raw::c_int;
use std::path::PathBuf;
use std::str;

/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
#[non_exhaustive]
pub enum Error {
    /// An error from an underlying SQLite call.
    SqliteFailure(ffi::Error, Option<String>),

    /// Error reported when attempting to open a connection when SQLite was
    /// configured to allow single-threaded use only.
    SqliteSingleThreadedMode,

    /// Error when the value of a particular column is requested, but it cannot
    /// be converted to the requested Rust type.
    FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync>),

    /// Error when SQLite gives us an integral value outside the range of the
    /// requested type (e.g., trying to get the value 1000 into a `u8`).
    /// The associated `usize` is the column index,
    /// and the associated `i64` is the value returned by SQLite.
    IntegralValueOutOfRange(usize, i64),

    /// Error converting a string to UTF-8.
    Utf8Error(str::Utf8Error),

    /// Error converting a string to a C-compatible string because it contained
    /// an embedded nul.
    NulError(::std::ffi::NulError),

    /// Error when using SQL named parameters and passing a parameter name not
    /// present in the SQL.
    InvalidParameterName(String),

    /// Error converting a file path to a string.
    InvalidPath(PathBuf),

    /// Error returned when an `execute` call returns rows.
    ExecuteReturnedResults,

    /// Error when a query that was expected to return at least one row (e.g.,
    /// for `query_row`) did not return any.
    QueryReturnedNoRows,

    /// Error when the value of a particular column is requested, but the index
    /// is out of range for the statement.
    InvalidColumnIndex(usize),

    /// Error when the value of a named column is requested, but no column
    /// matches the name for the statement.
    InvalidColumnName(String),

    /// Error when the value of a particular column is requested, but the type
    /// of the result in that column cannot be converted to the requested
    /// Rust type.
    InvalidColumnType(usize, String, Type),

    /// Error when a query that was expected to insert one row did not insert
    /// any or insert many.
    StatementChangedRows(usize),

    /// Error returned by `functions::Context::get` when the function argument
    /// cannot be converted to the requested type.
    #[cfg(feature = "functions")]
    InvalidFunctionParameterType(usize, Type),
    /// Error returned by `vtab::Values::get` when the filter argument cannot
    /// be converted to the requested type.
    #[cfg(feature = "vtab")]
    InvalidFilterParameterType(usize, Type),

    /// An error case available for implementors of custom user functions (e.g.,
    /// `create_scalar_function`).
    #[cfg(feature = "functions")]
    #[allow(dead_code)]
    UserFunctionError(Box<dyn error::Error + Send + Sync>),

    /// Error available for the implementors of the `ToSql` trait.
    ToSqlConversionFailure(Box<dyn error::Error + Send + Sync>),

    /// Error when the SQL is not a `SELECT`, is not read-only.
    InvalidQuery,

    /// An error case available for implementors of custom modules (e.g.,
    /// `create_module`).
    #[cfg(feature = "vtab")]
    #[allow(dead_code)]
    ModuleError(String),

    #[cfg(feature = "functions")]
    UnwindingPanic,

    /// An error returned when `Context::get_aux` attempts to retrieve data
    /// of a different type than what had been stored using `Context::set_aux`.
    #[cfg(feature = "functions")]
    GetAuxWrongType,

    /// Error when the SQL contains multiple statements.
    MultipleStatement,
    /// Error when the number of bound parameters does not match the number of
    /// parameters in the query. The first `usize` is how many parameters were
    /// given, the 2nd is how many were expected.
    InvalidParameterCount(usize, usize),
}

impl PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        match (self, other) {
            (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
            (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
            (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
                i1 == i2 && n1 == n2
            }
            (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
            (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
            (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
            (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
            (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
            (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
            (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
            (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
            (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
                i1 == i2 && t1 == t2 && n1 == n2
            }
            (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
            #[cfg(feature = "functions")]
            (
                Error::InvalidFunctionParameterType(i1, t1),
                Error::InvalidFunctionParameterType(i2, t2),
            ) => i1 == i2 && t1 == t2,
            #[cfg(feature = "vtab")]
            (
                Error::InvalidFilterParameterType(i1, t1),
                Error::InvalidFilterParameterType(i2, t2),
            ) => i1 == i2 && t1 == t2,
            (Error::InvalidQuery, Error::InvalidQuery) => true,
            #[cfg(feature = "vtab")]
            (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
            #[cfg(feature = "functions")]
            (Error::UnwindingPanic, Error::UnwindingPanic) => true,
            #[cfg(feature = "functions")]
            (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
            (Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
                i1 == i2 && n1 == n2
            }
            (..) => false,
        }
    }
}

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

impl From<::std::ffi::NulError> for Error {
    fn from(err: ::std::ffi::NulError) -> Error {
        Error::NulError(err)
    }
}

const UNKNOWN_COLUMN: usize = std::usize::MAX;

/// The conversion isn't precise, but it's convenient to have it
/// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
impl From<FromSqlError> for Error {
    fn from(err: FromSqlError) -> Error {
        // The error type requires index and type fields, but they aren't known in this
        // context.
        match err {
            FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(_) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
            }
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(_) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
            }
            FromSqlError::Other(source) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
            }
            _ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::SqliteFailure(ref err, None) => err.fmt(f),
            Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
            Error::SqliteSingleThreadedMode => write!(
                f,
                "SQLite was compiled or configured for single-threaded use only"
            ),
            Error::FromSqlConversionFailure(i, ref t, ref err) => {
                if i != UNKNOWN_COLUMN {
                    write!(
                        f,
                        "Conversion error from type {} at index: {}, {}",
                        t, i, err
                    )
                } else {
                    err.fmt(f)
                }
            }
            Error::IntegralValueOutOfRange(col, val) => {
                if col != UNKNOWN_COLUMN {
                    write!(f, "Integer {} out of range at index {}", val, col)
                } else {
                    write!(f, "Integer {} out of range", val)
                }
            }
            Error::Utf8Error(ref err) => err.fmt(f),
            Error::NulError(ref err) => err.fmt(f),
            Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
            Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
            Error::ExecuteReturnedResults => {
                write!(f, "Execute returned results - did you mean to call query?")
            }
            Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
            Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
            Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
            Error::InvalidColumnType(i, ref name, ref t) => write!(
                f,
                "Invalid column type {} at index: {}, name: {}",
                t, i, name
            ),
            Error::InvalidParameterCount(i1, n1) => write!(
                f,
                "Wrong number of parameters passed to query. Got {}, needed {}",
                i1, n1
            ),
            Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(i, ref t) => {
                write!(f, "Invalid function parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(i, ref t) => {
                write!(f, "Invalid filter parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.fmt(f),
            Error::ToSqlConversionFailure(ref err) => err.fmt(f),
            Error::InvalidQuery => write!(f, "Query is not read-only"),
            #[cfg(feature = "vtab")]
            Error::ModuleError(ref desc) => write!(f, "{}", desc),
            #[cfg(feature = "functions")]
            Error::UnwindingPanic => write!(f, "unwinding panic"),
            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
            Error::MultipleStatement => write!(f, "Multiple statements provided"),
        }
    }
}

impl error::Error for Error {
    #[allow(deprecated)]
    fn description(&self) -> &str {
        match *self {
            Error::SqliteFailure(ref err, None) => err.description(),
            Error::SqliteFailure(_, Some(ref s)) => s,
            Error::SqliteSingleThreadedMode => {
                "SQLite was compiled or configured for single-threaded use only"
            }
            Error::FromSqlConversionFailure(_, _, ref err) => err.description(),
            Error::IntegralValueOutOfRange(..) => "integral value out of range of requested type",
            Error::Utf8Error(ref err) => err.description(),
            Error::InvalidParameterName(_) => "invalid parameter name",
            Error::NulError(ref err) => err.description(),
            Error::InvalidPath(_) => "invalid path",
            Error::ExecuteReturnedResults => {
                "execute returned results - did you mean to call query?"
            }
            Error::InvalidParameterCount(..) => "Wrong number of parameters passed to query.",
            Error::QueryReturnedNoRows => "query returned no rows",
            Error::InvalidColumnIndex(_) => "invalid column index",
            Error::InvalidColumnName(_) => "invalid column name",
            Error::InvalidColumnType(..) => "invalid column type",
            Error::StatementChangedRows(_) => "query inserted zero or more than one row",

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(..) => "invalid function parameter type",
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(..) => "invalid filter parameter type",
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.description(),
            Error::ToSqlConversionFailure(ref err) => err.description(),
            Error::InvalidQuery => "query is not read-only",
            #[cfg(feature = "vtab")]
            Error::ModuleError(ref desc) => desc,
            #[cfg(feature = "functions")]
            Error::UnwindingPanic => "unwinding panic",
            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => "get_aux called with wrong type",
            Error::MultipleStatement => "multiple statements provided",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            Error::SqliteFailure(ref err, _) => Some(err),
            Error::Utf8Error(ref err) => Some(err),
            Error::NulError(ref err) => Some(err),

            Error::IntegralValueOutOfRange(..)
            | Error::SqliteSingleThreadedMode
            | Error::InvalidParameterName(_)
            | Error::ExecuteReturnedResults
            | Error::QueryReturnedNoRows
            | Error::InvalidColumnIndex(_)
            | Error::InvalidColumnName(_)
            | Error::InvalidColumnType(..)
            | Error::InvalidPath(_)
            | Error::InvalidParameterCount(..)
            | Error::StatementChangedRows(_)
            | Error::InvalidQuery
            | Error::MultipleStatement => None,

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(..) => None,
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(..) => None,

            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => Some(&**err),

            Error::FromSqlConversionFailure(_, _, ref err)
            | Error::ToSqlConversionFailure(ref err) => Some(&**err),

            #[cfg(feature = "vtab")]
            Error::ModuleError(_) => None,

            #[cfg(feature = "functions")]
            Error::UnwindingPanic => None,

            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => None,
        }
    }
}

// These are public but not re-exported by lib.rs, so only visible within crate.

pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
    Error::SqliteFailure(ffi::Error::new(code), message)
}

pub fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
    let message = if db.is_null() {
        None
    } else {
        Some(unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) })
    };
    error_from_sqlite_code(code, message)
}

macro_rules! check {
    ($funcall:expr) => {{
        let rc = $funcall;
        if rc != crate::ffi::SQLITE_OK {
            return Err(crate::error::error_from_sqlite_code(rc, None).into());
        }
    }};
}
<commit_msg>Implement std::error::Error::source instead of cause (#683)<commit_after>use crate::types::FromSqlError;
use crate::types::Type;
use crate::{errmsg_to_string, ffi};
use std::error;
use std::fmt;
use std::os::raw::c_int;
use std::path::PathBuf;
use std::str;

/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
#[non_exhaustive]
pub enum Error {
    /// An error from an underlying SQLite call.
    SqliteFailure(ffi::Error, Option<String>),

    /// Error reported when attempting to open a connection when SQLite was
    /// configured to allow single-threaded use only.
    SqliteSingleThreadedMode,

    /// Error when the value of a particular column is requested, but it cannot
    /// be converted to the requested Rust type.
    FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync + 'static>),

    /// Error when SQLite gives us an integral value outside the range of the
    /// requested type (e.g., trying to get the value 1000 into a `u8`).
    /// The associated `usize` is the column index,
    /// and the associated `i64` is the value returned by SQLite.
    IntegralValueOutOfRange(usize, i64),

    /// Error converting a string to UTF-8.
    Utf8Error(str::Utf8Error),

    /// Error converting a string to a C-compatible string because it contained
    /// an embedded nul.
    NulError(::std::ffi::NulError),

    /// Error when using SQL named parameters and passing a parameter name not
    /// present in the SQL.
    InvalidParameterName(String),

    /// Error converting a file path to a string.
    InvalidPath(PathBuf),

    /// Error returned when an `execute` call returns rows.
    ExecuteReturnedResults,

    /// Error when a query that was expected to return at least one row (e.g.,
    /// for `query_row`) did not return any.
    QueryReturnedNoRows,

    /// Error when the value of a particular column is requested, but the index
    /// is out of range for the statement.
    InvalidColumnIndex(usize),

    /// Error when the value of a named column is requested, but no column
    /// matches the name for the statement.
    InvalidColumnName(String),

    /// Error when the value of a particular column is requested, but the type
    /// of the result in that column cannot be converted to the requested
    /// Rust type.
    InvalidColumnType(usize, String, Type),

    /// Error when a query that was expected to insert one row did not insert
    /// any or insert many.
    StatementChangedRows(usize),

    /// Error returned by `functions::Context::get` when the function argument
    /// cannot be converted to the requested type.
    #[cfg(feature = "functions")]
    InvalidFunctionParameterType(usize, Type),
    /// Error returned by `vtab::Values::get` when the filter argument cannot
    /// be converted to the requested type.
    #[cfg(feature = "vtab")]
    InvalidFilterParameterType(usize, Type),

    /// An error case available for implementors of custom user functions (e.g.,
    /// `create_scalar_function`).
    #[cfg(feature = "functions")]
    #[allow(dead_code)]
    UserFunctionError(Box<dyn error::Error + Send + Sync + 'static>),

    /// Error available for the implementors of the `ToSql` trait.
    ToSqlConversionFailure(Box<dyn error::Error + Send + Sync + 'static>),

    /// Error when the SQL is not a `SELECT`, is not read-only.
    InvalidQuery,

    /// An error case available for implementors of custom modules (e.g.,
    /// `create_module`).
    #[cfg(feature = "vtab")]
    #[allow(dead_code)]
    ModuleError(String),

    #[cfg(feature = "functions")]
    UnwindingPanic,

    /// An error returned when `Context::get_aux` attempts to retrieve data
    /// of a different type than what had been stored using `Context::set_aux`.
    #[cfg(feature = "functions")]
    GetAuxWrongType,

    /// Error when the SQL contains multiple statements.
    MultipleStatement,
    /// Error when the number of bound parameters does not match the number of
    /// parameters in the query. The first `usize` is how many parameters were
    /// given, the 2nd is how many were expected.
    InvalidParameterCount(usize, usize),
}

impl PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        match (self, other) {
            (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
            (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
            (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
                i1 == i2 && n1 == n2
            }
            (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
            (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
            (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
            (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
            (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
            (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
            (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
            (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
            (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
                i1 == i2 && t1 == t2 && n1 == n2
            }
            (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
            #[cfg(feature = "functions")]
            (
                Error::InvalidFunctionParameterType(i1, t1),
                Error::InvalidFunctionParameterType(i2, t2),
            ) => i1 == i2 && t1 == t2,
            #[cfg(feature = "vtab")]
            (
                Error::InvalidFilterParameterType(i1, t1),
                Error::InvalidFilterParameterType(i2, t2),
            ) => i1 == i2 && t1 == t2,
            (Error::InvalidQuery, Error::InvalidQuery) => true,
            #[cfg(feature = "vtab")]
            (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
            #[cfg(feature = "functions")]
            (Error::UnwindingPanic, Error::UnwindingPanic) => true,
            #[cfg(feature = "functions")]
            (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
            (Error::InvalidParameterCount(i1, n1), Error::InvalidParameterCount(i2, n2)) => {
                i1 == i2 && n1 == n2
            }
            (..) => false,
        }
    }
}

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

impl From<::std::ffi::NulError> for Error {
    fn from(err: ::std::ffi::NulError) -> Error {
        Error::NulError(err)
    }
}

const UNKNOWN_COLUMN: usize = std::usize::MAX;

/// The conversion isn't precise, but it's convenient to have it
/// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
impl From<FromSqlError> for Error {
    fn from(err: FromSqlError) -> Error {
        // The error type requires index and type fields, but they aren't known in this
        // context.
        match err {
            FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(_) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
            }
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(_) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
            }
            FromSqlError::Other(source) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
            }
            _ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::SqliteFailure(ref err, None) => err.fmt(f),
            Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
            Error::SqliteSingleThreadedMode => write!(
                f,
                "SQLite was compiled or configured for single-threaded use only"
            ),
            Error::FromSqlConversionFailure(i, ref t, ref err) => {
                if i != UNKNOWN_COLUMN {
                    write!(
                        f,
                        "Conversion error from type {} at index: {}, {}",
                        t, i, err
                    )
                } else {
                    err.fmt(f)
                }
            }
            Error::IntegralValueOutOfRange(col, val) => {
                if col != UNKNOWN_COLUMN {
                    write!(f, "Integer {} out of range at index {}", val, col)
                } else {
                    write!(f, "Integer {} out of range", val)
                }
            }
            Error::Utf8Error(ref err) => err.fmt(f),
            Error::NulError(ref err) => err.fmt(f),
            Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
            Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
            Error::ExecuteReturnedResults => {
                write!(f, "Execute returned results - did you mean to call query?")
            }
            Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
            Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
            Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
            Error::InvalidColumnType(i, ref name, ref t) => write!(
                f,
                "Invalid column type {} at index: {}, name: {}",
                t, i, name
            ),
            Error::InvalidParameterCount(i1, n1) => write!(
                f,
                "Wrong number of parameters passed to query. Got {}, needed {}",
                i1, n1
            ),
            Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(i, ref t) => {
                write!(f, "Invalid function parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(i, ref t) => {
                write!(f, "Invalid filter parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.fmt(f),
            Error::ToSqlConversionFailure(ref err) => err.fmt(f),
            Error::InvalidQuery => write!(f, "Query is not read-only"),
            #[cfg(feature = "vtab")]
            Error::ModuleError(ref desc) => write!(f, "{}", desc),
            #[cfg(feature = "functions")]
            Error::UnwindingPanic => write!(f, "unwinding panic"),
            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
            Error::MultipleStatement => write!(f, "Multiple statements provided"),
        }
    }
}

impl error::Error for Error {
    #[allow(deprecated)]
    fn description(&self) -> &str {
        match *self {
            Error::SqliteFailure(ref err, None) => err.description(),
            Error::SqliteFailure(_, Some(ref s)) => s,
            Error::SqliteSingleThreadedMode => {
                "SQLite was compiled or configured for single-threaded use only"
            }
            Error::FromSqlConversionFailure(_, _, ref err) => err.description(),
            Error::IntegralValueOutOfRange(..) => "integral value out of range of requested type",
            Error::Utf8Error(ref err) => err.description(),
            Error::InvalidParameterName(_) => "invalid parameter name",
            Error::NulError(ref err) => err.description(),
            Error::InvalidPath(_) => "invalid path",
            Error::ExecuteReturnedResults => {
                "execute returned results - did you mean to call query?"
            }
            Error::InvalidParameterCount(..) => "Wrong number of parameters passed to query.",
            Error::QueryReturnedNoRows => "query returned no rows",
            Error::InvalidColumnIndex(_) => "invalid column index",
            Error::InvalidColumnName(_) => "invalid column name",
            Error::InvalidColumnType(..) => "invalid column type",
            Error::StatementChangedRows(_) => "query inserted zero or more than one row",

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(..) => "invalid function parameter type",
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(..) => "invalid filter parameter type",
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.description(),
            Error::ToSqlConversionFailure(ref err) => err.description(),
            Error::InvalidQuery => "query is not read-only",
            #[cfg(feature = "vtab")]
            Error::ModuleError(ref desc) => desc,
            #[cfg(feature = "functions")]
            Error::UnwindingPanic => "unwinding panic",
            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => "get_aux called with wrong type",
            Error::MultipleStatement => "multiple statements provided",
        }
    }

    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match *self {
            Error::SqliteFailure(ref err, _) => Some(err),
            Error::Utf8Error(ref err) => Some(err),
            Error::NulError(ref err) => Some(err),

            Error::IntegralValueOutOfRange(..)
            | Error::SqliteSingleThreadedMode
            | Error::InvalidParameterName(_)
            | Error::ExecuteReturnedResults
            | Error::QueryReturnedNoRows
            | Error::InvalidColumnIndex(_)
            | Error::InvalidColumnName(_)
            | Error::InvalidColumnType(..)
            | Error::InvalidPath(_)
            | Error::InvalidParameterCount(..)
            | Error::StatementChangedRows(_)
            | Error::InvalidQuery
            | Error::MultipleStatement => None,

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(..) => None,
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(..) => None,

            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => Some(&**err),

            Error::FromSqlConversionFailure(_, _, ref err)
            | Error::ToSqlConversionFailure(ref err) => Some(&**err),

            #[cfg(feature = "vtab")]
            Error::ModuleError(_) => None,

            #[cfg(feature = "functions")]
            Error::UnwindingPanic => None,

            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => None,
        }
    }
}

// These are public but not re-exported by lib.rs, so only visible within crate.

pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
    Error::SqliteFailure(ffi::Error::new(code), message)
}

pub fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
    let message = if db.is_null() {
        None
    } else {
        Some(unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) })
    };
    error_from_sqlite_code(code, message)
}

macro_rules! check {
    ($funcall:expr) => {{
        let rc = $funcall;
        if rc != crate::ffi::SQLITE_OK {
            return Err(crate::error::error_from_sqlite_code(rc, None).into());
        }
    }};
}
<|endoftext|>


<commit_before>use xcb::Atom;
use xcb::base::{ ConnError, GenericError };
use std::fmt;
use std::sync::mpsc::SendError;
use std::error::Error as StdError;

#[must_use]
#[derive(Debug)]
pub enum Error {
    Set(SendError<Atom>),
    XcbConn(ConnError),
    XcbGeneric(GenericError),
    Lock,
    Timeout,
    Owner
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match self {
            Set(e) => write!(f, "{}: {:?}", self.description(), e),
            XcbConn(e) => write!(f, "{}: {:?}", self.description(), e),
            XcbGeneric(e) => write!(f, "{}: {:?}", self.description(), e),
            Lock | Timeout | Owner => write!(f, "{}", self.description()),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match self {
            Set(_) => "XCB - couldn't set atom",
            XcbConn(_) => "XCB connection error",
            XcbGeneric(_) => "XCB generic error",
            Lock => "XCB: Lock is poisoned",
            Timeout => "Selection timed out",
            Owner => "Failed to set new owner of XCB selection",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;
        match self {
            Set(e) => e.cause(),
            XcbConn(e) => e.cause(),
            XcbGeneric(e) => e.cause(),
            Lock | Timeout | Owner => None,
        }
    }
}

macro_rules! define_from {
    ( $item:ident from $err:ty ) => {
        impl From<$err> for Error {
            fn from(err: $err) -> Error {
                Error::$item(err)
            }
        }
    }
}

define_from!(Set from SendError<Atom>);
define_from!(XcbConn from ConnError);
define_from!(XcbGeneric from GenericError);
<commit_msg>fix cause<commit_after>use xcb::Atom;
use xcb::base::{ ConnError, GenericError };
use std::fmt;
use std::sync::mpsc::SendError;
use std::error::Error as StdError;

#[must_use]
#[derive(Debug)]
pub enum Error {
    Set(SendError<Atom>),
    XcbConn(ConnError),
    XcbGeneric(GenericError),
    Lock,
    Timeout,
    Owner
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match self {
            Set(e) => write!(f, "{}: {:?}", self.description(), e),
            XcbConn(e) => write!(f, "{}: {:?}", self.description(), e),
            XcbGeneric(e) => write!(f, "{}: {:?}", self.description(), e),
            Lock | Timeout | Owner => write!(f, "{}", self.description()),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match self {
            Set(_) => "XCB - couldn't set atom",
            XcbConn(_) => "XCB connection error",
            XcbGeneric(_) => "XCB generic error",
            Lock => "XCB: Lock is poisoned",
            Timeout => "Selection timed out",
            Owner => "Failed to set new owner of XCB selection",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;
        match self {
            Set(e) => Some(e),
            XcbConn(e) => Some(e),
            XcbGeneric(e) => Some(e),
            Lock | Timeout | Owner => None,
        }
    }
}

macro_rules! define_from {
    ( $item:ident from $err:ty ) => {
        impl From<$err> for Error {
            fn from(err: $err) -> Error {
                Error::$item(err)
            }
        }
    }
}

define_from!(Set from SendError<Atom>);
define_from!(XcbConn from ConnError);
define_from!(XcbGeneric from GenericError);
<|endoftext|>


<commit_before>//! `std:error:Error` implementations

use std::fmt;
use std::io;
use std::error::{Error, FromError};

/// `Error` variants for public errors in this crate
#[derive(Debug)]
pub enum Chip8Error {
    /// I/O error
    Io(&'static str, Option<io::Error>),
}

impl fmt::Display for Chip8Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        return write!(fmt, "{}", self.description())
    }
}

impl Error for Chip8Error {
    fn description(&self) -> &str {
        match *self {
            Chip8Error::Io(desc, _) => desc,
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            Chip8Error::Io(_, Some(ref cause)) => Some(cause),
            _ => None,
        }
    }
}

impl FromError<io::Error> for Chip8Error {
    fn from_error(err: io::Error) -> Chip8Error {
        Chip8Error::Io("Internal IO error: ", Some(err))
    }
}
<commit_msg>Replace `FromError` with `From`<commit_after>//! `std:error:Error` implementations

use std::fmt;
use std::io;
use std::error::Error;
use std::convert::From;

/// `Error` variants for public errors in this crate
#[derive(Debug)]
pub enum Chip8Error {
    /// I/O error
    Io(&'static str, Option<io::Error>),
}

impl fmt::Display for Chip8Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        return write!(fmt, "{}", self.description())
    }
}

impl Error for Chip8Error {
    fn description(&self) -> &str {
        match *self {
            Chip8Error::Io(desc, _) => desc,
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            Chip8Error::Io(_, Some(ref cause)) => Some(cause),
            _ => None,
        }
    }
}

impl From<io::Error> for Chip8Error {
    fn from(err: io::Error) -> Chip8Error {
        Chip8Error::Io("I/O error", Some(err))
    }
}
<|endoftext|>