<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use mock::{ClientRequest, HttpBuffer, ServerRequest};

use rand::{self, Rng, ThreadRng};

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::Cursor;
use std::{io, iter};

#[derive(Debug)]
struct TestFields {
    texts: HashMap<String, String>,
    files: HashMap<String, Vec<u8>>,
}

//#[test]
fn local_test() {
    do_test(test_client, "Regular");
}

#[test]
fn local_test_lazy() {
    do_test(test_client_lazy, "Lazy");
}

fn do_test(client: fn(&TestFields) -> HttpBuffer, name: &str) {
    let _ = ::env_logger::init();

    let test_fields = gen_test_fields();

    let buf = client(&test_fields);

    info!("Testing {} client", name);

    trace!(
        "\n==Test Buffer Begin==\n{}\n==Test Buffer End==",
        String::from_utf8_lossy(&buf.buf)
    );

    test_server(buf, test_fields);
}

fn gen_test_fields() -> TestFields {
    const MIN_FIELDS: usize = 1;
    const MAX_FIELDS: usize = 3;

    let mut rng = rand::weak_rng();

    let texts_count = rng.gen_range(MIN_FIELDS, MAX_FIELDS);
    let files_count = rng.gen_range(MIN_FIELDS, MAX_FIELDS);

    TestFields {
        texts: (0..texts_count).map(|_| (gen_string(), gen_string())).collect(),
        files: (0..files_count).map(|_| (gen_string(), gen_bytes())).collect(),
    }
}

fn gen_string() -> String {
    const MIN_LEN: usize = 2;
    const MAX_LEN: usize = 5;
    const MAX_DASHES: usize = 2;

    let mut rng_1 = rand::thread_rng();
    let mut rng_2 = rand::thread_rng();

    let str_len_1 = rng_1.gen_range(MIN_LEN, MAX_LEN + 1);
    let str_len_2 = rng_2.gen_range(MIN_LEN, MAX_LEN + 1);
    let num_dashes = rng_1.gen_range(0, MAX_DASHES + 1);

    rng_1.gen_ascii_chars().take(str_len_1)
        .chain(iter::repeat('-').take(num_dashes))
        .chain(rng_2.gen_ascii_chars().take(str_len_2))
        .collect()
}

fn gen_bytes() -> Vec<u8> {
    gen_string().into_bytes()
}

fn test_client(test_fields: &TestFields) -> HttpBuffer {
    use client::Multipart;

    let request = ClientRequest::default();

    let mut test_files = test_fields.files.iter();

    let mut multipart = Multipart::from_request(request).unwrap();

    // Intersperse file fields amongst text fields
    for (name, text) in &test_fields.texts {
        for (file_name, file) in &mut test_files {
            multipart.write_stream(file_name, &mut &**file, Some(file_name), None).unwrap();
        }

        multipart.write_text(name, text).unwrap();
    }

    // Write remaining files
    for (file_name, file) in test_files {
       multipart.write_stream(file_name, &mut &**file, None, None).unwrap();
    }

    multipart.send().unwrap()
}

fn test_client_lazy(test_fields: &TestFields) -> HttpBuffer {
    use client::lazy::Multipart;

    let mut multipart = Multipart::new();

    let mut test_files = test_fields.files.iter();

    for (name, text) in &test_fields.texts {
        for (file_name, file) in &mut test_files {
            multipart.add_stream(&**file_name, Cursor::new(file), Some(&**file_name), None);
        }

        multipart.add_text(&**name, &**text);
    }

    for (file_name, file) in test_files {
        multipart.add_stream(&**file_name, Cursor::new(file), None as Option<&str>, None);
    }

    let mut prepared = multipart.prepare().unwrap();

    let mut buf = Vec::new();

    let boundary = prepared.boundary().to_owned();
    let content_len = prepared.content_len();

    prepared.read_to_end(&mut buf).unwrap();

    HttpBuffer::with_buf(buf, boundary, content_len)
}

fn test_server(buf: HttpBuffer, mut fields: TestFields) {
    use server::{Multipart, MultipartData};

    let server_buf = buf.for_server();

    if let Some(content_len) = server_buf.content_len {
        assert!(content_len == server_buf.data.len() as u64, "Supplied content_len different from actual");
    }

    let mut multipart = Multipart::from_request(server_buf)
        .unwrap_or_else(|_| panic!("Buffer should be multipart!"));

    trace!("Fields for server test: {:?}", fields);

    while let Ok(Some(mut field)) = multipart.read_entry() {
        match field.data {
            MultipartData::Text(text) => {
                let test_text = fields.texts.remove(&field.name);

                assert!(
                    test_text.is_some(),
                    "Got text field that wasn't in original dataset: {:?} : {:?} ",
                    field.name, text
                );

                let test_text = test_text.unwrap();

                assert!(
                    text == test_text,
                    "Unexpected data for field {:?}: Expected {:?}, got {:?}",
                    field.name, test_text, text
                );

            },
            MultipartData::File(ref mut file) => {
                let test_bytes = fields.files.remove(&field.name).unwrap();

                let mut bytes = Vec::with_capacity(test_bytes.len());
                file.read_to_end(&mut bytes).unwrap();

                assert!(bytes == test_bytes, "Unexpected data for file {:?}: Expected {:?}, Got {:?}",
                        field.name, String::from_utf8_lossy(&test_bytes), String::from_utf8_lossy(&bytes)
                );
            },
        }
    }

    assert!(fields.texts.is_empty(), "Text fields were not exhausted! Text fields: {:?}", fields.texts);
    assert!(fields.files.is_empty(), "File fields were not exhausted! File fields: {:?}", fields.files);
}

<commit_msg>Remove unused imports in local_test<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use mock::{ClientRequest, HttpBuffer};

use rand::{self, Rng};

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::Cursor;
use std::iter;

#[derive(Debug)]
struct TestFields {
    texts: HashMap<String, String>,
    files: HashMap<String, Vec<u8>>,
}

//#[test]
fn local_test() {
    do_test(test_client, "Regular");
}

#[test]
fn local_test_lazy() {
    do_test(test_client_lazy, "Lazy");
}

fn do_test(client: fn(&TestFields) -> HttpBuffer, name: &str) {
    let _ = ::env_logger::init();

    let test_fields = gen_test_fields();

    let buf = client(&test_fields);

    info!("Testing {} client", name);

    trace!(
        "\n==Test Buffer Begin==\n{}\n==Test Buffer End==",
        String::from_utf8_lossy(&buf.buf)
    );

    test_server(buf, test_fields);
}

fn gen_test_fields() -> TestFields {
    const MIN_FIELDS: usize = 1;
    const MAX_FIELDS: usize = 3;

    let mut rng = rand::weak_rng();

    let texts_count = rng.gen_range(MIN_FIELDS, MAX_FIELDS);
    let files_count = rng.gen_range(MIN_FIELDS, MAX_FIELDS);

    TestFields {
        texts: (0..texts_count).map(|_| (gen_string(), gen_string())).collect(),
        files: (0..files_count).map(|_| (gen_string(), gen_bytes())).collect(),
    }
}

fn gen_string() -> String {
    const MIN_LEN: usize = 2;
    const MAX_LEN: usize = 5;
    const MAX_DASHES: usize = 2;

    let mut rng_1 = rand::thread_rng();
    let mut rng_2 = rand::thread_rng();

    let str_len_1 = rng_1.gen_range(MIN_LEN, MAX_LEN + 1);
    let str_len_2 = rng_2.gen_range(MIN_LEN, MAX_LEN + 1);
    let num_dashes = rng_1.gen_range(0, MAX_DASHES + 1);

    rng_1.gen_ascii_chars().take(str_len_1)
        .chain(iter::repeat('-').take(num_dashes))
        .chain(rng_2.gen_ascii_chars().take(str_len_2))
        .collect()
}

fn gen_bytes() -> Vec<u8> {
    gen_string().into_bytes()
}

fn test_client(test_fields: &TestFields) -> HttpBuffer {
    use client::Multipart;

    let request = ClientRequest::default();

    let mut test_files = test_fields.files.iter();

    let mut multipart = Multipart::from_request(request).unwrap();

    // Intersperse file fields amongst text fields
    for (name, text) in &test_fields.texts {
        for (file_name, file) in &mut test_files {
            multipart.write_stream(file_name, &mut &**file, Some(file_name), None).unwrap();
        }

        multipart.write_text(name, text).unwrap();
    }

    // Write remaining files
    for (file_name, file) in test_files {
       multipart.write_stream(file_name, &mut &**file, None, None).unwrap();
    }

    multipart.send().unwrap()
}

fn test_client_lazy(test_fields: &TestFields) -> HttpBuffer {
    use client::lazy::Multipart;

    let mut multipart = Multipart::new();

    let mut test_files = test_fields.files.iter();

    for (name, text) in &test_fields.texts {
        for (file_name, file) in &mut test_files {
            multipart.add_stream(&**file_name, Cursor::new(file), Some(&**file_name), None);
        }

        multipart.add_text(&**name, &**text);
    }

    for (file_name, file) in test_files {
        multipart.add_stream(&**file_name, Cursor::new(file), None as Option<&str>, None);
    }

    let mut prepared = multipart.prepare().unwrap();

    let mut buf = Vec::new();

    let boundary = prepared.boundary().to_owned();
    let content_len = prepared.content_len();

    prepared.read_to_end(&mut buf).unwrap();

    HttpBuffer::with_buf(buf, boundary, content_len)
}

fn test_server(buf: HttpBuffer, mut fields: TestFields) {
    use server::{Multipart, MultipartData};

    let server_buf = buf.for_server();

    if let Some(content_len) = server_buf.content_len {
        assert!(content_len == server_buf.data.len() as u64, "Supplied content_len different from actual");
    }

    let mut multipart = Multipart::from_request(server_buf)
        .unwrap_or_else(|_| panic!("Buffer should be multipart!"));

    trace!("Fields for server test: {:?}", fields);

    while let Ok(Some(mut field)) = multipart.read_entry() {
        match field.data {
            MultipartData::Text(text) => {
                let test_text = fields.texts.remove(&field.name);

                assert!(
                    test_text.is_some(),
                    "Got text field that wasn't in original dataset: {:?} : {:?} ",
                    field.name, text
                );

                let test_text = test_text.unwrap();

                assert!(
                    text == test_text,
                    "Unexpected data for field {:?}: Expected {:?}, got {:?}",
                    field.name, test_text, text
                );

            },
            MultipartData::File(ref mut file) => {
                let test_bytes = fields.files.remove(&field.name).unwrap();

                let mut bytes = Vec::with_capacity(test_bytes.len());
                file.read_to_end(&mut bytes).unwrap();

                assert!(bytes == test_bytes, "Unexpected data for file {:?}: Expected {:?}, Got {:?}",
                        field.name, String::from_utf8_lossy(&test_bytes), String::from_utf8_lossy(&bytes)
                );
            },
        }
    }

    assert!(fields.texts.is_empty(), "Text fields were not exhausted! Text fields: {:?}", fields.texts);
    assert!(fields.files.is_empty(), "File fields were not exhausted! File fields: {:?}", fields.files);
}

<|endoftext|>


<commit_before>use num::traits::{ToPrimitive, NumCast};
use std::marker::{PhantomData};
use std::collections::{VecMap};
use std::fmt::{Debug};
use image::{GenericImage, SubImage, Pixel};
use ::geom::{V2};
use super::canvas::{CanvasBuilder, Image};

/// A cache that loads sprites and stores them efficiently indexed by
/// enum constants given by the user.
///
/// Use an enum that contains names for all the sprites as the key type.
pub struct SpriteCache<T> {
    cache: VecMap<Image>,
    // Lock the cache into the specific enum type even though it doesn't
    // show up in the actual implementation, just to keep usage clearer.
    phantom: PhantomData<T>,
}

impl<T: Debug+Copy+SpriteKey> SpriteCache<T> {
    pub fn new() -> SpriteCache<T> {
        SpriteCache {
            cache: VecMap::new(),
            phantom: PhantomData,
        }
    }

    /// Try to retrieve an image with the given identifier.
    pub fn get(&self, key: T) -> Option<Image> {
        self.cache.get(&SpriteCache::index(key)).map(|&x| x)
    }

    /// Add an image to the CanvasBuilder atlas for the given identifier key.
    ///
    /// Trying to add multiple sprites with the same key is considered a
    /// bug and will cause a panic.
    pub fn add<P, I>(&mut self, builder: &mut CanvasBuilder, key: T, offset: V2<i32>, image: &I)
        where P: Pixel<Subpixel=u8> + 'static,
              I: GenericImage<Pixel=P>
    {
        let idx = SpriteCache::index(key);
        assert!(self.cache.get(&idx).is_none(), format!("Adding sprite {:?} twice", key));

        self.cache.insert(idx, builder.add_image(offset, image));
    }

    /// Add multiple images from a sprite sheet.
    ///
    /// The sheet images are assumed to be in a grid with sprite_size
    /// cells. The sheet is read from top to bottom in left-to-right
    /// rows. Sprites are read and given cache keys corresponding to the
    /// values in the keys Vec as long as there are items left in keys.
    /// If there are more keys in the keys Vec than there are sprites in
    /// the sprite sheet, the function will panic.
    pub fn batch_add<P, I>(&mut self, builder: &mut CanvasBuilder, offset: V2<i32>, sprite_size: V2<u32>,
                           sprite_sheet: &mut I, keys: Vec<T>)
        where P: Pixel<Subpixel=u8> + 'static,
              I: GenericImage<Pixel=P> + 'static
    {
        let (sw, sh) = sprite_sheet.dimensions();
        let V2(w, h) = sprite_size;
        let (cols, rows) = (sw / sprite_size.0, sh / sprite_size.1);
        assert!(keys.len() as u32 <= rows * cols, "More keys specified than there are sprites on the sheet");
        for i in 0..keys.len() {
            let sub = SubImage::new(sprite_sheet, (i as u32 % cols) * w, (i as u32 / cols) * h, w, h);
            self.add(builder, keys[i], offset, &sub);
        }
    }

    fn index(key: T) -> usize {
        key.to_usize()
    }
}

// TODO: Find a way to convert the type param to usize that can use a
// derive-statment or something, instead of needing the boilerplate of
// implementing this trait...
pub trait SpriteKey {
    fn to_usize(self) -> usize;
}

impl<T: ToPrimitive> SpriteKey for T {
    fn to_usize(self) -> usize {
        NumCast::from(self).unwrap()
    }
}
<commit_msg>API support for sprite sequences<commit_after>use num::traits::{ToPrimitive, NumCast};
use std::marker::{PhantomData};
use std::collections::{VecMap};
use std::fmt::{Debug};
use image::{GenericImage, SubImage, Pixel};
use ::geom::{V2};
use super::canvas::{CanvasBuilder, Image};

/// A cache that loads sprites and stores them efficiently indexed by
/// enum constants given by the user.
///
/// Use an enum that contains names for all the sprites as the key type.
pub struct SpriteCache<T> {
    cache: VecMap<Image>,
    // Lock the cache into the specific enum type even though it doesn't
    // show up in the actual implementation, just to keep usage clearer.
    phantom: PhantomData<T>,
}

impl<T: Debug+Copy+SpriteKey> SpriteCache<T> {
    pub fn new() -> SpriteCache<T> {
        SpriteCache {
            cache: VecMap::new(),
            phantom: PhantomData,
        }
    }

    /// Try to retrieve an image with the given identifier.
    pub fn get(&self, key: T) -> Option<Image> {
        self.cache.get(&SpriteCache::index(key)).map(|&x| x)
    }

    /// Try to retrieve an image some steps ahead of the given key.
    ///
    /// Useful for animations and variants where there are deterministic
    /// consecutive sequences of frames and you don't want to hardcode
    /// every frame as a separate constant.
    pub fn get_nth(&self, key: T, offset: usize) -> Option<Image> {
        self.cache.get(&(SpriteCache::index(key) + offset)).map(|&x| x)
    }

    /// Add an image to the CanvasBuilder atlas for the given identifier key.
    ///
    /// Trying to add multiple sprites with the same key is considered a
    /// bug and will cause a panic.
    pub fn add<P, I>(&mut self, builder: &mut CanvasBuilder, key: T, offset: V2<i32>, image: &I)
        where P: Pixel<Subpixel=u8> + 'static,
              I: GenericImage<Pixel=P>
    {
        let idx = SpriteCache::index(key);
        assert!(self.cache.get(&idx).is_none(), format!("Adding sprite {:?} twice", key));

        self.cache.insert(idx, builder.add_image(offset, image));
    }

    /// Add multiple images from a sprite sheet.
    ///
    /// The sheet images are assumed to be in a grid with sprite_size
    /// cells. The sheet is read from top to bottom in left-to-right
    /// rows. Sprites are read and given cache keys corresponding to the
    /// values in the keys Vec as long as there are items left in keys.
    /// If there are more keys in the keys Vec than there are sprites in
    /// the sprite sheet, the function will panic.
    pub fn batch_add<P, I>(&mut self, builder: &mut CanvasBuilder, offset: V2<i32>, sprite_size: V2<u32>,
                           sprite_sheet: &mut I, keys: Vec<T>)
        where P: Pixel<Subpixel=u8> + 'static,
              I: GenericImage<Pixel=P> + 'static
    {
        let (sw, sh) = sprite_sheet.dimensions();
        let V2(w, h) = sprite_size;
        let (cols, rows) = (sw / sprite_size.0, sh / sprite_size.1);
        assert!(keys.len() as u32 <= rows * cols, "More keys specified than there are sprites on the sheet");
        for i in 0..keys.len() {
            let sub = SubImage::new(sprite_sheet, (i as u32 % cols) * w, (i as u32 / cols) * h, w, h);
            self.add(builder, keys[i], offset, &sub);
        }
    }

    fn index(key: T) -> usize {
        key.to_usize()
    }
}

// TODO: Find a way to convert the type param to usize that can use a
// derive-statment or something, instead of needing the boilerplate of
// implementing this trait...
pub trait SpriteKey {
    fn to_usize(self) -> usize;
}

impl<T: ToPrimitive> SpriteKey for T {
    fn to_usize(self) -> usize {
        NumCast::from(self).unwrap()
    }
}
<|endoftext|>


<commit_before>extern crate proxer;

use proxer::Client;
use proxer::parameter;
use proxer::Endpoint;

fn main() {

    let prxr = Client::with_env_key("PROXER_API_KEY").unwrap();

    let res = prxr.api().info().get_fullentry(parameter::InfoGetFullEntry {id: 53}).send();

    eprintln!("{:#?}", res);
}
<commit_msg>add test<commit_after>extern crate proxer;

use proxer::Client;
use proxer::parameter;
use proxer::Endpoint;
use std::error::Error;
use proxer::Pager;
use proxer::Pageable;
use std::ops::Add;

fn main() {
    get_comments();
}

fn get_fullentry() {
    let prxr = Client::with_env_key("PROXER_API_KEY").unwrap();

    let req = prxr
        .api()
        .info()
        .get_fullentry(parameter::InfoGetFullEntry {id: 53});

    let res = prxr.execute(req);

    eprintln!("{:#?}", res);
}

fn get_comments() {
    let prxr = Client::with_env_key("PROXER_API_KEY").unwrap();

    let req = prxr.api().info().get_comments(parameter::InfoGetComments {
        id: 53,
        p: None,
        limit: None,
        sort: None
    });

    let pager = req.pager(prxr);

    let mut counter = 0;

    for comment in pager {
        counter = counter.add(1);
        let comment = comment.unwrap();

        println!("{}", counter);
        println!("{}", comment.username);
        println!("{}", comment.episode);
        println!("{}", comment.rating);

        println!();

    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use error::{Result, Error};
use hcore::os::users;
use hcore::package::PackageInstall;

static LOGKEY: &'static str = "UR";

const DEFAULT_USER: &'static str = "hab";
const DEFAULT_GROUP: &'static str = "hab";

/// This function checks to see if a custom SVC_USER and SVC_GROUP has
/// been specified as part of the package metadata.
/// If a pkg_svc_user and pkg_svc_group have been defined, check if:
///     a) we are root
///     b) we are the specified user:group
///     c) fail otherwise
/// If pkg_svc_user and pkg_svc_group have NOT been defined, return None.
fn check_pkg_user_and_group(pkg_install: &PackageInstall) -> Result<Option<(String, String)>> {
    let svc_user = try!(pkg_install.svc_user());
    let svc_group = try!(pkg_install.svc_group());
    match (svc_user, svc_group) {
        (Some(user), Some(group)) => {
            // a package has a SVC_USER and SVC_GROUP defined,
            // these MUST exist in order to continue
            debug!("SVC_USER = {}", &user);
            debug!("SVC_GROUP = {}", &group);
            if let None = users::get_uid_by_name(&user) {
                return Err(sup_error!(Error::Permissions(format!("Package requires user {} to \
                                                                  exist, but it doesn't",
                                                                 user))));
            }
            if let None = users::get_gid_by_name(&group) {
                return Err(sup_error!(Error::Permissions(format!("Package requires group {} \
                                                                  to exist, but it doesn't",
                                                                 group))));
            }

            let current_user = users::get_current_username();
            let current_group = users::get_current_groupname();

            if let None = current_user {
                return Err(sup_error!(Error::Permissions("Can't determine current user"
                    .to_string())));
            }

            if let None = current_group {
                return Err(sup_error!(Error::Permissions("Can't determine current group"
                    .to_string())));
            }

            let current_user = current_user.unwrap();
            let current_group = current_group.unwrap();

            if current_user == "root" {
                Ok(Some((user, group)))
            } else {
                if current_user == user && current_group == group {
                    // ok, sup is running as svc_user/svc_group already
                    Ok(Some((user, group)))
                } else {
                    let msg = format!("Package must run as {}:{} or root", &user, &group);
                    return Err(sup_error!(Error::Permissions(msg)));
                }
            }
        }
        _ => {
            debug!("User/group not specified in package, running with default");
            Ok(None)
        }
    }
}

/// checks to see if hab/hab exists, if not, fall back to
/// current user/group. If that fails, then return an error.
fn get_default_user_and_group() -> Result<(String, String)> {
    let uid = users::get_uid_by_name(DEFAULT_USER);
    let gid = users::get_gid_by_name(DEFAULT_GROUP);
    match (uid, gid) {
        (Some(uid), Some(gid)) => return Ok((DEFAULT_USER.to_string(), DEFAULT_GROUP.to_string())),
        _ => {
            debug!("hab:hab does NOT exist");
            let user = users::get_current_username();
            let group = users::get_current_groupname();
            match (user, group) {
                (Some(user), Some(group)) => {
                    debug!("Running as {}/{}", user, group);
                    return Ok((user, group));
                }
                _ => {
                    return Err(sup_error!(Error::Permissions("Can't determine current user:group"
                        .to_string())))
                }
            }
        }
    }
}

/// check and see if a user/group is specified in package metadata.
/// if not, we'll try and use hab/hab.
/// If hab/hab doesn't exist, try to use (current username, current group).
/// If that doesn't work, then give up.
#[cfg(any(target_os="linux", target_os="macos"))]
pub fn get_user_and_group(pkg_install: &PackageInstall) -> Result<(String, String)> {
    if let Some((user, group)) = try!(check_pkg_user_and_group(&pkg_install)) {
        Ok((user, group))
    } else {
        let defaults = try!(get_default_user_and_group());
        Ok(defaults)
    }
}

#[cfg(target_os = "windows")]
pub fn get_user_and_group(pkg_install: &PackageInstall) -> Result<(String, String)> {
    unimplemented!();
}

pub fn user_name_to_uid(user: &str) -> Option<u32> {
    users::get_uid_by_name(user)
}

pub fn group_name_to_gid(group: &str) -> Option<u32> {
    users::get_gid_by_name(group)
}
<commit_msg>removing unnecessary os splitting in supervisor<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use error::{Result, Error};
use hcore::os::users;
use hcore::package::PackageInstall;

static LOGKEY: &'static str = "UR";

const DEFAULT_USER: &'static str = "hab";
const DEFAULT_GROUP: &'static str = "hab";

/// This function checks to see if a custom SVC_USER and SVC_GROUP has
/// been specified as part of the package metadata.
/// If a pkg_svc_user and pkg_svc_group have been defined, check if:
///     a) we are root
///     b) we are the specified user:group
///     c) fail otherwise
/// If pkg_svc_user and pkg_svc_group have NOT been defined, return None.
fn check_pkg_user_and_group(pkg_install: &PackageInstall) -> Result<Option<(String, String)>> {
    let svc_user = try!(pkg_install.svc_user());
    let svc_group = try!(pkg_install.svc_group());
    match (svc_user, svc_group) {
        (Some(user), Some(group)) => {
            // a package has a SVC_USER and SVC_GROUP defined,
            // these MUST exist in order to continue
            debug!("SVC_USER = {}", &user);
            debug!("SVC_GROUP = {}", &group);
            if let None = users::get_uid_by_name(&user) {
                return Err(sup_error!(Error::Permissions(format!("Package requires user {} to \
                                                                  exist, but it doesn't",
                                                                 user))));
            }
            if let None = users::get_gid_by_name(&group) {
                return Err(sup_error!(Error::Permissions(format!("Package requires group {} \
                                                                  to exist, but it doesn't",
                                                                 group))));
            }

            let current_user = users::get_current_username();
            let current_group = users::get_current_groupname();

            if let None = current_user {
                return Err(sup_error!(Error::Permissions("Can't determine current user"
                    .to_string())));
            }

            if let None = current_group {
                return Err(sup_error!(Error::Permissions("Can't determine current group"
                    .to_string())));
            }

            let current_user = current_user.unwrap();
            let current_group = current_group.unwrap();

            if current_user == "root" {
                Ok(Some((user, group)))
            } else {
                if current_user == user && current_group == group {
                    // ok, sup is running as svc_user/svc_group already
                    Ok(Some((user, group)))
                } else {
                    let msg = format!("Package must run as {}:{} or root", &user, &group);
                    return Err(sup_error!(Error::Permissions(msg)));
                }
            }
        }
        _ => {
            debug!("User/group not specified in package, running with default");
            Ok(None)
        }
    }
}

/// checks to see if hab/hab exists, if not, fall back to
/// current user/group. If that fails, then return an error.
fn get_default_user_and_group() -> Result<(String, String)> {
    let uid = users::get_uid_by_name(DEFAULT_USER);
    let gid = users::get_gid_by_name(DEFAULT_GROUP);
    match (uid, gid) {
        (Some(uid), Some(gid)) => return Ok((DEFAULT_USER.to_string(), DEFAULT_GROUP.to_string())),
        _ => {
            debug!("hab:hab does NOT exist");
            let user = users::get_current_username();
            let group = users::get_current_groupname();
            match (user, group) {
                (Some(user), Some(group)) => {
                    debug!("Running as {}/{}", user, group);
                    return Ok((user, group));
                }
                _ => {
                    return Err(sup_error!(Error::Permissions("Can't determine current user:group"
                        .to_string())))
                }
            }
        }
    }
}

/// check and see if a user/group is specified in package metadata.
/// if not, we'll try and use hab/hab.
/// If hab/hab doesn't exist, try to use (current username, current group).
/// If that doesn't work, then give up.
pub fn get_user_and_group(pkg_install: &PackageInstall) -> Result<(String, String)> {
    if let Some((user, group)) = try!(check_pkg_user_and_group(&pkg_install)) {
        Ok((user, group))
    } else {
        let defaults = try!(get_default_user_and_group());
        Ok(defaults)
    }
}

pub fn user_name_to_uid(user: &str) -> Option<u32> {
    users::get_uid_by_name(user)
}

pub fn group_name_to_gid(group: &str) -> Option<u32> {
    users::get_gid_by_name(group)
}
<|endoftext|>


<commit_before>use std::process::exit;

use clap;
use cargo_shim::{
    Profile,
    CargoPackage,
    CargoProject,
    CargoTarget,
    BuildType,
    BuildConfig,
    TargetKind,
    CargoResult,
    target_to_build_target
};

use config::Config;
use emscripten::initialize_emscripten;
use error::Error;
use wasm;

pub struct BuildArgsMatcher< 'a > {
    pub matches: &'a clap::ArgMatches< 'a >,
    pub project: &'a CargoProject
}

impl< 'a > BuildArgsMatcher< 'a > {
    fn requested_build_type( &self ) -> BuildType {
        if self.matches.is_present( "release" ) {
            BuildType::Release
        } else {
            BuildType::Debug
        }
    }

    pub fn targeting_emscripten_asmjs( &self ) -> bool {
        !self.targeting_emscripten_wasm() && !self.targeting_native_wasm()
    }

    pub fn targeting_emscripten_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm-emscripten" )
    }

    pub fn targeting_native_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm" )
    }

    pub fn targeting_wasm( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_native_wasm()
    }

    pub fn targeting_emscripten( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_emscripten_asmjs()
    }

    fn use_system_emscripten( &self ) -> bool {
        self.matches.is_present( "use-system-emscripten" )
    }

    fn build_type( &self ) -> BuildType {
        let build_type = self.requested_build_type();
        if self.targeting_native_wasm() && build_type == BuildType::Debug {
            // TODO: Remove this in the future.
            println_err!( "warning: debug builds on the wasm-unknown-unknown are currently totally broken" );
            println_err!( "         forcing a release build" );
            return BuildType::Release;
        }

        build_type
    }

    fn package( &self ) -> Result< Option< &CargoPackage >, Error > {
        if let Some( name ) = self.matches.value_of( "package" ) {
            match self.project.packages.iter().find( |package| package.name == name ) {
                None => Err( Error::ConfigurationError( format!( "package `{}` not found", name ) ) ),
                package => Ok( package )
            }
        } else {
            Ok( None )
        }
    }

    pub fn package_or_default( &self ) -> Result< &CargoPackage, Error > {
        Ok( self.package()?.unwrap_or_else( || self.project.default_package() ) )
    }

    fn target( &'a self, package: &'a CargoPackage ) -> Result< Option< &'a CargoTarget >, Error > {
        let targets = &package.targets;
        if self.matches.is_present( "lib" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Lib ) {
                None => return Err( Error::ConfigurationError( format!( "no library targets found" ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bin" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bin && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bin target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "example" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Example && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no example target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bench" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bench && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bench target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else {
            Ok( None )
        }
    }

    pub fn target_or_select< F >( &'a self, package: &'a CargoPackage, filter: F ) -> Result< Vec< &'a CargoTarget >, Error >
        where for< 'r > F: Fn( &'r CargoTarget ) -> bool
    {
        Ok( self.target( package )?.map( |target| vec![ target ] ).unwrap_or_else( || {
            package.targets.iter().filter( |target| filter( target ) ).collect()
        }))
    }

    fn triplet_or_default( &self ) -> &str {
        if self.matches.is_present( "target-webasm") {
            "wasm32-unknown-unknown"
        } else if self.matches.is_present( "target-webasm-emscripten" ) {
            "wasm32-unknown-emscripten"
        } else {
            "asmjs-unknown-emscripten"
        }
    }

    fn features( &self ) -> Vec< &str > {
        if let Some( features ) = self.matches.value_of( "features" ) {
            features.split_whitespace().collect()
        } else {
            Vec::new()
        }
    }

    pub fn prepare_builder( &self, config: &Config, package: &CargoPackage, target: &CargoTarget, profile: Profile ) -> Builder {
        let mut extra_paths = Vec::new();
        let mut extra_rustflags = Vec::new();
        let mut extra_environment = Vec::new();

        if self.targeting_emscripten() {
            if let Some( emscripten ) = initialize_emscripten( self.use_system_emscripten(), self.targeting_wasm() ) {
                extra_paths.push( emscripten.emscripten_path.clone() );

                let emscripten_path = emscripten.emscripten_path.to_string_lossy().into_owned();
                let emscripten_llvm_path = emscripten.emscripten_llvm_path.to_string_lossy().into_owned();

                extra_environment.push( ("EMSCRIPTEN".to_owned(), emscripten_path) );
                extra_environment.push( ("EMSCRIPTEN_FASTCOMP".to_owned(), emscripten_llvm_path.clone()) );
                extra_environment.push( ("LLVM".to_owned(), emscripten_llvm_path) );
                if let Some( binaryen_path ) = emscripten.binaryen_path {
                    let binaryen_path = binaryen_path.to_string_lossy().into_owned();
                    extra_environment.push( ("BINARYEN".to_owned(), binaryen_path) );
                }
            }
        }

        if let Some( ref link_args ) = config.link_args {
            for arg in link_args {
                if arg.contains( " " ) {
                    // Not sure how to handle spaces, as `-C link-arg="{}"` doesn't work.
                    println_err!( "error: you have a space in one of the entries in `link-args` in your `Web.toml`;" );
                    println_err!( "       this is currently unsupported - aborting!" );
                    exit( 101 );
                }

                extra_rustflags.push( "-C".to_owned() );
                extra_rustflags.push( format!( "link-arg={}", arg ) );
            }
        }

        if self.targeting_native_wasm() && self.requested_build_type() == BuildType::Debug {
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "debuginfo=2".to_owned() );
        }

        Builder::new( BuildConfig {
            build_target: target_to_build_target( target, profile ),
            build_type: self.build_type(),
            triplet: Some( self.triplet_or_default().into() ),
            package: Some( package.name.clone() ),
            features: self.features().into_iter().map( |feature| feature.to_owned() ).collect(),
            no_default_features: self.matches.is_present( "no-default-features" ),
            enable_all_features: self.matches.is_present( "all-features" ),
            extra_paths,
            extra_rustflags,
            extra_environment
        })
    }
}

pub struct Builder( BuildConfig );

impl Builder {
    pub fn new( build_config: BuildConfig ) -> Self {
        Builder( build_config )
    }

    pub fn run( &self ) -> Result< CargoResult, Error > {
        let mut result = self.0.build();
        if result.is_ok() == false {
            return Err( Error::BuildError );
        }

        let extra_artifacts = wasm::process_wasm_files( &self.0, result.artifacts() );
        for artifact in extra_artifacts {
            result.add_artifact( artifact );
        }

        Ok( result )
    }
}
<commit_msg>Set the NO_EXIT_RUNTIME link arg when compiling under Emscripten<commit_after>use std::process::exit;

use clap;
use cargo_shim::{
    Profile,
    CargoPackage,
    CargoProject,
    CargoTarget,
    BuildType,
    BuildConfig,
    TargetKind,
    CargoResult,
    target_to_build_target
};

use config::Config;
use emscripten::initialize_emscripten;
use error::Error;
use wasm;

pub struct BuildArgsMatcher< 'a > {
    pub matches: &'a clap::ArgMatches< 'a >,
    pub project: &'a CargoProject
}

impl< 'a > BuildArgsMatcher< 'a > {
    fn requested_build_type( &self ) -> BuildType {
        if self.matches.is_present( "release" ) {
            BuildType::Release
        } else {
            BuildType::Debug
        }
    }

    pub fn targeting_emscripten_asmjs( &self ) -> bool {
        !self.targeting_emscripten_wasm() && !self.targeting_native_wasm()
    }

    pub fn targeting_emscripten_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm-emscripten" )
    }

    pub fn targeting_native_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm" )
    }

    pub fn targeting_wasm( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_native_wasm()
    }

    pub fn targeting_emscripten( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_emscripten_asmjs()
    }

    fn use_system_emscripten( &self ) -> bool {
        self.matches.is_present( "use-system-emscripten" )
    }

    fn build_type( &self ) -> BuildType {
        let build_type = self.requested_build_type();
        if self.targeting_native_wasm() && build_type == BuildType::Debug {
            // TODO: Remove this in the future.
            println_err!( "warning: debug builds on the wasm-unknown-unknown are currently totally broken" );
            println_err!( "         forcing a release build" );
            return BuildType::Release;
        }

        build_type
    }

    fn package( &self ) -> Result< Option< &CargoPackage >, Error > {
        if let Some( name ) = self.matches.value_of( "package" ) {
            match self.project.packages.iter().find( |package| package.name == name ) {
                None => Err( Error::ConfigurationError( format!( "package `{}` not found", name ) ) ),
                package => Ok( package )
            }
        } else {
            Ok( None )
        }
    }

    pub fn package_or_default( &self ) -> Result< &CargoPackage, Error > {
        Ok( self.package()?.unwrap_or_else( || self.project.default_package() ) )
    }

    fn target( &'a self, package: &'a CargoPackage ) -> Result< Option< &'a CargoTarget >, Error > {
        let targets = &package.targets;
        if self.matches.is_present( "lib" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Lib ) {
                None => return Err( Error::ConfigurationError( format!( "no library targets found" ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bin" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bin && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bin target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "example" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Example && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no example target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bench" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bench && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bench target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else {
            Ok( None )
        }
    }

    pub fn target_or_select< F >( &'a self, package: &'a CargoPackage, filter: F ) -> Result< Vec< &'a CargoTarget >, Error >
        where for< 'r > F: Fn( &'r CargoTarget ) -> bool
    {
        Ok( self.target( package )?.map( |target| vec![ target ] ).unwrap_or_else( || {
            package.targets.iter().filter( |target| filter( target ) ).collect()
        }))
    }

    fn triplet_or_default( &self ) -> &str {
        if self.matches.is_present( "target-webasm") {
            "wasm32-unknown-unknown"
        } else if self.matches.is_present( "target-webasm-emscripten" ) {
            "wasm32-unknown-emscripten"
        } else {
            "asmjs-unknown-emscripten"
        }
    }

    fn features( &self ) -> Vec< &str > {
        if let Some( features ) = self.matches.value_of( "features" ) {
            features.split_whitespace().collect()
        } else {
            Vec::new()
        }
    }

    pub fn prepare_builder( &self, config: &Config, package: &CargoPackage, target: &CargoTarget, profile: Profile ) -> Builder {
        let mut extra_paths = Vec::new();
        let mut extra_rustflags = Vec::new();
        let mut extra_environment = Vec::new();

        if self.targeting_emscripten() {
            if let Some( emscripten ) = initialize_emscripten( self.use_system_emscripten(), self.targeting_wasm() ) {
                extra_paths.push( emscripten.emscripten_path.clone() );

                let emscripten_path = emscripten.emscripten_path.to_string_lossy().into_owned();
                let emscripten_llvm_path = emscripten.emscripten_llvm_path.to_string_lossy().into_owned();

                extra_environment.push( ("EMSCRIPTEN".to_owned(), emscripten_path) );
                extra_environment.push( ("EMSCRIPTEN_FASTCOMP".to_owned(), emscripten_llvm_path.clone()) );
                extra_environment.push( ("LLVM".to_owned(), emscripten_llvm_path) );
                if let Some( binaryen_path ) = emscripten.binaryen_path {
                    let binaryen_path = binaryen_path.to_string_lossy().into_owned();
                    extra_environment.push( ("BINARYEN".to_owned(), binaryen_path) );
                }
            }

            // When compiling tests we want the exit runtime,
            // when compiling for the Web we don't want it
            // since that's more efficient.
            let exit_runtime = profile == Profile::Main;

            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "link-arg=-s".to_owned() );
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( format!( "link-arg=NO_EXIT_RUNTIME={}", exit_runtime as u32 ) );
        }

        if let Some( ref link_args ) = config.link_args {
            for arg in link_args {
                if arg.contains( " " ) {
                    // Not sure how to handle spaces, as `-C link-arg="{}"` doesn't work.
                    println_err!( "error: you have a space in one of the entries in `link-args` in your `Web.toml`;" );
                    println_err!( "       this is currently unsupported - aborting!" );
                    exit( 101 );
                }

                extra_rustflags.push( "-C".to_owned() );
                extra_rustflags.push( format!( "link-arg={}", arg ) );
            }
        }

        if self.targeting_native_wasm() && self.requested_build_type() == BuildType::Debug {
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "debuginfo=2".to_owned() );
        }

        Builder::new( BuildConfig {
            build_target: target_to_build_target( target, profile ),
            build_type: self.build_type(),
            triplet: Some( self.triplet_or_default().into() ),
            package: Some( package.name.clone() ),
            features: self.features().into_iter().map( |feature| feature.to_owned() ).collect(),
            no_default_features: self.matches.is_present( "no-default-features" ),
            enable_all_features: self.matches.is_present( "all-features" ),
            extra_paths,
            extra_rustflags,
            extra_environment
        })
    }
}

pub struct Builder( BuildConfig );

impl Builder {
    pub fn new( build_config: BuildConfig ) -> Self {
        Builder( build_config )
    }

    pub fn run( &self ) -> Result< CargoResult, Error > {
        let mut result = self.0.build();
        if result.is_ok() == false {
            return Err( Error::BuildError );
        }

        let extra_artifacts = wasm::process_wasm_files( &self.0, result.artifacts() );
        for artifact in extra_artifacts {
            result.add_artifact( artifact );
        }

        Ok( result )
    }
}
<|endoftext|>


<commit_before>//! Prepared statements cache for faster execution.
extern crate lru_cache;

use {Result, Connection, Statement};
use self::lru_cache::LruCache;

/// Prepared statements cache.
///
/// FIXME limitation: the same SQL can be cached only once...
#[derive(Debug)]
pub struct StatementCache<'conn> {
    conn: &'conn Connection,
    cache: LruCache<String, Statement<'conn>>,
}

pub struct CachedStatement<'conn> {
    stmt: Statement<'conn>,
    cache: &'conn StatementCache<'conn>,
    pub cacheable : bool,
}

impl<'conn> Drop for CachedStatement<'conn> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if self.cacheable {
            // FIXME cannot borrow immutable borrowed content `*self.cache` as mutable
            //self.cache.release(self.stmt, false);
        } else {
            self.stmt.finalize_();
        }
    }
}

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
        StatementCache {
            conn: conn,
            cache: LruCache::new(capacity),
        }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    ///
    /// # Failure
    ///
    /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails.
    pub fn get(&mut self, sql: &str) -> Result<Statement<'conn>> {
        let stmt = self.cache.remove(sql);
        match stmt {
            Some(stmt) => Ok(stmt),
            _ => self.conn.prepare(sql),
        }
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed
    /// and the underlying SQLite finalize call fails.
    pub fn release(&mut self, mut stmt: Statement<'conn>, discard: bool) -> Result<()> {
        if discard {
            return stmt.finalize();
        }
        stmt.reset_if_needed();
        stmt.clear_bindings();
        self.cache.insert(stmt.sql(), stmt).map_or(Ok(()), |stmt| stmt.finalize())
    }

    /// Flush the prepared statement cache
    pub fn clear(&mut self) {
        self.cache.clear();
    }

    /// Return current cache size.
    pub fn len(&self) -> usize {
        self.cache.len()
    }

    /// Return maximum cache size.
    pub fn capacity(&self) -> usize {
        self.cache.capacity()
    }

    /// Set the maximum number of cached statements.
    pub fn set_capacity(&mut self, capacity: usize) {
        self.cache.set_capacity(capacity);
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::StatementCache;

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let mut cache = StatementCache::new(&db, 10);
        assert_eq!(0, cache.len());
        assert_eq!(10, cache.capacity());

        let sql = "PRAGMA schema_version";
        let mut stmt = cache.get(sql).unwrap();
        assert_eq!(0, cache.len());
        assert_eq!(0, stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));

        // println!("NEW {:?}", stmt);
        cache.release(stmt, false).unwrap();
        assert_eq!(1, cache.len());

        stmt = cache.get(sql).unwrap();
        assert_eq!(0, cache.len());
        assert_eq!(0, stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));

        // println!("CACHED {:?}", stmt);
        cache.release(stmt, true).unwrap();
        assert_eq!(0, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(10, cache.capacity());
    }
}
<commit_msg>Introduce a RefCell in CachedStatement.<commit_after>//! Prepared statements cache for faster execution.
extern crate lru_cache;

use std::cell::RefCell;
use {Result, Connection, Statement};
use self::lru_cache::LruCache;

/// Prepared statements cache.
///
/// FIXME limitation: the same SQL can be cached only once...
#[derive(Debug)]
pub struct StatementCache<'conn> {
    conn: &'conn Connection,
    cache: LruCache<String, Statement<'conn>>,
}

pub struct CachedStatement<'conn> {
    stmt: Statement<'conn>,
    cache: RefCell<StatementCache<'conn>>,
    pub cacheable : bool,
}

impl<'conn> Drop for CachedStatement<'conn> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if self.cacheable {
            // FIXME: cannot move out of type `cache::CachedStatement<'conn>`, which defines the `Drop` trait [E0509]
            //self.cache.borrow_mut().release(self.stmt, false);
        } else {
            self.stmt.finalize_();
        }
    }
}

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
        StatementCache {
            conn: conn,
            cache: LruCache::new(capacity),
        }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    ///
    /// # Failure
    ///
    /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails.
    pub fn get(&mut self, sql: &str) -> Result<Statement<'conn>> {
        let stmt = self.cache.remove(sql);
        match stmt {
            Some(stmt) => Ok(stmt),
            _ => self.conn.prepare(sql),
        }
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed
    /// and the underlying SQLite finalize call fails.
    pub fn release(&mut self, mut stmt: Statement<'conn>, discard: bool) -> Result<()> {
        if discard {
            return stmt.finalize();
        }
        stmt.reset_if_needed();
        stmt.clear_bindings();
        self.cache.insert(stmt.sql(), stmt).map_or(Ok(()), |stmt| stmt.finalize())
    }

    /// Flush the prepared statement cache
    pub fn clear(&mut self) {
        self.cache.clear();
    }

    /// Return current cache size.
    pub fn len(&self) -> usize {
        self.cache.len()
    }

    /// Return maximum cache size.
    pub fn capacity(&self) -> usize {
        self.cache.capacity()
    }

    /// Set the maximum number of cached statements.
    pub fn set_capacity(&mut self, capacity: usize) {
        self.cache.set_capacity(capacity);
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::StatementCache;

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let mut cache = StatementCache::new(&db, 10);
        assert_eq!(0, cache.len());
        assert_eq!(10, cache.capacity());

        let sql = "PRAGMA schema_version";
        let mut stmt = cache.get(sql).unwrap();
        assert_eq!(0, cache.len());
        assert_eq!(0, stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));

        // println!("NEW {:?}", stmt);
        cache.release(stmt, false).unwrap();
        assert_eq!(1, cache.len());

        stmt = cache.get(sql).unwrap();
        assert_eq!(0, cache.len());
        assert_eq!(0, stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));

        // println!("CACHED {:?}", stmt);
        cache.release(stmt, true).unwrap();
        assert_eq!(0, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(10, cache.capacity());
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::io::{BufRead, Write};
use std::thread;
use std::net::{TcpListener, TcpStream};
use std::io::BufReader;

use ::page;

/// modified from gkbrk's demo:
/// https://gist.github.com/gkbrk/bea6dee7c0478395b718

fn handle_client(mut stream: TcpStream) {
let mut reader = BufReader::new(stream.try_clone().unwrap());
    stream.write("220 urdict 0.1.0\r\n".as_bytes()).unwrap();
    loop {
        let mut line = String::new();
        let line_len = reader.read_line(&mut line).unwrap();
        if line_len > 0{
            println!("{}", line);
            let pieces: Vec<&str> = line.trim().split(" ").collect();
            match pieces[0].to_lowercase().as_ref() {
                "define" => {
                    let word = pieces[2].replace("\"", "");
                    println!("{}", word);

                    if let Some(def) = page::find_on_urban_dict(&word) {
                        stream.write(format!("150 {} definitions retrieved\r\n", 1).as_bytes()).unwrap();

                        stream.write(format!("151 \"{}\" gcide", def.word).as_bytes()).unwrap();
                        stream.write(format!(" \"Urban Dictionary {} {}\"\r\n", def.contributor, def.date).as_bytes()).unwrap();
                        stream.write(format!("{}\r\n.\r\n", def.def).as_bytes()).unwrap();

                        stream.write("250 ok\r\n".as_bytes()).unwrap();
                        println!("found {}", word);
                    } else {
                        //TODO
                    }
                },
                "match" => {
                    // TODO
                    stream.write("152 0 matches found\r\n".as_bytes()).unwrap();
                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                }
                "quit" => {
                    stream.write("221 bye\r\n".as_bytes()).unwrap();
                    break;
                },
                "client" => {
                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                }
                _ => {
                    println!("{}", line.trim());
                }
            }
        }else{
            println!("Client disconnected");
            break;
        }
    }
}

pub fn start_server(host: &str, port: u16) {
    let listener = TcpListener::bind(&(host, port)).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move|| {
                    handle_client(stream);
                });
            },
            Err(e) => {
                println!("{}", e.description());
            }
        }
    }
}
<commit_msg>(feat) dictd similar<commit_after>use std::error::Error;
use std::io::{BufRead, Write};
use std::thread;
use std::net::{TcpListener, TcpStream};
use std::io::BufReader;

use ::page;

/// modified from gkbrk's demo:
/// https://gist.github.com/gkbrk/bea6dee7c0478395b718

fn handle_client(mut stream: TcpStream) {
let mut reader = BufReader::new(stream.try_clone().unwrap());
    stream.write("220 urdict 0.1.0\r\n".as_bytes()).unwrap();
    loop {
        let mut line = String::new();
        let line_len = reader.read_line(&mut line).unwrap();
        if line_len > 0{
            let pieces: Vec<&str> = line.trim().split(" ").collect();
            match pieces[0].to_lowercase().as_ref() {
                "define" => {
                    let word = pieces[2].replace("\"", "");

                    if let Some(def) = page::find_on_urban_dict(&word) {
                        stream.write(format!("150 {} definitions retrieved\r\n", 1).as_bytes()).unwrap();

                        stream.write(format!("151 \"{}\" urdict", def.word).as_bytes()).unwrap();
                        stream.write(format!(" \"Urban Dictionary {} {}\"\r\n", def.contributor, def.date).as_bytes()).unwrap();
                        stream.write(format!("{}\r\n.\r\n", def.def).as_bytes()).unwrap();
                    } else {
                        stream.write(format!("150 0 definitions retrieved\r\n").as_bytes()).unwrap();
                    }
                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                },
                "match" => {
                    let word = pieces[3].replace("\"", "");
                    if let Some(def) = page::find_on_urban_dict(&word) {
                        if let Some(similars) = def.similars {
                            stream.write(format!("152 {} matches found\r\n", similars.len()).as_bytes()).unwrap();
                            for s in similars {
                                stream.write(format!("urdict \"{}\"\r\n", s).as_bytes()).unwrap();
                            }
                            stream.write(".\r\n".as_bytes()).unwrap();
                        } else {
                            stream.write("152 0 matches found\r\n".as_bytes()).unwrap();
                        }
                    } else {
                        stream.write("152 0 matches found\r\n".as_bytes()).unwrap();
                    }

                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                }
                "quit" => {
                    stream.write("221 bye\r\n".as_bytes()).unwrap();
                    break;
                },
                "client" => {
                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                }
                _ => {
                    println!("{}", line.trim());
                }
            }
        }else{
            println!("Client disconnected");
            break;
        }
    }
}

pub fn start_server(host: &str, port: u16) {
    let listener = TcpListener::bind(&(host, port)).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move|| {
                    handle_client(stream);
                });
            },
            Err(e) => {
                println!("{}", e.description());
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::context::ContextError;
use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`
/// - `Error` guarantees that a backtrace will exist, even if the error type
///   did not provide one
/// - `Error` is represented as a narrow pointer - exactly one word in size,
///   instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    #[doc(hidden)]
    pub fn new_adhoc<M>(message: M) -> Self
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        let backtrace = match error.backtrace() {
            Some(_) => None,
            None => Some(Backtrace::capture()),
        };

        unsafe {
            let obj = mem::transmute::<&dyn StdError, TraitObject>(&error);
            let vtable = obj.vtable;
            let inner = Box::new(ErrorImpl {
                vtable,
                type_id,
                backtrace,
                error,
            });
            Error {
                inner: mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner),
            }
        }
    }

    /// Wrap the error value with additional context.
    pub fn context<C>(self, context: C) -> Self
    where
        C: Display + Send + Sync + 'static,
    {
        Error::from(ContextError {
            error: self,
            context,
        })
    }

    /// View this error object as the underlying error.
    pub fn as_dyn_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        self.inner.error()
    }

    /// View this error object as the underlying error, mutably.
    pub fn as_dyn_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        self.inner.error_mut()
    }

    /// Get the backtrace for this Error.
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of the chain of source errors contained by this Error.
    ///
    /// This iterator will visit every error in the cause chain of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn chain(&self) -> Chain {
        Chain {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E>(&self) -> bool
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E>(self) -> Result<E, Self>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E>(&self) -> Option<&E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Self {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;
    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut errors = self.chain().skip(1).enumerate();

        if let Some((n, error)) = errors.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in errors {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        let backtrace = self.backtrace();

        match backtrace.status() {
            BacktraceStatus::Captured => {
                writeln!(f, "\n{}", backtrace)?;
            }
            BacktraceStatus::Disabled => {
                writeln!(
                    f,
                    "\nbacktrace disabled; run with RUST_LIB_BACKTRACE=1 environment variable to display a backtrace"
                )?;
            }
            _ => {}
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M>(M);

impl<M> Debug for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M> Display for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &self.error,
            vtable: self.vtable,
        };

        unsafe { mem::transmute::<TraitObject, &(dyn StdError + Send + Sync + 'static)>(object) }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &mut self.error,
            vtable: self.vtable,
        };

        unsafe {
            mem::transmute::<TraitObject, &mut (dyn StdError + Send + Sync + 'static)>(object)
        }
    }
}

/// Iterator of a chain of source errors.
pub struct Chain<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Chain<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

#[cfg(test)]
mod repr_correctness {
    use super::*;
    use std::marker::Unpin;
    use std::mem;
    use std::sync::atomic::AtomicBool;
    use std::sync::atomic::Ordering::SeqCst;
    use std::sync::Arc;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[test]
    fn error_autotraits() {
        fn assert<E: Unpin + Send + Sync + 'static>() {}
        assert::<Error>();
    }

    #[test]
    fn drop_works() {
        #[derive(Debug)]
        struct DetectDrop {
            has_dropped: Arc<AtomicBool>,
        }

        impl StdError for DetectDrop {}

        impl Display for DetectDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }

        impl Drop for DetectDrop {
            fn drop(&mut self) {
                let already_dropped = self.has_dropped.swap(true, SeqCst);
                assert!(!already_dropped);
            }
        }

        let has_dropped = Arc::new(AtomicBool::new(false));

        drop(Error::from(DetectDrop {
            has_dropped: has_dropped.clone(),
        }));

        assert!(has_dropped.load(SeqCst));
    }
}
<commit_msg>Touch up Debug impl for Error<commit_after>use crate::context::ContextError;
use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`
/// - `Error` guarantees that a backtrace will exist, even if the error type
///   did not provide one
/// - `Error` is represented as a narrow pointer - exactly one word in size,
///   instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    #[doc(hidden)]
    pub fn new_adhoc<M>(message: M) -> Self
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        let backtrace = match error.backtrace() {
            Some(_) => None,
            None => Some(Backtrace::capture()),
        };

        unsafe {
            let obj = mem::transmute::<&dyn StdError, TraitObject>(&error);
            let vtable = obj.vtable;
            let inner = Box::new(ErrorImpl {
                vtable,
                type_id,
                backtrace,
                error,
            });
            Error {
                inner: mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner),
            }
        }
    }

    /// Wrap the error value with additional context.
    pub fn context<C>(self, context: C) -> Self
    where
        C: Display + Send + Sync + 'static,
    {
        Error::from(ContextError {
            error: self,
            context,
        })
    }

    /// View this error object as the underlying error.
    pub fn as_dyn_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        self.inner.error()
    }

    /// View this error object as the underlying error, mutably.
    pub fn as_dyn_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        self.inner.error_mut()
    }

    /// Get the backtrace for this Error.
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of the chain of source errors contained by this Error.
    ///
    /// This iterator will visit every error in the cause chain of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn chain(&self) -> Chain {
        Chain {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E>(&self) -> bool
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E>(self) -> Result<E, Self>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E>(&self) -> Option<&E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Self {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;
    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut chain = self.chain().skip(1).enumerate();
        if let Some((n, error)) = chain.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in chain {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        let backtrace = self.backtrace();
        match backtrace.status() {
            BacktraceStatus::Captured => {
                writeln!(f, "\n{}", backtrace)?;
            }
            BacktraceStatus::Disabled => {
                writeln!(
                    f,
                    "\nbacktrace disabled; run with RUST_LIB_BACKTRACE=1 environment variable to display a backtrace"
                )?;
            }
            _ => {}
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M>(M);

impl<M> Debug for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M> Display for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &self.error,
            vtable: self.vtable,
        };

        unsafe { mem::transmute::<TraitObject, &(dyn StdError + Send + Sync + 'static)>(object) }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &mut self.error,
            vtable: self.vtable,
        };

        unsafe {
            mem::transmute::<TraitObject, &mut (dyn StdError + Send + Sync + 'static)>(object)
        }
    }
}

/// Iterator of a chain of source errors.
pub struct Chain<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Chain<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

#[cfg(test)]
mod repr_correctness {
    use super::*;
    use std::marker::Unpin;
    use std::mem;
    use std::sync::atomic::AtomicBool;
    use std::sync::atomic::Ordering::SeqCst;
    use std::sync::Arc;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[test]
    fn error_autotraits() {
        fn assert<E: Unpin + Send + Sync + 'static>() {}
        assert::<Error>();
    }

    #[test]
    fn drop_works() {
        #[derive(Debug)]
        struct DetectDrop {
            has_dropped: Arc<AtomicBool>,
        }

        impl StdError for DetectDrop {}

        impl Display for DetectDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }

        impl Drop for DetectDrop {
            fn drop(&mut self) {
                let already_dropped = self.has_dropped.swap(true, SeqCst);
                assert!(!already_dropped);
            }
        }

        let has_dropped = Arc::new(AtomicBool::new(false));

        drop(Error::from(DetectDrop {
            has_dropped: has_dropped.clone(),
        }));

        assert!(has_dropped.load(SeqCst));
    }
}
<|endoftext|>


<commit_before>//! This module focuses on handling errors generated when using Ardite in a
//! graceful manner.

use std::io::Error as IOError;
use std::error::Error as ErrorTrait;
use std::fmt::{Display, Formatter, Result as FmtResult};

#[cfg(test)]
use regex::Regex;
use serde_json::error::Error as JSONError;
use serde_yaml::error::Error as YAMLError;

/// Any error generated by Ardite or it‘s drivers should be output using this
/// type. This allows for a comprehensive display of the error when a service
/// reports it to the user.
///
/// Information included with the error includes an `ErrorCode` (which maps to
/// an HTTP status code), a message, and an optional hint telling the user how
/// to fix the error.
///
/// Typically hints should be included for what would be considered the `4xx`
/// (in HTTP language) class of error codes.
///
/// # Tips For Writing Good Hint Messages
/// - Write in the second person (“You should…”).
/// - Always recommend a solution (“You should try…”, not “You must do…”).
/// - Be as specific as possible, if you have line numbers give them. If you
///   have file paths provide them.
/// - If it is a common error which generally confuses developers, provide a
///   link to a page which better explains the error and specific steps to
///   fix it.
#[derive(PartialEq, Debug)]
pub struct Error {
  /// A specific error code which describes the error.
  code: ErrorCode,
  /// A message providing more detail beyond the error code.
  message: String,
  /// A hint to the user on what to do next to try and avoid the error
  /// happening again. This is optional.
  hint: Option<String>
}

impl Error {
  /// Easily create a new error.
  pub fn new<S>(code: ErrorCode, message: S, hint: Option<S>) -> Self where S: Into<String> {
    Error {
      code: code,
      message: message.into(),
      hint: hint.map(|string| string.into())
    }
  }

  /// Get the code for the error.
  pub fn code(&self) -> &ErrorCode {
    &self.code
  }

  /// Get the message for the error.
  pub fn message(&self) -> &str {
    &self.message
  }

  /// Get the hint—for the error (see what I did there?).
  pub fn hint(&self) -> Option<&str> {
    self.hint.as_ref().map(|s| s.as_str())
  }

  /// Gets an object which represents the error.
  ///
  /// # Example
  /// ```rust
  /// #[macro_use(value)]
  /// extern crate ardite;
  ///
  /// use ardite::error::{Error, NotFound};
  ///
  /// # fn main() {
  ///
  /// let error = Error::new(NotFound, "Not found…", Some("Go to the light!"));
  ///
  /// let value = value!({
  ///   "error" => true,
  ///   "message" => "Not found…",
  ///   "hint" => "Go to the light!"
  /// });
  ///
  /// assert_eq!(error.to_value(), value);
  ///
  /// # }
  /// ```
  pub fn to_value(&self) -> Value {
    let mut object = Object::new();

    // TODO: implement an insert method which isn‘t as strict.
    object.insert("error".to_owned(), Value::Boolean(true));
    object.insert("message".to_owned(), Value::String(self.message.clone()));

    if let Some(ref hint) = self.hint {
      object.insert("hint".to_owned(), Value::String(hint.clone()));
    }

    Value::Object(object)
  }

  /// Convenience function for saying a thing failed validation using
  /// `ErrorCode::BadRequest`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::invalid("Failed validation.", "Try fixing your syntax!");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::BadRequest, "Failed validation.", Some("Try fixing your syntax!")));
  /// ```
  pub fn invalid<S1, S2>(message: S1, hint: S2) -> Self where S1: Into<String>, S2: Into<String> {
    Error {
      code: ErrorCode::BadRequest,
      message: message.into(),
      hint: Some(hint.into())
    }
  }

  /// Convenience function for saying there was an internal error using
  /// `ErrorCode::Internal`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::internal("Something blew up.");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::Internal, "Something blew up.", None));
  /// ```
  pub fn internal<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::Internal,
      message: message.into(),
      hint: None
    }
  }

  /// Convenience function for creating an unimplemented error with a plain
  /// message describing what is unimplemented using
  /// `ErrorCode::NotImplemented`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::unimplemented("Cache invalidation is hard.");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::NotImplemented, "Cache invalidation is hard.", None));
  /// ```
  pub fn unimplemented<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::NotImplemented,
      message: message.into(),
      hint: None
    }
  }

  /// Special assertion for error messages. Takes a regular expression string
  /// argument which will automatically be constructed into a regualr
  /// expression. Only available in testing environments. Panics if the regular
  /// expression doesn’t match the error message string.
  #[cfg(test)]
  pub fn assert_message(&self, regex_str: &str) {
    if !Regex::new(regex_str).unwrap().is_match(&self.message) {
      panic!("Error message \"{}\" does not match regex /{}/", self.message, regex_str);
    }
  }
}

impl Display for Error {
  fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
    try!(write!(fmt, "\ncode: {}", self.code));
    try!(write!(fmt, "\nmessage: {}", self.message));

    if let Some(ref hint) = self.hint {
      try!(write!(fmt, "\nhint: {}", hint));
    }

    Ok(())
  }
}

impl ErrorTrait for Error {
  fn description(&self) -> &str {
    self.message.as_str()
  }
}

impl From<IOError> for Error {
  fn from(error: IOError) -> Self {
    Error {
      code: ErrorCode::Internal,
      message: error.description().to_owned(),
      hint: None
    }
  }
}

impl From<JSONError> for Error {
  fn from(error: JSONError) -> Self {
    match error {
      JSONError::Syntax(_, line, column) => {
        Error {
          code: ErrorCode::BadRequest,
          message: "Syntax error.".to_owned(),
          hint: Some(format!("Max sure your JSON syntax is correct around line {} column {}.", line, column))
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_owned(),
          hint: None
        }
      }
    }
  }
}

impl From<YAMLError> for Error {
  fn from(error: YAMLError) -> Self {
    match error {
      YAMLError::Custom(ref message) => {
        Error {
          code: ErrorCode::BadRequest,
          message: message.to_owned(),
          hint: Some("Make sure your YAML syntax is correct.".to_owned())
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_owned(),
          hint: None
        }
      }
    }
  }
}

/// The code of an error. Designed to easily map to [HTTP status codes][1],
/// however only a subset of these codes are supported and some custom codes
/// were added.
///
/// [1]: http://www.restapitutorial.com/httpstatuscodes.html
#[derive(PartialEq, Debug)]
pub enum ErrorCode {
  /// A bad syntax was used.
  BadRequest,
  /// Permissions do not allow this to happen.
  Forbidden,
  /// Resource was not found.
  NotFound,
  /// The requested resource is not acceptable.
  NotAcceptable,
  /// Present data made the request fail.
  Conflict,
  /// There was an invalid range.
  BadRange,
  /// Something bad happened inside a driver.
  Internal,
  /// The feature has not been implemented.
  NotImplemented
}

// Dump all the error codes into the export space.
pub use ErrorCode::*;

impl ErrorCode {
  pub fn code(&self) -> u16 {
    match *self {
      BadRequest => 400,
      Forbidden => 403,
      NotFound => 404,
      NotAcceptable => 406,
      Conflict => 409,
      BadRange => 416,
      Internal => 500,
      NotImplemented => 501
    }
  }

  pub fn reason(&self) -> &str {
    match *self {
      BadRequest => "Bad Request",
      Forbidden => "Forbidden",
      NotFound => "Not Found",
      NotAcceptable => "Not Acceptable",
      Conflict => "Conflict",
      BadRange => "Range Not Satisfiable",
      Internal => "Internal Error",
      NotImplemented => "Not Implemented"
    }
  }
}

impl Display for ErrorCode {
  fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
    try!(write!(fmt, "{} {}", self.code(), self.reason()));
    Ok(())
  }
}
<commit_msg>fix(error): add value imports to error<commit_after>//! This module focuses on handling errors generated when using Ardite in a
//! graceful manner.

use std::io::Error as IOError;
use std::error::Error as ErrorTrait;
use std::fmt::{Display, Formatter, Result as FmtResult};

#[cfg(test)]
use regex::Regex;
use serde_json::error::Error as JSONError;
use serde_yaml::error::Error as YAMLError;

use value::{Object, Value};

/// Any error generated by Ardite or it‘s drivers should be output using this
/// type. This allows for a comprehensive display of the error when a service
/// reports it to the user.
///
/// Information included with the error includes an `ErrorCode` (which maps to
/// an HTTP status code), a message, and an optional hint telling the user how
/// to fix the error.
///
/// Typically hints should be included for what would be considered the `4xx`
/// (in HTTP language) class of error codes.
///
/// # Tips For Writing Good Hint Messages
/// - Write in the second person (“You should…”).
/// - Always recommend a solution (“You should try…”, not “You must do…”).
/// - Be as specific as possible, if you have line numbers give them. If you
///   have file paths provide them.
/// - If it is a common error which generally confuses developers, provide a
///   link to a page which better explains the error and specific steps to
///   fix it.
#[derive(PartialEq, Debug)]
pub struct Error {
  /// A specific error code which describes the error.
  code: ErrorCode,
  /// A message providing more detail beyond the error code.
  message: String,
  /// A hint to the user on what to do next to try and avoid the error
  /// happening again. This is optional.
  hint: Option<String>
}

impl Error {
  /// Easily create a new error.
  pub fn new<S>(code: ErrorCode, message: S, hint: Option<S>) -> Self where S: Into<String> {
    Error {
      code: code,
      message: message.into(),
      hint: hint.map(|string| string.into())
    }
  }

  /// Get the code for the error.
  pub fn code(&self) -> &ErrorCode {
    &self.code
  }

  /// Get the message for the error.
  pub fn message(&self) -> &str {
    &self.message
  }

  /// Get the hint—for the error (see what I did there?).
  pub fn hint(&self) -> Option<&str> {
    self.hint.as_ref().map(|s| s.as_str())
  }

  /// Gets an object which represents the error.
  ///
  /// # Example
  /// ```rust
  /// #[macro_use(value)]
  /// extern crate ardite;
  ///
  /// use ardite::error::{Error, NotFound};
  ///
  /// # fn main() {
  ///
  /// let error = Error::new(NotFound, "Not found…", Some("Go to the light!"));
  ///
  /// let value = value!({
  ///   "error" => true,
  ///   "message" => "Not found…",
  ///   "hint" => "Go to the light!"
  /// });
  ///
  /// assert_eq!(error.to_value(), value);
  ///
  /// # }
  /// ```
  pub fn to_value(&self) -> Value {
    let mut object = Object::new();

    // TODO: implement an insert method which isn‘t as strict.
    object.insert("error".to_owned(), Value::Boolean(true));
    object.insert("message".to_owned(), Value::String(self.message.clone()));

    if let Some(ref hint) = self.hint {
      object.insert("hint".to_owned(), Value::String(hint.clone()));
    }

    Value::Object(object)
  }

  /// Convenience function for saying a thing failed validation using
  /// `ErrorCode::BadRequest`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::invalid("Failed validation.", "Try fixing your syntax!");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::BadRequest, "Failed validation.", Some("Try fixing your syntax!")));
  /// ```
  pub fn invalid<S1, S2>(message: S1, hint: S2) -> Self where S1: Into<String>, S2: Into<String> {
    Error {
      code: ErrorCode::BadRequest,
      message: message.into(),
      hint: Some(hint.into())
    }
  }

  /// Convenience function for saying there was an internal error using
  /// `ErrorCode::Internal`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::internal("Something blew up.");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::Internal, "Something blew up.", None));
  /// ```
  pub fn internal<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::Internal,
      message: message.into(),
      hint: None
    }
  }

  /// Convenience function for creating an unimplemented error with a plain
  /// message describing what is unimplemented using
  /// `ErrorCode::NotImplemented`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::unimplemented("Cache invalidation is hard.");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::NotImplemented, "Cache invalidation is hard.", None));
  /// ```
  pub fn unimplemented<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::NotImplemented,
      message: message.into(),
      hint: None
    }
  }

  /// Special assertion for error messages. Takes a regular expression string
  /// argument which will automatically be constructed into a regualr
  /// expression. Only available in testing environments. Panics if the regular
  /// expression doesn’t match the error message string.
  #[cfg(test)]
  pub fn assert_message(&self, regex_str: &str) {
    if !Regex::new(regex_str).unwrap().is_match(&self.message) {
      panic!("Error message \"{}\" does not match regex /{}/", self.message, regex_str);
    }
  }
}

impl Display for Error {
  fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
    try!(write!(fmt, "\ncode: {}", self.code));
    try!(write!(fmt, "\nmessage: {}", self.message));

    if let Some(ref hint) = self.hint {
      try!(write!(fmt, "\nhint: {}", hint));
    }

    Ok(())
  }
}

impl ErrorTrait for Error {
  fn description(&self) -> &str {
    self.message.as_str()
  }
}

impl From<IOError> for Error {
  fn from(error: IOError) -> Self {
    Error {
      code: ErrorCode::Internal,
      message: error.description().to_owned(),
      hint: None
    }
  }
}

impl From<JSONError> for Error {
  fn from(error: JSONError) -> Self {
    match error {
      JSONError::Syntax(_, line, column) => {
        Error {
          code: ErrorCode::BadRequest,
          message: "Syntax error.".to_owned(),
          hint: Some(format!("Max sure your JSON syntax is correct around line {} column {}.", line, column))
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_owned(),
          hint: None
        }
      }
    }
  }
}

impl From<YAMLError> for Error {
  fn from(error: YAMLError) -> Self {
    match error {
      YAMLError::Custom(ref message) => {
        Error {
          code: ErrorCode::BadRequest,
          message: message.to_owned(),
          hint: Some("Make sure your YAML syntax is correct.".to_owned())
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_owned(),
          hint: None
        }
      }
    }
  }
}

/// The code of an error. Designed to easily map to [HTTP status codes][1],
/// however only a subset of these codes are supported and some custom codes
/// were added.
///
/// [1]: http://www.restapitutorial.com/httpstatuscodes.html
#[derive(PartialEq, Debug)]
pub enum ErrorCode {
  /// A bad syntax was used.
  BadRequest,
  /// Permissions do not allow this to happen.
  Forbidden,
  /// Resource was not found.
  NotFound,
  /// The requested resource is not acceptable.
  NotAcceptable,
  /// Present data made the request fail.
  Conflict,
  /// There was an invalid range.
  BadRange,
  /// Something bad happened inside a driver.
  Internal,
  /// The feature has not been implemented.
  NotImplemented
}

// Dump all the error codes into the export space.
pub use ErrorCode::*;

impl ErrorCode {
  pub fn code(&self) -> u16 {
    match *self {
      BadRequest => 400,
      Forbidden => 403,
      NotFound => 404,
      NotAcceptable => 406,
      Conflict => 409,
      BadRange => 416,
      Internal => 500,
      NotImplemented => 501
    }
  }

  pub fn reason(&self) -> &str {
    match *self {
      BadRequest => "Bad Request",
      Forbidden => "Forbidden",
      NotFound => "Not Found",
      NotAcceptable => "Not Acceptable",
      Conflict => "Conflict",
      BadRange => "Range Not Satisfiable",
      Internal => "Internal Error",
      NotImplemented => "Not Implemented"
    }
  }
}

impl Display for ErrorCode {
  fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
    try!(write!(fmt, "{} {}", self.code(), self.reason()));
    Ok(())
  }
}
<|endoftext|>