<commit_before>use summary::Summary;

struct BoxplotData {
    box_lo: f64,
    box_mid: f64,
    box_hi: f64,
    wh_lo: f64,
    wh_hi: f64,
}

impl BoxplotData {
    fn from_summary(summary: &Summary) -> Self {
        let range = summary.max() - summary.min();
        let n = |x| (x - summary.min()) / range;

        BoxplotData {
            box_lo: n(summary.percentile(0.25).unwrap()),
            box_mid: n(summary.median()),
            box_hi: n(summary.percentile(0.75).unwrap()),
            wh_lo: n(summary.min()),
            wh_hi: n(summary.max()),
        }
    }
}

struct BoxplotCols {
    box_lo: usize,
    box_mid: usize,
    box_hi: usize,
    wh_lo: usize,
    wh_hi: usize,
}

impl BoxplotCols {
    fn new(data: &BoxplotData, width: usize) -> Self {
        let max_col  = (width - 1) as f64;
        let to_col = |x: f64| (x * max_col).floor() as usize;

        BoxplotCols {
            box_lo: to_col(data.box_lo),
            box_mid: to_col(data.box_mid),
            box_hi: to_col(data.box_hi),
            wh_lo: to_col(data.wh_lo),
            wh_hi: to_col(data.wh_hi),
        }
    }
}

struct RowChars {
    wh_lo: &'static str,
    wh_lo_box_lo_fill: &'static str,
    box_lo: &'static str,
    box_lo_box_mid_fill: &'static str,
    box_mid: &'static str,
    box_mid_box_hi_fill: &'static str,
    box_hi: &'static str,
    box_hi_wh_hi_fill: &'static str,
    wh_hi: &'static str,
}

impl RowChars {
    pub fn render(&self, row: &mut Vec<String>, cols: &BoxplotCols) {
        row[cols.wh_lo] = self.wh_lo.to_string();
        for i in (cols.wh_lo + 1)..cols.box_lo {
            row[i] = self.wh_lo_box_lo_fill.to_string();
        }
        row[cols.box_lo] = self.box_lo.to_string();
        for i in (cols.box_lo + 1)..cols.box_mid {
            row[i] = self.box_lo_box_mid_fill.to_string();
        }
        row[cols.box_mid] = self.box_mid.to_string();
        for i in (cols.box_mid + 1)..cols.box_hi {
            row[i] = self.box_mid_box_hi_fill.to_string();
        }
        row[cols.box_hi] = self.box_hi.to_string();
        for i in (cols.box_hi + 1)..cols.wh_hi {
            row[i] = self.box_hi_wh_hi_fill.to_string();
        }
        row[cols.wh_hi] = self.wh_hi.to_string();
    }
}

struct BoxplotChars(RowChars, RowChars, RowChars);

impl BoxplotChars {
    pub fn plot(&self, summary: &Summary, width: usize) -> String {
        let data = BoxplotData::from_summary(summary);
        let cols = BoxplotCols::new(&data, width);

        let mut plot = Plot::new(width);

        self.0.render(&mut plot.0, &cols);
        self.1.render(&mut plot.1, &cols);
        self.2.render(&mut plot.2, &cols);

        plot.render()
    }
}

static ASCII_CHARS: BoxplotChars = BoxplotChars(
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
    RowChars {
        wh_lo: "|",
        wh_lo_box_lo_fill: "-",
        box_lo: "|",
        box_lo_box_mid_fill: " ",
        box_mid: "|",
        box_mid_box_hi_fill: " ",
        box_hi: "|",
        box_hi_wh_hi_fill: "-",
        wh_hi: "|",
    },
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
);

static UNICODE_CHARS: BoxplotChars = BoxplotChars(
    RowChars {
        wh_lo: "┬",
        wh_lo_box_lo_fill: " ",
        box_lo: "┌",
        box_lo_box_mid_fill: "─",
        box_mid: "┬",
        box_mid_box_hi_fill: "─",
        box_hi: "┐",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┬",
    },
    RowChars {
        wh_lo: "├",
        wh_lo_box_lo_fill: "─",
        box_lo: "┤",
        box_lo_box_mid_fill: " ",
        box_mid: "│",
        box_mid_box_hi_fill: " ",
        box_hi: "├",
        box_hi_wh_hi_fill: "─",
        wh_hi: "┤",
    },
    RowChars {
        wh_lo: "┴",
        wh_lo_box_lo_fill: " ",
        box_lo: "└",
        box_lo_box_mid_fill: "─",
        box_mid: "┴",
        box_mid_box_hi_fill: "─",
        box_hi: "┘",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┴",
    },
);

fn make_row(width: usize) -> Vec<String> {
    use std::iter::repeat;

    let mut row = vec![];
    row.extend(repeat(String::from("")).take(width));

    row
}

struct Plot(Vec<String>, Vec<String>, Vec<String>);

impl Plot {
    fn new(width: usize) -> Self {
        Plot(make_row(width), make_row(width), make_row(width))
    }

    fn render(&self) -> String {
        let rows = vec![
            self.0.join(""),
            self.1.join(""),
            self.2.join(""),
        ];

        rows.join("\n")
    }
}

pub fn ascii_summary_plot(summary: &Summary, width: usize) -> String {
    ASCII_CHARS.plot(summary, width)
}

pub fn summary_plot(summary: &Summary, width: usize) -> String {
    UNICODE_CHARS.plot(summary, width)
}

fn make_padding(cols: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(String::from(" ")).take(cols))
}

fn pad(s: &String, cols: usize) -> String {
    let padding = make_padding(cols);

    let padded: Vec<String> = s
        .split("\n")
        .map(|l| format!("{}{}", padding, l))
        .collect();

    padded.join("\n")
}

pub fn comparison_plot(
    summary1: &Summary,
    summary2: &Summary,
    width: usize,
    ascii: bool,
) -> String {
    let min = summary1.min().min(summary2.min());
    let max = summary1.max().max(summary2.max());

    let range = max - min;
    let range1 = summary1.max() - summary1.min();
    let range2 = summary2.max() - summary2.min();

    let proportion1 = range1 / range;
    let proportion2 = range2 / range;

    let width1 = (proportion1 * (width as f64)).floor() as usize;
    let width2 = (proportion2 * (width as f64)).floor() as usize;

    let offset1 = {
        let neg_proportion = (summary1.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };
    let offset2 = {
        let neg_proportion = (summary2.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };

    let (plot1, plot2) = if ascii {
        let plot1 = ascii_summary_plot(&summary1, width1);
        let plot2 = ascii_summary_plot(&summary2, width2);
        (plot1, plot2)
    } else {
        let plot1 = summary_plot(&summary1, width1);
        let plot2 = summary_plot(&summary2, width2);
        (plot1, plot2)
    };

    format!("{}\n{}", pad(&plot1, offset1), pad(&plot2, offset2))
}
<commit_msg>Rename `BoxplotData` to `Boxplot`<commit_after>use summary::Summary;

struct Boxplot {
    box_lo: f64,
    box_mid: f64,
    box_hi: f64,
    wh_lo: f64,
    wh_hi: f64,
}

impl Boxplot {
    fn from_summary(summary: &Summary) -> Self {
        let range = summary.max() - summary.min();
        let n = |x| (x - summary.min()) / range;

        Boxplot {
            box_lo: n(summary.percentile(0.25).unwrap()),
            box_mid: n(summary.median()),
            box_hi: n(summary.percentile(0.75).unwrap()),
            wh_lo: n(summary.min()),
            wh_hi: n(summary.max()),
        }
    }
}

struct BoxplotCols {
    box_lo: usize,
    box_mid: usize,
    box_hi: usize,
    wh_lo: usize,
    wh_hi: usize,
}

impl BoxplotCols {
    fn new(data: &Boxplot, width: usize) -> Self {
        let max_col  = (width - 1) as f64;
        let to_col = |x: f64| (x * max_col).floor() as usize;

        BoxplotCols {
            box_lo: to_col(data.box_lo),
            box_mid: to_col(data.box_mid),
            box_hi: to_col(data.box_hi),
            wh_lo: to_col(data.wh_lo),
            wh_hi: to_col(data.wh_hi),
        }
    }
}

struct RowChars {
    wh_lo: &'static str,
    wh_lo_box_lo_fill: &'static str,
    box_lo: &'static str,
    box_lo_box_mid_fill: &'static str,
    box_mid: &'static str,
    box_mid_box_hi_fill: &'static str,
    box_hi: &'static str,
    box_hi_wh_hi_fill: &'static str,
    wh_hi: &'static str,
}

impl RowChars {
    pub fn render(&self, row: &mut Vec<String>, cols: &BoxplotCols) {
        row[cols.wh_lo] = self.wh_lo.to_string();
        for i in (cols.wh_lo + 1)..cols.box_lo {
            row[i] = self.wh_lo_box_lo_fill.to_string();
        }
        row[cols.box_lo] = self.box_lo.to_string();
        for i in (cols.box_lo + 1)..cols.box_mid {
            row[i] = self.box_lo_box_mid_fill.to_string();
        }
        row[cols.box_mid] = self.box_mid.to_string();
        for i in (cols.box_mid + 1)..cols.box_hi {
            row[i] = self.box_mid_box_hi_fill.to_string();
        }
        row[cols.box_hi] = self.box_hi.to_string();
        for i in (cols.box_hi + 1)..cols.wh_hi {
            row[i] = self.box_hi_wh_hi_fill.to_string();
        }
        row[cols.wh_hi] = self.wh_hi.to_string();
    }
}

struct BoxplotChars(RowChars, RowChars, RowChars);

impl BoxplotChars {
    pub fn plot(&self, summary: &Summary, width: usize) -> String {
        let data = Boxplot::from_summary(summary);
        let cols = BoxplotCols::new(&data, width);

        let mut plot = Plot::new(width);

        self.0.render(&mut plot.0, &cols);
        self.1.render(&mut plot.1, &cols);
        self.2.render(&mut plot.2, &cols);

        plot.render()
    }
}

static ASCII_CHARS: BoxplotChars = BoxplotChars(
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
    RowChars {
        wh_lo: "|",
        wh_lo_box_lo_fill: "-",
        box_lo: "|",
        box_lo_box_mid_fill: " ",
        box_mid: "|",
        box_mid_box_hi_fill: " ",
        box_hi: "|",
        box_hi_wh_hi_fill: "-",
        wh_hi: "|",
    },
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
);

static UNICODE_CHARS: BoxplotChars = BoxplotChars(
    RowChars {
        wh_lo: "┬",
        wh_lo_box_lo_fill: " ",
        box_lo: "┌",
        box_lo_box_mid_fill: "─",
        box_mid: "┬",
        box_mid_box_hi_fill: "─",
        box_hi: "┐",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┬",
    },
    RowChars {
        wh_lo: "├",
        wh_lo_box_lo_fill: "─",
        box_lo: "┤",
        box_lo_box_mid_fill: " ",
        box_mid: "│",
        box_mid_box_hi_fill: " ",
        box_hi: "├",
        box_hi_wh_hi_fill: "─",
        wh_hi: "┤",
    },
    RowChars {
        wh_lo: "┴",
        wh_lo_box_lo_fill: " ",
        box_lo: "└",
        box_lo_box_mid_fill: "─",
        box_mid: "┴",
        box_mid_box_hi_fill: "─",
        box_hi: "┘",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┴",
    },
);

fn make_row(width: usize) -> Vec<String> {
    use std::iter::repeat;

    let mut row = vec![];
    row.extend(repeat(String::from("")).take(width));

    row
}

struct Plot(Vec<String>, Vec<String>, Vec<String>);

impl Plot {
    fn new(width: usize) -> Self {
        Plot(make_row(width), make_row(width), make_row(width))
    }

    fn render(&self) -> String {
        let rows = vec![
            self.0.join(""),
            self.1.join(""),
            self.2.join(""),
        ];

        rows.join("\n")
    }
}

pub fn ascii_summary_plot(summary: &Summary, width: usize) -> String {
    ASCII_CHARS.plot(summary, width)
}

pub fn summary_plot(summary: &Summary, width: usize) -> String {
    UNICODE_CHARS.plot(summary, width)
}

fn make_padding(cols: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(String::from(" ")).take(cols))
}

fn pad(s: &String, cols: usize) -> String {
    let padding = make_padding(cols);

    let padded: Vec<String> = s
        .split("\n")
        .map(|l| format!("{}{}", padding, l))
        .collect();

    padded.join("\n")
}

pub fn comparison_plot(
    summary1: &Summary,
    summary2: &Summary,
    width: usize,
    ascii: bool,
) -> String {
    let min = summary1.min().min(summary2.min());
    let max = summary1.max().max(summary2.max());

    let range = max - min;
    let range1 = summary1.max() - summary1.min();
    let range2 = summary2.max() - summary2.min();

    let proportion1 = range1 / range;
    let proportion2 = range2 / range;

    let width1 = (proportion1 * (width as f64)).floor() as usize;
    let width2 = (proportion2 * (width as f64)).floor() as usize;

    let offset1 = {
        let neg_proportion = (summary1.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };
    let offset2 = {
        let neg_proportion = (summary2.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };

    let (plot1, plot2) = if ascii {
        let plot1 = ascii_summary_plot(&summary1, width1);
        let plot2 = ascii_summary_plot(&summary2, width2);
        (plot1, plot2)
    } else {
        let plot1 = summary_plot(&summary1, width1);
        let plot2 = summary_plot(&summary2, width2);
        (plot1, plot2)
    };

    format!("{}\n{}", pad(&plot1, offset1), pad(&plot2, offset2))
}
<|endoftext|>


<commit_before>use std::os::getenv;

fn main() {
    print("content-type: text/plain\r\n\r\n");
    print("hello from ");
    let path = match getenv("PATH_INFO") {
        Some(m) => m,
        None => ~"you didn't specify a path :("
    };
    println(path);
}<commit_msg>Actually adding a simple request structure to handle important CGI varaibles<commit_after>use std::os::getenv;

struct Request {
    path: ~str,
    querystring: ~str
}

fn main() {
    print("content-type: text/plain\r\n\r\n");
    println("hello from rust!");
    let req=Request{ path: getenv("PATH_INFO").unwrap_or(~""), querystring: getenv("QUERY_STRING").unwrap_or(~"")};
    println!("path: {:s}", req.path);
    println!("querystring: {:s}", req.querystring);
    println("done!");
}<|endoftext|>


<commit_before>use clap::{App, Arg, ErrorKind};

static HELP: &str = "prog

USAGE:
    prog [OPTIONS]

OPTIONS:
    -a
    -b
    -c
    -h, --help    Print help information
";

static ONLY_B_ERROR: &str = "error: The following required arguments were not provided:
    -c

USAGE:
    prog [OPTIONS] -c -b

For more information try --help
";

static ONLY_C_ERROR: &str = "error: The following required arguments were not provided:
    -b

USAGE:
    prog [OPTIONS] -b -c

For more information try --help
";

fn app() -> App<'static> {
    App::new("prog")
        .arg(
            Arg::new("a")
                .short('a')
                .required_unless_present_any(&["b", "c"])
                .conflicts_with_all(&["b", "c"]),
        )
        .arg(
            Arg::new("b")
                .short('b')
                .required_unless_present("a")
                .requires("c"),
        )
        .arg(
            Arg::new("c")
                .short('c')
                .required_unless_present("a")
                .requires("b"),
        )
}

#[test]
fn valid_cases() {
    let res = app().try_get_matches_from(vec!["", "-a"]);
    assert!(res.is_ok(), "{}", res.unwrap_err());
    let res = app().clone().try_get_matches_from(vec!["", "-b", "-c"]);
    assert!(res.is_ok(), "{}", res.unwrap_err());
    let res = app().try_get_matches_from(vec!["", "-c", "-b"]);
    assert!(res.is_ok(), "{}", res.unwrap_err());
}

#[test]
fn help_text() {
    let res = app().try_get_matches_from(vec!["prog", "--help"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    assert_eq!(err.kind, ErrorKind::DisplayHelp);
    println!("{}", err.to_string());
    assert_eq!(err.to_string(), HELP);
}

#[test]
fn no_duplicate_error() {
    let res = app().try_get_matches_from(vec!["", "-b"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
    assert_eq!(err.to_string(), ONLY_B_ERROR);

    let res = app().try_get_matches_from(vec!["", "-c"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
    assert_eq!(err.to_string(), ONLY_C_ERROR);
}
<commit_msg>style: remove 'from_string' call from 'format' args<commit_after>use clap::{App, Arg, ErrorKind};

static HELP: &str = "prog

USAGE:
    prog [OPTIONS]

OPTIONS:
    -a
    -b
    -c
    -h, --help    Print help information
";

static ONLY_B_ERROR: &str = "error: The following required arguments were not provided:
    -c

USAGE:
    prog [OPTIONS] -c -b

For more information try --help
";

static ONLY_C_ERROR: &str = "error: The following required arguments were not provided:
    -b

USAGE:
    prog [OPTIONS] -b -c

For more information try --help
";

fn app() -> App<'static> {
    App::new("prog")
        .arg(
            Arg::new("a")
                .short('a')
                .required_unless_present_any(&["b", "c"])
                .conflicts_with_all(&["b", "c"]),
        )
        .arg(
            Arg::new("b")
                .short('b')
                .required_unless_present("a")
                .requires("c"),
        )
        .arg(
            Arg::new("c")
                .short('c')
                .required_unless_present("a")
                .requires("b"),
        )
}

#[test]
fn valid_cases() {
    let res = app().try_get_matches_from(vec!["", "-a"]);
    assert!(res.is_ok(), "{}", res.unwrap_err());
    let res = app().clone().try_get_matches_from(vec!["", "-b", "-c"]);
    assert!(res.is_ok(), "{}", res.unwrap_err());
    let res = app().try_get_matches_from(vec!["", "-c", "-b"]);
    assert!(res.is_ok(), "{}", res.unwrap_err());
}

#[test]
fn help_text() {
    let res = app().try_get_matches_from(vec!["prog", "--help"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    assert_eq!(err.kind, ErrorKind::DisplayHelp);
    println!("{}", err);
    assert_eq!(err.to_string(), HELP);
}

#[test]
fn no_duplicate_error() {
    let res = app().try_get_matches_from(vec!["", "-b"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
    assert_eq!(err.to_string(), ONLY_B_ERROR);

    let res = app().try_get_matches_from(vec!["", "-c"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
    assert_eq!(err.to_string(), ONLY_C_ERROR);
}
<|endoftext|>


<commit_before>use console;
use glium;
use mvp;
use shaders;
use units;
use utils;

pub struct Renderer {
    pub screen_size: units::Size2D,
    pub size: units::Size2D,
    pub display: glium::backend::glutin_backend::GlutinFacade,
    pub program: glium::Program,
    pub indices: glium::IndexBuffer<u16>,
    pub texture: glium::texture::Texture2d,
    pub vertex_buffer: console::VertexBuffer,
}

impl Renderer {
    pub fn new(width: i32, height: i32, tile_size: i32, texture_path: &str) -> Self {
        let screen_size = units::Size2D::new(width, height);
        let size = units::Size2D::new((screen_size.width / tile_size),
                                      (screen_size.height / tile_size));

        let display = display(screen_size);
        let program = program(&display);
        let indices = indices(&display, size);
        let texture = texture(&display, texture_path);
        let vertex_buffer = console::VertexBuffer::new(size);

        Renderer {
            size: size,
            screen_size: screen_size,
            display: display,
            program: program,
            indices: indices,
            texture: texture,
            vertex_buffer: vertex_buffer,
        }
    }

    pub fn render(&self) {
        use glium::Surface;

        let vb = glium::VertexBuffer::new(&self.display, &self.vertex_buffer.data()).unwrap();

        let cam_uniforms = {
            let mat4_id = utils::mat4_id();
            let ortho_projection = utils::ortho_projection(self.screen_size);

            let cam = [[1.0, 0.0, 0.0, 0.0],
                       [0.0, 1.0, 0.0, 0.0],
                       [0.0, 0.0, 1.0, 0.0],
                       [-768.0, -512.0, 0.0, 1.0]];

            let tileset = self.texture
                .sampled()
                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest);

            uniform! {
                mvp: mvp::model_view_projection(mat4_id, cam, ortho_projection),
                tileset: tileset,
            }
        };

        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);
        target.draw(&vb,
                  &self.indices,
                  &self.program,
                  &cam_uniforms,
                  &Default::default())
            .unwrap();
        target.finish().unwrap();
    }

    pub fn set(&mut self, screen_point: units::ScreenPoint2D, tile: console::Tile) {
        self.vertex_buffer.set(screen_point, tile);
    }
}

fn display(screen_size: units::Size2D) -> glium::backend::glutin_backend::GlutinFacade {
    use glium::DisplayBuild;
    glium::glutin::WindowBuilder::new()
        .with_dimensions(screen_size.width as u32, screen_size.height as u32)
        .build_glium()
        .unwrap()
}

fn program(display: &glium::backend::glutin_backend::GlutinFacade) -> glium::Program {
    glium::Program::from_source(display as &glium::backend::Facade,
                                &shaders::VERTEX,
                                &shaders::FRAGMENT,
                                None)
        .unwrap()
}

fn indices(
    display: &glium::backend::glutin_backend::GlutinFacade,
    size: units::Size2D
) -> glium::IndexBuffer<u16> {
    use glium::index::PrimitiveType;

    let indices = utils::indices((size.width * size.height) as usize);
    glium::IndexBuffer::new(display as &glium::backend::Facade,
                            PrimitiveType::TrianglesList,
                            &indices)
        .unwrap()
}

fn texture(
    display: &glium::backend::glutin_backend::GlutinFacade,
    path: &str
) -> glium::texture::Texture2d {
    let png = utils::read_bytes(path).expect("Texture not found");
    let texture = utils::read_png_to_texture(&png[..]);
    glium::texture::Texture2d::new(display as &glium::backend::Facade, texture).unwrap()
}
<commit_msg>chore(utils): better error msg<commit_after>use console;
use glium;
use mvp;
use shaders;
use units;
use utils;

pub struct Renderer {
    pub screen_size: units::Size2D,
    pub size: units::Size2D,
    pub display: glium::backend::glutin_backend::GlutinFacade,
    pub program: glium::Program,
    pub indices: glium::IndexBuffer<u16>,
    pub texture: glium::texture::Texture2d,
    pub vertex_buffer: console::VertexBuffer,
}

impl Renderer {
    pub fn new(width: i32, height: i32, tile_size: i32, texture_path: &str) -> Self {
        let screen_size = units::Size2D::new(width, height);
        let size = units::Size2D::new((screen_size.width / tile_size),
                                      (screen_size.height / tile_size));

        let display = display(screen_size);
        let program = program(&display);
        let indices = indices(&display, size);
        let texture = texture(&display, texture_path);
        let vertex_buffer = console::VertexBuffer::new(size);

        Renderer {
            size: size,
            screen_size: screen_size,
            display: display,
            program: program,
            indices: indices,
            texture: texture,
            vertex_buffer: vertex_buffer,
        }
    }

    pub fn render(&self) {
        use glium::Surface;

        let vb = glium::VertexBuffer::new(&self.display, &self.vertex_buffer.data()).unwrap();

        let cam_uniforms = {
            let mat4_id = utils::mat4_id();
            let ortho_projection = utils::ortho_projection(self.screen_size);

            let cam = [[1.0, 0.0, 0.0, 0.0],
                       [0.0, 1.0, 0.0, 0.0],
                       [0.0, 0.0, 1.0, 0.0],
                       [-768.0, -512.0, 0.0, 1.0]];

            let tileset = self.texture
                .sampled()
                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest);

            uniform! {
                mvp: mvp::model_view_projection(mat4_id, cam, ortho_projection),
                tileset: tileset,
            }
        };

        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);
        target.draw(&vb,
                  &self.indices,
                  &self.program,
                  &cam_uniforms,
                  &Default::default())
            .unwrap();
        target.finish().unwrap();
    }

    pub fn set(&mut self, screen_point: units::ScreenPoint2D, tile: console::Tile) {
        self.vertex_buffer.set(screen_point, tile);
    }
}

fn display(screen_size: units::Size2D) -> glium::backend::glutin_backend::GlutinFacade {
    use glium::DisplayBuild;
    glium::glutin::WindowBuilder::new()
        .with_dimensions(screen_size.width as u32, screen_size.height as u32)
        .build_glium()
        .unwrap()
}

fn program(display: &glium::backend::glutin_backend::GlutinFacade) -> glium::Program {
    glium::Program::from_source(display as &glium::backend::Facade,
                                &shaders::VERTEX,
                                &shaders::FRAGMENT,
                                None)
        .unwrap()
}

fn indices(
    display: &glium::backend::glutin_backend::GlutinFacade,
    size: units::Size2D
) -> glium::IndexBuffer<u16> {
    use glium::index::PrimitiveType;

    let indices = utils::indices((size.width * size.height) as usize);
    glium::IndexBuffer::new(display as &glium::backend::Facade,
                            PrimitiveType::TrianglesList,
                            &indices)
        .unwrap()
}

fn texture(
    display: &glium::backend::glutin_backend::GlutinFacade,
    path: &str
) -> glium::texture::Texture2d {
    let png = utils::read_bytes(path).expect(&format!("Texture not found: {}", path)[..]);
    let texture = utils::read_png_to_texture(&png[..]);
    glium::texture::Texture2d::new(display as &glium::backend::Facade, texture).unwrap()
}
<|endoftext|>


<commit_before>//! Iron's HTTP Response representation and associated methods.

use std::io::{IoResult, File, MemReader};
use std::path::BytesContainer;
use std::fmt::{Show, Formatter, FormatError};

use typemap::TypeMap;
use plugin::Extensible;
use super::status;
use super::status::Status;
use http::headers::response::HeaderCollection;
use http::headers::content_type::MediaType;
use Url;

pub use http::server::response::ResponseWriter as HttpResponse;

use content_type::get_content_type;

/// The response representation given to `Middleware`
pub struct Response {
    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Option<Box<Reader + Send>>,

    /// The headers of the response.
    pub headers: HeaderCollection,

    /// The response status-code.
    pub status: Option<Status>,

    /// A TypeMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: TypeMap
}

impl Response {
    /// Construct a blank Response
    pub fn new() -> Response {
        Response {
            headers: HeaderCollection::new(),
            status: None, // Start with no response code.
            body: None, // Start with no body.
            extensions: TypeMap::new()
        }
    }

    /// Create a new response with the status.
    pub fn status(status: status::Status) -> Response {
        Response {
            body: None,
            headers: HeaderCollection::new(),
            status: Some(status),
            extensions: TypeMap::new()
        }
    }

    /// Create a new response with the specified body and status.
    pub fn with<B: BytesContainer>(status: status::Status, body: B) -> Response {
        Response {
            body: Some(box MemReader::new(body.container_as_bytes().to_vec()) as Box<Reader + Send>),
            headers: HeaderCollection::new(),
            status: Some(status),
            extensions: TypeMap::new()
        }
    }

    /// Create a new Response with the `location` header set to the specified url.
    pub fn redirect(status: status::Status, url: Url) -> Response {
        let mut headers = HeaderCollection::new();
        headers.location = Some(url.into_generic_url());
        Response {
            body: None,
            headers: headers,
            status: Some(status),
            extensions: TypeMap::new()
        }
    }

    /// Create a response from a file on disk.
    ///
    /// The status code is set to 200 OK and the content type is autodetected based on
    /// the file extension.
    pub fn from_file(path: &Path) -> IoResult<Response> {
        let file = try!(File::open(path));
        let mut response = Response::new();
        response.status = Some(status::Ok);
        response.body = Some(box file as Box<Reader + Send>);
        response.headers.content_type = path.extension_str().and_then(get_content_type);
        Ok(response)
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, http_res: &mut HttpResponse) {
        http_res.headers = self.headers.clone();

        // Default to a 404 if no response code was set
        http_res.status = self.status.clone().unwrap_or(status::NotFound);

        // Read the body into the http_res body
        let mut body = self.body.unwrap_or_else(|| box MemReader::new(vec![]) as Box<Reader + Send>);
        let _ = match body.read_to_end() {
            Ok(body_content) => {
                let plain_txt = MediaType {
                    type_: "text".to_string(),
                    subtype: "plain".to_string(),
                    parameters: vec![]
                };

                // Set content length and type
                http_res.headers.content_length =
                    Some(body_content.len());
                http_res.headers.content_type =
                    Some(http_res.headers.content_type.clone().unwrap_or(plain_txt));

                // Write the body
                http_res.write(body_content.as_slice())
            },
            Err(e) => Err(e)
        // Catch errors from reading + writing
        }.map_err(|e| {
            error!("Error reading/writing body: {}", e);
            http_res.status = status::InternalServerError;
            let _ = http_res.write(b"Internal Server Error")
                // Something is really, really wrong.
                .map_err(|e| error!("Error writing error message: {}", e));
        });
    }
}

impl Show for Response {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        try!(writeln!(f, "Response {{"));

        try!(writeln!(f, "    status: {}", self.status));

        try!(write!(f, "}}"));
        Ok(())
    }
}

// Allow plugins to attach to responses.
impl Extensible for Response {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_content_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<commit_msg>(refactor) Use the new FileError wrapper instead of IoError<commit_after>//! Iron's HTTP Response representation and associated methods.

use std::io::{File, MemReader};
use std::path::BytesContainer;
use std::fmt::{Show, Formatter, FormatError};

use typemap::TypeMap;
use plugin::Extensible;

use http::headers::response::HeaderCollection;
use http::headers::content_type::MediaType;

use errors::FileError;
use status::{mod, Status};
use {Url};

pub use http::server::response::ResponseWriter as HttpResponse;

use content_type::get_content_type;

/// The response representation given to `Middleware`
pub struct Response {
    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Option<Box<Reader + Send>>,

    /// The headers of the response.
    pub headers: HeaderCollection,

    /// The response status-code.
    pub status: Option<Status>,

    /// A TypeMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: TypeMap
}

impl Response {
    /// Construct a blank Response
    pub fn new() -> Response {
        Response {
            headers: HeaderCollection::new(),
            status: None, // Start with no response code.
            body: None, // Start with no body.
            extensions: TypeMap::new()
        }
    }

    /// Create a new response with the status.
    pub fn status(status: status::Status) -> Response {
        Response {
            body: None,
            headers: HeaderCollection::new(),
            status: Some(status),
            extensions: TypeMap::new()
        }
    }

    /// Create a new response with the specified body and status.
    pub fn with<B: BytesContainer>(status: status::Status, body: B) -> Response {
        Response {
            body: Some(box MemReader::new(body.container_as_bytes().to_vec()) as Box<Reader + Send>),
            headers: HeaderCollection::new(),
            status: Some(status),
            extensions: TypeMap::new()
        }
    }

    /// Create a new Response with the `location` header set to the specified url.
    pub fn redirect(status: status::Status, url: Url) -> Response {
        let mut headers = HeaderCollection::new();
        headers.location = Some(url.into_generic_url());
        Response {
            body: None,
            headers: headers,
            status: Some(status),
            extensions: TypeMap::new()
        }
    }

    /// Create a response from a file on disk.
    ///
    /// The status code is set to 200 OK and the content type is autodetected based on
    /// the file extension.
    pub fn from_file(path: &Path) -> Result<Response, FileError> {
        let file = try!(File::open(path).map_err(FileError::new));
        let mut response = Response::new();
        response.status = Some(status::Ok);
        response.body = Some(box file as Box<Reader + Send>);
        response.headers.content_type = path.extension_str().and_then(get_content_type);
        Ok(response)
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, http_res: &mut HttpResponse) {
        http_res.headers = self.headers.clone();

        // Default to a 404 if no response code was set
        http_res.status = self.status.clone().unwrap_or(status::NotFound);

        // Read the body into the http_res body
        let mut body = self.body.unwrap_or_else(|| box MemReader::new(vec![]) as Box<Reader + Send>);
        let _ = match body.read_to_end() {
            Ok(body_content) => {
                let plain_txt = MediaType {
                    type_: "text".to_string(),
                    subtype: "plain".to_string(),
                    parameters: vec![]
                };

                // Set content length and type
                http_res.headers.content_length =
                    Some(body_content.len());
                http_res.headers.content_type =
                    Some(http_res.headers.content_type.clone().unwrap_or(plain_txt));

                // Write the body
                http_res.write(body_content.as_slice())
            },
            Err(e) => Err(e)
        // Catch errors from reading + writing
        }.map_err(|e| {
            error!("Error reading/writing body: {}", e);
            http_res.status = status::InternalServerError;
            let _ = http_res.write(b"Internal Server Error")
                // Something is really, really wrong.
                .map_err(|e| error!("Error writing error message: {}", e));
        });
    }
}

impl Show for Response {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        try!(writeln!(f, "Response {{"));

        try!(writeln!(f, "    status: {}", self.status));

        try!(write!(f, "}}"));
        Ok(())
    }
}

// Allow plugins to attach to responses.
impl Extensible for Response {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_content_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<|endoftext|>


<commit_before>use chrono::prelude::*;
use serde::{
    de::{
        self,
        Deserializer,
        MapAccess,
        Visitor,
    },
    Deserialize,
};
use std::{
    collections::HashMap,
    fmt,
    str::FromStr,
    time::SystemTime,
};

#[derive(Debug, PartialEq)]
pub struct PeriodTime(SystemTime);

impl From<SystemTime> for PeriodTime {
    fn from(st: SystemTime) -> Self {
        PeriodTime(st)
    }
}

impl From<PeriodTime> for SystemTime {
    fn from(pt: PeriodTime) -> Self {
        pt.0
    }
}

#[derive(Debug, PartialEq, Default)]
pub struct MetricsHierarchy(HashMap<String, Vec<String>>);

impl MetricsHierarchy {
    pub fn new() -> Self {
        Self(HashMap::new())
    }

    pub fn insert(&mut self, parent_metric: String, children_metrics: Vec<String>) {
        self.0.insert(parent_metric, children_metrics);
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "usage_report")]
pub struct UsageReport {
    pub metric:        String,
    pub period:        Period,
    pub period_start:  PeriodTime,
    pub period_end:    PeriodTime,
    pub max_value:     u64,
    pub current_value: u64,
}

// Unfortunately the XML output from Apisonator includes a rather useless "usage_reports" tag that
// is then followed by a "usage_report" tag in each UsageReport, so we need to wrap that up.
#[derive(Debug, Deserialize, PartialEq)]
pub enum UsageReports {
    #[serde(rename = "usage_report")]
    UsageReports(Vec<UsageReport>),
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "status")]
pub struct Authorization {
    authorized:    bool,
    plan:          String,
    usage_reports: UsageReports,

    #[serde(rename = "hierarchy")]
    metrics_hierarchy: Option<MetricsHierarchy>,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct PeriodInstance {
    start: SystemTime,
    end:   SystemTime,
}

#[derive(Debug, PartialEq)]
pub enum Period {
    Minute,
    Hour,
    Day,
    Week,
    Month,
    Year,
    Eternity,
}

struct PeriodStringVisitor;

impl<'de> Visitor<'de> for PeriodStringVisitor {
    type Value = Period;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string that represents a period")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where E: de::Error
    {
        match v {
            "minute" => Ok(Period::Minute),
            "hour" => Ok(Period::Hour),
            "day" => Ok(Period::Day),
            "week" => Ok(Period::Week),
            "month" => Ok(Period::Month),
            "year" => Ok(Period::Year),
            "eternity" => Ok(Period::Eternity),
            _ => Err(E::custom("Invalid period")),
        }
    }
}

impl<'de> Deserialize<'de> for Period {
    fn deserialize<D>(deserializer: D) -> Result<Period, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_any(PeriodStringVisitor)
    }
}

struct TimestampVisitor;

impl<'de> Visitor<'de> for TimestampVisitor {
    type Value = PeriodTime;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string that represents a timestamp")
    }

    fn visit_map<V>(self, mut map: V) -> Result<PeriodTime, V::Error>
        where V: MapAccess<'de>
    {
        // We know there's only one key with one value.
        // The key is not used, but we need to call "next_key()". From the
        // docs: "Calling `next_value` before `next_key` is incorrect and is
        // allowed to panic or return bogus results.".
        let _key: Option<String> = map.next_key()?;
        let timestamp: String = map.next_value()?;

        let dt = DateTime::parse_from_str(timestamp.as_str(), "%Y-%m-%d %H:%M:%S %z").unwrap();

        Ok(PeriodTime(dt.into()))
    }
}

impl<'de> Deserialize<'de> for PeriodTime {
    fn deserialize<D>(deserializer: D) -> Result<PeriodTime, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_any(TimestampVisitor)
    }
}

struct MetricsHierarchyVisitor;

impl<'de> Visitor<'de> for MetricsHierarchyVisitor {
    type Value = MetricsHierarchy;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a structure that represents a hierarchy of metrics")
    }

    fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
        where V: MapAccess<'de>
    {
        let mut hierarchy = MetricsHierarchy::new();

        // The key in the hierarchy structure is always "metric". It is not
        // used, but we need to read it to get the value.
        while let Some(_) = map.next_key::<String>()? {
            let val: HashMap<String, String> = map.next_value()?;

            let parent_metric = val["name"].to_owned();
            let children_metrics = val["children"].split(' ').map(|s| s.to_owned()).collect();

            hierarchy.insert(parent_metric, children_metrics);
        }

        Ok(hierarchy)
    }
}

impl<'de> Deserialize<'de> for MetricsHierarchy {
    fn deserialize<D>(deserializer: D) -> Result<MetricsHierarchy, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_any(MetricsHierarchyVisitor)
    }
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct UsageData {
    max_value:     u64,
    current_value: u64,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct Metric(pub String);

impl FromStr for Authorization {
    type Err = serde_xml_rs::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        serde_xml_rs::from_str(s)
    }
}

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

    #[test]
    fn parse() {
        let s = r##"
        <?xml version="1.0" encoding="UTF-8"?>
        <status>
            <authorized>true</authorized>
            <plan>App Plan</plan>
            <usage_reports>
                <usage_report metric="products" period="minute">
                    <period_start>2019-06-05 16:24:00 +0000</period_start>
                    <period_end>2019-06-05 16:25:00 +0000</period_end>
                    <max_value>5</max_value>
                    <current_value>0</current_value>
                </usage_report>
                <usage_report metric="products" period="month">
                    <period_start>2019-06-01 00:00:00 +0000</period_start>
                    <period_end>2019-07-01 00:00:00 +0000</period_end>
                    <max_value>50</max_value>
                    <current_value>0</current_value>
                </usage_report>
            </usage_reports>
        </status>
        "##;

        let parsed_auth = Authorization::from_str(s).unwrap();

        let expected_auth = Authorization { authorized:        true,
                                            plan:              String::from("App Plan"),
                                            metrics_hierarchy: None,
                                            usage_reports:     UsageReports::UsageReports(vec![
                UsageReport {
                    metric: String::from("products"),
                    period: Period::Minute,
                    period_start: PeriodTime(Utc.ymd(2019, 6, 5).and_hms(16, 24, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2019, 6, 5).and_hms(16, 25, 0).into()),
                    max_value: 5,
                    current_value: 0,
                },
                UsageReport {
                    metric: String::from("products"),
                    period: Period::Month,
                    period_start: PeriodTime(Utc.ymd(2019, 6, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2019, 7, 1).and_hms(0, 0, 0).into()),
                    max_value: 50,
                    current_value: 0,
                },
            ]), };

        assert_eq!(parsed_auth, expected_auth);
    }

    #[test]
    fn parse_metrics_hierarchy() {
        let xml_response = r##"
        <?xml version="1.0" encoding="UTF-8"?>
        <status>
            <authorized>true</authorized>
            <plan>Basic</plan>
            <usage_reports>
                <usage_report metric="parent1" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>20</current_value>
                </usage_report>
                <usage_report metric="parent2" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>10</current_value>
                </usage_report>
                <usage_report metric="child1" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>10</current_value>
                </usage_report>
                <usage_report metric="child2" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>10</current_value>
                </usage_report>
                <usage_report metric="child3" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>10</current_value>
                </usage_report>
            </usage_reports>
            <hierarchy>
                <metric name="parent1" children="child1 child2" />
                <metric name="parent2" children="child3" />
            </hierarchy>
        </status>
        "##;

        let parsed_auth = Authorization::from_str(xml_response).unwrap();

        let mut expected_hierarchy = MetricsHierarchy::new();
        expected_hierarchy.insert(String::from("parent1"), vec![String::from("child1"),
                                                                String::from("child2")]);
        expected_hierarchy.insert(String::from("parent2"), vec![String::from("child3")]);

        let expected_auth = Authorization { authorized:        true,
                                            plan:              String::from("Basic"),
                                            metrics_hierarchy: Some(expected_hierarchy),
                                            usage_reports:     UsageReports::UsageReports(vec![
                UsageReport {
                    metric: String::from("parent1"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 20,
                },
                UsageReport {
                    metric: String::from("parent2"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 10,
                },
                UsageReport {
                    metric: String::from("child1"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 10,
                },
                UsageReport {
                    metric: String::from("child2"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 10,
                },
                UsageReport {
                    metric: String::from("child3"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 10,
                },
            ]), };

        assert_eq!(parsed_auth, expected_auth);
    }
}
<commit_msg>response: add minimal behaviour to MetricsHierarchy<commit_after>use chrono::prelude::*;
use serde::{
    de::{
        self,
        Deserializer,
        MapAccess,
        Visitor,
    },
    Deserialize,
};
use std::{
    collections::{
        hash_map::{
            Iter,
            IterMut,
        },
        HashMap,
    },
    fmt,
    str::FromStr,
    time::SystemTime,
};

#[derive(Debug, PartialEq)]
pub struct PeriodTime(SystemTime);

impl From<SystemTime> for PeriodTime {
    fn from(st: SystemTime) -> Self {
        PeriodTime(st)
    }
}

impl From<PeriodTime> for SystemTime {
    fn from(pt: PeriodTime) -> Self {
        pt.0
    }
}

// We might want to consider moving from a HashMap to a Vec, as most of the time this hashmap will
// contain a (very) small number of entries.
#[derive(Debug, Clone, PartialEq, Default)]
pub struct MetricsHierarchy(HashMap<String, Vec<String>>);

impl MetricsHierarchy {
    pub fn new() -> Self {
        Self(HashMap::new())
    }

    pub fn insert<S: Into<String>, V: Into<Vec<String>>>(&mut self,
                                                         parent_metric: S,
                                                         children_metrics: V)
                                                         -> Option<Vec<String>> {
        self.0.insert(parent_metric.into(), children_metrics.into())
    }

    pub fn remove<S: AsRef<str>>(&mut self, parent_metric: S) -> Option<Vec<String>> {
        self.0.remove(parent_metric.as_ref())
    }

    pub fn iter(&self) -> Iter<String, Vec<String>> {
        self.0.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<String, Vec<String>> {
        self.0.iter_mut()
    }

    pub fn into_inner(self) -> HashMap<String, Vec<String>> {
        self.0
    }

    /// Retrieves the parent metric of a given metric. Note that Apisonator metrics have 0 or
    /// 1 parent metrics, not multiple.
    pub fn parent_of(&self, metric_name: &str) -> Option<&str> {
        self.iter().find_map(|(parent, v)| {
                       if v.iter().any(|child| metric_name == child) {
                           Some(parent.as_str())
                       } else {
                           None
                       }
                   })
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "usage_report")]
pub struct UsageReport {
    pub metric:        String,
    pub period:        Period,
    pub period_start:  PeriodTime,
    pub period_end:    PeriodTime,
    pub max_value:     u64,
    pub current_value: u64,
}

// Unfortunately the XML output from Apisonator includes a rather useless "usage_reports" tag that
// is then followed by a "usage_report" tag in each UsageReport, so we need to wrap that up.
#[derive(Debug, Deserialize, PartialEq)]
pub enum UsageReports {
    #[serde(rename = "usage_report")]
    UsageReports(Vec<UsageReport>),
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "status")]
pub struct Authorization {
    authorized:    bool,
    plan:          String,
    usage_reports: UsageReports,

    #[serde(rename = "hierarchy")]
    metrics_hierarchy: Option<MetricsHierarchy>,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct PeriodInstance {
    start: SystemTime,
    end:   SystemTime,
}

#[derive(Debug, PartialEq)]
pub enum Period {
    Minute,
    Hour,
    Day,
    Week,
    Month,
    Year,
    Eternity,
}

struct PeriodStringVisitor;

impl<'de> Visitor<'de> for PeriodStringVisitor {
    type Value = Period;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string that represents a period")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where E: de::Error
    {
        match v {
            "minute" => Ok(Period::Minute),
            "hour" => Ok(Period::Hour),
            "day" => Ok(Period::Day),
            "week" => Ok(Period::Week),
            "month" => Ok(Period::Month),
            "year" => Ok(Period::Year),
            "eternity" => Ok(Period::Eternity),
            _ => Err(E::custom("Invalid period")),
        }
    }
}

impl<'de> Deserialize<'de> for Period {
    fn deserialize<D>(deserializer: D) -> Result<Period, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_any(PeriodStringVisitor)
    }
}

struct TimestampVisitor;

impl<'de> Visitor<'de> for TimestampVisitor {
    type Value = PeriodTime;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string that represents a timestamp")
    }

    fn visit_map<V>(self, mut map: V) -> Result<PeriodTime, V::Error>
        where V: MapAccess<'de>
    {
        // We know there's only one key with one value.
        // The key is not used, but we need to call "next_key()". From the
        // docs: "Calling `next_value` before `next_key` is incorrect and is
        // allowed to panic or return bogus results.".
        let _key: Option<String> = map.next_key()?;
        let timestamp: String = map.next_value()?;

        let dt = DateTime::parse_from_str(timestamp.as_str(), "%Y-%m-%d %H:%M:%S %z").unwrap();

        Ok(PeriodTime(dt.into()))
    }
}

impl<'de> Deserialize<'de> for PeriodTime {
    fn deserialize<D>(deserializer: D) -> Result<PeriodTime, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_any(TimestampVisitor)
    }
}

struct MetricsHierarchyVisitor;

impl<'de> Visitor<'de> for MetricsHierarchyVisitor {
    type Value = MetricsHierarchy;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a structure that represents a hierarchy of metrics")
    }

    fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
        where V: MapAccess<'de>
    {
        let mut hierarchy = MetricsHierarchy::new();

        // The key in the hierarchy structure is always "metric". It is not
        // used, but we need to read it to get the value.
        while let Some(_) = map.next_key::<String>()? {
            let val: HashMap<String, String> = map.next_value()?;

            let parent_metric = val["name"].to_owned();
            let children_metrics = val["children"].split(' ')
                                                  .map(|s| s.to_owned())
                                                  .collect::<Vec<_>>();

            hierarchy.insert(parent_metric, children_metrics);
        }

        Ok(hierarchy)
    }
}

impl<'de> Deserialize<'de> for MetricsHierarchy {
    fn deserialize<D>(deserializer: D) -> Result<MetricsHierarchy, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_any(MetricsHierarchyVisitor)
    }
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct UsageData {
    max_value:     u64,
    current_value: u64,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct Metric(pub String);

impl FromStr for Authorization {
    type Err = serde_xml_rs::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        serde_xml_rs::from_str(s)
    }
}

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

    #[test]
    fn parse() {
        let s = r##"
        <?xml version="1.0" encoding="UTF-8"?>
        <status>
            <authorized>true</authorized>
            <plan>App Plan</plan>
            <usage_reports>
                <usage_report metric="products" period="minute">
                    <period_start>2019-06-05 16:24:00 +0000</period_start>
                    <period_end>2019-06-05 16:25:00 +0000</period_end>
                    <max_value>5</max_value>
                    <current_value>0</current_value>
                </usage_report>
                <usage_report metric="products" period="month">
                    <period_start>2019-06-01 00:00:00 +0000</period_start>
                    <period_end>2019-07-01 00:00:00 +0000</period_end>
                    <max_value>50</max_value>
                    <current_value>0</current_value>
                </usage_report>
            </usage_reports>
        </status>
        "##;

        let parsed_auth = Authorization::from_str(s).unwrap();

        let expected_auth = Authorization { authorized:        true,
                                            plan:              String::from("App Plan"),
                                            metrics_hierarchy: None,
                                            usage_reports:     UsageReports::UsageReports(vec![
                UsageReport {
                    metric: String::from("products"),
                    period: Period::Minute,
                    period_start: PeriodTime(Utc.ymd(2019, 6, 5).and_hms(16, 24, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2019, 6, 5).and_hms(16, 25, 0).into()),
                    max_value: 5,
                    current_value: 0,
                },
                UsageReport {
                    metric: String::from("products"),
                    period: Period::Month,
                    period_start: PeriodTime(Utc.ymd(2019, 6, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2019, 7, 1).and_hms(0, 0, 0).into()),
                    max_value: 50,
                    current_value: 0,
                },
            ]), };

        assert_eq!(parsed_auth, expected_auth);
    }

    #[test]
    fn parse_metrics_hierarchy() {
        let xml_response = r##"
        <?xml version="1.0" encoding="UTF-8"?>
        <status>
            <authorized>true</authorized>
            <plan>Basic</plan>
            <usage_reports>
                <usage_report metric="parent1" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>20</current_value>
                </usage_report>
                <usage_report metric="parent2" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>10</current_value>
                </usage_report>
                <usage_report metric="child1" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>10</current_value>
                </usage_report>
                <usage_report metric="child2" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>10</current_value>
                </usage_report>
                <usage_report metric="child3" period="day">
                    <period_start>2016-01-01 00:00:00 +0000</period_start>
                    <period_end>2016-01-02 00:00:00 +0000</period_end>
                    <max_value>100</max_value>
                    <current_value>10</current_value>
                </usage_report>
            </usage_reports>
            <hierarchy>
                <metric name="parent1" children="child1 child2" />
                <metric name="parent2" children="child3" />
            </hierarchy>
        </status>
        "##;

        let parsed_auth = Authorization::from_str(xml_response).unwrap();

        let mut expected_hierarchy = MetricsHierarchy::new();
        expected_hierarchy.insert("parent1", vec![String::from("child1"), String::from("child2")]);
        expected_hierarchy.insert("parent2", vec![String::from("child3")]);

        let expected_auth = Authorization { authorized:        true,
                                            plan:              String::from("Basic"),
                                            metrics_hierarchy: Some(expected_hierarchy),
                                            usage_reports:     UsageReports::UsageReports(vec![
                UsageReport {
                    metric: String::from("parent1"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 20,
                },
                UsageReport {
                    metric: String::from("parent2"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 10,
                },
                UsageReport {
                    metric: String::from("child1"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 10,
                },
                UsageReport {
                    metric: String::from("child2"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 10,
                },
                UsageReport {
                    metric: String::from("child3"),
                    period: Period::Day,
                    period_start: PeriodTime(Utc.ymd(2016, 1, 1).and_hms(0, 0, 0).into()),
                    period_end: PeriodTime(Utc.ymd(2016, 1, 2).and_hms(0, 0, 0).into()),
                    max_value: 100,
                    current_value: 10,
                },
            ]), };

        assert_eq!(parsed_auth, expected_auth);
    }

    #[test]
    fn metrics_hierarchy_remove() {
        let mut hierarchy = MetricsHierarchy::new();

        hierarchy.insert("parent1", vec![String::from("child1"), String::from("child2")]);
        hierarchy.insert("parent2", vec![String::from("child3")]);

        hierarchy.remove("parent1");

        let mut expected_hierarchy = MetricsHierarchy::new();

        expected_hierarchy.insert("parent2", vec![String::from("child3")]);

        assert_eq!(hierarchy, expected_hierarchy);
    }

    #[test]
    fn metrics_hierarchy_parent_of() {
        let a_parent = "a_parent";
        let mut hierarchy = MetricsHierarchy::new();

        hierarchy.insert(a_parent, vec![String::from("child1"), String::from("child2")]);
        hierarchy.insert("parent2", vec![String::from("child3")]);

        assert_eq!(hierarchy.parent_of("child2"), Some(a_parent));
        assert_eq!(hierarchy.parent_of("child3"), Some("parent2"));
        assert_eq!(hierarchy.parent_of("nonchild"), None);
        assert_eq!(hierarchy.parent_of(a_parent), None);
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

extern crate pest;
extern crate pest_meta;

use std::collections::HashMap;

use pest::{Atomicity, Error, ParserState, Position};
use pest::iterators::Pairs;

use pest_meta::ast::{Expr, Rule, RuleType};

pub struct Vm {
    rules: HashMap<String, Rule>
}

impl Vm {
    pub fn new(rules: Vec<Rule>) -> Vm {
        let rules = rules.into_iter().map(|r| (r.name.clone(), r)).collect();
        Vm { rules }
    }

    pub fn parse<'i>(
        &self,
        rule: &str,
        input: &'i str
    ) -> Option<Result<Pairs<'i, &str>, Error<'i, &str>>> {
        if let Some(rule) = self.rules.get(rule) {
            let result = pest::state(input, |mut state, pos| {
                self.parse_rule(input, rule, pos, &mut state)
            });

            Some(result)
        } else {
            None
        }
    }

    fn parse_rule<'a, 'i>(
        &self,
        input: &'i str,
        rule: &'a Rule,
        pos: Position<'i>,
        state: &mut ParserState<'i, &'a str>
    ) -> Result<Position<'i>, Position<'i>> {
        let is_atomic = (rule.ty == RuleType::Atomic || rule.ty == RuleType::CompoundAtomic)
            || &rule.name == "whitespace" || &rule.name == "comment";

        match rule.ty {
            RuleType::Normal => state.rule(&rule.name, pos, |state, pos| {
                self.parse_expr(input, &rule.expr, is_atomic, pos, state)
            }),
            RuleType::Silent => self.parse_expr(input, &rule.expr, is_atomic, pos, state),
            RuleType::Atomic => state.rule(&rule.name, pos, |state, pos| {
                state.atomic(Atomicity::Atomic, move |state| {
                    self.parse_expr(input, &rule.expr, is_atomic, pos, state)
                })
            }),
            RuleType::CompoundAtomic => state.atomic(Atomicity::CompoundAtomic, move |state| {
                state.rule(&rule.name, pos, |state, pos| {
                    self.parse_expr(input, &rule.expr, is_atomic, pos, state)
                })
            }),
            RuleType::NonAtomic => state.atomic(Atomicity::NonAtomic, move |state| {
                state.rule(&rule.name, pos, |state, pos| {
                    self.parse_expr(input, &rule.expr, is_atomic, pos, state)
                })
            })
        }
    }

    fn parse_expr<'i>(
        &self,
        input: &'i str,
        expr: &Expr,
        is_atomic: bool,
        pos: Position,
        state: &mut ParserState<'i, &str>
    ) -> Result<Position<'i>, Position<'i>> {
        unimplemented!()
    }
}
<commit_msg>Added skip to VM.<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

extern crate pest;
extern crate pest_meta;

use std::collections::HashMap;

use pest::{Atomicity, Error, ParserState, Position};
use pest::iterators::Pairs;

use pest_meta::ast::{Expr, Rule, RuleType};

pub struct Vm {
    rules: HashMap<String, Rule>
}

impl Vm {
    pub fn new(rules: Vec<Rule>) -> Vm {
        let rules = rules.into_iter().map(|r| (r.name.clone(), r)).collect();
        Vm { rules }
    }

    pub fn parse<'i>(
        &self,
        rule: &str,
        input: &'i str
    ) -> Option<Result<Pairs<'i, &str>, Error<'i, &str>>> {
        if let Some(rule) = self.rules.get(rule) {
            let result = pest::state(input, |mut state, pos| {
                self.parse_rule(rule, pos, &mut state)
            });

            Some(result)
        } else {
            None
        }
    }

    fn parse_rule<'a, 'i>(
        &self,
        rule: &'a Rule,
        pos: Position<'i>,
        state: &mut ParserState<'i, &'a str>
    ) -> Result<Position<'i>, Position<'i>> {
        if &rule.name == "whitespace" || &rule.name == "comment" {
            match rule.ty {
                RuleType::Normal => state.rule(&rule.name, pos, |state, pos| {
                    state.atomic(Atomicity::Atomic, move |state| {
                        self.parse_expr(&rule.expr, pos, state)
                    })
                }),
                RuleType::Silent => state.atomic(Atomicity::Atomic, move |state| {
                    self.parse_expr(&rule.expr, pos, state)
                }),
                RuleType::Atomic => state.rule(&rule.name, pos, |state, pos| {
                    state.atomic(Atomicity::Atomic, move |state| {
                        self.parse_expr(&rule.expr, pos, state)
                    })
                }),
                RuleType::CompoundAtomic => state.atomic(Atomicity::CompoundAtomic, move |state| {
                    state.rule(&rule.name, pos, |state, pos| {
                        self.parse_expr(&rule.expr, pos, state)
                    })
                }),
                RuleType::NonAtomic => state.atomic(Atomicity::Atomic, move |state| {
                    state.rule(&rule.name, pos, |state, pos| {
                        self.parse_expr(&rule.expr, pos, state)
                    })
                })
            }
        } else {
            match rule.ty {
                RuleType::Normal => state.rule(&rule.name, pos, |state, pos| {
                    self.parse_expr(&rule.expr, pos, state)
                }),
                RuleType::Silent => self.parse_expr(&rule.expr, pos, state),
                RuleType::Atomic => state.rule(&rule.name, pos, |state, pos| {
                    state.atomic(Atomicity::Atomic, move |state| {
                        self.parse_expr(&rule.expr, pos, state)
                    })
                }),
                RuleType::CompoundAtomic => state.atomic(Atomicity::CompoundAtomic, move |state| {
                    state.rule(&rule.name, pos, |state, pos| {
                        self.parse_expr(&rule.expr, pos, state)
                    })
                }),
                RuleType::NonAtomic => state.atomic(Atomicity::NonAtomic, move |state| {
                    state.rule(&rule.name, pos, |state, pos| {
                        self.parse_expr(&rule.expr, pos, state)
                    })
                })
            }
        }
    }

    fn parse_expr<'i>(
        &self,
        expr: &Expr,
        pos: Position<'i>,
        state: &mut ParserState<'i, &str>
    ) -> Result<Position<'i>, Position<'i>> {
        unimplemented!()
    }

    fn skip<'a, 'i>(
        &'a self,
        pos: Position<'i>,
        state: &mut ParserState<'i, &'a str>
    ) -> Result<Position<'i>, Position<'i>> {
        match (self.rules.get("whitespace"), self.rules.get("comment")) {
            (None, None) => Ok(pos),
            (Some(whitespace), None) => if state.atomicity == Atomicity::NonAtomic {
                pos.repeat(|pos| {
                    self.parse_rule(whitespace, pos, state)
                })
            } else {
                Ok(pos)
            },
            (None, Some(comment)) => if state.atomicity == Atomicity::NonAtomic {
                pos.repeat(|pos| {
                    self.parse_rule(comment, pos, state)
                })
            } else {
                Ok(pos)
            },
            (Some(whitespace), Some(comment)) => if state.atomicity == Atomicity::NonAtomic {
                state.sequence(move |state| {
                    pos.sequence(|pos| {
                        pos.repeat(|pos| {
                            self.parse_rule(whitespace, pos, state)
                        }).and_then(|pos| {
                            pos.repeat(|pos| {
                                state.sequence(move |state| {
                                    pos.sequence(|pos| {
                                        self.parse_rule(comment, pos, state).and_then(|pos| {
                                            pos.repeat(|pos| {
                                                self.parse_rule(whitespace, pos, state)
                                            })
                                        })
                                    })
                                })
                            })
                        })
                    })
                })
            } else {
                Ok(pos)
            }
        }
    }
}
<|endoftext|>


<commit_before>use libc::c_char;
use std::cell::Cell;
use std::error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::mem::transmute;
use std::os::raw::c_void;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};

use crate::sys;

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = sys::SDL_errorcode::SDL_ENOMEM as i32,
    ReadError = sys::SDL_errorcode::SDL_EFREAD as i32,
    WriteError = sys::SDL_errorcode::SDL_EFWRITE as i32,
    SeekError = sys::SDL_errorcode::SDL_EFSEEK as i32,
    UnsupportedError = sys::SDL_errorcode::SDL_UNSUPPORTED as i32,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            NoMemError => write!(f, "Out of memory"),
            ReadError => write!(f, "Error reading from datastream"),
            WriteError => write!(f, "Error writing to datastream"),
            SeekError => write!(f, "Error seeking in datastream"),
            UnsupportedError => write!(f, "Unknown SDL error"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            NoMemError => "out of memory",
            ReadError => "error reading from datastream",
            WriteError => "error writing to datastream",
            SeekError => "error seeking in datastream",
            UnsupportedError => "unknown SDL error",
        }
    }
}

/// True if the main thread has been declared. The main thread is declared when
/// SDL is first initialized.
static IS_MAIN_THREAD_DECLARED: AtomicBool = AtomicBool::new(false);

/// Number of active `SdlDrop` objects keeping SDL alive.
static SDL_COUNT: AtomicU32 = AtomicU32::new(0);

thread_local! {
    /// True if the current thread is the main thread.
    static IS_MAIN_THREAD: Cell<bool> = Cell::new(false);
}

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: SdlDrop,
}

impl Sdl {
    #[inline]
    #[doc(alias = "SDL_Init")]
    fn new() -> Result<Sdl, String> {
        // Check if we can safely initialize SDL on this thread.
        let was_main_thread_declared = IS_MAIN_THREAD_DECLARED.swap(true, Ordering::SeqCst);

        IS_MAIN_THREAD.with(|is_main_thread| {
            if was_main_thread_declared {
                if !is_main_thread.get() {
                    return Err("Cannot initialize `Sdl` from more than once thread.".to_owned());
                }
            } else {
                is_main_thread.set(true);
            }
            Ok(())
        })?;

        // Initialize SDL.
        if SDL_COUNT.fetch_add(1, Ordering::Relaxed) == 0 {
            let result;

            unsafe {
                result = sys::SDL_Init(0);
            }

            if result != 0 {
                SDL_COUNT.store(0, Ordering::Relaxed);
                return Err(get_error());
            }
        }

        Ok(Sdl { sdldrop: SdlDrop { _anticonstructor: std::ptr::null_mut() }})
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> Result<AudioSubsystem, String> {
        AudioSubsystem::new(self)
    }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> Result<EventSubsystem, String> {
        EventSubsystem::new(self)
    }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> Result<JoystickSubsystem, String> {
        JoystickSubsystem::new(self)
    }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> Result<HapticSubsystem, String> {
        HapticSubsystem::new(self)
    }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> Result<GameControllerSubsystem, String> {
        GameControllerSubsystem::new(self)
    }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn sensor(&self) -> Result<SensorSubsystem, String> {
        SensorSubsystem::new(self)
    }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> Result<TimerSubsystem, String> {
        TimerSubsystem::new(self)
    }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> Result<VideoSubsystem, String> {
        VideoSubsystem::new(self)
    }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> Result<EventPump, String> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> SdlDrop {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use, the library is quit.
#[doc(hidden)]
#[derive(Debug)]
pub struct SdlDrop {
    // Make it impossible to construct `SdlDrop` without access to this member,
    // and opt out of Send and Sync.
    _anticonstructor: *mut c_void,
}

impl Clone for SdlDrop {
    fn clone(&self) -> SdlDrop {
        let prev_count = SDL_COUNT.fetch_add(1, Ordering::Relaxed);
        assert!(prev_count > 0);
        SdlDrop { _anticonstructor: std::ptr::null_mut() }
    }
}

impl Drop for SdlDrop {
    #[inline]
    #[doc(alias = "SDL_Quit")]
    fn drop(&mut self) {
        let prev_count = SDL_COUNT.fetch_sub(1, Ordering::Relaxed);
        assert!(prev_count > 0);
        if prev_count == 1 {
            unsafe {
                sys::SDL_Quit();
            }
        }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr, $counter:ident, nosync) => {
        static $counter: AtomicU32 = AtomicU32::new(0);

        #[derive(Debug, Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: SubsystemDrop,
        }

        impl $name {
            #[inline]
            #[doc(alias = "SDL_InitSubSystem")]
            fn new(sdl: &Sdl) -> Result<$name, String> {
                if $counter.fetch_add(1, Ordering::Relaxed) == 0 {
                    let result;

                    unsafe {
                        result = sys::SDL_InitSubSystem($flag);
                    }

                    if result != 0 {
                        $counter.store(0, Ordering::Relaxed);
                        return Err(get_error());
                    }
                }

                Ok($name {
                    _subsystem_drop: SubsystemDrop {
                        _sdldrop: sdl.sdldrop.clone(),
                        counter: &$counter,
                        flag: $flag,
                    },
                })
            }

            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl {
                    sdldrop: self._subsystem_drop._sdldrop.clone(),
                }
            }
        }
    };
    ($name:ident, $flag:expr, $counter:ident, sync) => {
        subsystem!($name, $flag, $counter, nosync);
        unsafe impl Sync for $name {}
    };
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Debug)]
struct SubsystemDrop {
    _sdldrop: SdlDrop,
    counter: &'static AtomicU32,
    flag: u32,
}

impl Clone for SubsystemDrop {
    fn clone(&self) -> SubsystemDrop {
        let prev_count = self.counter.fetch_add(1, Ordering::Relaxed);
        assert!(prev_count > 0);
        SubsystemDrop {
            _sdldrop: self._sdldrop.clone(),
            counter: self.counter,
            flag: self.flag,
        }
    }
}

impl Drop for SubsystemDrop {
    #[inline]
    #[doc(alias = "SDL_QuitSubSystem")]
    fn drop(&mut self) {
        let prev_count = self.counter.fetch_sub(1, Ordering::Relaxed);
        assert!(prev_count > 0);
        if prev_count == 1 {
            unsafe {
                sys::SDL_QuitSubSystem(self.flag);
            }
        }
    }
}

subsystem!(AudioSubsystem, sys::SDL_INIT_AUDIO, AUDIO_COUNT, nosync);
subsystem!(
    GameControllerSubsystem,
    sys::SDL_INIT_GAMECONTROLLER,
    GAMECONTROLLER_COUNT,
    nosync
);
subsystem!(HapticSubsystem, sys::SDL_INIT_HAPTIC, HAPTIC_COUNT, nosync);
subsystem!(JoystickSubsystem, sys::SDL_INIT_JOYSTICK, JOYSTICK_COUNT, nosync);
subsystem!(VideoSubsystem, sys::SDL_INIT_VIDEO, VIDEO_COUNT, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, sys::SDL_INIT_TIMER, TIMER_COUNT, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, sys::SDL_INIT_EVENTS, EVENTS_COUNT, sync);
subsystem!(SensorSubsystem, sys::SDL_INIT_SENSOR, SENSOR_COUNT, sync);

static IS_EVENT_PUMP_ALIVE: AtomicBool = AtomicBool::new(false);

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _event_subsystem: EventSubsystem,
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    #[doc(alias = "SDL_InitSubSystem")]
    fn new(sdl: &Sdl) -> Result<EventPump, String> {
        // Called on the main SDL thread.
        if IS_EVENT_PUMP_ALIVE.load(Ordering::Relaxed) {
            Err("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".to_owned())
        } else {
            let _event_subsystem = sdl.event()?;
            IS_EVENT_PUMP_ALIVE.store(true, Ordering::Relaxed);
            Ok(EventPump { _event_subsystem })
        }
    }
}

impl Drop for EventPump {
    #[inline]
    #[doc(alias = "SDL_QuitSubSystem")]
    fn drop(&mut self) {
        // Called on the main SDL thread.
        assert!(IS_EVENT_PUMP_ALIVE.load(Ordering::Relaxed));
        IS_EVENT_PUMP_ALIVE.store(false, Ordering::Relaxed);
    }
}

/// Get platform name
#[inline]
#[doc(alias = "SDL_GetPlatform")]
pub fn get_platform() -> &'static str {
    unsafe { CStr::from_ptr(sys::SDL_GetPlatform()).to_str().unwrap() }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
#[doc(alias = "SDL_GetError")]
pub fn init() -> Result<Sdl, String> {
    Sdl::new()
}

pub fn get_error() -> String {
    unsafe {
        let err = sys::SDL_GetError();
        CStr::from_ptr(err as *const _).to_str().unwrap().to_owned()
    }
}

#[doc(alias = "SDL_SetError")]
pub fn set_error(err: &str) -> Result<(), NulError> {
    let c_string = CString::new(err)?;
    unsafe {
        sys::SDL_SetError(
            b"%s\0".as_ptr() as *const c_char,
            c_string.as_ptr() as *const c_char,
        );
    }
    Ok(())
}

#[doc(alias = "SDL_Error")]
pub fn set_error_from_code(err: Error) {
    unsafe {
        sys::SDL_Error(transmute(err));
    }
}

#[doc(alias = "SDL_ClearError")]
pub fn clear_error() {
    unsafe {
        sys::SDL_ClearError();
    }
}
<commit_msg>cargo fmt<commit_after>use libc::c_char;
use std::cell::Cell;
use std::error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::mem::transmute;
use std::os::raw::c_void;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};

use crate::sys;

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = sys::SDL_errorcode::SDL_ENOMEM as i32,
    ReadError = sys::SDL_errorcode::SDL_EFREAD as i32,
    WriteError = sys::SDL_errorcode::SDL_EFWRITE as i32,
    SeekError = sys::SDL_errorcode::SDL_EFSEEK as i32,
    UnsupportedError = sys::SDL_errorcode::SDL_UNSUPPORTED as i32,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            NoMemError => write!(f, "Out of memory"),
            ReadError => write!(f, "Error reading from datastream"),
            WriteError => write!(f, "Error writing to datastream"),
            SeekError => write!(f, "Error seeking in datastream"),
            UnsupportedError => write!(f, "Unknown SDL error"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            NoMemError => "out of memory",
            ReadError => "error reading from datastream",
            WriteError => "error writing to datastream",
            SeekError => "error seeking in datastream",
            UnsupportedError => "unknown SDL error",
        }
    }
}

/// True if the main thread has been declared. The main thread is declared when
/// SDL is first initialized.
static IS_MAIN_THREAD_DECLARED: AtomicBool = AtomicBool::new(false);

/// Number of active `SdlDrop` objects keeping SDL alive.
static SDL_COUNT: AtomicU32 = AtomicU32::new(0);

thread_local! {
    /// True if the current thread is the main thread.
    static IS_MAIN_THREAD: Cell<bool> = Cell::new(false);
}

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: SdlDrop,
}

impl Sdl {
    #[inline]
    #[doc(alias = "SDL_Init")]
    fn new() -> Result<Sdl, String> {
        // Check if we can safely initialize SDL on this thread.
        let was_main_thread_declared = IS_MAIN_THREAD_DECLARED.swap(true, Ordering::SeqCst);

        IS_MAIN_THREAD.with(|is_main_thread| {
            if was_main_thread_declared {
                if !is_main_thread.get() {
                    return Err("Cannot initialize `Sdl` from more than once thread.".to_owned());
                }
            } else {
                is_main_thread.set(true);
            }
            Ok(())
        })?;

        // Initialize SDL.
        if SDL_COUNT.fetch_add(1, Ordering::Relaxed) == 0 {
            let result;

            unsafe {
                result = sys::SDL_Init(0);
            }

            if result != 0 {
                SDL_COUNT.store(0, Ordering::Relaxed);
                return Err(get_error());
            }
        }

        Ok(Sdl {
            sdldrop: SdlDrop {
                _anticonstructor: std::ptr::null_mut(),
            },
        })
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> Result<AudioSubsystem, String> {
        AudioSubsystem::new(self)
    }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> Result<EventSubsystem, String> {
        EventSubsystem::new(self)
    }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> Result<JoystickSubsystem, String> {
        JoystickSubsystem::new(self)
    }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> Result<HapticSubsystem, String> {
        HapticSubsystem::new(self)
    }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> Result<GameControllerSubsystem, String> {
        GameControllerSubsystem::new(self)
    }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn sensor(&self) -> Result<SensorSubsystem, String> {
        SensorSubsystem::new(self)
    }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> Result<TimerSubsystem, String> {
        TimerSubsystem::new(self)
    }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> Result<VideoSubsystem, String> {
        VideoSubsystem::new(self)
    }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> Result<EventPump, String> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> SdlDrop {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use, the library is quit.
#[doc(hidden)]
#[derive(Debug)]
pub struct SdlDrop {
    // Make it impossible to construct `SdlDrop` without access to this member,
    // and opt out of Send and Sync.
    _anticonstructor: *mut c_void,
}

impl Clone for SdlDrop {
    fn clone(&self) -> SdlDrop {
        let prev_count = SDL_COUNT.fetch_add(1, Ordering::Relaxed);
        assert!(prev_count > 0);
        SdlDrop {
            _anticonstructor: std::ptr::null_mut(),
        }
    }
}

impl Drop for SdlDrop {
    #[inline]
    #[doc(alias = "SDL_Quit")]
    fn drop(&mut self) {
        let prev_count = SDL_COUNT.fetch_sub(1, Ordering::Relaxed);
        assert!(prev_count > 0);
        if prev_count == 1 {
            unsafe {
                sys::SDL_Quit();
            }
        }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr, $counter:ident, nosync) => {
        static $counter: AtomicU32 = AtomicU32::new(0);

        #[derive(Debug, Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: SubsystemDrop,
        }

        impl $name {
            #[inline]
            #[doc(alias = "SDL_InitSubSystem")]
            fn new(sdl: &Sdl) -> Result<$name, String> {
                if $counter.fetch_add(1, Ordering::Relaxed) == 0 {
                    let result;

                    unsafe {
                        result = sys::SDL_InitSubSystem($flag);
                    }

                    if result != 0 {
                        $counter.store(0, Ordering::Relaxed);
                        return Err(get_error());
                    }
                }

                Ok($name {
                    _subsystem_drop: SubsystemDrop {
                        _sdldrop: sdl.sdldrop.clone(),
                        counter: &$counter,
                        flag: $flag,
                    },
                })
            }

            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl {
                    sdldrop: self._subsystem_drop._sdldrop.clone(),
                }
            }
        }
    };
    ($name:ident, $flag:expr, $counter:ident, sync) => {
        subsystem!($name, $flag, $counter, nosync);
        unsafe impl Sync for $name {}
    };
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Debug)]
struct SubsystemDrop {
    _sdldrop: SdlDrop,
    counter: &'static AtomicU32,
    flag: u32,
}

impl Clone for SubsystemDrop {
    fn clone(&self) -> SubsystemDrop {
        let prev_count = self.counter.fetch_add(1, Ordering::Relaxed);
        assert!(prev_count > 0);
        SubsystemDrop {
            _sdldrop: self._sdldrop.clone(),
            counter: self.counter,
            flag: self.flag,
        }
    }
}

impl Drop for SubsystemDrop {
    #[inline]
    #[doc(alias = "SDL_QuitSubSystem")]
    fn drop(&mut self) {
        let prev_count = self.counter.fetch_sub(1, Ordering::Relaxed);
        assert!(prev_count > 0);
        if prev_count == 1 {
            unsafe {
                sys::SDL_QuitSubSystem(self.flag);
            }
        }
    }
}

subsystem!(AudioSubsystem, sys::SDL_INIT_AUDIO, AUDIO_COUNT, nosync);
subsystem!(
    GameControllerSubsystem,
    sys::SDL_INIT_GAMECONTROLLER,
    GAMECONTROLLER_COUNT,
    nosync
);
subsystem!(HapticSubsystem, sys::SDL_INIT_HAPTIC, HAPTIC_COUNT, nosync);
subsystem!(
    JoystickSubsystem,
    sys::SDL_INIT_JOYSTICK,
    JOYSTICK_COUNT,
    nosync
);
subsystem!(VideoSubsystem, sys::SDL_INIT_VIDEO, VIDEO_COUNT, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, sys::SDL_INIT_TIMER, TIMER_COUNT, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, sys::SDL_INIT_EVENTS, EVENTS_COUNT, sync);
subsystem!(SensorSubsystem, sys::SDL_INIT_SENSOR, SENSOR_COUNT, sync);

static IS_EVENT_PUMP_ALIVE: AtomicBool = AtomicBool::new(false);

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _event_subsystem: EventSubsystem,
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    #[doc(alias = "SDL_InitSubSystem")]
    fn new(sdl: &Sdl) -> Result<EventPump, String> {
        // Called on the main SDL thread.
        if IS_EVENT_PUMP_ALIVE.load(Ordering::Relaxed) {
            Err("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".to_owned())
        } else {
            let _event_subsystem = sdl.event()?;
            IS_EVENT_PUMP_ALIVE.store(true, Ordering::Relaxed);
            Ok(EventPump { _event_subsystem })
        }
    }
}

impl Drop for EventPump {
    #[inline]
    #[doc(alias = "SDL_QuitSubSystem")]
    fn drop(&mut self) {
        // Called on the main SDL thread.
        assert!(IS_EVENT_PUMP_ALIVE.load(Ordering::Relaxed));
        IS_EVENT_PUMP_ALIVE.store(false, Ordering::Relaxed);
    }
}

/// Get platform name
#[inline]
#[doc(alias = "SDL_GetPlatform")]
pub fn get_platform() -> &'static str {
    unsafe { CStr::from_ptr(sys::SDL_GetPlatform()).to_str().unwrap() }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
#[doc(alias = "SDL_GetError")]
pub fn init() -> Result<Sdl, String> {
    Sdl::new()
}

pub fn get_error() -> String {
    unsafe {
        let err = sys::SDL_GetError();
        CStr::from_ptr(err as *const _).to_str().unwrap().to_owned()
    }
}

#[doc(alias = "SDL_SetError")]
pub fn set_error(err: &str) -> Result<(), NulError> {
    let c_string = CString::new(err)?;
    unsafe {
        sys::SDL_SetError(
            b"%s\0".as_ptr() as *const c_char,
            c_string.as_ptr() as *const c_char,
        );
    }
    Ok(())
}

#[doc(alias = "SDL_Error")]
pub fn set_error_from_code(err: Error) {
    unsafe {
        sys::SDL_Error(transmute(err));
    }
}

#[doc(alias = "SDL_ClearError")]
pub fn clear_error() {
    unsafe {
        sys::SDL_ClearError();
    }
}
<|endoftext|>