<commit_before>// Copyright(C) 2016 Chris Liebert
extern crate glium;
extern crate image;
extern crate nalgebra;

use std::collections::HashMap;

use common;
use common::{Camera, Mesh, Scene, Shader, Vertex8f32};
use loader::DBLoader;

use glium::backend::glutin_backend::GlutinFacade;
use glium::{Program, Surface, Version};

implement_vertex!(Vertex8f32, position, normal, texcoord);

pub struct Renderer {
	pub index_buffer: glium::index::NoIndices,
	pub scene: Scene,
	pub textures: HashMap<String, glium::texture::CompressedSrgbTexture2d>,
	pub vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>>,
}

impl Renderer {
	pub fn new(display: &GlutinFacade, scene: Scene) -> Renderer {

		let mut vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>> =
			Vec::with_capacity(scene.meshes.len());

		for i in 0..scene.meshes.len() {
			vertex_buffers.push(glium::vertex::VertexBuffer::new(display, &scene.meshes[i].vertices).unwrap());
		}

		let index_buffer: glium::index::NoIndices =
			glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

		let mut textures: HashMap<String, glium::texture::CompressedSrgbTexture2d> = HashMap::new();

		for i in 0..scene.images.len() {
			//TODO: determine image format by name extension if nessisary
			//let image = image::load_from_memory_with_format(&scene.images[i].image, image::PNG).unwrap().to_rgba();
			let image = image::load_from_memory(&scene.images[i].image).unwrap().to_rgba();

			let image_dimensions = image.dimensions();
			let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(),
			                                                               image_dimensions);
			let opengl_texture: glium::texture::CompressedSrgbTexture2d =
				glium::texture::CompressedSrgbTexture2d::new(display, image).unwrap();
			textures.insert(scene.images[i].name.clone(), opengl_texture);
		}

		// Get the screen width and height in pixels
		let screen_width: u32;
		let screen_height: u32;
		match display.get_window() {
			Some(window) =>  {
				let pixel_dimensions: (u32,u32) = window.get_inner_size_pixels().unwrap();
				screen_width = pixel_dimensions.0;
				screen_height = pixel_dimensions.1;
			},
			None => {
				panic!("Error retrieving window when querying display size.");
			}
		}

		Renderer {
			index_buffer: index_buffer,
			scene: scene,
			textures: textures,
			vertex_buffers: vertex_buffers,
		}
	}

	pub fn get_mesh(&self, name: &str) -> Option<&Mesh> {
		for i in 0..self.vertex_buffers.len() as usize {
			if self.scene.meshes[i].name.eq(name) {
				return Some(&self.scene.meshes[i]);
			}
		}
		return None;
	}

	#[allow(unused_assignments)]
	pub fn create_shader_program(&self, shader_name: &str, dbloader: &DBLoader, display: &GlutinFacade) -> glium::program::Program {
		let supported_glsl_version: Version = display.get_supported_glsl_version();
		let api: glium::Api = supported_glsl_version.0;
		let major_version : u8 = supported_glsl_version.1;
		let minor_version : u8 = supported_glsl_version.2;
		let mut glsl_version_string: String = major_version.to_string();
		glsl_version_string.push_str(&minor_version.to_string());
		glsl_version_string.push('0');
		let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

		match api {
				glium::Api::Gl => {
					use_gles = false;
				},
				glium::Api::GlEs => {
					use_gles = true;
					glsl_version_string.push_str(" es");
				},
		};

		let glsl_version_number: u32 = match glsl_version_string.parse() {
			Ok(s) => s,
			Err(e) =>  {
				// This is not likely to happen
				panic!("Unable to parse supported glsl version string: {}", e);
			},
		};

		println!("Using glsl version {}", &glsl_version_string);

		let shader: Shader = dbloader.load_shader(shader_name, &glsl_version_string);

		let program: Program;

		if use_gles {
			program = program!(display,
				glsl_version_number es => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
			.unwrap();
		} else {
			program = program!(display,
				glsl_version_number => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
			.unwrap();
		}

		// Shader compilation no longer required
		display.release_shader_compiler();
		return program;
	}

	pub fn render(&self, display: &GlutinFacade, program: &glium::program::Program, camera: &Camera) {
		let mut target = display.draw();
		// TODO: generate this texture instead of loading from sqlite
		let default_blank_texture = &self.textures["DEFAULT_BLANK_TEXTURE.png"];
		target.clear_color(0.0, 0.0, 0.0, 1.0);
		for i in 0..self.vertex_buffers.len() as usize {
			let material_index: usize = self.scene.meshes[i].material_index.clone();
			let diffuse = self.scene.materials[material_index].diffuse.clone();
			let diffuse_texname: String =
				self.scene.materials[material_index].diffuse_texname.clone();
			let opengl_texture: &glium::texture::CompressedSrgbTexture2d;
			if diffuse_texname.len() == 0 {
				opengl_texture = &default_blank_texture;
			} else {
				match self.textures.get(&diffuse_texname) {
					Some(t) => {
						opengl_texture = &t;
					},
					None => {
						println!("Unable to load {}, using blank texture instead.", diffuse_texname);
						opengl_texture = &default_blank_texture;
					},
				}
			}
			let uniforms: glium::uniforms::UniformsStorage<_, _> = uniform! {
				projection: *camera.projection_matrix.borrow(),
				modelview: *camera.modelview_matrix.borrow(),
				light_position_worldspace: [2.0, 10.0, 1.0f32],
				diffuse: diffuse,
				diffuse_texture: opengl_texture,
				model: *(*self.scene.meshes[i].matrix.borrow()).as_ref(),
			};

			target.draw(&self.vertex_buffers[i],
				&self.index_buffer,
				program,
				&uniforms,
				&Default::default())
				.unwrap();
		}
		target.finish().unwrap();
	}
}
<commit_msg>removed un-needed logic to retrieve screen dimensions, changed clear_color to clear_color_and_depth<commit_after>// Copyright(C) 2016 Chris Liebert
extern crate glium;
extern crate image;
extern crate nalgebra;

use std::collections::HashMap;

use common;
use common::{Camera, Mesh, Scene, Shader, Vertex8f32};
use loader::DBLoader;

use glium::backend::glutin_backend::GlutinFacade;
use glium::{Program, Surface, Version};

implement_vertex!(Vertex8f32, position, normal, texcoord);

pub struct Renderer {
	pub index_buffer: glium::index::NoIndices,
	pub scene: Scene,
	pub textures: HashMap<String, glium::texture::CompressedSrgbTexture2d>,
	pub vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>>,
}

impl Renderer {
	pub fn new(display: &GlutinFacade, scene: Scene) -> Renderer {

		let mut vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>> =
			Vec::with_capacity(scene.meshes.len());

		for i in 0..scene.meshes.len() {
			vertex_buffers.push(glium::vertex::VertexBuffer::new(display, &scene.meshes[i].vertices).unwrap());
		}

		let index_buffer: glium::index::NoIndices =
			glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

		let mut textures: HashMap<String, glium::texture::CompressedSrgbTexture2d> = HashMap::new();

		for i in 0..scene.images.len() {
			//TODO: determine image format by name extension if nessisary
			//let image = image::load_from_memory_with_format(&scene.images[i].image, image::PNG).unwrap().to_rgba();
			let image = image::load_from_memory(&scene.images[i].image).unwrap().to_rgba();

			let image_dimensions = image.dimensions();
			let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(),
			                                                               image_dimensions);
			let opengl_texture: glium::texture::CompressedSrgbTexture2d =
				glium::texture::CompressedSrgbTexture2d::new(display, image).unwrap();
			textures.insert(scene.images[i].name.clone(), opengl_texture);
		}

		Renderer {
			index_buffer: index_buffer,
			scene: scene,
			textures: textures,
			vertex_buffers: vertex_buffers,
		}
	}

	pub fn get_mesh(&self, name: &str) -> Option<&Mesh> {
		for i in 0..self.vertex_buffers.len() as usize {
			if self.scene.meshes[i].name.eq(name) {
				return Some(&self.scene.meshes[i]);
			}
		}
		return None;
	}

	#[allow(unused_assignments)]
	pub fn create_shader_program(&self, shader_name: &str, dbloader: &DBLoader, display: &GlutinFacade) -> glium::program::Program {
		let supported_glsl_version: Version = display.get_supported_glsl_version();
		let api: glium::Api = supported_glsl_version.0;
		let major_version : u8 = supported_glsl_version.1;
		let minor_version : u8 = supported_glsl_version.2;
		let mut glsl_version_string: String = major_version.to_string();
		glsl_version_string.push_str(&minor_version.to_string());
		glsl_version_string.push('0');
		let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

		match api {
				glium::Api::Gl => {
					use_gles = false;
				},
				glium::Api::GlEs => {
					use_gles = true;
					glsl_version_string.push_str(" es");
				},
		};

		let glsl_version_number: u32 = match glsl_version_string.parse() {
			Ok(s) => s,
			Err(e) =>  {
				// This is not likely to happen
				panic!("Unable to parse supported glsl version string: {}", e);
			},
		};

		println!("Using glsl version {}", &glsl_version_string);

		let shader: Shader = dbloader.load_shader(shader_name, &glsl_version_string);

		let program: Program;

		if use_gles {
			program = program!(display,
				glsl_version_number es => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
			.unwrap();
		} else {
			program = program!(display,
				glsl_version_number => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
			.unwrap();
		}

		// Shader compilation no longer required
		display.release_shader_compiler();
		return program;
	}

	pub fn render(&self, display: &GlutinFacade, program: &glium::program::Program, camera: &Camera) {
		let mut target = display.draw();
		// TODO: generate this texture instead of loading from sqlite
		let default_blank_texture = &self.textures["DEFAULT_BLANK_TEXTURE.png"];
		target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
		for i in 0..self.vertex_buffers.len() as usize {
			let material_index: usize = self.scene.meshes[i].material_index.clone();
			let diffuse = self.scene.materials[material_index].diffuse.clone();
			let diffuse_texname: String =
				self.scene.materials[material_index].diffuse_texname.clone();
			let opengl_texture: &glium::texture::CompressedSrgbTexture2d;
			if diffuse_texname.len() == 0 {
				opengl_texture = &default_blank_texture;
			} else {
				match self.textures.get(&diffuse_texname) {
					Some(t) => {
						opengl_texture = &t;
					},
					None => {
						println!("Unable to load {}, using blank texture instead.", diffuse_texname);
						opengl_texture = &default_blank_texture;
					},
				}
			}
			let uniforms: glium::uniforms::UniformsStorage<_, _> = uniform! {
				projection: *camera.projection_matrix.borrow(),
				modelview: *camera.modelview_matrix.borrow(),
				light_position_worldspace: [2.0, 10.0, 1.0f32],
				diffuse: diffuse,
				diffuse_texture: opengl_texture,
				model: *(*self.scene.meshes[i].matrix.borrow()).as_ref(),
			};

			target.draw(&self.vertex_buffers[i],
				&self.index_buffer,
				program,
				&uniforms,
				&Default::default())
				.unwrap();
		}
		target.finish().unwrap();
	}
}
<|endoftext|>


<commit_before>//! Structures that model an SMTP response.
//!
//! An SMTP response consists of a status code, and zero or more lines of text.
//! This module does not derive any meaning from the response text.

use nom::{crlf, ErrorKind as NomErrorKind, IResult as NomResult, Needed};
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::str::{FromStr, from_utf8};

/// First digit indicates severity
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
pub enum Severity {
    /// 2yx
    PositiveCompletion,
    /// 3yz
    PositiveIntermediate,
    /// 4yz
    TransientNegativeCompletion,
    /// 5yz
    PermanentNegativeCompletion,
}

impl Severity {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Severity> {
        parse_severity(input)
    }

    pub fn numeric(&self) -> u8 {
        match *self {
           Severity::PositiveCompletion => 2,
           Severity::PositiveIntermediate => 3,
           Severity::TransientNegativeCompletion => 4,
           Severity::PermanentNegativeCompletion => 5,
        }
    }

    /// Tells if the response is positive
    pub fn is_positive(&self) -> bool {
        match *self {
            Severity::PositiveCompletion | Severity::PositiveIntermediate => true,
            _ => false,
        }
    }
}

impl FromStr for Severity {
    type Err = ();

    fn from_str(s: &str) -> Result<Severity, ()> {
        match Severity::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Severity {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.numeric())
    }
}

/// Second digit indicates category
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
pub enum Category {
    /// x0z
    Syntax,
    /// x1z
    Information,
    /// x2z
    Connections,
    /// x3z
    Unspecified3,
    /// x4z
    Unspecified4,
    /// x5z
    MailSystem,
}

impl Category {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Category> {
        parse_category(input)
    }

    pub fn numeric(&self) -> u8 {
        match *self {
           Category::Syntax => 0,
           Category::Information => 1,
           Category::Connections => 2,
           Category::Unspecified3 => 3,
           Category::Unspecified4 => 4,
           Category::MailSystem => 5,
        }
    }
}

impl FromStr for Category {
    type Err = ();

    fn from_str(s: &str) -> Result<Category, ()> {
        match Category::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Category {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.numeric())
    }
}

/// Third digit indicates detail
#[derive(PartialEq,Eq,Clone,Debug)]
pub struct Detail(pub u8);

impl Detail {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Detail> {
        parse_detail(input)
    }
}

impl FromStr for Detail {
    type Err = ();

    fn from_str(s: &str) -> Result<Detail, ()> {
        match Detail::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Detail {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.0)
    }
}

/// Represents a 3 digit SMTP response code
#[derive(PartialEq,Eq,Clone,Debug)]
pub struct Code {
    /// First digit of the response code
    pub severity: Severity,
    /// Second digit of the response code
    pub category: Category,
    /// Third digit of the response code
    pub detail: Detail,
}

impl Code {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Code> {
        parse_code(input)
    }
}

impl FromStr for Code {
    type Err = ();

    fn from_str(s: &str) -> Result<Code, ()> {
        match Code::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Code {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}{}{}", self.severity, self.category, self.detail)
    }
}

/// An SMTP reply, with separate code and message
///
/// The text message is optional, and may be empty
#[derive(PartialEq,Eq,Clone,Debug)]
pub struct Response {
    /// Response code
    pub code: Code,
    /// Server response text
    pub message: Vec<String>,
}

impl Response {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Response> {
        parse_response(input)
    }

    /// Returns only the first word of the message if possible
    pub fn first_word(&self) -> Option<&str> {
        self.message.get(0).and_then(|line| line.split_whitespace().next())
    }
}

impl FromStr for Response {
    type Err = ();

    fn from_str(s: &str) -> Result<Response, ()> {
        match Response::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Response {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let last_idx = self.message.len() - 1;
        for (i, line) in self.message.iter().enumerate() {
            let delim = if i == last_idx { ' ' } else { '-' };
            write!(f, "{}{}{}\r\n", &self.code, delim, line)?
        }
        Ok(())
    }
}

// Parsers.
//
// FIXME: These are here, because we can't reference e.g. `Code::parse` from
// within the nom macros. But perhaps this is a bug?

fn parse_severity(input: &[u8]) -> NomResult<&[u8], Severity> {
    if input.len() == 0 {
        return NomResult::Incomplete(Needed::Size(1));
    }

    let severity = match input[0] {
        b'2' => Severity::PositiveCompletion,
        b'3' => Severity::PositiveIntermediate,
        b'4' => Severity::TransientNegativeCompletion,
        b'5' => Severity::PermanentNegativeCompletion,
        _ => return NomResult::Error(NomErrorKind::Custom(0)),
    };

    NomResult::Done(&input[1..], severity)
}

fn parse_category(input: &[u8]) -> NomResult<&[u8], Category> {
    if input.len() == 0 {
        return NomResult::Incomplete(Needed::Size(1));
    }

    let category = match input[0] {
        b'0' => Category::Syntax,
        b'1' => Category::Information,
        b'2' => Category::Connections,
        b'3' => Category::Unspecified3,
        b'4' => Category::Unspecified4,
        b'5' => Category::MailSystem,
        _ => return NomResult::Error(NomErrorKind::Custom(0)),
    };

    NomResult::Done(&input[1..], category)
}

fn parse_detail(input: &[u8]) -> NomResult<&[u8], Detail> {
    if input.len() == 0 {
        return NomResult::Incomplete(Needed::Size(1));
    }

    let detail = match input[0] {
        c @ b'0' ... b'9' => Detail(c - b'0'),
        _ => return NomResult::Error(NomErrorKind::Custom(0)),
    };

    NomResult::Done(&input[1..], detail)
}

named!(parse_code<Code>,
    map!(
        tuple!(parse_severity, parse_category, parse_detail),
        |(severity, category, detail)| {
            Code {
                severity: severity,
                category: category,
                detail: detail,
            }
        }
    )
);

named!(parse_response<Response>,
    map_res!(
        tuple!(
            // Parse any number of continuation lines.
            many0!(
                tuple!(
                    parse_code,
                    preceded!(
                        char!(b'-'),
                        take_until_and_consume!(b"\r\n".as_ref())
                    )
                )
            ),
            // Parse the final line.
            tuple!(
                parse_code,
                terminated!(
                    opt!(
                        preceded!(
                            char!(b' '),
                            take_until!(b"\r\n".as_ref())
                        )
                    ),
                    crlf
                )
            )
        ),
        |(lines, (last_code, last_line)): (Vec<_>, _)| {
            // Check that all codes are equal.
            if !lines.iter().all(|&(ref code, _)| *code == last_code) {
                return Err(());
            }

            // Extract text from lines, and append last line.
            let mut lines = lines.into_iter()
                .map(|(_, text)| text)
                .collect::<Vec<_>>();
            if let Some(text) = last_line {
                lines.push(text);
            }

            Ok(Response {
                code: last_code,
                message: lines.into_iter()
                    .map(|line| from_utf8(line).map(|s| s.to_string()))
                    .collect::<Result<Vec<_>, _>>()
                    .map_err(|_| ())?,
            })
        }
    )
);

#[cfg(test)]
mod test {
    use ::{Category, Code, Detail, Response, Severity};

    #[test]
    fn test() {
        for (input, normalized, expect) in vec![
            (
                "421-First line\r\n421-Second line\r\n421 Third line\r\n",
                "421-First line\r\n421-Second line\r\n421 Third line\r\n",
                Response {
                    code: Code {
                        severity: Severity::TransientNegativeCompletion,
                        category: Category::Connections,
                        detail: Detail(1),
                    },
                    message: vec![
                        "First line".to_string(),
                        "Second line".to_string(),
                        "Third line".to_string(),
                    ],
                },
            ),
            (
                "210 Only line\r\n",
                "210 Only line\r\n",
                    Response {
                    code: Code {
                        severity: Severity::PositiveCompletion,
                        category: Category::Information,
                        detail: Detail(0),
                    },
                    message: vec![
                        "Only line".to_string(),
                    ],
                },
            ),
            (
                "229-Only line\r\n229\r\n",
                "229 Only line\r\n",
                Response {
                    code: Code {
                        severity: Severity::PositiveCompletion,
                        category: Category::Connections,
                        detail: Detail(9),
                    },
                    message: vec![
                        "Only line".to_string(),
                    ],
                },
            ),
        ] {
            let (rest, sub) = Response::parse(input.as_bytes()).unwrap();
            assert_eq!(rest.len(), 0);
            assert_eq!(sub, expect);
            assert_eq!(expect.to_string(), normalized);
        }

        for (word, input) in vec![
            (Some("me".as_ref()), vec!["me", "8BITMIME", "SIZE 42"]),
            (Some("me".as_ref()), vec!["me mo", "8BITMIME", "SIZE 42"]),
            (None, vec![]),
            (None, vec![" "]),
            (None, vec!["  "]),
            (None, vec![""]),
        ] {
            let sub = Response {
                code: Code {
                    severity: Severity::TransientNegativeCompletion,
                    category: Category::Connections,
                    detail: Detail(1),
                },
                message: input.into_iter()
                    .map(|s| s.to_string())
                    .collect(),
            };
            assert_eq!(sub.first_word(), word);
        }
    }
}
<commit_msg>Consistent `tests` module naming<commit_after>//! Structures that model an SMTP response.
//!
//! An SMTP response consists of a status code, and zero or more lines of text.
//! This module does not derive any meaning from the response text.

use nom::{crlf, ErrorKind as NomErrorKind, IResult as NomResult, Needed};
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::str::{FromStr, from_utf8};

/// First digit indicates severity
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
pub enum Severity {
    /// 2yx
    PositiveCompletion,
    /// 3yz
    PositiveIntermediate,
    /// 4yz
    TransientNegativeCompletion,
    /// 5yz
    PermanentNegativeCompletion,
}

impl Severity {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Severity> {
        parse_severity(input)
    }

    pub fn numeric(&self) -> u8 {
        match *self {
           Severity::PositiveCompletion => 2,
           Severity::PositiveIntermediate => 3,
           Severity::TransientNegativeCompletion => 4,
           Severity::PermanentNegativeCompletion => 5,
        }
    }

    /// Tells if the response is positive
    pub fn is_positive(&self) -> bool {
        match *self {
            Severity::PositiveCompletion | Severity::PositiveIntermediate => true,
            _ => false,
        }
    }
}

impl FromStr for Severity {
    type Err = ();

    fn from_str(s: &str) -> Result<Severity, ()> {
        match Severity::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Severity {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.numeric())
    }
}

/// Second digit indicates category
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
pub enum Category {
    /// x0z
    Syntax,
    /// x1z
    Information,
    /// x2z
    Connections,
    /// x3z
    Unspecified3,
    /// x4z
    Unspecified4,
    /// x5z
    MailSystem,
}

impl Category {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Category> {
        parse_category(input)
    }

    pub fn numeric(&self) -> u8 {
        match *self {
           Category::Syntax => 0,
           Category::Information => 1,
           Category::Connections => 2,
           Category::Unspecified3 => 3,
           Category::Unspecified4 => 4,
           Category::MailSystem => 5,
        }
    }
}

impl FromStr for Category {
    type Err = ();

    fn from_str(s: &str) -> Result<Category, ()> {
        match Category::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Category {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.numeric())
    }
}

/// Third digit indicates detail
#[derive(PartialEq,Eq,Clone,Debug)]
pub struct Detail(pub u8);

impl Detail {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Detail> {
        parse_detail(input)
    }
}

impl FromStr for Detail {
    type Err = ();

    fn from_str(s: &str) -> Result<Detail, ()> {
        match Detail::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Detail {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.0)
    }
}

/// Represents a 3 digit SMTP response code
#[derive(PartialEq,Eq,Clone,Debug)]
pub struct Code {
    /// First digit of the response code
    pub severity: Severity,
    /// Second digit of the response code
    pub category: Category,
    /// Third digit of the response code
    pub detail: Detail,
}

impl Code {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Code> {
        parse_code(input)
    }
}

impl FromStr for Code {
    type Err = ();

    fn from_str(s: &str) -> Result<Code, ()> {
        match Code::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Code {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}{}{}", self.severity, self.category, self.detail)
    }
}

/// An SMTP reply, with separate code and message
///
/// The text message is optional, and may be empty
#[derive(PartialEq,Eq,Clone,Debug)]
pub struct Response {
    /// Response code
    pub code: Code,
    /// Server response text
    pub message: Vec<String>,
}

impl Response {
    pub fn parse(input: &[u8]) -> NomResult<&[u8], Response> {
        parse_response(input)
    }

    /// Returns only the first word of the message if possible
    pub fn first_word(&self) -> Option<&str> {
        self.message.get(0).and_then(|line| line.split_whitespace().next())
    }
}

impl FromStr for Response {
    type Err = ();

    fn from_str(s: &str) -> Result<Response, ()> {
        match Response::parse(s.as_bytes()) {
            NomResult::Done(_, res) => Ok(res),
            _ => Err(()),
        }
    }
}

impl Display for Response {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let last_idx = self.message.len() - 1;
        for (i, line) in self.message.iter().enumerate() {
            let delim = if i == last_idx { ' ' } else { '-' };
            write!(f, "{}{}{}\r\n", &self.code, delim, line)?
        }
        Ok(())
    }
}

// Parsers.
//
// FIXME: These are here, because we can't reference e.g. `Code::parse` from
// within the nom macros. But perhaps this is a bug?

fn parse_severity(input: &[u8]) -> NomResult<&[u8], Severity> {
    if input.len() == 0 {
        return NomResult::Incomplete(Needed::Size(1));
    }

    let severity = match input[0] {
        b'2' => Severity::PositiveCompletion,
        b'3' => Severity::PositiveIntermediate,
        b'4' => Severity::TransientNegativeCompletion,
        b'5' => Severity::PermanentNegativeCompletion,
        _ => return NomResult::Error(NomErrorKind::Custom(0)),
    };

    NomResult::Done(&input[1..], severity)
}

fn parse_category(input: &[u8]) -> NomResult<&[u8], Category> {
    if input.len() == 0 {
        return NomResult::Incomplete(Needed::Size(1));
    }

    let category = match input[0] {
        b'0' => Category::Syntax,
        b'1' => Category::Information,
        b'2' => Category::Connections,
        b'3' => Category::Unspecified3,
        b'4' => Category::Unspecified4,
        b'5' => Category::MailSystem,
        _ => return NomResult::Error(NomErrorKind::Custom(0)),
    };

    NomResult::Done(&input[1..], category)
}

fn parse_detail(input: &[u8]) -> NomResult<&[u8], Detail> {
    if input.len() == 0 {
        return NomResult::Incomplete(Needed::Size(1));
    }

    let detail = match input[0] {
        c @ b'0' ... b'9' => Detail(c - b'0'),
        _ => return NomResult::Error(NomErrorKind::Custom(0)),
    };

    NomResult::Done(&input[1..], detail)
}

named!(parse_code<Code>,
    map!(
        tuple!(parse_severity, parse_category, parse_detail),
        |(severity, category, detail)| {
            Code {
                severity: severity,
                category: category,
                detail: detail,
            }
        }
    )
);

named!(parse_response<Response>,
    map_res!(
        tuple!(
            // Parse any number of continuation lines.
            many0!(
                tuple!(
                    parse_code,
                    preceded!(
                        char!(b'-'),
                        take_until_and_consume!(b"\r\n".as_ref())
                    )
                )
            ),
            // Parse the final line.
            tuple!(
                parse_code,
                terminated!(
                    opt!(
                        preceded!(
                            char!(b' '),
                            take_until!(b"\r\n".as_ref())
                        )
                    ),
                    crlf
                )
            )
        ),
        |(lines, (last_code, last_line)): (Vec<_>, _)| {
            // Check that all codes are equal.
            if !lines.iter().all(|&(ref code, _)| *code == last_code) {
                return Err(());
            }

            // Extract text from lines, and append last line.
            let mut lines = lines.into_iter()
                .map(|(_, text)| text)
                .collect::<Vec<_>>();
            if let Some(text) = last_line {
                lines.push(text);
            }

            Ok(Response {
                code: last_code,
                message: lines.into_iter()
                    .map(|line| from_utf8(line).map(|s| s.to_string()))
                    .collect::<Result<Vec<_>, _>>()
                    .map_err(|_| ())?,
            })
        }
    )
);

#[cfg(test)]
mod tests {
    use ::{Category, Code, Detail, Response, Severity};

    #[test]
    fn test() {
        for (input, normalized, expect) in vec![
            (
                "421-First line\r\n421-Second line\r\n421 Third line\r\n",
                "421-First line\r\n421-Second line\r\n421 Third line\r\n",
                Response {
                    code: Code {
                        severity: Severity::TransientNegativeCompletion,
                        category: Category::Connections,
                        detail: Detail(1),
                    },
                    message: vec![
                        "First line".to_string(),
                        "Second line".to_string(),
                        "Third line".to_string(),
                    ],
                },
            ),
            (
                "210 Only line\r\n",
                "210 Only line\r\n",
                    Response {
                    code: Code {
                        severity: Severity::PositiveCompletion,
                        category: Category::Information,
                        detail: Detail(0),
                    },
                    message: vec![
                        "Only line".to_string(),
                    ],
                },
            ),
            (
                "229-Only line\r\n229\r\n",
                "229 Only line\r\n",
                Response {
                    code: Code {
                        severity: Severity::PositiveCompletion,
                        category: Category::Connections,
                        detail: Detail(9),
                    },
                    message: vec![
                        "Only line".to_string(),
                    ],
                },
            ),
        ] {
            let (rest, sub) = Response::parse(input.as_bytes()).unwrap();
            assert_eq!(rest.len(), 0);
            assert_eq!(sub, expect);
            assert_eq!(expect.to_string(), normalized);
        }

        for (word, input) in vec![
            (Some("me".as_ref()), vec!["me", "8BITMIME", "SIZE 42"]),
            (Some("me".as_ref()), vec!["me mo", "8BITMIME", "SIZE 42"]),
            (None, vec![]),
            (None, vec![" "]),
            (None, vec!["  "]),
            (None, vec![""]),
        ] {
            let sub = Response {
                code: Code {
                    severity: Severity::TransientNegativeCompletion,
                    category: Category::Connections,
                    detail: Detail(1),
                },
                message: input.into_iter()
                    .map(|s| s.to_string())
                    .collect(),
            };
            assert_eq!(sub.first_word(), word);
        }
    }
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;
use spin::RwLock;
use core::hash::{Hash, Hasher};
// Compiler warns about a field not exported in core.
#[allow(deprecated)]
use core::hash::SipHasher;
use collections::vec::Vec;
use core::mem;
use core::cmp;

enum HashMapMember<K: Hash + cmp::PartialEq, V> {
    None,
    Tombstone,
    Bucket(Bucket<K, V>),
}

struct Bucket<K: Hash + cmp::PartialEq, V> {
    key: K,
    value: Arc<V>,
}

pub struct HashMap<K: Hash + cmp::PartialEq, V> {
    count: usize,
    table: RwLock<Vec<HashMapMember<K, V>>>,
    rebalance_factor: usize,
}

impl<K: Hash + cmp::PartialEq, V> Bucket<K, V> {
    fn new(key: K, value: Arc<V>) -> Self {
        Bucket {
            key: key,
            value: value,
        }
    }
}

impl<K: Hash + cmp::PartialEq, V> HashMap<K, V> {
    pub fn new(size: usize) -> Self {
        let mut table = vec![];
        for _ in 0..size {
            table.push(HashMapMember::None);
        }
        HashMap {
            count: 0,
            table: RwLock::new(table),
            rebalance_factor: 4
        }
    }

    fn should_resize(&self) -> bool {
        let size = self.table.read().len();
        (size - self.count) < (size / self.rebalance_factor)
    }

    fn rebalance(&mut self) {
        let mut table = self.table.write();
        let mut temp = HashMap::new(table.len() * 2);
        for entry in table.drain(1..) {
            match entry {
                HashMapMember::Bucket(b) => temp.insert_rc(b.key, b.value),
                _ => continue,
            }
        }
        mem::replace(&mut *table, temp.table.into_inner());
    }

    // Compiler warns about a field not exported in core.
    #[allow(deprecated)]
    fn get_index(&self, key: &K) -> usize {
        let mut hasher = SipHasher::new();
        key.hash(&mut hasher);
        (hasher.finish() as usize) % self.table.read().len()
    }

    pub fn remove(&mut self, key: K) {
        let index = self.get_index(&key);
        let mut table = self.table.write();
        let (begin, end) = table.split_at_mut(index);
        for entry in end.iter_mut().chain(begin) {
            match entry {
                &mut HashMapMember::Tombstone => continue,
                &mut HashMapMember::None => return,
                &mut HashMapMember::Bucket(ref mut b) if b.key != key => continue,
                loc @ &mut HashMapMember::Bucket(_) => {
                    *loc = HashMapMember::Tombstone;
                    return;
                }
            }
        }
    }

    pub fn insert_rc(&mut self, key: K, value: Arc<V>) {
        self.count += 1;
        if self.should_resize() {
            self.rebalance();
        }
        let index = self.get_index(&key);
        let mut table = self.table.write();
        let (begin, end) = table.split_at_mut(index);
        for entry in end.iter_mut().chain(begin) {
            match entry {
                &mut HashMapMember::Tombstone => continue,
                loc @ &mut HashMapMember::None => {
                    *loc = HashMapMember::Bucket(Bucket::new(key, value));
                    return;
                }
                &mut HashMapMember::Bucket(ref mut b) => {
                    if b.key == key {
                        b.value = value;
                        return;
                    } else {
                        continue;
                    }
                }
            }
        }
    }

    pub fn insert(&mut self, key: K, value: V) {
        self.insert_rc(key, Arc::new(value))
    }

    pub fn contains(&self, key: &K) -> bool {
        let index = self.get_index(key);
        let table = self.table.read();
        let (begin, end) = table.split_at(index);
        for entry in end.iter().chain(begin) {
            match *entry {
                HashMapMember::Tombstone => continue,
                HashMapMember::None => return false,
                HashMapMember::Bucket(ref b) => {
                    if &b.key == key {
                        return true;
                    } else {
                        continue;
                    }
                }
            }
        }
        false
    }

    pub fn get(&self, key: &K) -> Option<Arc<V>> {
        let index = self.get_index(key);
        let mut table = self.table.write();
        let (begin, end) = table.split_at_mut(index);
        for entry in end.iter_mut().chain(begin) {
            match *entry {
                HashMapMember::Tombstone => continue,
                HashMapMember::None => return None,
                HashMapMember::Bucket(ref b) => {
                    if &b.key == key {
                        return Some(b.value.clone());
                    } else {
                        continue;
                    }
                }
            }
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use alloc::rc::Arc;
    use super::HashMap;

    #[test]
    fn test_new() {
        let ht = HashMap::<i32, i32>::new(10);
        let length = ht.table.read().len();
        assert_eq!(length, 10);

        let ht1 = HashMap::<&str, &str>::new(100);
        let length = ht1.table.read().len();
        assert_eq!(length, 100);

        #[allow(unused)]
        struct Custom<'a> {
            int_field: i32,
            str_field: &'a str,
        }

        let ht2 = HashMap::<i32, Custom>::new(1000);
        let length = ht2.table.read().len();
        assert_eq!(length, 1000);
    }

    #[test]
    fn test_basic_operations() {
        let mut ht = HashMap::<i32, i32>::new(10);
        let k = 42;
        ht.insert(k, 43);
        assert!(ht.contains(&k));
        assert_eq!(ht.get(&k), Some(Arc::new(43)));

        ht.remove(42);
        assert!(!ht.contains(&k));
        assert_eq!(ht.get(&k), None);

        ht.insert(42, 44);
        assert!(ht.contains(&k));
        assert_eq!(ht.get(&k), Some(Arc::new(44)));

        ht.insert(42, 45);
        assert!(ht.contains(&k));
        assert_eq!(ht.get(&k), Some(Arc::new(45)));
    }

    #[test]
    fn test_rebalance() {

        let initial_size = 4;
        let mut ht = HashMap::<usize, usize>::new(initial_size);
        assert_eq!(ht.count, 0);

        ht.insert(0, 0);
        assert_eq!(ht.count, 1);
        assert_eq!(ht.table.read().len(), 4);

        ht.insert(1, 1);
        assert_eq!(ht.count, 2);
        assert_eq!(ht.table.read().len(), 4);

        ht.insert(2, 2);
        assert_eq!(ht.count, 3);
        assert_eq!(ht.table.read().len(), 8);

        ht.insert(3, 3);
        assert_eq!(ht.count, 4);
        assert!(!ht.should_resize());
        assert_eq!(ht.table.read().len(), 8);

        ht.insert(4, 4);
        assert_eq!(ht.count, 5);
        assert!(!ht.should_resize());
        assert_eq!(ht.table.read().len(), 8);

        ht.insert(5, 5);
        assert_eq!(ht.count, 6);
        assert!(!ht.should_resize());
        assert_eq!(ht.table.read().len(), 16);
    }
}
<commit_msg>Fix typo in tests<commit_after>use alloc::arc::Arc;
use spin::RwLock;
use core::hash::{Hash, Hasher};
// Compiler warns about a field not exported in core.
#[allow(deprecated)]
use core::hash::SipHasher;
use collections::vec::Vec;
use core::mem;
use core::cmp;

enum HashMapMember<K: Hash + cmp::PartialEq, V> {
    None,
    Tombstone,
    Bucket(Bucket<K, V>),
}

struct Bucket<K: Hash + cmp::PartialEq, V> {
    key: K,
    value: Arc<V>,
}

pub struct HashMap<K: Hash + cmp::PartialEq, V> {
    count: usize,
    table: RwLock<Vec<HashMapMember<K, V>>>,
    rebalance_factor: usize,
}

impl<K: Hash + cmp::PartialEq, V> Bucket<K, V> {
    fn new(key: K, value: Arc<V>) -> Self {
        Bucket {
            key: key,
            value: value,
        }
    }
}

impl<K: Hash + cmp::PartialEq, V> HashMap<K, V> {
    pub fn new(size: usize) -> Self {
        let mut table = vec![];
        for _ in 0..size {
            table.push(HashMapMember::None);
        }
        HashMap {
            count: 0,
            table: RwLock::new(table),
            rebalance_factor: 4
        }
    }

    fn should_resize(&self) -> bool {
        let size = self.table.read().len();
        (size - self.count) < (size / self.rebalance_factor)
    }

    fn rebalance(&mut self) {
        let mut table = self.table.write();
        let mut temp = HashMap::new(table.len() * 2);
        for entry in table.drain(1..) {
            match entry {
                HashMapMember::Bucket(b) => temp.insert_rc(b.key, b.value),
                _ => continue,
            }
        }
        mem::replace(&mut *table, temp.table.into_inner());
    }

    // Compiler warns about a field not exported in core.
    #[allow(deprecated)]
    fn get_index(&self, key: &K) -> usize {
        let mut hasher = SipHasher::new();
        key.hash(&mut hasher);
        (hasher.finish() as usize) % self.table.read().len()
    }

    pub fn remove(&mut self, key: K) {
        let index = self.get_index(&key);
        let mut table = self.table.write();
        let (begin, end) = table.split_at_mut(index);
        for entry in end.iter_mut().chain(begin) {
            match entry {
                &mut HashMapMember::Tombstone => continue,
                &mut HashMapMember::None => return,
                &mut HashMapMember::Bucket(ref mut b) if b.key != key => continue,
                loc @ &mut HashMapMember::Bucket(_) => {
                    *loc = HashMapMember::Tombstone;
                    return;
                }
            }
        }
    }

    pub fn insert_rc(&mut self, key: K, value: Arc<V>) {
        self.count += 1;
        if self.should_resize() {
            self.rebalance();
        }
        let index = self.get_index(&key);
        let mut table = self.table.write();
        let (begin, end) = table.split_at_mut(index);
        for entry in end.iter_mut().chain(begin) {
            match entry {
                &mut HashMapMember::Tombstone => continue,
                loc @ &mut HashMapMember::None => {
                    *loc = HashMapMember::Bucket(Bucket::new(key, value));
                    return;
                }
                &mut HashMapMember::Bucket(ref mut b) => {
                    if b.key == key {
                        b.value = value;
                        return;
                    } else {
                        continue;
                    }
                }
            }
        }
    }

    pub fn insert(&mut self, key: K, value: V) {
        self.insert_rc(key, Arc::new(value))
    }

    pub fn contains(&self, key: &K) -> bool {
        let index = self.get_index(key);
        let table = self.table.read();
        let (begin, end) = table.split_at(index);
        for entry in end.iter().chain(begin) {
            match *entry {
                HashMapMember::Tombstone => continue,
                HashMapMember::None => return false,
                HashMapMember::Bucket(ref b) => {
                    if &b.key == key {
                        return true;
                    } else {
                        continue;
                    }
                }
            }
        }
        false
    }

    pub fn get(&self, key: &K) -> Option<Arc<V>> {
        let index = self.get_index(key);
        let mut table = self.table.write();
        let (begin, end) = table.split_at_mut(index);
        for entry in end.iter_mut().chain(begin) {
            match *entry {
                HashMapMember::Tombstone => continue,
                HashMapMember::None => return None,
                HashMapMember::Bucket(ref b) => {
                    if &b.key == key {
                        return Some(b.value.clone());
                    } else {
                        continue;
                    }
                }
            }
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use alloc::arc::Arc;
    use super::HashMap;

    #[test]
    fn test_new() {
        let ht = HashMap::<i32, i32>::new(10);
        let length = ht.table.read().len();
        assert_eq!(length, 10);

        let ht1 = HashMap::<&str, &str>::new(100);
        let length = ht1.table.read().len();
        assert_eq!(length, 100);

        #[allow(unused)]
        struct Custom<'a> {
            int_field: i32,
            str_field: &'a str,
        }

        let ht2 = HashMap::<i32, Custom>::new(1000);
        let length = ht2.table.read().len();
        assert_eq!(length, 1000);
    }

    #[test]
    fn test_basic_operations() {
        let mut ht = HashMap::<i32, i32>::new(10);
        let k = 42;
        ht.insert(k, 43);
        assert!(ht.contains(&k));
        assert_eq!(ht.get(&k), Some(Arc::new(43)));

        ht.remove(42);
        assert!(!ht.contains(&k));
        assert_eq!(ht.get(&k), None);

        ht.insert(42, 44);
        assert!(ht.contains(&k));
        assert_eq!(ht.get(&k), Some(Arc::new(44)));

        ht.insert(42, 45);
        assert!(ht.contains(&k));
        assert_eq!(ht.get(&k), Some(Arc::new(45)));
    }

    #[test]
    fn test_rebalance() {

        let initial_size = 4;
        let mut ht = HashMap::<usize, usize>::new(initial_size);
        assert_eq!(ht.count, 0);

        ht.insert(0, 0);
        assert_eq!(ht.count, 1);
        assert_eq!(ht.table.read().len(), 4);

        ht.insert(1, 1);
        assert_eq!(ht.count, 2);
        assert_eq!(ht.table.read().len(), 4);

        ht.insert(2, 2);
        assert_eq!(ht.count, 3);
        assert_eq!(ht.table.read().len(), 8);

        ht.insert(3, 3);
        assert_eq!(ht.count, 4);
        assert!(!ht.should_resize());
        assert_eq!(ht.table.read().len(), 8);

        ht.insert(4, 4);
        assert_eq!(ht.count, 5);
        assert!(!ht.should_resize());
        assert_eq!(ht.table.read().len(), 8);

        ht.insert(5, 5);
        assert_eq!(ht.count, 6);
        assert!(!ht.should_resize());
        assert_eq!(ht.table.read().len(), 16);
    }
}
<|endoftext|>


<commit_before>//! The HTTP module which provides functions for performing requests to
//! endpoints in Discord's API.
//!
//! An important function of the REST API is ratelimiting. Requests to endpoints
//! are ratelimited to prevent spam, and once ratelimited Discord will stop
//! performing requests. The library implements protection to pre-emptively
//! ratelimit, to ensure that no wasted requests are made.
//!
//! The HTTP module comprises of two types of requests:
//!
//! - REST API requests, which require an authorization token;
//! - Other requests, which do not require an authorization token.
//!
//! The former require a [`Client`] to have logged in, while the latter may be
//! made regardless of any other usage of the library.
//!
//! If a request spuriously fails, it will be retried once.
//!
//! Note that you may want to perform requests through a [model]s'
//! instance methods where possible, as they each offer different
//! levels of a high-level interface to the HTTP module.
//!
//! [`Client`]: ../client/struct.Client.html
//! [model]: ../model/index.html

pub mod client;
pub mod ratelimiting;
pub mod request;
pub mod routing;

mod error;

pub use reqwest::StatusCode;
pub use self::client::*;
pub use self::error::Error as HttpError;

use reqwest::Method;
use crate::model::prelude::*;
use self::request::Request;
use std::{
    borrow::Cow,
    fs::File,
    path::{Path, PathBuf},
};

#[cfg(any(feature = "client", feature = "http"))]
use std::sync::Arc;

#[cfg(feature = "cache")]
use crate::cache::CacheRwLock;
#[cfg(feature = "client")]
use crate::client::Context;
#[cfg(feature = "client")]
use crate::CacheAndHttp;

/// This trait will be required by functions that need [`Http`] and can
/// optionally use a [`CacheRwLock`] to potentially avoid REST-requests.
///
/// The types [`Context`], [`CacheRwLock`], and [`Http`] implement this trait
/// and thus passing these to functions expecting `impl CacheHttp` is possible.
///
/// In a situation where you have the `cache`-feature enabled but you do not
/// pass a cache, the function will behave as if no `cache`-feature is active.
///
/// If you are calling a function that expects `impl CacheHttp` as argument
/// and you wish to utilise the `cache`-feature but you got no access to a
/// [`Context`], you can pass a tuple of `(CacheRwLock, Http)`.
///
/// [`CacheRwLock`]: ../cache/struct.CacheRwLock.html
/// [`Http`]: client/struct.Http.html
/// [`Context`]: ../client/struct.Context.html
pub trait CacheHttp {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http;
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { None }
}

#[cfg(feature = "client")]
impl CacheHttp for Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &mut Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &&mut Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for CacheAndHttp {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &CacheAndHttp {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for Arc<CacheAndHttp> {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(all(feature = "cache", feature = "http"))]
impl CacheHttp for (&CacheRwLock, &Http) {
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.0) }
    fn http(&self) -> &Http { &self.1 }
}

#[cfg(feature = "http")]
impl CacheHttp for &Http {
    fn http(&self) -> &Http { *self }
}

#[cfg(feature = "http")]
impl CacheHttp for Arc<Http> {
    fn http(&self) -> &Http { &*self }
}

#[cfg(all(feature = "cache", feature = "http"))]
impl AsRef<CacheRwLock> for (&CacheRwLock, &Http) {
    fn as_ref(&self) -> &CacheRwLock {
        self.0
    }
}

#[cfg(feature = "cache")]
impl AsRef<Http> for (&CacheRwLock, &Http) {
    fn as_ref(&self) -> &Http {
        self.1
    }
}

/// An method used for ratelimiting special routes.
///
/// This is needed because `reqwest`'s `Method` enum does not derive Copy.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LightMethod {
    /// Indicates that a route is for the `DELETE` method only.
    Delete,
    /// Indicates that a route is for the `GET` method only.
    Get,
    /// Indicates that a route is for the `PATCH` method only.
    Patch,
    /// Indicates that a route is for the `POST` method only.
    Post,
    /// Indicates that a route is for the `PUT` method only.
    Put,
}

impl LightMethod {
    pub fn reqwest_method(self) -> Method {
        match self {
            LightMethod::Delete => Method::DELETE,
            LightMethod::Get => Method::GET,
            LightMethod::Patch => Method::PATCH,
            LightMethod::Post => Method::POST,
            LightMethod::Put => Method::PUT,
        }
    }
}

/// Enum that allows a user to pass a `Path` or a `File` type to `send_files`
#[derive(Clone, Debug)]
pub enum AttachmentType<'a> {
    /// Indicates that the `AttachmentType` is a byte slice with a filename.
    Bytes{ data: Cow<'a, [u8]>, filename: String } ,
    /// Indicates that the `AttachmentType` is a `File`
    File{ file: &'a File, filename: String },
    /// Indicates that the `AttachmentType` is a `Path`
    Path(&'a Path),
    /// Indicates that the `AttachmentType` is an image URL.
    Image(&'a str),
    #[doc(hidden)]
    __Nonexhaustive,
}

impl<'a> From<(&'a [u8], &str)> for AttachmentType<'a> {
    fn from(params: (&'a [u8], &str)) -> AttachmentType<'a> { AttachmentType::Bytes{ data: Cow::Borrowed(params.0), filename: params.1.to_string() } }
}

impl<'a> From<&'a str> for AttachmentType<'a> {
    /// Constructs an `AttachmentType` from a string.
    /// This string may refer to the path of a file on disk, or the http url to an image on the internet.
    fn from(s: &'a str) -> AttachmentType<'_> {
        if s.starts_with("http://") || s.starts_with("https://") {
            AttachmentType::Image(s)
        } else {
            AttachmentType::Path(Path::new(s))
        }
    }
}

impl<'a> From<&'a Path> for AttachmentType<'a> {
    fn from(path: &'a Path) -> AttachmentType<'_> {
        AttachmentType::Path(path)
    }
}

impl<'a> From<&'a PathBuf> for AttachmentType<'a> {
    fn from(pathbuf: &'a PathBuf) -> AttachmentType<'_> { AttachmentType::Path(pathbuf.as_path()) }
}

impl<'a> From<(&'a File, &str)> for AttachmentType<'a> {
    fn from(f: (&'a File, &str)) -> AttachmentType<'a> { AttachmentType::File{ file: f.0, filename: f.1.to_string() } }
}

/// Representation of the method of a query to send for the [`get_guilds`]
/// function.
///
/// [`get_guilds`]: fn.get_guilds.html
pub enum GuildPagination {
    /// The Id to get the guilds after.
    After(GuildId),
    /// The Id to get the guilds before.
    Before(GuildId),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[cfg(test)]
mod test {
    use super::AttachmentType;
    use std::path::Path;

    #[test]
    fn test_attachment_type() {
        assert!(match AttachmentType::from(Path::new("./dogs/corgis/kona.png")) {
            AttachmentType::Path(_) => true,
            _ => false,
        });
        assert!(match AttachmentType::from("./cats/copycat.png") {
            AttachmentType::Path(_) => true,
            _ => false,
        });
    }
}
<commit_msg>http: make error module public<commit_after>//! The HTTP module which provides functions for performing requests to
//! endpoints in Discord's API.
//!
//! An important function of the REST API is ratelimiting. Requests to endpoints
//! are ratelimited to prevent spam, and once ratelimited Discord will stop
//! performing requests. The library implements protection to pre-emptively
//! ratelimit, to ensure that no wasted requests are made.
//!
//! The HTTP module comprises of two types of requests:
//!
//! - REST API requests, which require an authorization token;
//! - Other requests, which do not require an authorization token.
//!
//! The former require a [`Client`] to have logged in, while the latter may be
//! made regardless of any other usage of the library.
//!
//! If a request spuriously fails, it will be retried once.
//!
//! Note that you may want to perform requests through a [model]s'
//! instance methods where possible, as they each offer different
//! levels of a high-level interface to the HTTP module.
//!
//! [`Client`]: ../client/struct.Client.html
//! [model]: ../model/index.html

pub mod client;
pub mod error;
pub mod ratelimiting;
pub mod request;
pub mod routing;

pub use reqwest::StatusCode;
pub use self::client::*;
pub use self::error::Error as HttpError;

use reqwest::Method;
use crate::model::prelude::*;
use self::request::Request;
use std::{
    borrow::Cow,
    fs::File,
    path::{Path, PathBuf},
};

#[cfg(any(feature = "client", feature = "http"))]
use std::sync::Arc;

#[cfg(feature = "cache")]
use crate::cache::CacheRwLock;
#[cfg(feature = "client")]
use crate::client::Context;
#[cfg(feature = "client")]
use crate::CacheAndHttp;

/// This trait will be required by functions that need [`Http`] and can
/// optionally use a [`CacheRwLock`] to potentially avoid REST-requests.
///
/// The types [`Context`], [`CacheRwLock`], and [`Http`] implement this trait
/// and thus passing these to functions expecting `impl CacheHttp` is possible.
///
/// In a situation where you have the `cache`-feature enabled but you do not
/// pass a cache, the function will behave as if no `cache`-feature is active.
///
/// If you are calling a function that expects `impl CacheHttp` as argument
/// and you wish to utilise the `cache`-feature but you got no access to a
/// [`Context`], you can pass a tuple of `(CacheRwLock, Http)`.
///
/// [`CacheRwLock`]: ../cache/struct.CacheRwLock.html
/// [`Http`]: client/struct.Http.html
/// [`Context`]: ../client/struct.Context.html
pub trait CacheHttp {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http;
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { None }
}

#[cfg(feature = "client")]
impl CacheHttp for Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &mut Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &&mut Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for CacheAndHttp {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &CacheAndHttp {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for Arc<CacheAndHttp> {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(all(feature = "cache", feature = "http"))]
impl CacheHttp for (&CacheRwLock, &Http) {
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.0) }
    fn http(&self) -> &Http { &self.1 }
}

#[cfg(feature = "http")]
impl CacheHttp for &Http {
    fn http(&self) -> &Http { *self }
}

#[cfg(feature = "http")]
impl CacheHttp for Arc<Http> {
    fn http(&self) -> &Http { &*self }
}

#[cfg(all(feature = "cache", feature = "http"))]
impl AsRef<CacheRwLock> for (&CacheRwLock, &Http) {
    fn as_ref(&self) -> &CacheRwLock {
        self.0
    }
}

#[cfg(feature = "cache")]
impl AsRef<Http> for (&CacheRwLock, &Http) {
    fn as_ref(&self) -> &Http {
        self.1
    }
}

/// An method used for ratelimiting special routes.
///
/// This is needed because `reqwest`'s `Method` enum does not derive Copy.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LightMethod {
    /// Indicates that a route is for the `DELETE` method only.
    Delete,
    /// Indicates that a route is for the `GET` method only.
    Get,
    /// Indicates that a route is for the `PATCH` method only.
    Patch,
    /// Indicates that a route is for the `POST` method only.
    Post,
    /// Indicates that a route is for the `PUT` method only.
    Put,
}

impl LightMethod {
    pub fn reqwest_method(self) -> Method {
        match self {
            LightMethod::Delete => Method::DELETE,
            LightMethod::Get => Method::GET,
            LightMethod::Patch => Method::PATCH,
            LightMethod::Post => Method::POST,
            LightMethod::Put => Method::PUT,
        }
    }
}

/// Enum that allows a user to pass a `Path` or a `File` type to `send_files`
#[derive(Clone, Debug)]
pub enum AttachmentType<'a> {
    /// Indicates that the `AttachmentType` is a byte slice with a filename.
    Bytes{ data: Cow<'a, [u8]>, filename: String } ,
    /// Indicates that the `AttachmentType` is a `File`
    File{ file: &'a File, filename: String },
    /// Indicates that the `AttachmentType` is a `Path`
    Path(&'a Path),
    /// Indicates that the `AttachmentType` is an image URL.
    Image(&'a str),
    #[doc(hidden)]
    __Nonexhaustive,
}

impl<'a> From<(&'a [u8], &str)> for AttachmentType<'a> {
    fn from(params: (&'a [u8], &str)) -> AttachmentType<'a> { AttachmentType::Bytes{ data: Cow::Borrowed(params.0), filename: params.1.to_string() } }
}

impl<'a> From<&'a str> for AttachmentType<'a> {
    /// Constructs an `AttachmentType` from a string.
    /// This string may refer to the path of a file on disk, or the http url to an image on the internet.
    fn from(s: &'a str) -> AttachmentType<'_> {
        if s.starts_with("http://") || s.starts_with("https://") {
            AttachmentType::Image(s)
        } else {
            AttachmentType::Path(Path::new(s))
        }
    }
}

impl<'a> From<&'a Path> for AttachmentType<'a> {
    fn from(path: &'a Path) -> AttachmentType<'_> {
        AttachmentType::Path(path)
    }
}

impl<'a> From<&'a PathBuf> for AttachmentType<'a> {
    fn from(pathbuf: &'a PathBuf) -> AttachmentType<'_> { AttachmentType::Path(pathbuf.as_path()) }
}

impl<'a> From<(&'a File, &str)> for AttachmentType<'a> {
    fn from(f: (&'a File, &str)) -> AttachmentType<'a> { AttachmentType::File{ file: f.0, filename: f.1.to_string() } }
}

/// Representation of the method of a query to send for the [`get_guilds`]
/// function.
///
/// [`get_guilds`]: fn.get_guilds.html
pub enum GuildPagination {
    /// The Id to get the guilds after.
    After(GuildId),
    /// The Id to get the guilds before.
    Before(GuildId),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[cfg(test)]
mod test {
    use super::AttachmentType;
    use std::path::Path;

    #[test]
    fn test_attachment_type() {
        assert!(match AttachmentType::from(Path::new("./dogs/corgis/kona.png")) {
            AttachmentType::Path(_) => true,
            _ => false,
        });
        assert!(match AttachmentType::from("./cats/copycat.png") {
            AttachmentType::Path(_) => true,
            _ => false,
        });
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::os::unix::io::RawFd;
use handle_table::{HandleTable, Handle};
use sys::unix::FdObserver;
use nix::sys::epoll;

pub struct Reactor {
    pub ep: RawFd,
    pub observers: HandleTable<FdObserver>,
    events: Vec<epoll::EpollEvent>
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            ep: try_syscall!(epoll::epoll_create()),
            observers: HandleTable::new(),
            events: Vec::with_capacity(1024),
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = match maybe_timeout {
            Some(t) if t >= ::time::Duration::zero() => t.num_milliseconds() as isize,
            _ => -1,
        };

        let events = unsafe {
            let ptr = (&mut self.events[..]).as_mut_ptr();
            ::std::slice::from_raw_parts_mut(ptr, self.events.capacity())
        };

        let n = try_syscall!(epoll::epoll_wait(self.ep, events, timeout));

        unsafe { self.events.set_len(n); }

        for event in &self.events {
            let handle = Handle { val: event.data as usize };

            if event.events.contains(epoll::EPOLLIN) || event.events.contains(epoll::EPOLLHUP) ||
               event.events.contains(epoll::EPOLLERR)
            {
                match self.observers[handle].read_fulfiller.take() {
                    None => (),
                    Some(fulfiller) => {
                        fulfiller.fulfill(());
                    }
                }
            }

            if event.events.contains(epoll::EPOLLOUT) || event.events.contains(epoll::EPOLLHUP) ||
               event.events.contains(epoll::EPOLLERR)
            {
                match self.observers[handle].write_fulfiller.take() {
                    None => (),
                    Some(fulfiller) => {
                        fulfiller.fulfill(());
                    }
                }
            }
        }
        Ok(())
    }

    pub fn new_observer(&mut self, fd: RawFd) -> Result<Handle, ::std::io::Error> {
        let observer = FdObserver { read_fulfiller: None, write_fulfiller: None };
        let handle = self.observers.push(observer);

        let info = epoll::EpollEvent {
            events: epoll::EPOLLIN | epoll::EPOLLOUT | epoll::EPOLLET,
            data: handle.val as u64
        };

        try_syscall!(epoll::epoll_ctl(self.ep, epoll::EpollOp::EpollCtlAdd, fd, &info));

        Ok(handle)
    }
}
<commit_msg>remove stray blank line<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::os::unix::io::RawFd;
use handle_table::{HandleTable, Handle};
use sys::unix::FdObserver;
use nix::sys::epoll;

pub struct Reactor {
    pub ep: RawFd,
    pub observers: HandleTable<FdObserver>,
    events: Vec<epoll::EpollEvent>
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            ep: try_syscall!(epoll::epoll_create()),
            observers: HandleTable::new(),
            events: Vec::with_capacity(1024),
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = match maybe_timeout {
            Some(t) if t >= ::time::Duration::zero() => t.num_milliseconds() as isize,
            _ => -1,
        };

        let events = unsafe {
            let ptr = (&mut self.events[..]).as_mut_ptr();
            ::std::slice::from_raw_parts_mut(ptr, self.events.capacity())
        };

        let n = try_syscall!(epoll::epoll_wait(self.ep, events, timeout));

        unsafe { self.events.set_len(n); }

        for event in &self.events {
            let handle = Handle { val: event.data as usize };

            if event.events.contains(epoll::EPOLLIN) || event.events.contains(epoll::EPOLLHUP) ||
               event.events.contains(epoll::EPOLLERR)
            {
                match self.observers[handle].read_fulfiller.take() {
                    None => (),
                    Some(fulfiller) => {
                        fulfiller.fulfill(());
                    }
                }
            }

            if event.events.contains(epoll::EPOLLOUT) || event.events.contains(epoll::EPOLLHUP) ||
               event.events.contains(epoll::EPOLLERR)
            {
                match self.observers[handle].write_fulfiller.take() {
                    None => (),
                    Some(fulfiller) => {
                        fulfiller.fulfill(());
                    }
                }
            }
        }
        Ok(())
    }

    pub fn new_observer(&mut self, fd: RawFd) -> Result<Handle, ::std::io::Error> {
        let observer = FdObserver { read_fulfiller: None, write_fulfiller: None };
        let handle = self.observers.push(observer);

        let info = epoll::EpollEvent {
            events: epoll::EPOLLIN | epoll::EPOLLOUT | epoll::EPOLLET,
            data: handle.val as u64
        };

        try_syscall!(epoll::epoll_ctl(self.ep, epoll::EpollOp::EpollCtlAdd, fd, &info));

        Ok(handle)
    }
}
<|endoftext|>


<commit_before>// (c) 2017 Productize SPRL <joost@productize.be>

use std::iter::Peekable;
use std::slice::Iter;

use Sexp;
pub use Result as SResult;

/// convert an `&Sexp` to something
pub trait FromSexp
    where Self: Sized
{
    /// convert from a symbolic-expression to something
    fn from_sexp(&Sexp) -> SResult<Self>;
}

/// convert from a symbolic-expression to something (dispatcher)
pub fn from_sexp<T: FromSexp>(s: &Sexp) -> SResult<T> {
    T::from_sexp(s)
}

/// Atom iterator wrapper
pub struct IterAtom<'a> {
    name: String,
    /// containing iterable (pub for now)
    pub iter: Peekable<Iter<'a, Sexp>>,
}

impl<'a> IterAtom<'a> {
    /// deconstruct a `Sexp` that is a list and starts with 'name'
    pub fn new(s: &'a Sexp, name: &str) -> SResult<IterAtom<'a>> {
        let v = s.list()?;
        let mut i = v.iter();
        let st = match i.next() {
            None => return Err(format!("missing first element {} in list {}", name, s).into()),
            Some(e) => e.string()?,
        };
        if st != name {
            return Err(format!("list {} doesn't start with {}, but with {}", s, name, st).into());
        }
        let i = i.peekable();
        Ok(IterAtom {
            name: name.into(),
            iter: i,
        })
    }

    fn expect<T, F>(&mut self, name: &str, get: F) -> SResult<T>
        where F: Fn(&Sexp) -> SResult<T>
    {
        match self.iter.next() {
            Some(x) => get(x),
            None => return Err(format!("missing {} field in {}", name, self.name).into()),
        }
    }

    /// expect an integer while iterating a `Sexp` list
    pub fn i(&mut self, name: &str) -> SResult<i64> {
        self.expect(name, |x| x.i().map_err(From::from))
    }

    /// expect a float while iterating a `Sexp` list
    pub fn f(&mut self, name: &str) -> SResult<f64> {
        self.expect(name, |x| x.f().map_err(From::from))
    }

    /// expect a String while iterating a `Sexp` list
    pub fn s(&mut self, name: &str) -> SResult<String> {
        self.expect(name, |x| x.s().map_err(From::from))
    }

    /// expect a list contained String while iterating a `Sexp` list
    pub fn s_in_list(&mut self, name: &str) -> SResult<String> {
        self.expect(name,
                    |x| x.named_value_s(name).map_err(From::from))
    }

    /// expect a list contained i64 while iterating a `Sexp` list
    pub fn i_in_list(&mut self, name: &str) -> SResult<i64> {
        self.expect(name, |x| x.named_value_i(name).map_err(From::from))
    }

    /// expect a list contained f64 while iterating a `Sexp` list
    pub fn f_in_list(&mut self, name: &str) -> SResult<f64> {
        self.expect(name, |x| x.named_value_f(name).map_err(From::from))
    }

    /// expect a `Sexp` while iterating a `Sexp` list
    pub fn t<T: FromSexp>(&mut self, name: &str) -> SResult<T> {
        self.expect(name, |x| T::from_sexp(x))
    }

    /// expect remainder of iterator to be a `Vec<T>`
    pub fn vec<T: FromSexp>(&mut self) -> SResult<Vec<T>> {
        let mut res = Vec::new();
        loop {
            match self.iter.next() {
                None => break,
                Some(e) => {
                    let p = from_sexp(e)?;
                    res.push(p);
                }
            }
        }
        Ok(res)
    }

    /// maybe something while iterating a `Sexp` list
    fn maybe<X, F>(&mut self, convert: F) -> Option<X>
        where F: Fn(&Sexp) -> SResult<X>
    {
        let res = match self.iter.peek() {
            None => None,
            Some(s) => {
                match convert(s) {
                    Ok(t) => Some(t),
                    Err(_) => None,
                }
            }
        };
        match res {
            Some(x) => {
                let _ = self.iter.next();
                Some(x)
            }
            x => x,
        }
    }

    /// maybe a `FromSexp` while iterating a `Sexp` list
    pub fn maybe_t<T: FromSexp>(&mut self) -> Option<T> {
        self.maybe(|x| T::from_sexp(x))
    }

    /// maybe a `String` while iterating a `Sexp` list
    pub fn maybe_s(&mut self) -> Option<String> {
        self.maybe(|x| x.s())
    }

    /// maybe an `i64` while iterating a `Sexp` list
    pub fn maybe_i(&mut self) -> Option<i64> {
        self.maybe(|x| x.i())
    }

    /// maybe an `f64` while iterating a `Sexp` list
    pub fn maybe_f(&mut self) -> Option<f64> {
        self.maybe(|x| x.f())
    }

    /// maybe a list containing a `String` while iterating a `Sexp` list
    pub fn maybe_s_in_list(&mut self, name:&str) -> Option<String> {
        self.maybe(|x| x.named_value_s(name))
    }

    /// maybe a list containing an `i64` while iterating a `Sexp` list
    pub fn maybe_i_in_list(&mut self, name:&str) -> Option<i64> {
        self.maybe(|x| x.named_value_i(name))
    }

    /// maybe a list containing an `f64` while iterating a `Sexp` list
    pub fn maybe_f_in_list(&mut self, name:&str) -> Option<f64> {
        self.maybe(|x| x.named_value_f(name))
    }
}
<commit_msg>t_in_list for iteratom<commit_after>// (c) 2017 Productize SPRL <joost@productize.be>

use std::iter::Peekable;
use std::slice::Iter;

use Sexp;
pub use Result as SResult;

/// convert an `&Sexp` to something
pub trait FromSexp
    where Self: Sized
{
    /// convert from a symbolic-expression to something
    fn from_sexp(&Sexp) -> SResult<Self>;
}

/// convert from a symbolic-expression to something (dispatcher)
pub fn from_sexp<T: FromSexp>(s: &Sexp) -> SResult<T> {
    T::from_sexp(s)
}

/// Atom iterator wrapper
pub struct IterAtom<'a> {
    name: String,
    /// containing iterable (pub for now)
    pub iter: Peekable<Iter<'a, Sexp>>,
}

impl<'a> IterAtom<'a> {
    /// deconstruct a `Sexp` that is a list and starts with 'name'
    pub fn new(s: &'a Sexp, name: &str) -> SResult<IterAtom<'a>> {
        let v = s.list()?;
        let mut i = v.iter();
        let st = match i.next() {
            None => return Err(format!("missing first element {} in list {}", name, s).into()),
            Some(e) => e.string()?,
        };
        if st != name {
            return Err(format!("list {} doesn't start with {}, but with {}", s, name, st).into());
        }
        let i = i.peekable();
        Ok(IterAtom {
            name: name.into(),
            iter: i,
        })
    }

    fn expect<T, F>(&mut self, name: &str, get: F) -> SResult<T>
        where F: Fn(&Sexp) -> SResult<T>
    {
        match self.iter.next() {
            Some(x) => get(x),
            None => return Err(format!("missing {} field in {}", name, self.name).into()),
        }
    }

    /// expect an integer while iterating a `Sexp` list
    pub fn i(&mut self, name: &str) -> SResult<i64> {
        self.expect(name, |x| x.i().map_err(From::from))
    }

    /// expect a float while iterating a `Sexp` list
    pub fn f(&mut self, name: &str) -> SResult<f64> {
        self.expect(name, |x| x.f().map_err(From::from))
    }

    /// expect a String while iterating a `Sexp` list
    pub fn s(&mut self, name: &str) -> SResult<String> {
        self.expect(name, |x| x.s().map_err(From::from))
    }

    /// expect a list contained String while iterating a `Sexp` list
    pub fn s_in_list(&mut self, name: &str) -> SResult<String> {
        self.expect(name,
                    |x| x.named_value_s(name).map_err(From::from))
    }

    /// expect a list contained i64 while iterating a `Sexp` list
    pub fn i_in_list(&mut self, name: &str) -> SResult<i64> {
        self.expect(name, |x| x.named_value_i(name).map_err(From::from))
    }

    /// expect a list contained f64 while iterating a `Sexp` list
    pub fn f_in_list(&mut self, name: &str) -> SResult<f64> {
        self.expect(name, |x| x.named_value_f(name).map_err(From::from))
    }

    /// expect a `Sexp` while iterating a `Sexp` list
    pub fn t<T: FromSexp>(&mut self, name: &str) -> SResult<T> {
        self.expect(name, |x| T::from_sexp(x))
    }

        /// expect a list containing a `Sexp` while iterating a `Sexp` list
    pub fn t_in_list<T: FromSexp>(&mut self, name: &str) -> SResult<T> {
        self.expect(name, |x| T::from_sexp(x.named_value(name)?))
    }

    /// expect remainder of iterator to be a `Vec<T>`
    pub fn vec<T: FromSexp>(&mut self) -> SResult<Vec<T>> {
        let mut res = Vec::new();
        loop {
            match self.iter.next() {
                None => break,
                Some(e) => {
                    let p = from_sexp(e)?;
                    res.push(p);
                }
            }
        }
        Ok(res)
    }

    /// maybe something while iterating a `Sexp` list
    fn maybe<X, F>(&mut self, convert: F) -> Option<X>
        where F: Fn(&Sexp) -> SResult<X>
    {
        let res = match self.iter.peek() {
            None => None,
            Some(s) => {
                match convert(s) {
                    Ok(t) => Some(t),
                    Err(_) => None,
                }
            }
        };
        match res {
            Some(x) => {
                let _ = self.iter.next();
                Some(x)
            }
            x => x,
        }
    }

    /// maybe a `FromSexp` while iterating a `Sexp` list
    pub fn maybe_t<T: FromSexp>(&mut self) -> Option<T> {
        self.maybe(|x| T::from_sexp(x))
    }

    /// maybe a `String` while iterating a `Sexp` list
    pub fn maybe_s(&mut self) -> Option<String> {
        self.maybe(|x| x.s())
    }

    /// maybe an `i64` while iterating a `Sexp` list
    pub fn maybe_i(&mut self) -> Option<i64> {
        self.maybe(|x| x.i())
    }

    /// maybe an `f64` while iterating a `Sexp` list
    pub fn maybe_f(&mut self) -> Option<f64> {
        self.maybe(|x| x.f())
    }

    /// maybe a list containing a `String` while iterating a `Sexp` list
    pub fn maybe_s_in_list(&mut self, name:&str) -> Option<String> {
        self.maybe(|x| x.named_value_s(name))
    }

    /// maybe a list containing an `i64` while iterating a `Sexp` list
    pub fn maybe_i_in_list(&mut self, name:&str) -> Option<i64> {
        self.maybe(|x| x.named_value_i(name))
    }

    /// maybe a list containing an `f64` while iterating a `Sexp` list
    pub fn maybe_f_in_list(&mut self, name:&str) -> Option<f64> {
        self.maybe(|x| x.named_value_f(name))
    }
}
<|endoftext|>


<commit_before>use error::*;
use super::Command;

use constant::*;
use lib::fs::*;
use lib::io::*;
use lib::setting::*;
use std::collections::BTreeSet;
use std::path::Path;

pub struct Ignore {
    pub command: Option<String>,
    pub paths  : Vec<String>,
}

impl Command for Ignore {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Ignore);
    }

    fn main(&self) -> Result<(), CliError> {
        match self.command {
            Some(ref c) => match c.as_ref() {
                "add"     => self.add(),
                "remove"  => self.remove(),
                "current" => self.ignore_current_files(),
                "clear"   => self.clear_ignore_file(),
                _         => Err(From::from(self.usage())),
            },
            None => Err(From::from(self.usage())),
        }
    }
}

impl Ignore {
    fn add(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be added to \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_added = paths
            .iter()
            .map(append_prefix_if_need)
            .filter(|p| Path::new(p).is_file())
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_added {
            print_with_tag(1, Tag::Info, format!("\"{}\" will be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .union(&ignores_to_be_added)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn remove(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        let ignores_to_be_removed = paths
            .iter()
            .map(append_prefix_if_need)
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_removed {
            print_with_tag(1, Tag::Info, format!("\"{}\" will not be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .difference(&ignores_to_be_removed)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn ignore_current_files(&self) -> Result<(), CliError> {
        println!("do current command");

        Ok(())
    }

    fn clear_ignore_file(&self) -> Result<(), CliError> {
        println!("do clear command");

        Ok(())
    }
}
<commit_msg>[Refactoring] Do not use useless "self"<commit_after>use error::*;
use super::Command;

use constant::*;
use lib::fs::*;
use lib::io::*;
use lib::setting::*;
use std::collections::BTreeSet;
use std::path::Path;

pub struct Ignore {
    pub command: Option<String>,
    pub paths  : Vec<String>,
}

impl Command for Ignore {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Ignore);
    }

    fn main(&self) -> Result<(), CliError> {
        match self.command {
            Some(ref c) => match c.as_ref() {
                "add"     => self.add(),
                "remove"  => self.remove(),
                "current" => Self::ignore_current_files(),
                "clear"   => Self::clear_ignore_file(),
                _         => Err(From::from(self.usage())),
            },
            None => Err(From::from(self.usage())),
        }
    }
}

impl Ignore {
    fn add(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be added to \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_added = paths
            .iter()
            .map(append_prefix_if_need)
            .filter(|p| Path::new(p).is_file())
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_added {
            print_with_tag(1, Tag::Info, format!("\"{}\" will be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .union(&ignores_to_be_added)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn remove(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        let ignores_to_be_removed = paths
            .iter()
            .map(append_prefix_if_need)
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_removed {
            print_with_tag(1, Tag::Info, format!("\"{}\" will not be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .difference(&ignores_to_be_removed)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn ignore_current_files() -> Result<(), CliError> {
        println!("do current command");

        Ok(())
    }

    fn clear_ignore_file() -> Result<(), CliError> {
        println!("do clear command");

        Ok(())
    }
}
<|endoftext|>