<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use shader_version::{opengl, glsl};
use graphics::BackEnd;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VERTEX_SHADER_XY_RGBA_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static VERTEX_SHADER_XY_RGBA_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_XY_RGBA_120: &'static str = "
#version 120
uniform vec4 color;

void main()
{
    gl_FragColor = color;
}
";

static FRAGMENT_SHADER_XY_RGBA_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

out vec4 out_color;

void main()
{
    out_color = color;
}
";

static VERTEX_SHADER_XY_RGBA_UV_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;
attribute vec2 uv;

uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static VERTEX_SHADER_XY_RGBA_UV_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_XY_RGBA_UV_120: &'static str = "
#version 120
uniform vec4 color;
uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    gl_FragColor = texture2D(s_texture, v_uv) * color;
}
";

static FRAGMENT_SHADER_XY_RGBA_UV_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;
uniform sampler2D s_texture;

out vec4 out_color;

in vec2 v_uv;

void main()
{
    out_color = texture(s_texture, v_uv) * color;
}
";

fn pick_120_150<T>(glsl: glsl::GLSL, for_120: T, for_150: T) -> T {
    match glsl {
        glsl::GLSL_1_10 => panic!("GLSL 1.10 not supported"),
        glsl::GLSL_1_20
      | glsl::GLSL_1_30
      | glsl::GLSL_1_40 => for_120,
        _ => for_150,
    }
}

struct XY {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: GLint,
}

impl Drop for XY {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl XY {
    fn new(glsl: glsl::GLSL) -> XY {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VERTEX_SHADER_XY_RGBA_120, VERTEX_SHADER_XY_RGBA_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FRAGMENT_SHADER_XY_RGBA_120, FRAGMENT_SHADER_XY_RGBA_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                "color".with_c_str(|name| gl::GetUniformLocation(program, name))
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        XY {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct XYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for XYRGBAUV {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl XYRGBAUV {
    fn new(glsl: glsl::GLSL) -> XYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VERTEX_SHADER_XY_RGBA_UV_120, VERTEX_SHADER_XY_RGBA_UV_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FRAGMENT_SHADER_XY_RGBA_UV_120, FRAGMENT_SHADER_XY_RGBA_UV_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                "color".with_c_str(|name| gl::GetUniformLocation(program, name))
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        XYRGBAUV {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    xy: XY,
    xy_rgba_uv: XYRGBAUV,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
    color: [f32, ..4],
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new(opengl: opengl::OpenGL) -> Gl {
        let glsl = opengl.to_GLSL();
        // Load the vertices, color and texture coord buffers.
        Gl {
            xy: XY::new(glsl),
            xy_rgba_uv: XYRGBAUV::new(glsl),
            current_program: None,
            color: [1.0, ..4],
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }
}

impl BackEnd<Texture> for Gl {
    fn clear(&mut self, color: [f32, ..4]) {
        unsafe {
            let [r, g, b, a] = color;
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn enable_alpha_blend(&mut self) {
        unsafe {
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        }
    }

    fn disable_alpha_blend(&mut self) {
        unsafe {
            gl::Disable(gl::BLEND);
        }
    }

    fn enable_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
        }
    }

    fn disable_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn color(&mut self, color: [f32, ..4]) {
        self.color = color;
    }

    fn tri_list(&mut self, vertices: &[f32]) {
        {
            // Set shader program.
            let shader_program = self.xy.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.xy;

        // xy makes two floats.
        let size_vertices: i32 = 2;
        let items: i32 = vertices.len() as i32 / size_vertices;

        let color = self.color;
        unsafe {
            gl::BindVertexArray(shader.vao);
            shader.pos.set(vertices);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);

            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);

            gl::DrawArrays(gl::TRIANGLES, 0, items);

            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv(&mut self, vertices: &[f32], texture_coords: &[f32]) {
        {
            // Set shader program.
            let shader_program = self.xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.xy_rgba_uv;

        let size_vertices: i32 = 2;
        let items: i32 = vertices.len() as i32 / size_vertices;

        let color = self.color;
        unsafe {
            gl::BindVertexArray(shader.vao);
            shader.pos.set(vertices);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
            shader.uv.set(texture_coords);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);

            gl::DrawArrays(gl::TRIANGLES, 0, items);

            gl::BindVertexArray(0);
        }
    }
}

<commit_msg>Using better name on shaders<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use shader_version::{opengl, glsl};
use graphics::BackEnd;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static VS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static FS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

void main()
{
    gl_FragColor = color;
}
";

static FS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

out vec4 out_color;

void main()
{
    out_color = color;
}
";

static VS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;
attribute vec2 uv;

uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static VS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static FS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;
uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    gl_FragColor = texture2D(s_texture, v_uv) * color;
}
";

static FS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;
uniform sampler2D s_texture;

out vec4 out_color;

in vec2 v_uv;

void main()
{
    out_color = texture(s_texture, v_uv) * color;
}
";

fn pick_120_150<T>(glsl: glsl::GLSL, for_120: T, for_150: T) -> T {
    match glsl {
        glsl::GLSL_1_10 => panic!("GLSL 1.10 not supported"),
        glsl::GLSL_1_20
      | glsl::GLSL_1_30
      | glsl::GLSL_1_40 => for_120,
        _ => for_150,
    }
}

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: GLint,
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: glsl::GLSL) -> Colored {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_COLORED_120, VS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_COLORED_120, FS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                "color".with_c_str(|name| gl::GetUniformLocation(program, name))
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: glsl::GLSL) -> Textured {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_TEXTURED_120, VS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_TEXTURED_120, FS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                "color".with_c_str(|name| gl::GetUniformLocation(program, name))
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
    color: [f32, ..4],
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new(opengl: opengl::OpenGL) -> Gl {
        let glsl = opengl.to_GLSL();
        // Load the vertices, color and texture coord buffers.
        Gl {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
            color: [1.0, ..4],
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }
}

impl BackEnd<Texture> for Gl {
    fn clear(&mut self, color: [f32, ..4]) {
        unsafe {
            let [r, g, b, a] = color;
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn enable_alpha_blend(&mut self) {
        unsafe {
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        }
    }

    fn disable_alpha_blend(&mut self) {
        unsafe {
            gl::Disable(gl::BLEND);
        }
    }

    fn enable_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
        }
    }

    fn disable_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn color(&mut self, color: [f32, ..4]) {
        self.color = color;
    }

    fn tri_list(&mut self, vertices: &[f32]) {
        {
            // Set shader program.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.colored;

        // xy makes two floats.
        let size_vertices: i32 = 2;
        let items: i32 = vertices.len() as i32 / size_vertices;

        let color = self.color;
        unsafe {
            gl::BindVertexArray(shader.vao);
            shader.pos.set(vertices);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);

            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);

            gl::DrawArrays(gl::TRIANGLES, 0, items);

            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv(&mut self, vertices: &[f32], texture_coords: &[f32]) {
        {
            // Set shader program.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.textured;

        let size_vertices: i32 = 2;
        let items: i32 = vertices.len() as i32 / size_vertices;

        let color = self.color;
        unsafe {
            gl::BindVertexArray(shader.vao);
            shader.pos.set(vertices);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
            shader.uv.set(texture_coords);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);

            gl::DrawArrays(gl::TRIANGLES, 0, items);

            gl::BindVertexArray(0);
        }
    }
}

<|endoftext|>


<commit_before>extern crate openssl;
extern crate openssl_verify;

use std::io;
use std::fmt;
use std::error;
use self::openssl::crypto::pkey::PKey;
use self::openssl::crypto::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslContext, SslMethod, SSL_VERIFY_PEER, IntoSsl, SSL_OP_NO_SSLV2,
                         SSL_OP_NO_SSLV3, SSL_OP_NO_COMPRESSION, MidHandshakeSslStream};
use self::openssl::x509::X509;
use self::openssl_verify::verify_callback;

pub struct Error(ssl::Error);

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

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

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

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

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

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Pkcs12 {
    cert: X509,
    pkey: PKey,
    chain: Vec<X509>,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));

        Ok(Pkcs12 {
            cert: parsed.cert,
            pkey: parsed.pkey,
            chain: parsed.chain.into_iter().collect(),
        })
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

fn ctx() -> Result<SslContext, Error> {
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ctx.set_default_verify_paths());
    Ok(ctx)
}

pub struct ClientBuilder(SslContext);

impl ClientBuilder {
    pub fn new() -> Result<ClientBuilder, Error> {
        ctx().map(ClientBuilder)
    }

    pub fn handshake<S>(&self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut ssl = try!(self.0.into_ssl());
        try!(ssl.set_hostname(domain));
        let domain = domain.to_owned();
        ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify_callback(&domain, p, x));

        let s = try!(ssl::SslStream::connect(ssl, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ClientBuilder`.
pub trait ClientBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ClientBuilderExt for ::ClientBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct ServerBuilder(SslContext);

impl ServerBuilder {
    pub fn new(pkcs12: Pkcs12) -> Result<ServerBuilder, Error> {
        let mut ctx = try!(ctx());
        try!(ctx.set_certificate(&pkcs12.cert));
        try!(ctx.set_private_key(&pkcs12.pkey));
        try!(ctx.check_private_key());
        for cert in &pkcs12.chain {
            try!(ctx.add_extra_chain_cert(&cert));
        }
        Ok(ServerBuilder(ctx))
    }

    pub fn handshake<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(ssl::SslStream::accept(&self.0, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ServerBuilder`.
pub trait ServerBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ServerBuilderExt for ::ServerBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

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

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}
<commit_msg>Remove unused imports<commit_after>extern crate openssl;
extern crate openssl_verify;

use std::io;
use std::fmt;
use std::error;
use self::openssl::crypto::pkey::PKey;
use self::openssl::crypto::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslContext, SslMethod, SSL_VERIFY_PEER, IntoSsl,
                         MidHandshakeSslStream};
use self::openssl::x509::X509;
use self::openssl_verify::verify_callback;

pub struct Error(ssl::Error);

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

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

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

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

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

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Pkcs12 {
    cert: X509,
    pkey: PKey,
    chain: Vec<X509>,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));

        Ok(Pkcs12 {
            cert: parsed.cert,
            pkey: parsed.pkey,
            chain: parsed.chain.into_iter().collect(),
        })
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

fn ctx() -> Result<SslContext, Error> {
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ctx.set_default_verify_paths());
    Ok(ctx)
}

pub struct ClientBuilder(SslContext);

impl ClientBuilder {
    pub fn new() -> Result<ClientBuilder, Error> {
        ctx().map(ClientBuilder)
    }

    pub fn handshake<S>(&self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut ssl = try!(self.0.into_ssl());
        try!(ssl.set_hostname(domain));
        let domain = domain.to_owned();
        ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify_callback(&domain, p, x));

        let s = try!(ssl::SslStream::connect(ssl, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ClientBuilder`.
pub trait ClientBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ClientBuilderExt for ::ClientBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct ServerBuilder(SslContext);

impl ServerBuilder {
    pub fn new(pkcs12: Pkcs12) -> Result<ServerBuilder, Error> {
        let mut ctx = try!(ctx());
        try!(ctx.set_certificate(&pkcs12.cert));
        try!(ctx.set_private_key(&pkcs12.pkey));
        try!(ctx.check_private_key());
        for cert in &pkcs12.chain {
            try!(ctx.add_extra_chain_cert(&cert));
        }
        Ok(ServerBuilder(ctx))
    }

    pub fn handshake<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(ssl::SslStream::accept(&self.0, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ServerBuilder`.
pub trait ServerBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ServerBuilderExt for ::ServerBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

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

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}
<|endoftext|>


<commit_before>use std::cmp::min;
use std::env;
use std::fs::{File};
use std::io::{BufReader, BufRead};
use std::str::FromStr;
use std::str::from_utf8;
use std::path::{Path, PathBuf};
use unshare::{Command, Stdio};

use libc::{geteuid, getegid};
use libc::{uid_t, gid_t};

use config::Range;
use config::Settings;
use self::Uidmap::*;
use process_util::{env_path_find, capture_stdout};

#[derive(Clone)]
pub enum Uidmap {
    Singleton(uid_t, gid_t),
    Ranges(Vec<(uid_t, uid_t, uid_t)>, Vec<(gid_t, gid_t, gid_t)>),
}

fn read_uid_map(file_path: &str, username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new(file_path)),
        "Can't open {path}: {err}", path=file_path);
    let mut res = Vec::new();
    let reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading {path}: {err}", path=file_path);
        let parts: Vec<&str> = line[..].split(':').collect();
        if parts.len() == 0 || parts[0].trim().starts_with('#') {
            continue;
        }
        if parts.len() != 3 {
            return Err(format!("{}:{}: Bad syntax: {:?}",
                file_path, num+1, line));
        }
        let start = FromStr::from_str(parts[1]);
        let count: Result<uid_t, _> = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("{}:{}: Bad syntax: {:?}",
                file_path, num+1, line));
        }
        if parts[0].eq(username) {
            let start: uid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

pub fn match_ranges(req: &Vec<Range>, allowed: &Vec<Range>, own_id: uid_t)
    -> Result<Vec<(uid_t, uid_t, uid_t)>, ()>
{
    let mut res = vec!((0, own_id, 1));
    let mut reqiter = req.iter();
    let mut reqval = *reqiter.next().unwrap();
    let mut allowiter = allowed.iter();
    let mut allowval = *allowiter.next().unwrap();
    loop {
        if reqval.start() == 0 {
            reqval = reqval.shift(1);
        }
        if allowval.start() == 0 {
            allowval = allowval.shift(1);
        }
        let clen = min(reqval.len(), allowval.len());
        if clen > 0 {
            res.push((reqval.start(), allowval.start(), clen));
        }
        reqval = reqval.shift(clen);
        allowval = allowval.shift(clen);
        if reqval.len() == 0 {
            reqval = match reqiter.next() {
                Some(val) => *val,
                None => break,
            };
        }
        if allowval.len() == 0 {
            allowval = match allowiter.next() {
                Some(val) => *val,
                None => return Err(()),
            };
        }
    }
    return Ok(res);
}

pub fn get_max_uidmap() -> Result<Uidmap, String>
{
    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };

    if uid == 0 && !Path::new("/etc/subuid").exists() {
        // For root user we may use all available user ids
        // This is useful mostly for running vagga in vagga
        let uid_rng = try!(read_uid_ranges("/proc/self/uid_map", true));
        let gid_rng = try!(read_uid_ranges("/proc/self/gid_map", true));
        return Ok(Ranges(
            uid_rng.into_iter()
                .map(|r| (r.start(), r.start(), r.len())).collect(),
            gid_rng.into_iter()
                .map(|r| (r.start(), r.start(), r.len())).collect()));
    }

    let mut cmd = Command::new(env_path_find("id")
                               .unwrap_or(PathBuf::from("/usr/bin/id")));
    cmd.arg("-u").arg("-n");
    if let Ok(path) = env::var("_VAGGA_PATH") {
        cmd.env("PATH", path);
    }
    cmd.stdin(Stdio::null()).stderr(Stdio::inherit());
    let username = try!(capture_stdout(cmd)
        .map_err(|e| format!("Error running `id -u -n`: {}", e))
        .and_then(|val| from_utf8(&val).map(|x| x.trim().to_string())
                   .map_err(|e| format!("Can't decode username: {}", e))));
    let uid_map = read_uid_map("/etc/subuid", &username)
        .map_err(|e| error!("Error reading uidmap: {}", e));
    let gid_map = read_uid_map("/etc/subgid", &username)
        .map_err(|e| error!("Error reading gidmap: {}", e));

    if let (Ok(uid_map), Ok(gid_map)) = (uid_map, gid_map) {
        let mut uids = vec!((0, uid, 1));
        for &rng in uid_map.iter() {
            let mut rng = rng;
            if uid >= rng.start() && uid <= rng.end() {
                // TODO(tailhook) implement better heuristic
                assert!(uid == rng.start());
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            uids.push((rng.start(), rng.start(), rng.len()));
        }

        let mut gids = vec!((0, gid, 1));
        for &rng in gid_map.iter() {
            let mut rng = rng;
            if gid >= rng.start() && gid <= rng.end() {
                // TODO(tailhook) implement better heuristic
                assert!(gid == rng.start());
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            gids.push((rng.start(), rng.start(), rng.len()));
        }

        return Ok(Ranges(uids, gids));
    } else {
        warn!("Could not read /etc/subuid or /etc/subgid \
            (see http://bit.ly/err_subuid)");
        return Ok(Singleton(uid, gid));
    }
}

fn read_uid_ranges(path: &str, read_inside: bool) -> Result<Vec<Range>, String>
{
    let file = BufReader::new(try!(File::open(&Path::new(path))
        .map_err(|e| format!("Error reading uid/gid map: {}", e))));
    let mut result = vec!();
    for line in file.lines() {
        let line = try!(line
            .map_err(|_| format!("Error reading uid/gid map")));
        let mut words = line[..].split_whitespace();
        let inside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let outside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let count: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        if read_inside {
            result.push(Range::new(inside, inside+count-1));
        } else {
            result.push(Range::new(outside, outside+count-1));
        }
    }
    return Ok(result);
}

pub fn map_users(settings: &Settings, uids: &Vec<Range>, gids: &Vec<Range>)
    -> Result<Uidmap, String>
{
    let default_uids = vec!(Range::new(0, 0));
    let default_gids = vec!(Range::new(0, 0));
    let uids = if uids.len() > 0 { uids } else { &default_uids };
    let gids = if gids.len() > 0 { gids } else { &default_gids };
    match settings.uid_map {
        None => {
            let ranges = try!(read_uid_ranges("/proc/self/uid_map", true));
            let uid_map = try!(match_ranges(uids, &ranges, 0)
                .map_err(|()| {
                    return format!("Number of allowed subuids is too small. \
                        Required {:?}, allowed {:?}. You either need to increase \
                        allowed numbers in /etc/subuid (preferred) or decrease \
                        needed ranges in vagga.yaml by adding `uids` key \
                        to container config", uids, ranges);
                }));
            let ranges = try!(read_uid_ranges("/proc/self/gid_map", true));
            let gid_map = try!(match_ranges(gids, &ranges, 0)
                .map_err(|()| {
                    return format!("Number of allowed subgids is too small. \
                        Required {:?}, allowed {:?}. You either need to increase \
                        allowed numbers in /etc/subgid (preferred) or decrease \
                        needed ranges in vagga.yaml by adding `gids` key \
                        to container config", gids, ranges);
                }));
            Ok(Ranges(uid_map, gid_map))
        },
        Some((ref uids, ref gids)) => {
            Ok(Ranges(uids.clone(), gids.clone()))
        }
    }
}
<commit_msg>Fix certain vagga in vagga in buildbot<commit_after>use std::cmp::min;
use std::env;
use std::fs::{File};
use std::io::{BufReader, BufRead};
use std::str::FromStr;
use std::str::from_utf8;
use std::path::{Path, PathBuf};
use unshare::{Command, Stdio};

use libc::{geteuid, getegid};
use libc::{uid_t, gid_t};

use config::Range;
use config::Settings;
use self::Uidmap::*;
use process_util::{env_path_find, capture_stdout};

#[derive(Clone)]
pub enum Uidmap {
    Singleton(uid_t, gid_t),
    Ranges(Vec<(uid_t, uid_t, uid_t)>, Vec<(gid_t, gid_t, gid_t)>),
}

fn read_uid_map(file_path: &str, username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new(file_path)),
        "Can't open {path}: {err}", path=file_path);
    let mut res = Vec::new();
    let reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading {path}: {err}", path=file_path);
        let parts: Vec<&str> = line[..].split(':').collect();
        if parts.len() == 0 || parts[0].trim().starts_with('#') {
            continue;
        }
        if parts.len() != 3 {
            return Err(format!("{}:{}: Bad syntax: {:?}",
                file_path, num+1, line));
        }
        let start = FromStr::from_str(parts[1]);
        let count: Result<uid_t, _> = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("{}:{}: Bad syntax: {:?}",
                file_path, num+1, line));
        }
        if parts[0].eq(username) {
            let start: uid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

pub fn match_ranges(req: &Vec<Range>, allowed: &Vec<Range>, own_id: uid_t)
    -> Result<Vec<(uid_t, uid_t, uid_t)>, ()>
{
    let mut res = vec!((0, own_id, 1));
    let mut reqiter = req.iter();
    let mut reqval = *reqiter.next().unwrap();
    let mut allowiter = allowed.iter();
    let mut allowval = *allowiter.next().unwrap();
    loop {
        if reqval.start() == 0 {
            reqval = reqval.shift(1);
        }
        if allowval.start() == 0 {
            allowval = allowval.shift(1);
        }
        let clen = min(reqval.len(), allowval.len());
        if clen > 0 {
            res.push((reqval.start(), allowval.start(), clen));
        }
        reqval = reqval.shift(clen);
        allowval = allowval.shift(clen);
        if reqval.len() == 0 {
            reqval = match reqiter.next() {
                Some(val) => *val,
                None => break,
            };
        }
        if allowval.len() == 0 {
            allowval = match allowiter.next() {
                Some(val) => *val,
                None => return Err(()),
            };
        }
    }
    return Ok(res);
}

fn map_all_ids() -> Result<Uidmap, String> {
    let uid_rng = try!(read_uid_ranges("/proc/self/uid_map", true));
    let gid_rng = try!(read_uid_ranges("/proc/self/gid_map", true));
    Ok(Ranges(
        uid_rng.into_iter().map(|r| (r.start(), r.start(), r.len())).collect(),
        gid_rng.into_iter().map(|r| (r.start(), r.start(), r.len())).collect(),
    ))
}

pub fn get_max_uidmap() -> Result<Uidmap, String>
{
    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };

    if uid == 0 && !Path::new("/etc/subuid").exists() {
        // For root user we may use all available user ids
        // This is useful mostly for running vagga in vagga
        return map_all_ids();
    }

    let mut cmd = Command::new(env_path_find("id")
                               .unwrap_or(PathBuf::from("/usr/bin/id")));
    cmd.arg("-u").arg("-n");
    if let Ok(path) = env::var("_VAGGA_PATH") {
        cmd.env("PATH", path);
    }
    cmd.stdin(Stdio::null()).stderr(Stdio::inherit());
    let username = try!(capture_stdout(cmd)
        .map_err(|e| format!("Error running `id -u -n`: {}", e))
        .and_then(|val| from_utf8(&val).map(|x| x.trim().to_string())
                   .map_err(|e| format!("Can't decode username: {}", e))));
    let uid_map = read_uid_map("/etc/subuid", &username)
        .map_err(|e| error!("Error reading uidmap: {}", e));
    let gid_map = read_uid_map("/etc/subgid", &username)
        .map_err(|e| error!("Error reading gidmap: {}", e));

    if let (Ok(uid_map), Ok(gid_map)) = (uid_map, gid_map) {
        if uid_map.len() == 0 && gid_map.len() == 0 && uid == 0 {
            // For root user we may use all available user ids
            // This is useful mostly for running vagga in vagga
            return map_all_ids();
        }
        let mut uids = vec!((0, uid, 1));
        for &rng in uid_map.iter() {
            let mut rng = rng;
            if uid >= rng.start() && uid <= rng.end() {
                // TODO(tailhook) implement better heuristic
                assert!(uid == rng.start());
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            uids.push((rng.start(), rng.start(), rng.len()));
        }

        let mut gids = vec!((0, gid, 1));
        for &rng in gid_map.iter() {
            let mut rng = rng;
            if gid >= rng.start() && gid <= rng.end() {
                // TODO(tailhook) implement better heuristic
                assert!(gid == rng.start());
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            gids.push((rng.start(), rng.start(), rng.len()));
        }

        return Ok(Ranges(uids, gids));
    } else {
        warn!("Could not read /etc/subuid or /etc/subgid \
            (see http://bit.ly/err_subuid)");
        return Ok(Singleton(uid, gid));
    }
}

fn read_uid_ranges(path: &str, read_inside: bool) -> Result<Vec<Range>, String>
{
    let file = BufReader::new(try!(File::open(&Path::new(path))
        .map_err(|e| format!("Error reading uid/gid map: {}", e))));
    let mut result = vec!();
    for line in file.lines() {
        let line = try!(line
            .map_err(|_| format!("Error reading uid/gid map")));
        let mut words = line[..].split_whitespace();
        let inside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let outside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let count: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        if read_inside {
            result.push(Range::new(inside, inside+count-1));
        } else {
            result.push(Range::new(outside, outside+count-1));
        }
    }
    return Ok(result);
}

pub fn map_users(settings: &Settings, uids: &Vec<Range>, gids: &Vec<Range>)
    -> Result<Uidmap, String>
{
    let default_uids = vec!(Range::new(0, 0));
    let default_gids = vec!(Range::new(0, 0));
    let uids = if uids.len() > 0 { uids } else { &default_uids };
    let gids = if gids.len() > 0 { gids } else { &default_gids };
    match settings.uid_map {
        None => {
            let ranges = try!(read_uid_ranges("/proc/self/uid_map", true));
            let uid_map = try!(match_ranges(uids, &ranges, 0)
                .map_err(|()| {
                    return format!("Number of allowed subuids is too small. \
                        Required {:?}, allowed {:?}. You either need to increase \
                        allowed numbers in /etc/subuid (preferred) or decrease \
                        needed ranges in vagga.yaml by adding `uids` key \
                        to container config", uids, ranges);
                }));
            let ranges = try!(read_uid_ranges("/proc/self/gid_map", true));
            let gid_map = try!(match_ranges(gids, &ranges, 0)
                .map_err(|()| {
                    return format!("Number of allowed subgids is too small. \
                        Required {:?}, allowed {:?}. You either need to increase \
                        allowed numbers in /etc/subgid (preferred) or decrease \
                        needed ranges in vagga.yaml by adding `gids` key \
                        to container config", gids, ranges);
                }));
            Ok(Ranges(uid_map, gid_map))
        },
        Some((ref uids, ref gids)) => {
            Ok(Ranges(uids.clone(), gids.clone()))
        }
    }
}
<|endoftext|>


<commit_before>use super::internal::*;
use super::*;
use std::iter;
use std::usize;

/// Iterator adaptor for [the `repeat()` function](fn.repeat.html).
pub struct Repeat<T: Clone + Send> {
    element: T,
}

/// Creates a parallel iterator that endlessly repeats `elt` (by
/// cloning it). Note that this iterator has "infinite" length, so
/// typically you would want to use `zip` or `take` or some other
/// means to shorten it, or consider using
/// [the `repeatn()` function](fn.repeatn.html) instead.
///
/// Example:
///
/// ```
/// use rayon::prelude::*;
/// use rayon::iter::repeat;
/// let x: Vec<(i32, i32)> = repeat(22).zip(0..3).collect();
/// assert_eq!(x, vec![(22, 0), (22, 1), (22, 2)]);
/// ```
pub fn repeat<T: Clone + Send>(elt: T) -> Repeat<T> {
    Repeat { element: elt }
}

impl<T> Repeat<T>
    where T: Clone + Send
{
    /// Take only `n` repeats of the element, similar to the general
    /// [`take()`](trait.IndexedParallelIterator.html#method.take).
    ///
    /// The resulting `RepeatN` is an `IndexedParallelIterator`, allowing
    /// more functionality than `Repeat` alone.
    pub fn take(self, n: usize) -> RepeatN<T> {
        repeatn(self.element, n)
    }

    /// Iterate tuples repeating the element with items from another
    /// iterator, similar to the general
    /// [`zip()`](trait.IndexedParallelIterator.html#method.zip).
    pub fn zip<Z>(self, zip_op: Z) -> Zip<RepeatN<T>, Z::Iter>
        where Z: IntoParallelIterator,
              Z::Iter: IndexedParallelIterator
    {
        let mut z = zip_op.into_par_iter();
        let n = z.len();
        self.take(n).zip(z)
    }
}

impl<T> ParallelIterator for Repeat<T>
    where T: Clone + Send
{
    type Item = T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = RepeatProducer { element: self.element };
        bridge_unindexed(producer, consumer)
    }
}

/// Unindexed producer for `Repeat`.
struct RepeatProducer<T: Clone + Send> {
    element: T,
}

impl<T: Clone + Send> UnindexedProducer for RepeatProducer<T> {
    type Item = T;

    fn split(self) -> (Self, Option<Self>) {
        (RepeatProducer { element: self.element.clone() },
         Some(RepeatProducer { element: self.element }))
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<T>
    {
        folder.consume_iter(iter::repeat(self.element))
    }
}

/// Iterator adaptor for [the `repeatn()` function](fn.repeatn.html).
pub struct RepeatN<T: Clone + Send> {
    element: T,
    count: usize,
}

/// Creates a parallel iterator that produces `n` repeats of `elt`
/// (by cloning it).
///
/// Example:
///
/// ```
/// use rayon::prelude::*;
/// use rayon::iter::repeatn;
/// let x: Vec<(i32, i32)> = repeatn(22, 3).zip(0..3).collect();
/// assert_eq!(x, vec![(22, 0), (22, 1), (22, 2)]);
/// ```
pub fn repeatn<T: Clone + Send>(elt: T, n: usize) -> RepeatN<T> {
    RepeatN { element: elt, count: n }
}

impl<T> ParallelIterator for RepeatN<T>
    where T: Clone + Send
{
    type Item = T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.count)
    }
}

impl<T> IndexedParallelIterator for RepeatN<T>
    where T: Clone + Send
{
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(RepeatNProducer { element: self.element, count: self.count })
    }

    fn len(&mut self) -> usize {
        self.count
    }
}

/// Producer for `RepeatN`.
struct RepeatNProducer<T: Clone + Send> {
    element: T,
    count: usize,
}

impl<T: Clone + Send> Producer for RepeatNProducer<T> {
    type Item = T;
    type IntoIter = Iter<T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter { element: self.element, count: self.count }
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        (RepeatNProducer { element: self.element.clone(), count: index },
         RepeatNProducer { element: self.element, count: self.count - index })
    }
}

/// Iterator for `RepeatN`.
///
/// This is conceptually like `std::iter::Take<std::iter::Repeat<T>>`, but
/// we need `DoubleEndedIterator` and unconditional `ExactSizeIterator`.
struct Iter<T: Clone> {
    element: T,
    count: usize,
}

impl<T: Clone> Iterator for Iter<T> {
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.count > 0 {
            self.count -= 1;
            Some(self.element.clone())
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.count, Some(self.count))
    }
}

impl<T: Clone> DoubleEndedIterator for Iter<T> {
    #[inline]
    fn next_back(&mut self) -> Option<T> {
        self.next()
    }
}

impl<T: Clone> ExactSizeIterator for Iter<T> {
    #[inline]
    fn len(&self) -> usize {
        self.count
    }
}
<commit_msg>Derive `Debug` for `Repeat` and `RepeatN`<commit_after>use super::internal::*;
use super::*;
use std::iter;
use std::usize;

/// Iterator adaptor for [the `repeat()` function](fn.repeat.html).
#[derive(Debug)]
pub struct Repeat<T: Clone + Send> {
    element: T,
}

/// Creates a parallel iterator that endlessly repeats `elt` (by
/// cloning it). Note that this iterator has "infinite" length, so
/// typically you would want to use `zip` or `take` or some other
/// means to shorten it, or consider using
/// [the `repeatn()` function](fn.repeatn.html) instead.
///
/// Example:
///
/// ```
/// use rayon::prelude::*;
/// use rayon::iter::repeat;
/// let x: Vec<(i32, i32)> = repeat(22).zip(0..3).collect();
/// assert_eq!(x, vec![(22, 0), (22, 1), (22, 2)]);
/// ```
pub fn repeat<T: Clone + Send>(elt: T) -> Repeat<T> {
    Repeat { element: elt }
}

impl<T> Repeat<T>
    where T: Clone + Send
{
    /// Take only `n` repeats of the element, similar to the general
    /// [`take()`](trait.IndexedParallelIterator.html#method.take).
    ///
    /// The resulting `RepeatN` is an `IndexedParallelIterator`, allowing
    /// more functionality than `Repeat` alone.
    pub fn take(self, n: usize) -> RepeatN<T> {
        repeatn(self.element, n)
    }

    /// Iterate tuples repeating the element with items from another
    /// iterator, similar to the general
    /// [`zip()`](trait.IndexedParallelIterator.html#method.zip).
    pub fn zip<Z>(self, zip_op: Z) -> Zip<RepeatN<T>, Z::Iter>
        where Z: IntoParallelIterator,
              Z::Iter: IndexedParallelIterator
    {
        let mut z = zip_op.into_par_iter();
        let n = z.len();
        self.take(n).zip(z)
    }
}

impl<T> ParallelIterator for Repeat<T>
    where T: Clone + Send
{
    type Item = T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = RepeatProducer { element: self.element };
        bridge_unindexed(producer, consumer)
    }
}

/// Unindexed producer for `Repeat`.
struct RepeatProducer<T: Clone + Send> {
    element: T,
}

impl<T: Clone + Send> UnindexedProducer for RepeatProducer<T> {
    type Item = T;

    fn split(self) -> (Self, Option<Self>) {
        (RepeatProducer { element: self.element.clone() },
         Some(RepeatProducer { element: self.element }))
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<T>
    {
        folder.consume_iter(iter::repeat(self.element))
    }
}

/// Iterator adaptor for [the `repeatn()` function](fn.repeatn.html).
#[derive(Debug)]
pub struct RepeatN<T: Clone + Send> {
    element: T,
    count: usize,
}

/// Creates a parallel iterator that produces `n` repeats of `elt`
/// (by cloning it).
///
/// Example:
///
/// ```
/// use rayon::prelude::*;
/// use rayon::iter::repeatn;
/// let x: Vec<(i32, i32)> = repeatn(22, 3).zip(0..3).collect();
/// assert_eq!(x, vec![(22, 0), (22, 1), (22, 2)]);
/// ```
pub fn repeatn<T: Clone + Send>(elt: T, n: usize) -> RepeatN<T> {
    RepeatN { element: elt, count: n }
}

impl<T> ParallelIterator for RepeatN<T>
    where T: Clone + Send
{
    type Item = T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.count)
    }
}

impl<T> IndexedParallelIterator for RepeatN<T>
    where T: Clone + Send
{
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(RepeatNProducer { element: self.element, count: self.count })
    }

    fn len(&mut self) -> usize {
        self.count
    }
}

/// Producer for `RepeatN`.
struct RepeatNProducer<T: Clone + Send> {
    element: T,
    count: usize,
}

impl<T: Clone + Send> Producer for RepeatNProducer<T> {
    type Item = T;
    type IntoIter = Iter<T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter { element: self.element, count: self.count }
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        (RepeatNProducer { element: self.element.clone(), count: index },
         RepeatNProducer { element: self.element, count: self.count - index })
    }
}

/// Iterator for `RepeatN`.
///
/// This is conceptually like `std::iter::Take<std::iter::Repeat<T>>`, but
/// we need `DoubleEndedIterator` and unconditional `ExactSizeIterator`.
struct Iter<T: Clone> {
    element: T,
    count: usize,
}

impl<T: Clone> Iterator for Iter<T> {
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.count > 0 {
            self.count -= 1;
            Some(self.element.clone())
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.count, Some(self.count))
    }
}

impl<T: Clone> DoubleEndedIterator for Iter<T> {
    #[inline]
    fn next_back(&mut self) -> Option<T> {
        self.next()
    }
}

impl<T: Clone> ExactSizeIterator for Iter<T> {
    #[inline]
    fn len(&self) -> usize {
        self.count
    }
}
<|endoftext|>


<commit_before>//! Defines common interfaces for interacting with statistical distributions and provides
//! concrete implementations for a variety of distributions.

use rand::Rng;
use super::result::Result;

pub use self::bernoulli::Bernoulli;
pub use self::binomial::Binomial;
pub use self::chi::Chi;
pub use self::chi_squared::ChiSquared;
pub use self::discrete_uniform::DiscreteUniform;
pub use self::exponential::Exponential;
pub use self::gamma::Gamma;
pub use self::log_normal::LogNormal;
pub use self::normal::Normal;
pub use self::poisson::Poisson;
pub use self::student_t::StudentT;
pub use self::triangular::Triangular;
pub use self::uniform::Uniform;
pub use self::weibull::Weibull;

mod bernoulli;
mod binomial;
mod chi;
mod chi_squared;
mod discrete_uniform;
mod exponential;
mod gamma;
mod log_normal;
mod normal;
mod poisson;
mod student_t;
mod triangular;
mod uniform;
mod weibull;

/// The `Distribution` trait is used to specify an interface
/// for sampling distributions
///
/// # Examples
///
/// A trivial implementation that just samples from the supplied
/// random number generator
///
/// ```
/// use rand::StdRng;
///
/// struct Foo;
///
/// impl Distribution for Foo {
///     fn sample<R: Rng>(&self, r: &mut R) -> f64 {
///         r.next_f64()
///     }
/// }
/// ```
pub trait Distribution {
    /// Draws a random sample using the supplied random number generator
    fn sample<R: Rng>(&self, r: &mut R) -> f64;
}

/// The `Univariate` trait extends the `Distribution`
/// trait provides an interface for interacting with
/// univariate statistical distributions.
///
/// # Remarks
///
/// All methods provided by the `Univariate` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedUnivariate`
/// trait provides a panic-safe interface for univariate distributions
pub trait Univariate : Distribution {
    fn mean(&self) -> f64;
    fn variance(&self) -> f64;
    fn std_dev(&self) -> f64;
    fn entropy(&self) -> f64;
    fn skewness(&self) -> f64;
    fn median(&self) -> f64;
    fn cdf(&self, x: f64) -> f64;
}

/// The `CheckedUnivariate` trait extends the `Distribution` trait and
/// provides a checked interface for interacting with univariate statistical
/// distributions. This means implementors should return an `Err` instead of
/// panicking on an invalid state or input.
pub trait CheckedUnivariate : Distribution {
    fn mean(&self) -> Result<f64>;
    fn variance(&self) -> Result<f64>;
    fn std_dev(&self) -> Result<f64>;
    fn entropy(&self) -> Result<f64>;
    fn skewness(&self) -> Result<f64>;
    fn median(&self) -> Result<f64>;
    fn cdf(&self) -> Result<f64>;
}

/// The `Continuous` trait extends the `Univariate`
/// trait and provides an interface for interacting with continuous
/// univariate statistical distributions
///
/// # Remarks
///
/// All methods provided by the `Continuous` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedContinuous`
/// trait provides a panic-safe interface for continuous distributions
pub trait Continuous : Univariate {
    fn mode(&self) -> f64;
    fn min(&self) -> f64;
    fn max(&self) -> f64;
    fn pdf(&self, x: f64) -> f64;
    fn ln_pdf(&self, x: f64) -> f64;
}

/// The `CheckedContinous` trait extends the `CheckedUnivariate`
/// trait and provides a checked interface for interacting with
/// continous univariate statistical distributions. This means
/// implementors should return an `Err` instead of panicking on
/// an invalid state or input.
pub trait CheckedContinuous : CheckedUnivariate {
    fn mode(&self) -> Result<f64>;
    fn min(&self) -> Result<f64>;
    fn max(&self) -> Result<f64>;
    fn pdf(&self, x: f64) -> Result<f64>;
    fn ln_pdf(&self, x: f64) -> Result<f64>;
}

/// The `Discrete` trait extends the `Univariate`
/// trait and provides an interface for interacting with discrete
/// univariate statistical distributions
///
/// # Remakrs
///
/// All methods provided by the `Discrete` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedDiscrete` trait
/// provides a panic-safe interface for discrete distributions
pub trait Discrete : Univariate {
    fn mode(&self) -> i64;
    fn min(&self) -> i64;
    fn max(&self) -> i64;
    fn pmf(&self, x: i64) -> f64;
    fn ln_pmf(&self, x: i64) -> f64;
}

/// The `CheckedDiscrete` trait extends the `CheckedUnivariate` trait
/// and provides a checked interface for interacting with discrete
/// univariate statistical distributions. This means implementors
/// should return an `Err` instead of panicking on an invalid state
/// or input
pub trait CheckedDiscrete : CheckedUnivariate {
    fn mode(&self) -> Result<i64>;
    fn min(&self) -> Result<i64>;
    fn max(&self) -> Result<i64>;
    fn pmf(&self, x: i64) -> Result<f64>;
    fn ln_pmf(&self, x: i64) -> Result<f64>;
}<commit_msg>doc comments for univariate trait<commit_after>//! Defines common interfaces for interacting with statistical distributions and provides
//! concrete implementations for a variety of distributions.

use rand::Rng;
use super::result::Result;

pub use self::bernoulli::Bernoulli;
pub use self::binomial::Binomial;
pub use self::chi::Chi;
pub use self::chi_squared::ChiSquared;
pub use self::discrete_uniform::DiscreteUniform;
pub use self::exponential::Exponential;
pub use self::gamma::Gamma;
pub use self::log_normal::LogNormal;
pub use self::normal::Normal;
pub use self::poisson::Poisson;
pub use self::student_t::StudentT;
pub use self::triangular::Triangular;
pub use self::uniform::Uniform;
pub use self::weibull::Weibull;

mod bernoulli;
mod binomial;
mod chi;
mod chi_squared;
mod discrete_uniform;
mod exponential;
mod gamma;
mod log_normal;
mod normal;
mod poisson;
mod student_t;
mod triangular;
mod uniform;
mod weibull;

/// The `Distribution` trait is used to specify an interface
/// for sampling distributions
///
/// # Examples
///
/// A trivial implementation that just samples from the supplied
/// random number generator
///
/// ```
/// use rand::StdRng;
///
/// struct Foo;
///
/// impl Distribution for Foo {
///     fn sample<R: Rng>(&self, r: &mut R) -> f64 {
///         r.next_f64()
///     }
/// }
/// ```
pub trait Distribution {
    /// Draws a random sample using the supplied random number generator
    fn sample<R: Rng>(&self, r: &mut R) -> f64;
}

/// The `Univariate` trait extends the `Distribution`
/// trait provides an interface for interacting with
/// univariate statistical distributions.
///
/// # Remarks
///
/// All methods provided by the `Univariate` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedUnivariate`
/// trait provides a panic-safe interface for univariate distributions
pub trait Univariate : Distribution {
    /// Returns the mean for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0, 1).unwrap();
    /// assert_eq!(0.5, n.mean());
    /// ```
    fn mean(&self) -> f64;

    /// Returns the variance for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0, 1).unwrap();
    /// assert_eq!(1.0 / 12.0, n.variance());
    /// ```
    fn variance(&self) -> f64;

    /// Returns the standard deviation for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0, 1).unwrap();
    /// assert_eq!((1f64 / 12f64).sqrt(), n.std_dev());
    /// ```
    fn std_dev(&self) -> f64;

    /// Returns the entropy for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0, 1).unwrap();
    /// assert_eq!(0.0, n.entropy());
    /// ```
    fn entropy(&self) -> f64;

    /// Returns the skewness for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0, 1).unwrap();
    /// assert_eq!(0.0, n.skewness());
    /// ```
    fn skewness(&self) -> f64;

    /// Returns the median for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0, 1).unwrap();
    /// assert_eq!(0.5, n.median());
    /// ```
    fn median(&self) -> f64;

    /// Returns the cumulative distribution function calculated
    /// at `x` for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Uniform;
    ///
    /// let n = Uniform::new(0, 1).unwrap();
    /// assert_eq!(0.5, n.cdf(0.5));
    /// ```
    fn cdf(&self, x: f64) -> f64;
}

/// The `CheckedUnivariate` trait extends the `Distribution` trait and
/// provides a checked interface for interacting with univariate statistical
/// distributions. This means implementors should return an `Err` instead of
/// panicking on an invalid state or input.
pub trait CheckedUnivariate : Distribution {
    fn mean(&self) -> Result<f64>;
    fn variance(&self) -> Result<f64>;
    fn std_dev(&self) -> Result<f64>;
    fn entropy(&self) -> Result<f64>;
    fn skewness(&self) -> Result<f64>;
    fn median(&self) -> Result<f64>;
    fn cdf(&self) -> Result<f64>;
}

/// The `Continuous` trait extends the `Univariate`
/// trait and provides an interface for interacting with continuous
/// univariate statistical distributions
///
/// # Remarks
///
/// All methods provided by the `Continuous` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedContinuous`
/// trait provides a panic-safe interface for continuous distributions
pub trait Continuous : Univariate {
    fn mode(&self) -> f64;
    fn min(&self) -> f64;
    fn max(&self) -> f64;
    fn pdf(&self, x: f64) -> f64;
    fn ln_pdf(&self, x: f64) -> f64;
}

/// The `CheckedContinous` trait extends the `CheckedUnivariate`
/// trait and provides a checked interface for interacting with
/// continous univariate statistical distributions. This means
/// implementors should return an `Err` instead of panicking on
/// an invalid state or input.
pub trait CheckedContinuous : CheckedUnivariate {
    fn mode(&self) -> Result<f64>;
    fn min(&self) -> Result<f64>;
    fn max(&self) -> Result<f64>;
    fn pdf(&self, x: f64) -> Result<f64>;
    fn ln_pdf(&self, x: f64) -> Result<f64>;
}

/// The `Discrete` trait extends the `Univariate`
/// trait and provides an interface for interacting with discrete
/// univariate statistical distributions
///
/// # Remakrs
///
/// All methods provided by the `Discrete` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution. The `CheckedDiscrete` trait
/// provides a panic-safe interface for discrete distributions
pub trait Discrete : Univariate {
    fn mode(&self) -> i64;
    fn min(&self) -> i64;
    fn max(&self) -> i64;
    fn pmf(&self, x: i64) -> f64;
    fn ln_pmf(&self, x: i64) -> f64;
}

/// The `CheckedDiscrete` trait extends the `CheckedUnivariate` trait
/// and provides a checked interface for interacting with discrete
/// univariate statistical distributions. This means implementors
/// should return an `Err` instead of panicking on an invalid state
/// or input
pub trait CheckedDiscrete : CheckedUnivariate {
    fn mode(&self) -> Result<i64>;
    fn min(&self) -> Result<i64>;
    fn max(&self) -> Result<i64>;
    fn pmf(&self, x: i64) -> Result<f64>;
    fn ln_pmf(&self, x: i64) -> Result<f64>;
}<|endoftext|>