<commit_before>#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{boot, App, Env};
use std::{
    fs::File,
    sync::{mpsc::channel, Arc, Mutex},
    thread,
    time::Duration,
};

use civet::Server as CivetServer;
use conduit_hyper::Service;
use futures::prelude::*;
use reqwest::blocking::Client;

enum Server {
    Civet(CivetServer),
    Hyper(tokio::runtime::Runtime, tokio::task::JoinHandle<()>),
}

use Server::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize logging
    env_logger::init();

    let config = cargo_registry::Config::default();
    let client = Client::new();

    let app = App::new(&config, Some(client));
    let app = cargo_registry::build_handler(Arc::new(app));

    // On every server restart, ensure the categories available in the database match
    // the information in *src/categories.toml*.
    let categories_toml = include_str!("../boot/categories.toml");
    boot::categories::sync(categories_toml).unwrap();

    let heroku = dotenv::var("HEROKU").is_ok();
    let fastboot = dotenv::var("USE_FASTBOOT").is_ok();

    let port = if heroku {
        8888
    } else {
        dotenv::var("PORT")
            .ok()
            .and_then(|s| s.parse().ok())
            .unwrap_or(8888)
    };
    let threads = dotenv::var("SERVER_THREADS")
        .map(|s| s.parse().expect("SERVER_THREADS was not a valid number"))
        .unwrap_or_else(|_| {
            if config.env == Env::Development {
                1
            } else {
                50
            }
        });

    let server = if dotenv::var("USE_HYPER").is_ok() {
        use tokio::io::AsyncWriteExt;
        use tokio::signal::unix::{signal, SignalKind};

        println!("Booting with a hyper based server");

        let mut rt = tokio::runtime::Builder::new()
            .threaded_scheduler()
            .enable_all()
            .build()
            .unwrap();

        let handler = Arc::new(conduit_hyper::BlockingHandler::new(app, threads as usize));
        let make_service =
            hyper::service::make_service_fn(move |socket: &hyper::server::conn::AddrStream| {
                let addr = socket.remote_addr();
                let handler = handler.clone();
                async move { Service::from_blocking(handler, addr) }
            });

        let addr = ([127, 0, 0, 1], port).into();
        let server = rt.block_on(async { hyper::Server::bind(&addr).serve(make_service) });

        let mut sig_int = rt.block_on(async { signal(SignalKind::interrupt()) })?;
        let mut sig_term = rt.block_on(async { signal(SignalKind::terminate()) })?;

        let server = server.with_graceful_shutdown(async move {
            // Wait for either signal
            futures::select! {
                _ = sig_int.recv().fuse() => (),
                _ = sig_term.recv().fuse() => (),
            };
            let mut stdout = tokio::io::stdout();
            stdout.write_all(b"Starting graceful shutdown\n").await.ok();
        });

        let server = rt.spawn(async { server.await.unwrap() });
        Hyper(rt, server)
    } else {
        println!("Booting with a civet based server");
        let mut cfg = civet::Config::new();
        cfg.port(port).threads(threads).keep_alive(true);
        Civet(CivetServer::start(cfg, app).unwrap())
    };

    println!("listening on port {}", port);

    // Give tokio a chance to spawn the first worker thread
    thread::sleep(Duration::from_millis(10));

    // Creating this file tells heroku to tell nginx that the application is ready
    // to receive traffic.
    if heroku {
        let path = if fastboot {
            "/tmp/backend-initialized"
        } else {
            "/tmp/app-initialized"
        };
        println!("Writing to {}", path);
        File::create(path).unwrap();
    }

    // Block the main thread until the server has shutdown
    match server {
        Hyper(mut rt, server) => {
            rt.block_on(async { server.await.unwrap() });
        }
        Civet(server) => {
            let (tx, rx) = channel::<()>();
            ctrlc_handler(move || tx.send(()).unwrap_or(()));
            rx.recv().unwrap();
            drop(server);
        }
    }

    println!("Server has gracefully shutdown!");
    Ok(())
}

fn ctrlc_handler<F>(f: F)
where
    F: FnOnce() + Send + 'static,
{
    let call_once = Mutex::new(Some(f));

    ctrlc::set_handler(move || {
        if let Some(f) = call_once.lock().unwrap().take() {
            println!("Starting graceful shutdown");
            f();
        } else {
            println!("Already sent signal to start graceful shutdown");
        }
    })
    .unwrap();
}
<commit_msg>Increase the default thread count to 5 in development<commit_after>#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{boot, App, Env};
use std::{
    fs::File,
    sync::{mpsc::channel, Arc, Mutex},
    thread,
    time::Duration,
};

use civet::Server as CivetServer;
use conduit_hyper::Service;
use futures::prelude::*;
use reqwest::blocking::Client;

enum Server {
    Civet(CivetServer),
    Hyper(tokio::runtime::Runtime, tokio::task::JoinHandle<()>),
}

use Server::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize logging
    env_logger::init();

    let config = cargo_registry::Config::default();
    let client = Client::new();

    let app = App::new(&config, Some(client));
    let app = cargo_registry::build_handler(Arc::new(app));

    // On every server restart, ensure the categories available in the database match
    // the information in *src/categories.toml*.
    let categories_toml = include_str!("../boot/categories.toml");
    boot::categories::sync(categories_toml).unwrap();

    let heroku = dotenv::var("HEROKU").is_ok();
    let fastboot = dotenv::var("USE_FASTBOOT").is_ok();

    let port = if heroku {
        8888
    } else {
        dotenv::var("PORT")
            .ok()
            .and_then(|s| s.parse().ok())
            .unwrap_or(8888)
    };
    let threads = dotenv::var("SERVER_THREADS")
        .map(|s| s.parse().expect("SERVER_THREADS was not a valid number"))
        .unwrap_or_else(|_| {
            if config.env == Env::Development {
                5
            } else {
                50
            }
        });

    let server = if dotenv::var("USE_HYPER").is_ok() {
        use tokio::io::AsyncWriteExt;
        use tokio::signal::unix::{signal, SignalKind};

        println!("Booting with a hyper based server");

        let mut rt = tokio::runtime::Builder::new()
            .threaded_scheduler()
            .enable_all()
            .build()
            .unwrap();

        let handler = Arc::new(conduit_hyper::BlockingHandler::new(app, threads as usize));
        let make_service =
            hyper::service::make_service_fn(move |socket: &hyper::server::conn::AddrStream| {
                let addr = socket.remote_addr();
                let handler = handler.clone();
                async move { Service::from_blocking(handler, addr) }
            });

        let addr = ([127, 0, 0, 1], port).into();
        let server = rt.block_on(async { hyper::Server::bind(&addr).serve(make_service) });

        let mut sig_int = rt.block_on(async { signal(SignalKind::interrupt()) })?;
        let mut sig_term = rt.block_on(async { signal(SignalKind::terminate()) })?;

        let server = server.with_graceful_shutdown(async move {
            // Wait for either signal
            futures::select! {
                _ = sig_int.recv().fuse() => (),
                _ = sig_term.recv().fuse() => (),
            };
            let mut stdout = tokio::io::stdout();
            stdout.write_all(b"Starting graceful shutdown\n").await.ok();
        });

        let server = rt.spawn(async { server.await.unwrap() });
        Hyper(rt, server)
    } else {
        println!("Booting with a civet based server");
        let mut cfg = civet::Config::new();
        cfg.port(port).threads(threads).keep_alive(true);
        Civet(CivetServer::start(cfg, app).unwrap())
    };

    println!("listening on port {}", port);

    // Give tokio a chance to spawn the first worker thread
    thread::sleep(Duration::from_millis(10));

    // Creating this file tells heroku to tell nginx that the application is ready
    // to receive traffic.
    if heroku {
        let path = if fastboot {
            "/tmp/backend-initialized"
        } else {
            "/tmp/app-initialized"
        };
        println!("Writing to {}", path);
        File::create(path).unwrap();
    }

    // Block the main thread until the server has shutdown
    match server {
        Hyper(mut rt, server) => {
            rt.block_on(async { server.await.unwrap() });
        }
        Civet(server) => {
            let (tx, rx) = channel::<()>();
            ctrlc_handler(move || tx.send(()).unwrap_or(()));
            rx.recv().unwrap();
            drop(server);
        }
    }

    println!("Server has gracefully shutdown!");
    Ok(())
}

fn ctrlc_handler<F>(f: F)
where
    F: FnOnce() + Send + 'static,
{
    let call_once = Mutex::new(Some(f));

    ctrlc::set_handler(move || {
        if let Some(f) = call_once.lock().unwrap().take() {
            println!("Starting graceful shutdown");
            f();
        } else {
            println!("Already sent signal to start graceful shutdown");
        }
    })
    .unwrap();
}
<|endoftext|>


<commit_before>//! Implement elementary coordinate operations.

use std::error::Error;
use std::fmt;
use std::fmt::Display;
use std::ops::{Add, Sub};
use std::str::FromStr;

#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
/// A three-dimensional coordinate.
///
/// # Examples
/// ```
/// # use grafen::coord::Coord;
/// let coord1 = Coord::new(1.0, 0.0, 1.0);
/// let coord2 = Coord::new(0.5, 0.5, 0.5);
///
/// assert_eq!(Coord::new(1.5, 0.5, 1.5), coord1 + coord2);
/// assert_eq!(Coord::new(0.5, -0.5, 0.5), coord1 - coord2);
/// ```
pub struct Coord {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl Coord {
    /// A coordinate at origo.
    pub const ORIGO: Self = Coord { x: 0.0, y: 0.0, z: 0.0 };

    /// Construct a new coordinate.
    pub fn new(x: f64, y: f64, z: f64) -> Coord {
        Coord { x: x, y: y, z: z }
    }

    /// Unpack the coordinate into a tuple.
    pub fn to_tuple(&self) -> (f64, f64, f64) {
        (self.x, self.y, self.z)
    }

    /// Calculate the absolute distance between two coordinates.
    pub fn distance(self, other: Coord) -> f64 {
        let dx = self - other;

        (dx.x * dx.x + dx.y * dx.y + dx.z * dx.z).sqrt()
    }

    /// Return the coordinate with its position adjusted to lie within the input box.
    ///
    /// If an input box size side is 0.0 (or smaller) the coordinate is not changed.
    pub fn with_pbc(self, box_size: Coord) -> Coord {
        let do_pbc = |mut c: f64, size: f64| {
            if size <= 0.0 {
                c
            } else {
                while c < 0.0 {
                    c += size;
                }

                c % size
            }
        };

        let (x, y, z) = self.to_tuple();
        Coord::new(do_pbc(x, box_size.x), do_pbc(y, box_size.y), do_pbc(z, box_size.z))
    }
}

impl Display for Coord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({:.1}, {:.1}, {:.1})", self.x, self.y, self.z)
    }
}

impl Add for Coord {
    type Output = Coord;

    fn add(self, other: Coord) -> Coord {
        Coord::new(self.x + other.x, self.y + other.y, self.z + other.z)
    }

}

impl Sub for Coord {
    type Output = Coord;

    fn sub(self, other: Coord) -> Coord {
        Coord::new(self.x - other.x, self.y - other.y, self.z - other.z)
    }

}

impl PartialEq for Coord {
    fn eq(&self, other: &Coord) -> bool {
        let atol = 1e-9;
        (self.x - other.x).abs() < atol
            && (self.y - other.y).abs() < atol
            && (self.z - other.z).abs() < atol
    }
}

impl FromStr for Coord {
    type Err = String;

    fn from_str(input: &str) -> Result<Coord, Self::Err> {
        let parse_opt_value = |value: Option<&str>| {
            value.ok_or("Not enough values to parse".to_string())
                 .and_then(|v| v.parse::<f64>().map_err(|err| err.description().to_string()))
        };

        let mut split = input.split_whitespace();
        let x = parse_opt_value(split.next())?;
        let y = parse_opt_value(split.next())?;
        let z = parse_opt_value(split.next())?;

        return Ok(Coord { x, y, z})
    }
}

/// Trait denoting the ability to `Translate` an object with a `Coord`.
pub trait Translate {
    fn translate(self, &Coord) -> Self;
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;

    #[test]
    fn coord_origo_is_correct() {
        assert_eq!(Coord::new(0.0, 0.0, 0.0), Coord::ORIGO);
    }

    #[test]
    fn coord_addition_and_subtraction() {
        let coord = Coord::new(0.0, 1.0, 2.0);
        assert_eq!(Coord::new(0.0, 2.0, 4.0), coord + coord);
        assert_eq!(Coord::new(0.0, 0.0, 0.0), coord - coord);

    }

    #[test]
    fn coord_eq_tolerance_small_deviation_passes() {
        // Allow for some deviation when testing for equality, since floating point
        // numbers are stupid.
        let coord = Coord::new(0.0, 0.0, 0.0);
        assert_eq!(coord, Coord::new(1e-10, 2e-10, 3e-10));
    }

    #[test]
    #[should_panic]
    fn coord_eq_tolerance_larger_deviation_does_not() {
        let coord = Coord::new(0.0, 0.0, 0.0);
        assert_eq!(coord, Coord::new(1e-9, 2e-9, 3e-9));
    }

    #[test]
    fn coord_distance_calc() {
        let coord1 = Coord::new(1.0, 1.0, 1.0);
        let coord2 = Coord::new(3.0, 3.0, 2.0);

        assert_eq!(3.0, Coord::distance(coord1, coord2));
        assert_eq!(3.0, coord1.distance(coord2));
    }

    #[test]
    fn coord_to_tuple() {
        let coord = Coord::new(1.0, 2.0, 3.0);
        assert_eq!((1.0, 2.0, 3.0), coord.to_tuple());
    }

    #[test]
    fn coord_with_set_pbc() {
        let box_size = Coord::new(2.0, 4.0, 6.0);
        assert_eq!(Coord::new(1.0, 1.0, 1.0), Coord::new(1.0, 1.0, 1.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 1.0, 1.0), Coord::new(3.0, 1.0, 1.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 0.5, 1.0), Coord::new(1.0, 4.5, 1.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 1.0, 1.0), Coord::new(1.0, 1.0, 13.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 1.0, 1.0), Coord::new(-1.0, 1.0, 1.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 3.0, 1.0), Coord::new(1.0, -1.0, 1.0).with_pbc(box_size));
    }

    #[test]
    fn coords_adjusted_by_pbc_with_size_0_does_not_change() {
        let box_size = Coord::new(0.0, 0.0, 0.0);
        let coord = Coord::new(1.0, 2.0, 3.0);
        assert_eq!(coord, coord.with_pbc(box_size));
    }

    #[test]
    fn coord_display_format() {
        let coord = Coord::ORIGO;
        assert_eq!("(0.0, 0.0, 0.0)", &format!("{}", coord));
    }

    #[test]
    fn coord_parsed_from_string() {
        assert_eq!(Ok(Coord::new(1.0, -1.0, 2.0)), Coord::from_str("1.0 -1.0 2.0"));
        assert_eq!(Ok(Coord::new(1.0, -1.0, 2.0)), Coord::from_str("1 -1.0 2"));
        assert_eq!(Ok(Coord::new(1.0, -1.0, 2.0)), Coord::from_str("\t1.0 -1.0 2.0"));
        assert!(Coord::from_str("").is_err());
        assert!(Coord::from_str("2.0 1.0").is_err());
    }
}
<commit_msg>Implement `Neg`, `AddAssign` and `SubAssign` for `Coord`<commit_after>//! Implement elementary coordinate operations.

use std::error::Error;
use std::fmt;
use std::fmt::Display;
use std::ops::{Add, AddAssign, Sub, SubAssign, Neg};
use std::str::FromStr;

#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
/// A three-dimensional coordinate.
///
/// # Examples
/// ```
/// # use grafen::coord::Coord;
/// let coord1 = Coord::new(1.0, 0.0, 1.0);
/// let coord2 = Coord::new(0.5, 0.5, 0.5);
///
/// assert_eq!(Coord::new(1.5, 0.5, 1.5), coord1 + coord2);
/// assert_eq!(Coord::new(0.5, -0.5, 0.5), coord1 - coord2);
/// ```
pub struct Coord {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl Coord {
    /// A coordinate at origo.
    pub const ORIGO: Self = Coord { x: 0.0, y: 0.0, z: 0.0 };

    /// Construct a new coordinate.
    pub fn new(x: f64, y: f64, z: f64) -> Coord {
        Coord { x: x, y: y, z: z }
    }

    /// Unpack the coordinate into a tuple.
    pub fn to_tuple(&self) -> (f64, f64, f64) {
        (self.x, self.y, self.z)
    }

    /// Calculate the absolute distance between two coordinates.
    pub fn distance(self, other: Coord) -> f64 {
        let dx = self - other;

        (dx.x * dx.x + dx.y * dx.y + dx.z * dx.z).sqrt()
    }

    /// Return the coordinate with its position adjusted to lie within the input box.
    ///
    /// If an input box size side is 0.0 (or smaller) the coordinate is not changed.
    pub fn with_pbc(self, box_size: Coord) -> Coord {
        let do_pbc = |mut c: f64, size: f64| {
            if size <= 0.0 {
                c
            } else {
                while c < 0.0 {
                    c += size;
                }

                c % size
            }
        };

        let (x, y, z) = self.to_tuple();
        Coord::new(do_pbc(x, box_size.x), do_pbc(y, box_size.y), do_pbc(z, box_size.z))
    }
}

impl Display for Coord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({:.1}, {:.1}, {:.1})", self.x, self.y, self.z)
    }
}

impl Add for Coord {
    type Output = Coord;

    fn add(self, other: Coord) -> Self::Output {
        Coord::new(self.x + other.x, self.y + other.y, self.z + other.z)
    }

}

impl AddAssign for Coord {
    fn add_assign(&mut self, other: Coord) {
        *self = Coord {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        };
    }
}

impl Sub for Coord {
    type Output = Coord;

    fn sub(self, other: Coord) -> Self::Output {
        Coord::new(self.x - other.x, self.y - other.y, self.z - other.z)
    }

}

impl SubAssign for Coord {
    fn sub_assign(&mut self, other: Coord) {
        *self = Coord {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
        };
    }
}

impl Neg for Coord {
    type Output = Coord;

    fn neg(self) -> Self::Output {
        Coord { x: -self.x, y: -self.y, z: -self.z }
    }
}

impl PartialEq for Coord {
    fn eq(&self, other: &Coord) -> bool {
        let atol = 1e-9;
        (self.x - other.x).abs() < atol
            && (self.y - other.y).abs() < atol
            && (self.z - other.z).abs() < atol
    }
}

impl FromStr for Coord {
    type Err = String;

    fn from_str(input: &str) -> Result<Coord, Self::Err> {
        let parse_opt_value = |value: Option<&str>| {
            value.ok_or("Not enough values to parse".to_string())
                 .and_then(|v| v.parse::<f64>().map_err(|err| err.description().to_string()))
        };

        let mut split = input.split_whitespace();
        let x = parse_opt_value(split.next())?;
        let y = parse_opt_value(split.next())?;
        let z = parse_opt_value(split.next())?;

        return Ok(Coord { x, y, z})
    }
}

/// Trait denoting the ability to `Translate` an object with a `Coord`.
pub trait Translate {
    fn translate(self, &Coord) -> Self;
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;

    #[test]
    fn coord_origo_is_correct() {
        assert_eq!(Coord::new(0.0, 0.0, 0.0), Coord::ORIGO);
    }

    #[test]
    fn coord_eq_tolerance_small_deviation_passes() {
        // Allow for some deviation when testing for equality, since floating point
        // numbers are stupid.
        let coord = Coord::new(0.0, 0.0, 0.0);
        assert_eq!(coord, Coord::new(1e-10, 2e-10, 3e-10));
    }

    #[test]
    #[should_panic]
    fn coord_eq_tolerance_larger_deviation_does_not() {
        let coord = Coord::new(0.0, 0.0, 0.0);
        assert_eq!(coord, Coord::new(1e-9, 2e-9, 3e-9));
    }

    #[test]
    fn coord_distance_calc() {
        let coord1 = Coord::new(1.0, 1.0, 1.0);
        let coord2 = Coord::new(3.0, 3.0, 2.0);

        assert_eq!(3.0, Coord::distance(coord1, coord2));
        assert_eq!(3.0, coord1.distance(coord2));
    }

    #[test]
    fn coord_to_tuple() {
        let coord = Coord::new(1.0, 2.0, 3.0);
        assert_eq!((1.0, 2.0, 3.0), coord.to_tuple());
    }

    #[test]
    fn coord_with_set_pbc() {
        let box_size = Coord::new(2.0, 4.0, 6.0);
        assert_eq!(Coord::new(1.0, 1.0, 1.0), Coord::new(1.0, 1.0, 1.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 1.0, 1.0), Coord::new(3.0, 1.0, 1.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 0.5, 1.0), Coord::new(1.0, 4.5, 1.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 1.0, 1.0), Coord::new(1.0, 1.0, 13.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 1.0, 1.0), Coord::new(-1.0, 1.0, 1.0).with_pbc(box_size));
        assert_eq!(Coord::new(1.0, 3.0, 1.0), Coord::new(1.0, -1.0, 1.0).with_pbc(box_size));
    }

    #[test]
    fn coords_adjusted_by_pbc_with_size_0_does_not_change() {
        let box_size = Coord::new(0.0, 0.0, 0.0);
        let coord = Coord::new(1.0, 2.0, 3.0);
        assert_eq!(coord, coord.with_pbc(box_size));
    }

    #[test]
    fn coord_display_format() {
        let coord = Coord::ORIGO;
        assert_eq!("(0.0, 0.0, 0.0)", &format!("{}", coord));
    }

    #[test]
    fn coord_parsed_from_string() {
        assert_eq!(Ok(Coord::new(1.0, -1.0, 2.0)), Coord::from_str("1.0 -1.0 2.0"));
        assert_eq!(Ok(Coord::new(1.0, -1.0, 2.0)), Coord::from_str("1 -1.0 2"));
        assert_eq!(Ok(Coord::new(1.0, -1.0, 2.0)), Coord::from_str("\t1.0 -1.0 2.0"));
        assert!(Coord::from_str("").is_err());
        assert!(Coord::from_str("2.0 1.0").is_err());
    }

    #[test]
    fn coord_operators() {
        let coord1 = Coord::new(0.0, 1.0, 2.0);
        let coord2 = Coord::new(3.0, 4.0, 5.0);

        assert_eq!(Coord::new(3.0, 5.0, 7.0), coord1 + coord2);
        assert_eq!(Coord::new(3.0, 3.0, 3.0), coord2 - coord1);
        assert_eq!(Coord::new(0.0, -1.0, -2.0), -coord1);
    }

    #[test]
    fn coord_assign_operators() {
        let mut coord1 = Coord::ORIGO;
        let coord2 = Coord::new(1.0, 2.0, 3.0);

        coord1 += coord2;
        assert_eq!(coord2, coord1);

        coord1 -= coord2;
        assert_eq!(Coord::ORIGO, coord1);
    }
}
<|endoftext|>


<commit_before>
//! Utilities for storing and drawing data in GPU buffers.

const DEFAULT_SIZE: usize = 100;

mod primitives;
mod vertex_buffer;
mod primitive_buffer;

pub use self::primitives::*;
pub use self::vertex_buffer::*;
pub use self::primitive_buffer::*;

<commit_msg>Added module doc to buffer<commit_after>
//! Utilities for storing and drawing data in GPU buffers.
//!
//! This module defines four primary structs for storing data:
//!
//!  - [`VertexBuffer`] is the simplest to use type, and you probably want to use it in most cases.
//!    To use it you define a custom type which implements [`Vertex`]. You can then store a slice of
//!    your custom vertex type in a buffer and draw it using any [`PrimitiveMode`] you like.
//!  - [`IndexedVertexBuffer`] works similarly to [`VertexBuffer`], but it allows you to specify a
//!    additional index buffer, which is handy when many primitives reuse the same vertices.
//!  - [`PrimitiveBuffer`] is a direct wrapper around a OpenGL buffer object. It allows you to
//!    store any type which implements [`VertexData`] in a graphics buffer. Primitive buffers are
//!    used when you need low level control over how data is managed, or when you want to do
//!    something not exposed through vertex buffers.
//!  - [`VertexArray`] is used to specify how data in a primitive buffer is passed to a shader. You
//!    usually want to use a [`VertexBuffer`], which automatically manages primitive buffers and
//!    vertex arrays for you.
//!
//! [`VertexBuffer`]:           struct.VertexBuffer.html
//! [`IndexedVertexBuffer`]:    struct.IndexedVertexBuffer.html
//! [`PrimitiveBuffer`]:        struct.PrimitiveBuffer.html
//! [`VertexArray`]:            struct.VertexArray.html
//! [`Vertex`]:                 trait.Vertex.html
//! [`VertexData`]:             trait.VertexData.html
//! [`PrimitiveMode`]:          enum.PrimitiveMode.html

const DEFAULT_SIZE: usize = 100;

mod primitives;
mod vertex_buffer;
mod primitive_buffer;

pub use self::primitives::*;
pub use self::vertex_buffer::*;
pub use self::primitive_buffer::*;

<|endoftext|>


<commit_before>// Copyright 2019, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! # Examples
//!
//! ```
//! use glib::prelude::*; // or `use gtk::prelude::*;`
//! use glib::ByteArray;
//!
//! let ba = ByteArray::from(b"def");
//! ba.append(b"ghi").prepend(b"abc");
//! ba.remove_range(3, 3);
//! assert_eq!(ba, "abcghi".as_bytes());
//! ```

use glib_sys;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::ptr::NonNull;
use std::slice;
use translate::*;

use Bytes;

glib_wrapper! {
    pub struct ByteArray(Shared<glib_sys::GByteArray>);

    match fn {
        ref => |ptr| glib_sys::g_byte_array_ref(ptr),
        unref => |ptr| glib_sys::g_byte_array_unref(ptr),
        get_type => || glib_sys::g_byte_array_get_type(),
    }
}

impl ByteArray {
    pub fn new() -> ByteArray {
        unsafe { from_glib_full(glib_sys::g_byte_array_new()) }
    }

    pub fn with_capacity(size: usize) -> ByteArray {
        unsafe { from_glib_full(glib_sys::g_byte_array_sized_new(size as u32)) }
    }

    pub fn into_gbytes(self) -> Bytes {
        unsafe {
            let s = mem::ManuallyDrop::new(self);
            from_glib_full(glib_sys::g_byte_array_free_to_bytes(mut_override(
                s.to_glib_none().0,
            )))
        }
    }

    pub fn append<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
        let bytes = data.as_ref();
        unsafe {
            glib_sys::g_byte_array_append(
                self.to_glib_none().0,
                bytes.as_ptr() as *const _,
                bytes.len() as u32,
            );
        }
        self
    }

    pub fn prepend<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
        let bytes = data.as_ref();
        unsafe {
            glib_sys::g_byte_array_prepend(
                self.to_glib_none().0,
                bytes.as_ptr() as *const _,
                bytes.len() as u32,
            );
        }
        self
    }

    pub fn remove_index(&self, index: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_index(self.to_glib_none().0, index as u32);
        }
    }

    pub fn remove_index_fast(&self, index: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_index_fast(self.to_glib_none().0, index as u32);
        }
    }

    pub fn remove_range(&self, index: usize, length: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_range(self.to_glib_none().0, index as u32, length as u32);
        }
    }

    pub unsafe fn set_size(&self, size: usize) {
        glib_sys::g_byte_array_set_size(self.to_glib_none().0, size as u32);
    }

    pub fn sort<F: FnMut(&u8, &u8) -> Ordering>(&self, compare_func: F) {
        unsafe extern "C" fn compare_func_trampoline(
            a: glib_sys::gconstpointer,
            b: glib_sys::gconstpointer,
            func: glib_sys::gpointer,
        ) -> i32 {
            let func = func as *mut &mut (dyn FnMut(&u8, &u8) -> Ordering);

            let a = &*(a as *const u8);
            let b = &*(b as *const u8);

            match (*func)(&a, &b) {
                Ordering::Less => -1,
                Ordering::Equal => 0,
                Ordering::Greater => 1,
            }
        }
        unsafe {
            let mut func = compare_func;
            let func_obj: &mut (dyn FnMut(&u8, &u8) -> Ordering) = &mut func;
            let func_ptr =
                &func_obj as *const &mut (dyn FnMut(&u8, &u8) -> Ordering) as glib_sys::gpointer;

            glib_sys::g_byte_array_sort_with_data(
                self.to_glib_none().0,
                Some(compare_func_trampoline),
                func_ptr,
            );
        }
    }
}

impl AsRef<[u8]> for ByteArray {
    fn as_ref(&self) -> &[u8] {
        &*self
    }
}

impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for ByteArray {
    fn from(value: &'a T) -> ByteArray {
        let ba = ByteArray::new();
        ba.append(value.borrow());
        ba
    }
}

impl Deref for ByteArray {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe {
            let mut ptr = (*self.to_glib_none().0).data;
            let len = (*self.to_glib_none().0).len as usize;
            debug_assert!(!ptr.is_null() || len == 0);
            if ptr.is_null() {
                ptr = NonNull::dangling().as_ptr();
            }
            slice::from_raw_parts(ptr as *const u8, len)
        }
    }
}

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

impl fmt::Debug for ByteArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ByteArray")
            .field("ptr", &self.to_glib_none().0)
            .field("data", &&self[..])
            .finish()
    }
}

macro_rules! impl_cmp {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
            #[inline]
            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
            #[inline]
            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }
    };
}

impl_cmp!(ByteArray, [u8]);
impl_cmp!(ByteArray, &'a [u8]);
impl_cmp!(&'a ByteArray, [u8]);
impl_cmp!(ByteArray, Vec<u8>);
impl_cmp!(&'a ByteArray, Vec<u8>);

impl PartialEq for ByteArray {
    fn eq(&self, other: &Self) -> bool {
        self[..] == other[..]
    }
}

impl Eq for ByteArray {}

impl Hash for ByteArray {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(&self[..], state)
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;

    #[test]
    fn various() {
        let ba: ByteArray = Default::default();
        ba.append("foo").append("bar").prepend("baz");
        ba.remove_index(0);
        ba.remove_index_fast(1);
        ba.remove_range(1, 2);
        ba.sort(|a, b| a.cmp(b));
        unsafe { ba.set_size(3) };
        assert_eq!(ba, "aab".as_bytes());
        let abc: &[u8] = b"abc";
        assert_eq!(ByteArray::from(abc), "abc".as_bytes());
    }

    #[test]
    fn hash() {
        let b1 = ByteArray::from(b"this is a test");
        let b2 = ByteArray::from(b"this is a test");
        let b3 = ByteArray::from(b"test");
        let mut set = HashSet::new();
        set.insert(b1);
        assert!(set.contains(&b2));
        assert!(!set.contains(&b3));
    }
}
<commit_msg>clippy: Use byte literals in byte array tests<commit_after>// Copyright 2019, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! # Examples
//!
//! ```
//! use glib::prelude::*; // or `use gtk::prelude::*;`
//! use glib::ByteArray;
//!
//! let ba = ByteArray::from(b"def");
//! ba.append(b"ghi").prepend(b"abc");
//! ba.remove_range(3, 3);
//! assert_eq!(ba, "abcghi".as_bytes());
//! ```

use glib_sys;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::ptr::NonNull;
use std::slice;
use translate::*;

use Bytes;

glib_wrapper! {
    pub struct ByteArray(Shared<glib_sys::GByteArray>);

    match fn {
        ref => |ptr| glib_sys::g_byte_array_ref(ptr),
        unref => |ptr| glib_sys::g_byte_array_unref(ptr),
        get_type => || glib_sys::g_byte_array_get_type(),
    }
}

impl ByteArray {
    pub fn new() -> ByteArray {
        unsafe { from_glib_full(glib_sys::g_byte_array_new()) }
    }

    pub fn with_capacity(size: usize) -> ByteArray {
        unsafe { from_glib_full(glib_sys::g_byte_array_sized_new(size as u32)) }
    }

    pub fn into_gbytes(self) -> Bytes {
        unsafe {
            let s = mem::ManuallyDrop::new(self);
            from_glib_full(glib_sys::g_byte_array_free_to_bytes(mut_override(
                s.to_glib_none().0,
            )))
        }
    }

    pub fn append<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
        let bytes = data.as_ref();
        unsafe {
            glib_sys::g_byte_array_append(
                self.to_glib_none().0,
                bytes.as_ptr() as *const _,
                bytes.len() as u32,
            );
        }
        self
    }

    pub fn prepend<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
        let bytes = data.as_ref();
        unsafe {
            glib_sys::g_byte_array_prepend(
                self.to_glib_none().0,
                bytes.as_ptr() as *const _,
                bytes.len() as u32,
            );
        }
        self
    }

    pub fn remove_index(&self, index: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_index(self.to_glib_none().0, index as u32);
        }
    }

    pub fn remove_index_fast(&self, index: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_index_fast(self.to_glib_none().0, index as u32);
        }
    }

    pub fn remove_range(&self, index: usize, length: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_range(self.to_glib_none().0, index as u32, length as u32);
        }
    }

    pub unsafe fn set_size(&self, size: usize) {
        glib_sys::g_byte_array_set_size(self.to_glib_none().0, size as u32);
    }

    pub fn sort<F: FnMut(&u8, &u8) -> Ordering>(&self, compare_func: F) {
        unsafe extern "C" fn compare_func_trampoline(
            a: glib_sys::gconstpointer,
            b: glib_sys::gconstpointer,
            func: glib_sys::gpointer,
        ) -> i32 {
            let func = func as *mut &mut (dyn FnMut(&u8, &u8) -> Ordering);

            let a = &*(a as *const u8);
            let b = &*(b as *const u8);

            match (*func)(&a, &b) {
                Ordering::Less => -1,
                Ordering::Equal => 0,
                Ordering::Greater => 1,
            }
        }
        unsafe {
            let mut func = compare_func;
            let func_obj: &mut (dyn FnMut(&u8, &u8) -> Ordering) = &mut func;
            let func_ptr =
                &func_obj as *const &mut (dyn FnMut(&u8, &u8) -> Ordering) as glib_sys::gpointer;

            glib_sys::g_byte_array_sort_with_data(
                self.to_glib_none().0,
                Some(compare_func_trampoline),
                func_ptr,
            );
        }
    }
}

impl AsRef<[u8]> for ByteArray {
    fn as_ref(&self) -> &[u8] {
        &*self
    }
}

impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for ByteArray {
    fn from(value: &'a T) -> ByteArray {
        let ba = ByteArray::new();
        ba.append(value.borrow());
        ba
    }
}

impl Deref for ByteArray {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe {
            let mut ptr = (*self.to_glib_none().0).data;
            let len = (*self.to_glib_none().0).len as usize;
            debug_assert!(!ptr.is_null() || len == 0);
            if ptr.is_null() {
                ptr = NonNull::dangling().as_ptr();
            }
            slice::from_raw_parts(ptr as *const u8, len)
        }
    }
}

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

impl fmt::Debug for ByteArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ByteArray")
            .field("ptr", &self.to_glib_none().0)
            .field("data", &&self[..])
            .finish()
    }
}

macro_rules! impl_cmp {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
            #[inline]
            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
            #[inline]
            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }
    };
}

impl_cmp!(ByteArray, [u8]);
impl_cmp!(ByteArray, &'a [u8]);
impl_cmp!(&'a ByteArray, [u8]);
impl_cmp!(ByteArray, Vec<u8>);
impl_cmp!(&'a ByteArray, Vec<u8>);

impl PartialEq for ByteArray {
    fn eq(&self, other: &Self) -> bool {
        self[..] == other[..]
    }
}

impl Eq for ByteArray {}

impl Hash for ByteArray {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(&self[..], state)
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;

    #[test]
    fn various() {
        let ba: ByteArray = Default::default();
        ba.append("foo").append("bar").prepend("baz");
        ba.remove_index(0);
        ba.remove_index_fast(1);
        ba.remove_range(1, 2);
        ba.sort(|a, b| a.cmp(b));
        unsafe { ba.set_size(3) };
        assert_eq!(ba, b"aab" as &[u8]);
        let abc: &[u8] = b"abc";
        assert_eq!(ByteArray::from(abc), b"abc" as &[u8]);
    }

    #[test]
    fn hash() {
        let b1 = ByteArray::from(b"this is a test");
        let b2 = ByteArray::from(b"this is a test");
        let b3 = ByteArray::from(b"test");
        let mut set = HashSet::new();
        set.insert(b1);
        assert!(set.contains(&b2));
        assert!(!set.contains(&b3));
    }
}
<|endoftext|>


<commit_before>/*!

*/

use backend::Facade;
use context::Context;
use ContextExt;
use version::Api;
use version::Version;
use gl;
use std::rc::Rc;
use std::mem;

pub use context::DebugCallbackBehavior;

/// Represents a callback that can be used for the debug output feature of OpenGL.
///
/// The first three parameters are self-explanatory. The fourth parameter is an identifier for this
/// message whose meaning is implementation-defined. The fifth parameter indicates whether glium
/// is already handling any possible error condition, so you don't need to print an error. The last
/// parameter is a message generated by the OpenGL implementation.
pub type DebugCallback = Box<dyn FnMut(Source, MessageType, Severity, u32, bool, &str)>;

/// Severity of a debug message.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum Severity {
    /// Anything that isn't an error or performance issue.
    Notification = gl::DEBUG_SEVERITY_NOTIFICATION,

    /// Redundant state-change performance warning, or unimportant undefined behavior.
    Low = gl::DEBUG_SEVERITY_LOW,

    /// Major performance warnings, shader compilation/linking warnings,
    /// or the use of deprecated functionality.
    Medium = gl::DEBUG_SEVERITY_MEDIUM,

    /// All OpenGL Errors, shader compilation/linking errors,
    /// or highly-dangerous undefined behavior.
    High = gl::DEBUG_SEVERITY_HIGH,
}

/// Source of a debug message.
#[derive(Clone, Copy, Debug)]
#[repr(u32)]
pub enum Source {
    /// Calls to the OpenGL API.
    Api = gl::DEBUG_SOURCE_API,

    /// Calls to a window-system API.
    WindowSystem = gl::DEBUG_SOURCE_WINDOW_SYSTEM,

    /// A compiler for a shading language.
    ShaderCompiler = gl::DEBUG_SOURCE_SHADER_COMPILER,

    /// An application associated with Openctxt.gl.
    ThirdParty = gl::DEBUG_SOURCE_THIRD_PARTY,

    /// Explicitly generated by Glium or the application.
    ///
    /// This should never happen, but is included here for completeness.
    Application = gl::DEBUG_SOURCE_APPLICATION,

    ///
    OtherSource = gl::DEBUG_SOURCE_OTHER,
}

/// Type of a debug message.
#[derive(Clone, Copy, Debug)]
#[repr(u32)]
pub enum MessageType {
    /// An error, typically from the API
    Error = gl::DEBUG_TYPE_ERROR,
    /// Some behavior marked deprecated has been used
    DeprecatedBehavior = gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR,
    /// Something has invoked undefined behavior
    UndefinedBehavior = gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR,
    /// Some functionality the user relies upon is not portable
    Portability = gl::DEBUG_TYPE_PORTABILITY,
    /// Code has triggered possible performance issues
    Performance = gl::DEBUG_TYPE_PERFORMANCE,
    /// Command stream annotation
    Marker = gl::DEBUG_TYPE_MARKER,
    /// Entering a debug group
    PushGroup = gl::DEBUG_TYPE_PUSH_GROUP,
    /// Leaving a debug group
    PopGroup = gl::DEBUG_TYPE_POP_GROUP,
    /// Any other event
    Other = gl::DEBUG_TYPE_OTHER,
}

/// Allows you to obtain the timestamp inside the OpenGL commands queue.
///
/// When you call functions in glium, they are not instantly executed. Instead they are
/// added in a commands queue that the backend executes asynchronously.
///
/// When you call `TimestampQuery::new`, a command is added to this list asking the
/// backend to send us the current timestamp. Thanks to this, you can know how much time
/// it takes to execute commands.
///
/// ## Example
///
/// ```no_run
/// # let display: glium::Display = unsafe { std::mem::uninitialized() };
/// let before = glium::debug::TimestampQuery::new(&display);
/// // do some stuff here
/// let after = glium::debug::TimestampQuery::new(&display);
///
/// match (after, before) {
///     (Some(after), Some(before)) => {
///         let elapsed = after.get() - before.get();
///         println!("Time it took to do stuff: {}", elapsed);
///     },
///     _ => ()
/// }
/// ```
///
pub struct TimestampQuery {
    context: Rc<Context>,
    id: gl::types::GLuint,
}

impl TimestampQuery {
    /// Creates a new `TimestampQuery`. Returns `None` if the backend doesn't support it.
    pub fn new<F: ?Sized>(facade: &F) -> Option<TimestampQuery> where F: Facade {
        let ctxt = facade.get_context().make_current();

        let id = if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                #[allow(deprecated)]
                let mut id = mem::uninitialized();
                ctxt.gl.GenQueries(1, &mut id);

                ctxt.gl.QueryCounter(id, gl::TIMESTAMP);

                Some(id)
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                #[allow(deprecated)]
                let mut id = mem::uninitialized();
                ctxt.gl.GenQueriesEXT(1, &mut id);

                ctxt.gl.QueryCounterEXT(id, gl::TIMESTAMP);

                Some(id)
            }

        } else {
            None
        };

        id.map(|q| TimestampQuery {
            context: facade.get_context().clone(),
            id: q
        })
    }

    /// Queries the counter to see if the timestamp is already available.
    ///
    /// It takes some time to retrieve the value, during which you can execute other
    /// functions.
    pub fn is_ready(&self) -> bool {
        let ctxt = self.context.make_current();

        if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                #[allow(deprecated)]
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectiv(self.id, gl::QUERY_RESULT_AVAILABLE, &mut value);
                value != 0
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                #[allow(deprecated)]
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectivEXT(self.id, gl::QUERY_RESULT_AVAILABLE_EXT, &mut value);
                value != 0
            }

        } else {
            unreachable!();
        }
    }

    /// Returns the value of the timestamp. Blocks until it is available.
    ///
    /// This function doesn't block if `is_ready` returns true.
    pub fn get(self) -> u64 {
        let ctxt = self.context.make_current();

        if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                #[allow(deprecated)]
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectui64v(self.id, gl::QUERY_RESULT, &mut value);
                ctxt.gl.DeleteQueries(1, [self.id].as_ptr());
                value
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                #[allow(deprecated)]
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectui64vEXT(self.id, gl::QUERY_RESULT_EXT, &mut value);
                ctxt.gl.DeleteQueriesEXT(1, [self.id].as_ptr());
                value
            }

        } else {
            unreachable!();
        }
    }
}
<commit_msg>all integers that can be 0<commit_after>/*!

*/

use backend::Facade;
use context::Context;
use ContextExt;
use version::Api;
use version::Version;
use gl;
use std::rc::Rc;
use std::mem;

pub use context::DebugCallbackBehavior;

/// Represents a callback that can be used for the debug output feature of OpenGL.
///
/// The first three parameters are self-explanatory. The fourth parameter is an identifier for this
/// message whose meaning is implementation-defined. The fifth parameter indicates whether glium
/// is already handling any possible error condition, so you don't need to print an error. The last
/// parameter is a message generated by the OpenGL implementation.
pub type DebugCallback = Box<dyn FnMut(Source, MessageType, Severity, u32, bool, &str)>;

/// Severity of a debug message.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum Severity {
    /// Anything that isn't an error or performance issue.
    Notification = gl::DEBUG_SEVERITY_NOTIFICATION,

    /// Redundant state-change performance warning, or unimportant undefined behavior.
    Low = gl::DEBUG_SEVERITY_LOW,

    /// Major performance warnings, shader compilation/linking warnings,
    /// or the use of deprecated functionality.
    Medium = gl::DEBUG_SEVERITY_MEDIUM,

    /// All OpenGL Errors, shader compilation/linking errors,
    /// or highly-dangerous undefined behavior.
    High = gl::DEBUG_SEVERITY_HIGH,
}

/// Source of a debug message.
#[derive(Clone, Copy, Debug)]
#[repr(u32)]
pub enum Source {
    /// Calls to the OpenGL API.
    Api = gl::DEBUG_SOURCE_API,

    /// Calls to a window-system API.
    WindowSystem = gl::DEBUG_SOURCE_WINDOW_SYSTEM,

    /// A compiler for a shading language.
    ShaderCompiler = gl::DEBUG_SOURCE_SHADER_COMPILER,

    /// An application associated with Openctxt.gl.
    ThirdParty = gl::DEBUG_SOURCE_THIRD_PARTY,

    /// Explicitly generated by Glium or the application.
    ///
    /// This should never happen, but is included here for completeness.
    Application = gl::DEBUG_SOURCE_APPLICATION,

    ///
    OtherSource = gl::DEBUG_SOURCE_OTHER,
}

/// Type of a debug message.
#[derive(Clone, Copy, Debug)]
#[repr(u32)]
pub enum MessageType {
    /// An error, typically from the API
    Error = gl::DEBUG_TYPE_ERROR,
    /// Some behavior marked deprecated has been used
    DeprecatedBehavior = gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR,
    /// Something has invoked undefined behavior
    UndefinedBehavior = gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR,
    /// Some functionality the user relies upon is not portable
    Portability = gl::DEBUG_TYPE_PORTABILITY,
    /// Code has triggered possible performance issues
    Performance = gl::DEBUG_TYPE_PERFORMANCE,
    /// Command stream annotation
    Marker = gl::DEBUG_TYPE_MARKER,
    /// Entering a debug group
    PushGroup = gl::DEBUG_TYPE_PUSH_GROUP,
    /// Leaving a debug group
    PopGroup = gl::DEBUG_TYPE_POP_GROUP,
    /// Any other event
    Other = gl::DEBUG_TYPE_OTHER,
}

/// Allows you to obtain the timestamp inside the OpenGL commands queue.
///
/// When you call functions in glium, they are not instantly executed. Instead they are
/// added in a commands queue that the backend executes asynchronously.
///
/// When you call `TimestampQuery::new`, a command is added to this list asking the
/// backend to send us the current timestamp. Thanks to this, you can know how much time
/// it takes to execute commands.
///
/// ## Example
///
/// ```no_run
/// # let display: glium::Display = unsafe { std::mem::uninitialized() };
/// let before = glium::debug::TimestampQuery::new(&display);
/// // do some stuff here
/// let after = glium::debug::TimestampQuery::new(&display);
///
/// match (after, before) {
///     (Some(after), Some(before)) => {
///         let elapsed = after.get() - before.get();
///         println!("Time it took to do stuff: {}", elapsed);
///     },
///     _ => ()
/// }
/// ```
///
pub struct TimestampQuery {
    context: Rc<Context>,
    id: gl::types::GLuint,
}

impl TimestampQuery {
    /// Creates a new `TimestampQuery`. Returns `None` if the backend doesn't support it.
    pub fn new<F: ?Sized>(facade: &F) -> Option<TimestampQuery> where F: Facade {
        let ctxt = facade.get_context().make_current();

        let id = if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut id = 0;
                ctxt.gl.GenQueries(1, &mut id);

                ctxt.gl.QueryCounter(id, gl::TIMESTAMP);

                Some(id)
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut id = 0;
                ctxt.gl.GenQueriesEXT(1, &mut id);

                ctxt.gl.QueryCounterEXT(id, gl::TIMESTAMP);

                Some(id)
            }

        } else {
            None
        };

        id.map(|q| TimestampQuery {
            context: facade.get_context().clone(),
            id: q
        })
    }

    /// Queries the counter to see if the timestamp is already available.
    ///
    /// It takes some time to retrieve the value, during which you can execute other
    /// functions.
    pub fn is_ready(&self) -> bool {
        let ctxt = self.context.make_current();

        if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut value = 0;
                ctxt.gl.GetQueryObjectiv(self.id, gl::QUERY_RESULT_AVAILABLE, &mut value);
                value != 0
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut value = 0;
                ctxt.gl.GetQueryObjectivEXT(self.id, gl::QUERY_RESULT_AVAILABLE_EXT, &mut value);
                value != 0
            }

        } else {
            unreachable!();
        }
    }

    /// Returns the value of the timestamp. Blocks until it is available.
    ///
    /// This function doesn't block if `is_ready` returns true.
    pub fn get(self) -> u64 {
        let ctxt = self.context.make_current();

        if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut value = 0;
                ctxt.gl.GetQueryObjectui64v(self.id, gl::QUERY_RESULT, &mut value);
                ctxt.gl.DeleteQueries(1, [self.id].as_ptr());
                value
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut value = 0;
                ctxt.gl.GetQueryObjectui64vEXT(self.id, gl::QUERY_RESULT_EXT, &mut value);
                ctxt.gl.DeleteQueriesEXT(1, [self.id].as_ptr());
                value
            }

        } else {
            unreachable!();
        }
    }
}
<|endoftext|>


<commit_before>use libc::c_int;
use std::error::Error;
use std::io::IoError;
use std::str;

use ffi;

#[deriving(Show, Eq, PartialEq)]
pub enum LmdbError {
    KeyExist,
    NotFound,
    PageNotFound,
    Corrupted,
    Panic,
    VersionMismatch,
    Invalid,
    MapFull,
    DbsFull,
    ReadersFull,
    TlsFull,
    TxnFull,
    CursorFull,
    PageFull,
    MapResized,
    Incompatible,
    BadRslot,
    BadTxn,
    BadValSize,
    BadDbi,
    Unknown(c_int),
    Io(IoError),
}

impl Error for LmdbError {
    fn description(&self) -> &str {
        let err_code = match *self {
            LmdbError::KeyExist => ffi::MDB_KEYEXIST,
            LmdbError::NotFound => ffi::MDB_NOTFOUND,
            LmdbError::PageNotFound => ffi::MDB_PAGE_NOTFOUND,
            LmdbError::Corrupted => ffi::MDB_CORRUPTED,
            LmdbError::Panic => ffi::MDB_PANIC,
            LmdbError::VersionMismatch => ffi::MDB_VERSION_MISMATCH,
            LmdbError::Invalid => ffi::MDB_INVALID,
            LmdbError::MapFull => ffi::MDB_MAP_FULL,
            LmdbError::DbsFull => ffi::MDB_DBS_FULL,
            LmdbError::ReadersFull => ffi::MDB_READERS_FULL,
            LmdbError::TlsFull => ffi::MDB_TLS_FULL,
            LmdbError::TxnFull => ffi::MDB_TXN_FULL,
            LmdbError::CursorFull => ffi::MDB_CURSOR_FULL,
            LmdbError::PageFull => ffi::MDB_PAGE_FULL,
            LmdbError::MapResized => ffi::MDB_MAP_RESIZED,
            LmdbError::Incompatible => ffi::MDB_INCOMPATIBLE,
            LmdbError::BadRslot => ffi::MDB_BAD_RSLOT,
            LmdbError::BadTxn => ffi::MDB_BAD_TXN,
            LmdbError::BadValSize => ffi::MDB_BAD_VALSIZE,
            LmdbError::BadDbi => ffi::MDB_BAD_DBI,
            LmdbError::Unknown(i) => i,
            LmdbError::Io(ref io_error) => return io_error.description(),
        };
        unsafe { str::from_c_str(ffi::mdb_strerror(err_code) as *const _) }
    }
}

impl LmdbError {

    pub fn from_err_code(err_code: c_int) -> LmdbError {
        match err_code {
            i if i > 0 => LmdbError::Io(IoError::from_errno(err_code as uint, true)),
            ffi::MDB_KEYEXIST => LmdbError::KeyExist,
            ffi::MDB_NOTFOUND => LmdbError::NotFound,
            ffi::MDB_PAGE_NOTFOUND => LmdbError::PageNotFound,
            ffi::MDB_CORRUPTED => LmdbError::Corrupted,
            ffi::MDB_PANIC => LmdbError::Panic,
            ffi::MDB_VERSION_MISMATCH => LmdbError::VersionMismatch,
            ffi::MDB_INVALID => LmdbError::Invalid,
            ffi::MDB_MAP_FULL => LmdbError::MapFull,
            ffi::MDB_DBS_FULL => LmdbError::DbsFull,
            ffi::MDB_READERS_FULL => LmdbError::ReadersFull,
            ffi::MDB_TLS_FULL => LmdbError::TlsFull,
            ffi::MDB_TXN_FULL => LmdbError::TxnFull,
            ffi::MDB_CURSOR_FULL => LmdbError::CursorFull,
            ffi::MDB_PAGE_FULL => LmdbError::PageFull,
            ffi::MDB_MAP_RESIZED => LmdbError::MapResized,
            ffi::MDB_INCOMPATIBLE => LmdbError::Incompatible,
            ffi::MDB_BAD_RSLOT => LmdbError::BadRslot,
            ffi::MDB_BAD_TXN => LmdbError::BadTxn,
            ffi::MDB_BAD_VALSIZE => LmdbError::BadValSize,
            i => LmdbError::Unknown(i),
        }
    }
}

pub type LmdbResult<T> = Result<T, LmdbError>;

pub fn lmdb_result(err_code: c_int) -> LmdbResult<()> {
    if err_code == ffi::MDB_SUCCESS {
        Ok(())
    } else {
        Err(LmdbError::from_err_code(err_code))
    }
}
<commit_msg>put LmdbError on a diet<commit_after>use libc::c_int;
use std::error::Error;
use std::str;

use ffi;

#[deriving(Show, Eq, PartialEq, Copy, Clone)]
pub struct LmdbError {
    err_code: c_int,
}

impl Error for LmdbError {
    fn description(&self) -> &str {
        unsafe { str::from_c_str(ffi::mdb_strerror(self.err_code) as *const _) }
    }
}

impl LmdbError {
    pub fn from_err_code(err_code: c_int) -> LmdbError {
        LmdbError { err_code: err_code}
    }
}

pub type LmdbResult<T> = Result<T, LmdbError>;

pub fn lmdb_result(err_code: c_int) -> LmdbResult<()> {
    if err_code == ffi::MDB_SUCCESS {
        Ok(())
    } else {
        Err(LmdbError::from_err_code(err_code))
    }
}

#[cfg(test)]
mod test {

    use std::error::Error;

    use super::*;
    use ffi;

    #[test]
    fn test_description() {
        assert_eq!("Permission denied",
                   LmdbError::from_err_code(13).description());
        assert_eq!("MDB_NOTFOUND: No matching key/data pair found",
                   LmdbError::from_err_code(ffi::MDB_NOTFOUND).description());
    }

}
<|endoftext|>


<commit_before>use std::convert::From;
use hyper::HttpError;
use std::io::Error as IoError;
use rustc_serialize::json::DecoderError;

/// An error returned by `Client` when an API call fails.
#[derive(Debug)]
pub enum Error {
    /// An error returned by etcd.
    Etcd(EtcdError),
    /// An HTTP error from attempting to connect to etcd.
    Http(HttpError),
    Io(IoError),
    JsonDecoderError(DecoderError),
}

/// An error returned by etcd.
#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)]
pub struct EtcdError {
    /// The key that was being operated upon or reason for the failure.
    pub cause: Option<String>,
    /// The etcd error code.
    pub errorCode: u64,
    /// The etcd index.
    pub index: u64,
    /// A human-friendly description of the error.
    pub message: String,
}

impl From<HttpError> for Error {
    fn from(error: HttpError) -> Error {
        Error::Http(error)
    }
}

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

impl From<DecoderError> for Error {
    fn from(error: DecoderError) -> Error {
        Error::JsonDecoderError(error)
    }
}
<commit_msg>Add documentation of new error types<commit_after>use std::convert::From;
use hyper::HttpError;
use std::io::Error as IoError;
use rustc_serialize::json::DecoderError;

/// An error returned by `Client` when an API call fails.
#[derive(Debug)]
pub enum Error {
    /// An error returned by etcd.
    Etcd(EtcdError),
    /// An HTTP error from attempting to connect to etcd.
    Http(HttpError),
    /// An IO error, which can happen when reading the HTTP response.
    Io(IoError),
    /// An error that occurs when the JSON response does not match the expected data structure.
    JsonDecoderError(DecoderError),
}

/// An error returned by etcd.
#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)]
pub struct EtcdError {
    /// The key that was being operated upon or reason for the failure.
    pub cause: Option<String>,
    /// The etcd error code.
    pub errorCode: u64,
    /// The etcd index.
    pub index: u64,
    /// A human-friendly description of the error.
    pub message: String,
}

impl From<HttpError> for Error {
    fn from(error: HttpError) -> Error {
        Error::Http(error)
    }
}

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

impl From<DecoderError> for Error {
    fn from(error: DecoderError) -> Error {
        Error::JsonDecoderError(error)
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;
use std::io::Error as IOError;
use std::string::FromUtf8Error;

use serde_json::error::Error as SerdeError;
#[cfg(feature = "dir_source")]
use walkdir::Error as WalkdirError;

use crate::template::Parameter;

/// Error when rendering data on template.
#[derive(Debug)]
pub struct RenderError {
    pub desc: String,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    cause: Option<Box<dyn Error + 'static>>,
}

impl fmt::Display for RenderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no) {
            (Some(line), Some(col)) => write!(
                f,
                "Error rendering \"{}\" line {}, col {}: {}",
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned(),),
                line,
                col,
                self.desc
            ),
            _ => write!(f, "{}", self.desc),
        }
    }
}

impl Error for RenderError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.cause.as_ref().map(|e| &**e)
    }
}

impl From<IOError> for RenderError {
    fn from(e: IOError) -> RenderError {
        RenderError::with(e)
    }
}

impl From<SerdeError> for RenderError {
    fn from(e: SerdeError) -> RenderError {
        RenderError::with(e)
    }
}

impl From<FromUtf8Error> for RenderError {
    fn from(e: FromUtf8Error) -> RenderError {
        RenderError::with(e)
    }
}

impl RenderError {
    pub fn new<T: AsRef<str>>(desc: T) -> RenderError {
        RenderError {
            desc: desc.as_ref().to_owned(),
            template_name: None,
            line_no: None,
            column_no: None,
            cause: None,
        }
    }

    pub fn strict_error(path: Option<&String>) -> RenderError {
        let msg = match path {
            Some(path) => format!("Variable {:?} not found in strict mode.", path),
            None => "Value is missing in strict mode".to_owned(),
        };
        RenderError::new(&msg)
    }

    pub fn with<E>(cause: E) -> RenderError
    where
        E: Error + Send + Sync + 'static,
    {
        let mut e = RenderError::new(cause.description());
        e.cause = Some(Box::new(cause));

        e
    }
}

quick_error! {
/// Template parsing error
    #[derive(PartialEq, Debug, Clone)]
    pub enum TemplateErrorReason {
        MismatchingClosedHelper(open: String, closed: String) {
            display("helper {:?} was opened, but {:?} is closing",
                open, closed)
        }
        MismatchingClosedDirective(open: Parameter, closed: Parameter) {
            display("directive {:?} was opened, but {:?} is closing",
                open, closed)
            description("wrong name of closing directive")
        }
        InvalidSyntax {
            display("invalid handlebars syntax.")
        }
        InvalidParam (param: String) {
            display("invalid parameter {:?}", param)
        }
        NestedSubexpression {
            display("nested subexpression is not supported")
        }
    }
}

/// Error on parsing template.
#[derive(Debug, PartialEq)]
pub struct TemplateError {
    pub reason: TemplateErrorReason,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    segment: Option<String>,
}

impl TemplateError {
    pub fn of(e: TemplateErrorReason) -> TemplateError {
        TemplateError {
            reason: e,
            template_name: None,
            line_no: None,
            column_no: None,
            segment: None,
        }
    }

    pub fn at(mut self, template_str: &str, line_no: usize, column_no: usize) -> TemplateError {
        self.line_no = Some(line_no);
        self.column_no = Some(column_no);
        self.segment = Some(template_segment(template_str, line_no, column_no));
        self
    }

    pub fn in_template(mut self, name: String) -> TemplateError {
        self.template_name = Some(name);
        self
    }
}

impl Error for TemplateError {
    fn description(&self) -> &str {
        self.reason.description()
    }
}

fn template_segment(template_str: &str, line: usize, col: usize) -> String {
    let range = 3;
    let line_start = if line >= range { line - range } else { 0 };
    let line_end = line + range;

    let mut buf = String::new();
    for (line_count, line_content) in template_str.lines().enumerate() {
        if line_count >= line_start && line_count <= line_end {
            buf.push_str(&format!("{:4} | {}\n", line_count, line_content));
            if line_count == line - 1 {
                buf.push_str("     |");
                for c in 0..line_content.len() {
                    if c != col {
                        buf.push_str("-");
                    } else {
                        buf.push_str("^");
                    }
                }
                buf.push_str("\n");
            }
        }
    }

    buf
}

impl fmt::Display for TemplateError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no, &self.segment) {
            (Some(line), Some(col), &Some(ref seg)) => writeln!(
                f,
                "Template error: {}\n    --> Template error in \"{}\":{}:{}\n     |\n{}     |\n     = reason: {}",
                self.reason,
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned()),
                line,
                col,
                seg,
                self.reason
            ),
            _ => write!(f, "{}", self.reason),
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum TemplateFileError {
        TemplateError(err: TemplateError) {
            from()
            cause(err)
            display("{}", err)
        }
        IOError(err: IOError, name: String) {
            cause(err)
            display("Template \"{}\": {}", name, err)
        }
    }
}

#[cfg(feature = "dir_source")]
impl From<WalkdirError> for TemplateFileError {
    fn from(error: WalkdirError) -> TemplateFileError {
        let path_string: String = error
            .path()
            .map(|p| p.to_string_lossy().to_string())
            .unwrap_or_default();
        TemplateFileError::IOError(IOError::from(error), path_string)
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum TemplateRenderError {
        TemplateError(err: TemplateError) {
            from()
            cause(err)
            display("{}", err)
        }
        RenderError(err: RenderError) {
            from()
            cause(err)
            display("{}", err)
        }
        IOError(err: IOError, name: String) {
            cause(err)
            display("Template \"{}\": {}", name, err)
        }
    }
}

impl TemplateRenderError {
    pub fn as_render_error(&self) -> Option<&RenderError> {
        if let TemplateRenderError::RenderError(ref e) = *self {
            Some(&e)
        } else {
            None
        }
    }
}
<commit_msg>(fix) deprecated apis<commit_after>use std::error::Error;
use std::fmt;
use std::io::Error as IOError;
use std::string::FromUtf8Error;

use serde_json::error::Error as SerdeError;
#[cfg(feature = "dir_source")]
use walkdir::Error as WalkdirError;

use crate::template::Parameter;

/// Error when rendering data on template.
#[derive(Debug)]
pub struct RenderError {
    pub desc: String,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    cause: Option<Box<dyn Error + 'static>>,
}

impl fmt::Display for RenderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no) {
            (Some(line), Some(col)) => write!(
                f,
                "Error rendering \"{}\" line {}, col {}: {}",
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned(),),
                line,
                col,
                self.desc
            ),
            _ => write!(f, "{}", self.desc),
        }
    }
}

impl Error for RenderError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.cause.as_ref().map(|e| &**e)
    }
}

impl From<IOError> for RenderError {
    fn from(e: IOError) -> RenderError {
        RenderError::with(e)
    }
}

impl From<SerdeError> for RenderError {
    fn from(e: SerdeError) -> RenderError {
        RenderError::with(e)
    }
}

impl From<FromUtf8Error> for RenderError {
    fn from(e: FromUtf8Error) -> RenderError {
        RenderError::with(e)
    }
}

impl RenderError {
    pub fn new<T: AsRef<str>>(desc: T) -> RenderError {
        RenderError {
            desc: desc.as_ref().to_owned(),
            template_name: None,
            line_no: None,
            column_no: None,
            cause: None,
        }
    }

    pub fn strict_error(path: Option<&String>) -> RenderError {
        let msg = match path {
            Some(path) => format!("Variable {:?} not found in strict mode.", path),
            None => "Value is missing in strict mode".to_owned(),
        };
        RenderError::new(&msg)
    }

    pub fn with<E>(cause: E) -> RenderError
    where
        E: Error + Send + Sync + 'static,
    {
        let mut e = RenderError::new(cause.to_string());
        e.cause = Some(Box::new(cause));

        e
    }
}

quick_error! {
/// Template parsing error
    #[derive(PartialEq, Debug, Clone)]
    pub enum TemplateErrorReason {
        MismatchingClosedHelper(open: String, closed: String) {
            display("helper {:?} was opened, but {:?} is closing",
                open, closed)
        }
        MismatchingClosedDirective(open: Parameter, closed: Parameter) {
            display("directive {:?} was opened, but {:?} is closing",
                open, closed)
            description("wrong name of closing directive")
        }
        InvalidSyntax {
            display("invalid handlebars syntax.")
        }
        InvalidParam (param: String) {
            display("invalid parameter {:?}", param)
        }
        NestedSubexpression {
            display("nested subexpression is not supported")
        }
    }
}

/// Error on parsing template.
#[derive(Debug, PartialEq)]
pub struct TemplateError {
    pub reason: TemplateErrorReason,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    segment: Option<String>,
}

impl TemplateError {
    pub fn of(e: TemplateErrorReason) -> TemplateError {
        TemplateError {
            reason: e,
            template_name: None,
            line_no: None,
            column_no: None,
            segment: None,
        }
    }

    pub fn at(mut self, template_str: &str, line_no: usize, column_no: usize) -> TemplateError {
        self.line_no = Some(line_no);
        self.column_no = Some(column_no);
        self.segment = Some(template_segment(template_str, line_no, column_no));
        self
    }

    pub fn in_template(mut self, name: String) -> TemplateError {
        self.template_name = Some(name);
        self
    }
}

impl Error for TemplateError {}

fn template_segment(template_str: &str, line: usize, col: usize) -> String {
    let range = 3;
    let line_start = if line >= range { line - range } else { 0 };
    let line_end = line + range;

    let mut buf = String::new();
    for (line_count, line_content) in template_str.lines().enumerate() {
        if line_count >= line_start && line_count <= line_end {
            buf.push_str(&format!("{:4} | {}\n", line_count, line_content));
            if line_count == line - 1 {
                buf.push_str("     |");
                for c in 0..line_content.len() {
                    if c != col {
                        buf.push_str("-");
                    } else {
                        buf.push_str("^");
                    }
                }
                buf.push_str("\n");
            }
        }
    }

    buf
}

impl fmt::Display for TemplateError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no, &self.segment) {
            (Some(line), Some(col), &Some(ref seg)) => writeln!(
                f,
                "Template error: {}\n    --> Template error in \"{}\":{}:{}\n     |\n{}     |\n     = reason: {}",
                self.reason,
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned()),
                line,
                col,
                seg,
                self.reason
            ),
            _ => write!(f, "{}", self.reason),
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum TemplateFileError {
        TemplateError(err: TemplateError) {
            from()
            cause(err)
            display("{}", err)
        }
        IOError(err: IOError, name: String) {
            cause(err)
            display("Template \"{}\": {}", name, err)
        }
    }
}

#[cfg(feature = "dir_source")]
impl From<WalkdirError> for TemplateFileError {
    fn from(error: WalkdirError) -> TemplateFileError {
        let path_string: String = error
            .path()
            .map(|p| p.to_string_lossy().to_string())
            .unwrap_or_default();
        TemplateFileError::IOError(IOError::from(error), path_string)
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum TemplateRenderError {
        TemplateError(err: TemplateError) {
            from()
            cause(err)
            display("{}", err)
        }
        RenderError(err: RenderError) {
            from()
            cause(err)
            display("{}", err)
        }
        IOError(err: IOError, name: String) {
            cause(err)
            display("Template \"{}\": {}", name, err)
        }
    }
}

impl TemplateRenderError {
    pub fn as_render_error(&self) -> Option<&RenderError> {
        if let TemplateRenderError::RenderError(ref e) = *self {
            Some(&e)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>//! Defines error types used by this library.

use Value;

use xml::common::TextPosition;
use xml::reader::Error as XmlError;

use std::collections::BTreeMap;
use std::fmt::{self, Display, Formatter};
use std::{error, io};

/// Errors that can occur when trying to perform an XML-RPC request.
///
/// This can be a lower-level error (for example, the HTTP request failed), a problem with the
/// server (maybe it's not implementing XML-RPC correctly), or just a failure to execute the
/// operation.
#[derive(Debug)]
pub struct Error(RequestErrorKind);

impl Error {
    /// If this `Error` was caused by the server responding with a `<fault>` response,
    /// returns the `Fault` in question.
    pub fn fault(&self) -> Option<&Fault> {
        match self.0 {
            RequestErrorKind::Fault(ref fault) => Some(fault),
            _ => None,
        }
    }
}

#[doc(hidden)] // hide internal impl
impl From<RequestErrorKind> for Error {
    fn from(kind: RequestErrorKind) -> Self {
        Error(kind)
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        self.0.fmt(fmt)
    }
}

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

    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        self.0.source()
    }
}

#[derive(Debug)]
pub enum RequestErrorKind {
    /// The response could not be parsed. This can happen when the server doesn't correctly
    /// implement the XML-RPC spec.
    ParseError(ParseError),

    /// A communication error originating from the transport used to perform the request.
    TransportError(Box<dyn error::Error + Send + Sync>),

    /// The server returned a `<fault>` response, indicating that the execution of the call
    /// encountered a problem (for example, an invalid (number of) arguments was passed).
    Fault(Fault),
}

impl From<ParseError> for RequestErrorKind {
    fn from(e: ParseError) -> Self {
        RequestErrorKind::ParseError(e)
    }
}

impl From<Fault> for RequestErrorKind {
    fn from(f: Fault) -> Self {
        RequestErrorKind::Fault(f)
    }
}

impl Display for RequestErrorKind {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        match *self {
            RequestErrorKind::ParseError(ref err) => write!(fmt, "parse error: {}", err),
            RequestErrorKind::TransportError(ref err) => write!(fmt, "transport error: {}", err),
            RequestErrorKind::Fault(ref err) => write!(fmt, "{}", err),
        }
    }
}

impl error::Error for RequestErrorKind {
    fn description(&self) -> &str {
        match *self {
            RequestErrorKind::ParseError(_) => "parse error",
            RequestErrorKind::TransportError(_) => "transport error",
            RequestErrorKind::Fault(_) => "server returned a fault",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            RequestErrorKind::ParseError(ref err) => Some(err),
            RequestErrorKind::TransportError(ref err) => Some(err.as_ref()),
            RequestErrorKind::Fault(ref err) => Some(err),
        }
    }
}

/// Describes possible error that can occur when parsing a `Response`.
#[derive(Debug, PartialEq)]
pub enum ParseError {
    /// Error while parsing (malformed?) XML.
    XmlError(XmlError),

    /// Could not parse the given CDATA as XML-RPC value.
    ///
    /// For example, `<value><int>AAA</int></value>` describes an invalid value.
    InvalidValue {
        /// The type for which an invalid value was supplied (eg. `int` or `dateTime.iso8601`).
        for_type: &'static str,
        /// The value we encountered, as a string.
        found: String,
        /// The position of the invalid value inside the XML document.
        position: TextPosition,
    },

    /// Found an unexpected tag, attribute, etc.
    UnexpectedXml {
        /// A short description of the kind of data that was expected.
        expected: String,
        found: Option<String>,
        /// The position of the unexpected data inside the XML document.
        position: TextPosition,
    },
}

impl From<XmlError> for ParseError {
    fn from(e: XmlError) -> Self {
        ParseError::XmlError(e)
    }
}

impl From<io::Error> for ParseError {
    fn from(e: io::Error) -> Self {
        ParseError::XmlError(XmlError::from(e))
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        match *self {
            ParseError::XmlError(ref err) => write!(fmt, "malformed XML: {}", err),
            ParseError::InvalidValue {
                for_type,
                ref found,
                ref position,
            } => write!(
                fmt,
                "invalid value for type '{}' at {}: {}",
                for_type, position, found
            ),
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: None,
            } => write!(
                fmt,
                "unexpected XML at {} (expected {})",
                position, expected
            ),
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: Some(ref found),
            } => write!(
                fmt,
                "unexpected XML at {} (expected {}, found {})",
                position, expected, found
            ),
        }
    }
}

impl error::Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::XmlError(ref err) => err.description(),
            ParseError::InvalidValue { .. } => "invalid value for type",
            ParseError::UnexpectedXml { .. } => "unexpected XML content",
        }
    }
}

/// A `<fault>` response, indicating that a request failed.
///
/// The XML-RPC specification requires that a `<faultCode>` and `<faultString>` is returned in the
/// `<fault>` case, further describing the error.
#[derive(Debug, PartialEq, Eq)]
pub struct Fault {
    /// An application-specific error code.
    pub fault_code: i32,
    /// Human-readable error description.
    pub fault_string: String,
}

impl Fault {
    /// Creates a `Fault` from a `Value`.
    ///
    /// The `Value` must be a `Value::Struct` with a `faultCode` and `faultString` field (and no
    /// other fields).
    ///
    /// Returns `None` if the value isn't a valid `Fault`.
    pub fn from_value(value: &Value) -> Option<Self> {
        match *value {
            Value::Struct(ref map) => {
                if map.len() != 2 {
                    // incorrect field count
                    return None;
                }

                match (map.get("faultCode"), map.get("faultString")) {
                    (Some(&Value::Int(fault_code)), Some(&Value::String(ref fault_string))) => {
                        Some(Fault {
                            fault_code,
                            fault_string: fault_string.to_string(),
                        })
                    }
                    _ => None,
                }
            }
            _ => None,
        }
    }

    /// Turns this `Fault` into an equivalent `Value`.
    ///
    /// The returned value can be parsed back into a `Fault` using `Fault::from_value` or returned
    /// as a `<fault>` error response by serializing it into a `<fault></fault>` tag.
    pub fn to_value(&self) -> Value {
        let mut map = BTreeMap::new();
        map.insert("faultCode".to_string(), Value::from(self.fault_code));
        map.insert(
            "faultString".to_string(),
            Value::from(self.fault_string.as_ref()),
        );

        Value::Struct(map)
    }
}

impl Display for Fault {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{} ({})", self.fault_string, self.fault_code)
    }
}

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

#[cfg(test)]
mod tests {
    use super::*;

    use std::error;

    #[test]
    fn fault_roundtrip() {
        let input = Fault {
            fault_code: -123456,
            fault_string: "The Bald Lazy House Jumps Over The Hyperactive Kitten".to_string(),
        };

        assert_eq!(Fault::from_value(&input.to_value()), Some(input));
    }

    #[test]
    fn error_impls_error() {
        fn assert_error<T: error::Error>() {}

        assert_error::<Error>();
    }

    #[test]
    fn error_is_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}

        assert_send_sync::<Error>();
    }
}
<commit_msg>Drop deprecated functions from std::error::Error impls<commit_after>//! Defines error types used by this library.

use Value;

use xml::common::TextPosition;
use xml::reader::Error as XmlError;

use std::collections::BTreeMap;
use std::fmt::{self, Display, Formatter};
use std::{error, io};

/// Errors that can occur when trying to perform an XML-RPC request.
///
/// This can be a lower-level error (for example, the HTTP request failed), a problem with the
/// server (maybe it's not implementing XML-RPC correctly), or just a failure to execute the
/// operation.
#[derive(Debug)]
pub struct Error(RequestErrorKind);

impl Error {
    /// If this `Error` was caused by the server responding with a `<fault>` response,
    /// returns the `Fault` in question.
    pub fn fault(&self) -> Option<&Fault> {
        match self.0 {
            RequestErrorKind::Fault(ref fault) => Some(fault),
            _ => None,
        }
    }
}

#[doc(hidden)] // hide internal impl
impl From<RequestErrorKind> for Error {
    fn from(kind: RequestErrorKind) -> Self {
        Error(kind)
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        self.0.fmt(fmt)
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        self.0.source()
    }
}

#[derive(Debug)]
pub enum RequestErrorKind {
    /// The response could not be parsed. This can happen when the server doesn't correctly
    /// implement the XML-RPC spec.
    ParseError(ParseError),

    /// A communication error originating from the transport used to perform the request.
    TransportError(Box<dyn error::Error + Send + Sync>),

    /// The server returned a `<fault>` response, indicating that the execution of the call
    /// encountered a problem (for example, an invalid (number of) arguments was passed).
    Fault(Fault),
}

impl From<ParseError> for RequestErrorKind {
    fn from(e: ParseError) -> Self {
        RequestErrorKind::ParseError(e)
    }
}

impl From<Fault> for RequestErrorKind {
    fn from(f: Fault) -> Self {
        RequestErrorKind::Fault(f)
    }
}

impl Display for RequestErrorKind {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        match *self {
            RequestErrorKind::ParseError(ref err) => write!(fmt, "parse error: {}", err),
            RequestErrorKind::TransportError(ref err) => write!(fmt, "transport error: {}", err),
            RequestErrorKind::Fault(ref err) => write!(fmt, "{}", err),
        }
    }
}

impl error::Error for RequestErrorKind {
    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            RequestErrorKind::ParseError(ref err) => Some(err),
            RequestErrorKind::TransportError(ref err) => Some(err.as_ref()),
            RequestErrorKind::Fault(ref err) => Some(err),
        }
    }
}

/// Describes possible error that can occur when parsing a `Response`.
#[derive(Debug, PartialEq)]
pub enum ParseError {
    /// Error while parsing (malformed?) XML.
    XmlError(XmlError),

    /// Could not parse the given CDATA as XML-RPC value.
    ///
    /// For example, `<value><int>AAA</int></value>` describes an invalid value.
    InvalidValue {
        /// The type for which an invalid value was supplied (eg. `int` or `dateTime.iso8601`).
        for_type: &'static str,
        /// The value we encountered, as a string.
        found: String,
        /// The position of the invalid value inside the XML document.
        position: TextPosition,
    },

    /// Found an unexpected tag, attribute, etc.
    UnexpectedXml {
        /// A short description of the kind of data that was expected.
        expected: String,
        found: Option<String>,
        /// The position of the unexpected data inside the XML document.
        position: TextPosition,
    },
}

impl From<XmlError> for ParseError {
    fn from(e: XmlError) -> Self {
        ParseError::XmlError(e)
    }
}

impl From<io::Error> for ParseError {
    fn from(e: io::Error) -> Self {
        ParseError::XmlError(XmlError::from(e))
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        match *self {
            ParseError::XmlError(ref err) => write!(fmt, "malformed XML: {}", err),
            ParseError::InvalidValue {
                for_type,
                ref found,
                ref position,
            } => write!(
                fmt,
                "invalid value for type '{}' at {}: {}",
                for_type, position, found
            ),
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: None,
            } => write!(
                fmt,
                "unexpected XML at {} (expected {})",
                position, expected
            ),
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: Some(ref found),
            } => write!(
                fmt,
                "unexpected XML at {} (expected {}, found {})",
                position, expected, found
            ),
        }
    }
}

impl error::Error for ParseError {
}

/// A `<fault>` response, indicating that a request failed.
///
/// The XML-RPC specification requires that a `<faultCode>` and `<faultString>` is returned in the
/// `<fault>` case, further describing the error.
#[derive(Debug, PartialEq, Eq)]
pub struct Fault {
    /// An application-specific error code.
    pub fault_code: i32,
    /// Human-readable error description.
    pub fault_string: String,
}

impl Fault {
    /// Creates a `Fault` from a `Value`.
    ///
    /// The `Value` must be a `Value::Struct` with a `faultCode` and `faultString` field (and no
    /// other fields).
    ///
    /// Returns `None` if the value isn't a valid `Fault`.
    pub fn from_value(value: &Value) -> Option<Self> {
        match *value {
            Value::Struct(ref map) => {
                if map.len() != 2 {
                    // incorrect field count
                    return None;
                }

                match (map.get("faultCode"), map.get("faultString")) {
                    (Some(&Value::Int(fault_code)), Some(&Value::String(ref fault_string))) => {
                        Some(Fault {
                            fault_code,
                            fault_string: fault_string.to_string(),
                        })
                    }
                    _ => None,
                }
            }
            _ => None,
        }
    }

    /// Turns this `Fault` into an equivalent `Value`.
    ///
    /// The returned value can be parsed back into a `Fault` using `Fault::from_value` or returned
    /// as a `<fault>` error response by serializing it into a `<fault></fault>` tag.
    pub fn to_value(&self) -> Value {
        let mut map = BTreeMap::new();
        map.insert("faultCode".to_string(), Value::from(self.fault_code));
        map.insert(
            "faultString".to_string(),
            Value::from(self.fault_string.as_ref()),
        );

        Value::Struct(map)
    }
}

impl Display for Fault {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{} ({})", self.fault_string, self.fault_code)
    }
}

impl error::Error for Fault {
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::error;

    #[test]
    fn fault_roundtrip() {
        let input = Fault {
            fault_code: -123456,
            fault_string: "The Bald Lazy House Jumps Over The Hyperactive Kitten".to_string(),
        };

        assert_eq!(Fault::from_value(&input.to_value()), Some(input));
    }

    #[test]
    fn error_impls_error() {
        fn assert_error<T: error::Error>() {}

        assert_error::<Error>();
    }

    #[test]
    fn error_is_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}

        assert_send_sync::<Error>();
    }
}
<|endoftext|>