<commit_before>use alloc::boxed::Box;

use core::cmp;

use arch::memory;

use system::graphics::{fast_copy, fast_set};

use super::FONT;
use super::color::Color;

/// The info of the VBE mode
#[derive(Copy, Clone, Default, Debug)]
#[repr(packed)]
pub struct VBEModeInfo {
    attributes: u16,
    win_a: u8,
    win_b: u8,
    granularity: u16,
    winsize: u16,
    segment_a: u16,
    segment_b: u16,
    winfuncptr: u32,
    bytesperscanline: u16,
    pub xresolution: u16,
    pub yresolution: u16,
    xcharsize: u8,
    ycharsize: u8,
    numberofplanes: u8,
    bitsperpixel: u8,
    numberofbanks: u8,
    memorymodel: u8,
    banksize: u8,
    numberofimagepages: u8,
    unused: u8,
    redmasksize: u8,
    redfieldposition: u8,
    greenmasksize: u8,
    greenfieldposition: u8,
    bluemasksize: u8,
    bluefieldposition: u8,
    rsvdmasksize: u8,
    rsvdfieldposition: u8,
    directcolormodeinfo: u8,
    physbaseptr: u32,
    offscreenmemoryoffset: u32,
    offscreenmemsize: u16,
}

pub static mut VBEMODEINFO: Option<VBEModeInfo> = None;

pub unsafe fn vbe_init(){
    let mode_info = *(0x5200 as *const VBEModeInfo);
    if mode_info.physbaseptr > 0 {
        VBEMODEINFO = Some(mode_info);
    }else{
        VBEMODEINFO = None;
    }
}

/// A display
pub struct Display {
    pub offscreen: *mut u32,
    pub onscreen: *mut u32,
    pub size: usize,
    pub width: usize,
    pub height: usize,
}

impl Display {
    pub fn root() -> Option<Box<Self>> {
        if let Some(mode_info) = unsafe { VBEMODEINFO } {
            let ret = box Display {
                offscreen: unsafe { memory::alloc(mode_info.xresolution as usize *
                                         mode_info.yresolution as usize * 4) as *mut u32 },
                onscreen: mode_info.physbaseptr as usize as *mut u32,
                size: mode_info.xresolution as usize * mode_info.yresolution as usize,
                width: mode_info.xresolution as usize,
                height: mode_info.yresolution as usize,
            };

            Some(ret)
        } else {
            None
        }
    }

    /// Set the color
    pub fn set(&self, color: Color) {
        unsafe {
            fast_set(self.offscreen, color.data, self.size);
        }
    }

    /// Scroll the display
    pub fn scroll(&self, rows: usize, color: Color) {
        if rows > 0 && rows < self.height {
            let offset = rows * self.width;
            unsafe {
                fast_copy(self.offscreen, self.offscreen.offset(offset as isize), self.size - offset);
                fast_set(self.offscreen.offset((self.size - offset) as isize), color.data, offset);
            }
        }
    }

    /// Flip the display
    pub fn flip(&self) {
        unsafe {
            fast_copy(self.onscreen, self.offscreen, self.size);
        }
    }

    /// Draw a rectangle
    pub fn rect(&self, x: usize, y: usize, w: usize, h: usize, color: Color) {
        let data = color.data;

        let start_y = cmp::min(self.height - 1, y);
        let end_y = cmp::min(self.height - 1, y + h);

        let start_x = cmp::min(self.width - 1, x);
        let len = cmp::min(self.width - 1, x + w) - start_x;

        for y in start_y..end_y {
            unsafe {
                fast_set(self.offscreen.offset((y * self.width + start_x) as isize), data, len);
            }
        }
    }

    /// Draw a char
    pub fn char(&self, x: usize, y: usize, character: char, color: Color) {
        if x + 8 <= self.width && y + 16 <= self.height {
            let data = color.data;
            let mut dst = unsafe { self.offscreen.offset((y * self.width + x) as isize) };

            let font_i = 16 * (character as usize);
            for row in 0..16 {
                let row_data = FONT[font_i + row];
                for col in 0..8 {
                    if (row_data >> (7 - col)) & 1 == 1 {
                        unsafe { *dst.offset(col) = data; }
                    }
                }
                dst = unsafe { dst.offset(self.width as isize) };
            }
        }
    }
}

impl Drop for Display {
    fn drop(&mut self) {
        unsafe {
            if self.offscreen as usize > 0 {
                memory::unalloc(self.offscreen as usize);
            }
        }
    }
}
<commit_msg>Fixes for real hardware - clear display on creation<commit_after>use alloc::boxed::Box;

use core::cmp;

use arch::memory;

use system::graphics::{fast_copy, fast_set};

use super::FONT;
use super::color::Color;

/// The info of the VBE mode
#[derive(Copy, Clone, Default, Debug)]
#[repr(packed)]
pub struct VBEModeInfo {
    attributes: u16,
    win_a: u8,
    win_b: u8,
    granularity: u16,
    winsize: u16,
    segment_a: u16,
    segment_b: u16,
    winfuncptr: u32,
    bytesperscanline: u16,
    pub xresolution: u16,
    pub yresolution: u16,
    xcharsize: u8,
    ycharsize: u8,
    numberofplanes: u8,
    bitsperpixel: u8,
    numberofbanks: u8,
    memorymodel: u8,
    banksize: u8,
    numberofimagepages: u8,
    unused: u8,
    redmasksize: u8,
    redfieldposition: u8,
    greenmasksize: u8,
    greenfieldposition: u8,
    bluemasksize: u8,
    bluefieldposition: u8,
    rsvdmasksize: u8,
    rsvdfieldposition: u8,
    directcolormodeinfo: u8,
    physbaseptr: u32,
    offscreenmemoryoffset: u32,
    offscreenmemsize: u16,
}

pub static mut VBEMODEINFO: Option<VBEModeInfo> = None;

pub unsafe fn vbe_init(){
    let mode_info = *(0x5200 as *const VBEModeInfo);
    if mode_info.physbaseptr > 0 {
        VBEMODEINFO = Some(mode_info);
    }else{
        VBEMODEINFO = None;
    }
}

/// A display
pub struct Display {
    pub offscreen: *mut u32,
    pub onscreen: *mut u32,
    pub size: usize,
    pub width: usize,
    pub height: usize,
}

impl Display {
    pub fn root() -> Option<Box<Self>> {
        if let Some(mode_info) = unsafe { VBEMODEINFO } {
            let ret = box Display {
                offscreen: unsafe { memory::alloc(mode_info.xresolution as usize *
                                         mode_info.yresolution as usize * 4) as *mut u32 },
                onscreen: mode_info.physbaseptr as usize as *mut u32,
                size: mode_info.xresolution as usize * mode_info.yresolution as usize,
                width: mode_info.xresolution as usize,
                height: mode_info.yresolution as usize,
            };

            ret.set(Color::new(0, 0, 0));

            Some(ret)
        } else {
            None
        }
    }

    /// Set the color
    pub fn set(&self, color: Color) {
        unsafe {
            fast_set(self.offscreen, color.data, self.size);
        }
    }

    /// Scroll the display
    pub fn scroll(&self, rows: usize, color: Color) {
        if rows > 0 && rows < self.height {
            let offset = rows * self.width;
            unsafe {
                fast_copy(self.offscreen, self.offscreen.offset(offset as isize), self.size - offset);
                fast_set(self.offscreen.offset((self.size - offset) as isize), color.data, offset);
            }
        }
    }

    /// Flip the display
    pub fn flip(&self) {
        unsafe {
            fast_copy(self.onscreen, self.offscreen, self.size);
        }
    }

    /// Draw a rectangle
    pub fn rect(&self, x: usize, y: usize, w: usize, h: usize, color: Color) {
        let data = color.data;

        let start_y = cmp::min(self.height - 1, y);
        let end_y = cmp::min(self.height - 1, y + h);

        let start_x = cmp::min(self.width - 1, x);
        let len = cmp::min(self.width - 1, x + w) - start_x;

        for y in start_y..end_y {
            unsafe {
                fast_set(self.offscreen.offset((y * self.width + start_x) as isize), data, len);
            }
        }
    }

    /// Draw a char
    pub fn char(&self, x: usize, y: usize, character: char, color: Color) {
        if x + 8 <= self.width && y + 16 <= self.height {
            let data = color.data;
            let mut dst = unsafe { self.offscreen.offset((y * self.width + x) as isize) };

            let font_i = 16 * (character as usize);
            for row in 0..16 {
                let row_data = FONT[font_i + row];
                for col in 0..8 {
                    if (row_data >> (7 - col)) & 1 == 1 {
                        unsafe { *dst.offset(col) = data; }
                    }
                }
                dst = unsafe { dst.offset(self.width as isize) };
            }
        }
    }
}

impl Drop for Display {
    fn drop(&mut self) {
        unsafe {
            if self.offscreen as usize > 0 {
                memory::unalloc(self.offscreen as usize);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 lazy-static.rs 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.

extern crate std;

use self::std::prelude::v1::*;
use self::std::cell::UnsafeCell;
use self::std::sync::{Once, ONCE_INIT};

pub struct Lazy<T: Sync>(UnsafeCell<Option<T>>, Once);

impl<T: Sync> Lazy<T> {
    #[inline(always)]
    pub const fn new() -> Self {
        Lazy(UnsafeCell::new(None), ONCE_INIT)
    }

    #[inline(always)]
    pub fn get<F>(&'static self, f: F) -> &T
        where F: FnOnce() -> T
    {
        unsafe {
            self.1.call_once(|| {
                *self.0.get() = Some(f());
            });

            match *self.0.get() {
                Some(ref x) => x,
                None => std::intrinsics::unreachable(),
            }
        }
    }
}

unsafe impl<T: Sync> Sync for Lazy<T> {}

#[macro_export]
#[allow_internal_unstable]
#[doc(hidden)]
macro_rules! __lazy_static_create {
    ($NAME:ident, $T:ty) => {
        static $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::new();
    }
}
<commit_msg>Switch lazy_static over to mutable statics instead of UnsafeCell on nightly<commit_after>// Copyright 2016 lazy-static.rs 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.

extern crate std;

use self::std::prelude::v1::*;
use self::std::sync::{Once, ONCE_INIT};

pub struct Lazy<T: Sync>(Option<T>, Once);

impl<T: Sync> Lazy<T> {
    #[inline(always)]
    pub const fn new() -> Self {
        Lazy(None, ONCE_INIT)
    }

    #[inline(always)]
    pub fn get<F>(&'static mut self, f: F) -> &T
        where F: FnOnce() -> T
    {
        {
            let r = &mut self.0;
            self.1.call_once(|| {
                *r = Some(f());
            });
        }
        unsafe {
            match self.0 {
                Some(ref x) => x,
                None => std::intrinsics::unreachable(),
            }
        }
    }
}

unsafe impl<T: Sync> Sync for Lazy<T> {}

#[macro_export]
#[allow_internal_unstable]
#[doc(hidden)]
macro_rules! __lazy_static_create {
    ($NAME:ident, $T:ty) => {
        static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::new();
    }
}
<|endoftext|>


<commit_before>//! Defines an instance of some piece of geometry in the scene, instances
//! can re-use loaded geometry but apply different transformations and materials
//! to them

use std::sync::Arc;

use geometry::{Geometry, Intersection};
use material::Material;
use linalg;

/// Defines an instance of some geometry with its own transform and material
pub struct Instance {
    /// The geometry that's being instanced. TODO: We must Box for now but this
    /// restriction will be lifted later
    geom: Arc<Box<Geometry + Send + Sync>>,
    /// The material being used by this instance.
    pub material: Arc<Box<Material + Send + Sync>>,
    /// The transform to world space
    transform: linalg::Transform,
}

impl Instance {
    /// Create a new instance of some geometry in the scene
    pub fn new(geom: Arc<Box<Geometry + Send + Sync>>, material: Arc<Box<Material + Send + Sync>>,
               transform: linalg::Transform)
               -> Instance {
        Instance { geom: geom, material: material, transform: transform }
    }
    /// Test the ray for intersection against this insance of geometry.
    /// returns Some(Intersection) if an intersection was found and None if not.
    /// If an intersection is found `ray.max_t` will be set accordingly
    pub fn intersect(&self, ray: &mut linalg::Ray) -> Option<Intersection> {
        let mut local = self.transform.inv_mul_ray(ray);
        let mut dg = match self.geom.intersect(&mut local) {
            Some(dg) => dg,
            None => return None,
        };
        ray.max_t = local.max_t;
        dg.p = self.transform * dg.p;
        dg.n = self.transform * dg.n;
        dg.ng = self.transform * dg.ng;
        Some(Intersection::new(dg, self))
    }
}

<commit_msg>Also need to transform dp_du/dv up to world space<commit_after>//! Defines an instance of some piece of geometry in the scene, instances
//! can re-use loaded geometry but apply different transformations and materials
//! to them

use std::sync::Arc;

use geometry::{Geometry, Intersection};
use material::Material;
use linalg;

/// Defines an instance of some geometry with its own transform and material
pub struct Instance {
    /// The geometry that's being instanced. TODO: We must Box for now but this
    /// restriction will be lifted later
    geom: Arc<Box<Geometry + Send + Sync>>,
    /// The material being used by this instance.
    pub material: Arc<Box<Material + Send + Sync>>,
    /// The transform to world space
    transform: linalg::Transform,
}

impl Instance {
    /// Create a new instance of some geometry in the scene
    pub fn new(geom: Arc<Box<Geometry + Send + Sync>>, material: Arc<Box<Material + Send + Sync>>,
               transform: linalg::Transform)
               -> Instance {
        Instance { geom: geom, material: material, transform: transform }
    }
    /// Test the ray for intersection against this insance of geometry.
    /// returns Some(Intersection) if an intersection was found and None if not.
    /// If an intersection is found `ray.max_t` will be set accordingly
    pub fn intersect(&self, ray: &mut linalg::Ray) -> Option<Intersection> {
        let mut local = self.transform.inv_mul_ray(ray);
        let mut dg = match self.geom.intersect(&mut local) {
            Some(dg) => dg,
            None => return None,
        };
        ray.max_t = local.max_t;
        dg.p = self.transform * dg.p;
        dg.n = self.transform * dg.n;
        dg.ng = self.transform * dg.ng;
        dg.dp_du = self.transform * dg.dp_du;
        dg.dp_dv = self.transform * dg.dp_dv;
        Some(Intersection::new(dg, self))
    }
}

<|endoftext|>


<commit_before>use std::task::TaskBuilder;
use std::io::IoError;
use std::collections::hashmap::HashMap;

use serialize::json;
use serialize::json::DecoderError;
use time::{get_time, Timespec};

use url::Url;
use url::form_urlencoded::serialize_owned;

use http::client::RequestWriter;
use http::method::Get;

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator
};
use message::{
    IrcMessage
};

static DEER: &'static str = concat!(
    "\u000301,01@@@@@@@@\u000300,00@\u000301,01@@\u000300,00@\u000301,01@\n",
    "\u000301,01@@@@@@@@\u000300,00@\u000301,01@@\u000300,00@\u000301,01@\n",
    "\u000301,01@@@@@@@@@\u000300,00@@\u000301,01@@\n",
    "\u000301,01@@@@@@@@\u000300,00@@@\u000301,01@@\n",
    "\u000301,01@@@@@@@@@\u000300,00@@\u000301,01@@\n",
    "\u000301,01@@\u000300,00@@@@@@@@@\u000301,01@@\n",
    "\u000301,01@\u000300,00@@@@@@@@@@\u000301,01@@\n",
    "\u000301,01@\u000300,00@@@@@@@@@@\u000301,01@@\n",
    "\u000301,01@\u000300,00@\u000301,01@\u000300,00@",
    "\u000301,01@@@@\u000300,00@\u000301,01@\u000300,00@\u000301,01@@\n",
    "\u000301,01@\u000300,00@\u000301,01@\u000300,00@",
    "\u000301,01@@@@\u000300,00@\u000301,01@\u000300,00@\u000301,01@@\n",
    "\u000301,01@\u000300,00@\u000301,01@\u000300,00@",
    "\u000301,01@@@@\u000300,00@\u000301,01@\u000300,00@\u000301,01@@");

static BASE_URL: &'static str = "http://deer.satf.se/deerlist.php";

#[deriving(Decodable, Encodable, Clone)]
struct DeerApiResponse {
    irccode: String
}

#[deriving(Show)]
enum DeerApiFailure {
    NoResponseError(IoError),
    ResponseReadError(IoError),
    ResponseDecodeError,
    ResponseDeserializeError(DecoderError)
}

fn get_deer_nocache(deer_name: &str) -> Result<DeerApiResponse, DeerApiFailure> {
    let mut url = match Url::parse(BASE_URL) {
        Ok(url) => url,
        Err(_err) => unreachable!()
    };
    url.query = Some(serialize_owned(vec![
        (String::from_str("deer"), String::from_str(deer_name)),
    ].as_slice()));

    let request: RequestWriter = RequestWriter::new(Get, url).unwrap();

    let mut response = match request.read_response() {
        Ok(response) => response,
        Err((_, io_error)) => return Err(NoResponseError(io_error))
    };
    let body = match response.read_to_end() {
        Ok(body) => body,
        Err(io_error) => return Err(ResponseReadError(io_error))
    };
    let body = match String::from_utf8(body) {
        Ok(body) => body,
        Err(_err) => return Err(ResponseDecodeError)
    };

    match json::decode::<DeerApiResponse>(body.as_slice()) {
        Ok(result) => Ok(result),
        Err(error) => Err(ResponseDeserializeError(error))
    }
}

fn get_deer(state: &mut DeerInternalState, deer_name: &str) -> Result<DeerApiResponse, DeerApiFailure> {
    let deer_name_alloc = String::from_str(deer_name);

    match state.cache.find(&deer_name_alloc) {
        Some(result) => return Ok(result.clone()),
        None => ()
    }

    match get_deer_nocache(deer_name) {
        Ok(response) => {
            state.cache.insert(
                String::from_str(deer_name),
                response.clone());
            Ok(response)
        },
        Err(err) => Err(err)
    }
}

pub struct DeerPlugin {
    sender: Option<SyncSender<(CommandMapperDispatch, IrcMessage)>>
}

impl DeerPlugin {
    pub fn new() -> DeerPlugin {
        DeerPlugin { sender: None }
    }
}

struct DeerInternalState {
    lines_sent: u64,
    last_request: Option<Timespec>,
    cache: HashMap<String, DeerApiResponse>,
}

impl DeerInternalState {
    fn new() -> DeerInternalState {
        DeerInternalState {
            lines_sent: 0,
            last_request: None,
            cache: HashMap::new(),
        }
    }

    fn throttle(&mut self) -> bool {
        let now = get_time();

        let (new_last_request, throttle_ok) = match self.last_request {
            Some(last_request) => {
                if (now - last_request).num_seconds() < 60 {
                    (Some(last_request), true)
                } else {
                    (Some(now), false)
                }
            },
            None => (Some(now), false)
        };
        self.last_request = new_last_request;
        throttle_ok
    }

    fn start(&mut self, rx: Receiver<(CommandMapperDispatch, IrcMessage)>) {
        for (m, message) in rx.iter() {
            if message.get_args().len() < 2 {
                continue
            }
            let command_data = match parse_command(&m, &message) {
                Some(DeerStats) => Some(DeerStats),
                Some(command_data) => {
                    if self.throttle() {
                        m.reply(String::from_str("2deer4plus"));
                        None
                    } else {
                        Some(command_data)
                    }
                },
                None => None
            };
            match command_data {
                Some(Deer) => {
                    for deer_line in DEER.split('\n') {
                        m.reply(String::from_str(deer_line));
                        self.lines_sent += 1;
                    }
                },
                Some(Deerkins(deer_name)) => {
                    match get_deer(self, deer_name) {
                        Ok(deer_data) => {
                            for deer_line in deer_data.irccode.as_slice().split('\n') {
                                m.reply(String::from_str(deer_line));
                                self.lines_sent += 1;
                            }
                        },
                        Err(err) => {
                            m.reply(format!("error: {}", err));
                        }
                    }
                },
                Some(DeerStats) => {
                    m.reply(format!("lines sent: {}", self.lines_sent));
                }
                None => continue
            };
        }
    }
}

enum DeerCommandType<'a> {
    Deer,
    Deerkins(&'a str),
    DeerStats
}

fn parse_deerkins<'a>(message: &'a IrcMessage) -> Option<DeerCommandType<'a>> {
    let message_body = message.get_arg(1).as_slice();
    match message_body.find(' ') {
        Some(idx) => Some(Deerkins(message_body.slice_from(idx + 1))),
        None => None
    }
}

fn parse_command<'a>(m: &CommandMapperDispatch, message: &'a IrcMessage) -> Option<DeerCommandType<'a>> {
    match m.command() {
        Some("deer") => Some(Deer),
        Some("deerkins") => parse_deerkins(message),
        Some("deerstats") => Some(DeerStats),
        Some(_) => None,
        None => None
    }
}

impl RustBotPlugin for DeerPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map("deer");
        conf.map("deerstats");
        conf.map("deerkins");
    }

    fn start(&mut self) {
        let (tx, rx) = sync_channel(10);
        self.sender = Some(tx);

        TaskBuilder::new().named("plugin-deer").spawn(proc() {
            let mut deer_internal_state = DeerInternalState::new();
            deer_internal_state.start(rx);
        });
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        match self.sender {
            Some(ref sender) => sender.send((m.clone(), message.clone())),
            None => ()
        };
    }
}
<commit_msg>Failures shouldn't trip the throttle counter<commit_after>use std::task::TaskBuilder;
use std::io::IoError;
use std::collections::hashmap::HashMap;

use serialize::json;
use serialize::json::DecoderError;
use time::{get_time, Timespec};

use url::Url;
use url::form_urlencoded::serialize_owned;

use http::client::RequestWriter;
use http::method::Get;

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator
};
use message::{
    IrcMessage
};

static DEER: &'static str = concat!(
    "\u000301,01@@@@@@@@\u000300,00@\u000301,01@@\u000300,00@\u000301,01@\n",
    "\u000301,01@@@@@@@@\u000300,00@\u000301,01@@\u000300,00@\u000301,01@\n",
    "\u000301,01@@@@@@@@@\u000300,00@@\u000301,01@@\n",
    "\u000301,01@@@@@@@@\u000300,00@@@\u000301,01@@\n",
    "\u000301,01@@@@@@@@@\u000300,00@@\u000301,01@@\n",
    "\u000301,01@@\u000300,00@@@@@@@@@\u000301,01@@\n",
    "\u000301,01@\u000300,00@@@@@@@@@@\u000301,01@@\n",
    "\u000301,01@\u000300,00@@@@@@@@@@\u000301,01@@\n",
    "\u000301,01@\u000300,00@\u000301,01@\u000300,00@",
    "\u000301,01@@@@\u000300,00@\u000301,01@\u000300,00@\u000301,01@@\n",
    "\u000301,01@\u000300,00@\u000301,01@\u000300,00@",
    "\u000301,01@@@@\u000300,00@\u000301,01@\u000300,00@\u000301,01@@\n",
    "\u000301,01@\u000300,00@\u000301,01@\u000300,00@",
    "\u000301,01@@@@\u000300,00@\u000301,01@\u000300,00@\u000301,01@@");

static BASE_URL: &'static str = "http://deer.satf.se/deerlist.php";

#[deriving(Decodable, Encodable, Clone)]
struct DeerApiResponse {
    irccode: String
}

#[deriving(Show)]
enum DeerApiFailure {
    NoResponseError(IoError),
    ResponseReadError(IoError),
    ResponseDecodeError,
    ResponseDeserializeError(DecoderError)
}

fn get_deer_nocache(deer_name: &str) -> Result<DeerApiResponse, DeerApiFailure> {
    let mut url = match Url::parse(BASE_URL) {
        Ok(url) => url,
        Err(_err) => unreachable!()
    };
    url.query = Some(serialize_owned(vec![
        (String::from_str("deer"), String::from_str(deer_name)),
    ].as_slice()));

    let request: RequestWriter = RequestWriter::new(Get, url).unwrap();

    let mut response = match request.read_response() {
        Ok(response) => response,
        Err((_, io_error)) => return Err(NoResponseError(io_error))
    };
    let body = match response.read_to_end() {
        Ok(body) => body,
        Err(io_error) => return Err(ResponseReadError(io_error))
    };
    let body = match String::from_utf8(body) {
        Ok(body) => body,
        Err(_err) => return Err(ResponseDecodeError)
    };

    match json::decode::<DeerApiResponse>(body.as_slice()) {
        Ok(result) => Ok(result),
        Err(error) => Err(ResponseDeserializeError(error))
    }
}

fn get_deer(state: &mut DeerInternalState, deer_name: &str) -> Result<DeerApiResponse, DeerApiFailure> {
    let deer_name_alloc = String::from_str(deer_name);

    match state.cache.find(&deer_name_alloc) {
        Some(result) => return Ok(result.clone()),
        None => ()
    }

    match get_deer_nocache(deer_name) {
        Ok(response) => {
            state.cache.insert(
                String::from_str(deer_name),
                response.clone());
            Ok(response)
        },
        Err(err) => Err(err)
    }
}

pub struct DeerPlugin {
    sender: Option<SyncSender<(CommandMapperDispatch, IrcMessage)>>
}

impl DeerPlugin {
    pub fn new() -> DeerPlugin {
        DeerPlugin { sender: None }
    }
}

struct DeerInternalState {
    lines_sent: u64,
    last_request: Option<Timespec>,
    cache: HashMap<String, DeerApiResponse>,
}

impl DeerInternalState {
    fn new() -> DeerInternalState {
        DeerInternalState {
            lines_sent: 0,
            last_request: None,
            cache: HashMap::new(),
        }
    }

    fn throttle_ok(&mut self) -> bool {
        let now = get_time();

        let (new_last_request, throttle_ok) = match self.last_request {
            Some(last_request) => {
                if (now - last_request).num_seconds() < 60 {
                    (Some(last_request), false)
                } else {
                    (Some(now), true)
                }
            },
            None => (Some(now), true)
        };
        self.last_request = new_last_request;
        throttle_ok
    }

    fn handle_command<'a>(&mut self, m: &CommandMapperDispatch, cmd: &'a DeerCommandType) {
        match cmd {
            &Deer => {
                for deer_line in DEER.split('\n') {
                    m.reply(String::from_str(deer_line));
                    self.lines_sent += 1;
                }
            },
            &Deerkins(deer_name) => {
                match get_deer(self, deer_name) {
                    Ok(deer_data) => {
                        for deer_line in deer_data.irccode.as_slice().split('\n') {
                            m.reply(String::from_str(deer_line));
                            self.lines_sent += 1;
                        }
                    },
                    Err(err) => {
                        m.reply(format!("error: {}", err));
                    }
                }
            },
            &DeerStats => {
                m.reply(format!("lines sent: {}", self.lines_sent));
            }
        };
    }

    fn start(&mut self, rx: Receiver<(CommandMapperDispatch, IrcMessage)>) {
        for (m, message) in rx.iter() {
            if message.get_args().len() < 2 {
                continue
            }
            match parse_command(&m, &message) {
                Some(ref command) => {
                    if self.throttle_ok() {
                        self.handle_command(&m, command);
                    } else {
                        m.reply(String::from_str("2deer4plus"))
                    }
                },
                None => ()
            }
        }
    }
}

enum DeerCommandType<'a> {
    Deer,
    Deerkins(&'a str),
    DeerStats
}

fn parse_deerkins<'a>(message: &'a IrcMessage) -> Option<DeerCommandType<'a>> {
    let message_body = message.get_arg(1).as_slice();
    match message_body.find(' ') {
        Some(idx) => Some(Deerkins(message_body.slice_from(idx + 1))),
        None => None
    }
}

fn parse_command<'a>(m: &CommandMapperDispatch, message: &'a IrcMessage) -> Option<DeerCommandType<'a>> {
    match m.command() {
        Some("deer") => Some(Deer),
        Some("deerkins") => parse_deerkins(message),
        Some("deerstats") => Some(DeerStats),
        Some(_) => None,
        None => None
    }
}

impl RustBotPlugin for DeerPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map("deer");
        conf.map("deerstats");
        conf.map("deerkins");
    }

    fn start(&mut self) {
        let (tx, rx) = sync_channel(10);
        self.sender = Some(tx);

        TaskBuilder::new().named("plugin-deer").spawn(proc() {
            let mut deer_internal_state = DeerInternalState::new();
            deer_internal_state.start(rx);
        });
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        match self.sender {
            Some(ref sender) => sender.send((m.clone(), message.clone())),
            None => ()
        };
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
pub mod test {
    use std::iter::Zip;
    use std::slice::Iter;
    use quick_csv::columns::Columns;
    use gtfs::error::ParseError;

    pub fn parse_row_harness<T, F: (Fn(Zip<Iter<String>, Columns>) -> Result<T, ParseError>)>(headers: Vec<&str>, values: Vec<&str>, parse_fn : F) -> Result<T, ParseError> {
        let header = make_header(headers);
        let (line, indices) = make_values(values);
        let column = Columns::new(&line, &indices);
        let row = make_row(&header, column);
        parse_fn(row)
    }

    fn make_row<'a, 'b>(headers: &'a Vec<String>, columns: Columns<'b>) -> Zip<Iter<'a, String>, Columns<'b>> {
        headers.iter().zip(columns)
    }

    fn make_header(headers: Vec<&str>) -> Vec<String> {
        headers.iter().map(|x| x.to_string()).collect::<Vec<String>>()
    }

    fn make_values(values: Vec<&str>) -> (String, Vec<usize>) {
        let line = values.join(",").to_string();
        // indices to the delimiter positions
        let mut indices : Vec<usize> = vec!();
        for value in values.iter() {
            let last_index = match indices.last() {
                Some(x) => x.clone() as i32,
                None => -1,
            };
            indices.push((last_index + value.len() as i32 + 1) as usize)
        }
        (line, indices)
    }
}
<commit_msg>Remove test utility for parsing quick_csv rows<commit_after><|endoftext|>


<commit_before>//! Contains node property related stuff.

use std::fmt;
use std::str;
use std::io::Read;
use byteorder::{LittleEndian, ReadBytesExt};
use flate2::read::ZlibDecoder;

macro_rules! try_opt {
    ($opt:expr) => (if let Some(val) = $opt {
        val
    } else {
        return None;
    });
}

#[derive(Clone)]
pub struct DelayedProperties {
    pub buffer: Vec<u8>,
    pub num_properties: usize,
}

impl DelayedProperties {
    pub fn from_vec_u8(vec: Vec<u8>, _version: i32, num_properties: usize) -> Self {
        DelayedProperties {
            buffer: vec,
            num_properties: num_properties,
        }
    }

    pub fn iter(&self) -> Iter {
        Iter {
            buffer: &self.buffer[..],
            rest_properties: self.num_properties,
        }
    }

    pub fn num_properties(&self) -> usize {
        self.num_properties
    }
}

impl fmt::Debug for DelayedProperties {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("DelayedProperties")
            .field("buffer_size", &self.buffer.len())
            .field("num_properties", &self.num_properties)
            .finish()
    }
}

pub struct Iter<'a> {
    buffer: &'a [u8],
    rest_properties: usize,
}

macro_rules! implement_iter_read {
    ($t:ty, $read_fun:ident, $size:expr) => (
        impl<'a> Iter<'a> {
            fn $read_fun(&mut self) -> Option<$t> {
                // TODO: Get size from `$t` at compile time.
                //const SIZE: usize = ::std::mem::size_of::<$t>(); // size_of() is not `const fn`.
                const SIZE: usize = $size;
                if self.buffer.len() < SIZE {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                }
                let val = self.buffer.$read_fun::<LittleEndian>().unwrap();
                Some(val)
            }
        }
    )
}

impl<'a> Iter<'a> {
    fn read_u8(&mut self) -> Option<u8> {
        const SIZE: usize = 1;
        if self.buffer.len() < SIZE {
            error!("Property data is too short");
            self.rest_properties = 0;
            return None;
        }
        let val = self.buffer.read_u8().unwrap();
        Some(val)
    }
}
implement_iter_read!(u32, read_u32, 4);
implement_iter_read!(i16, read_i16, 2);
implement_iter_read!(i32, read_i32, 4);
implement_iter_read!(i64, read_i64, 8);
implement_iter_read!(f32, read_f32, 4);
implement_iter_read!(f64, read_f64, 8);

impl<'a> Iterator for Iter<'a> {
    type Item = Property<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        macro_rules! read_primitive_prop {
            ($read_fun:ident, $variant:ident) => ({
                let val = try_opt!(self.$read_fun());
                self.rest_properties -= 1;
                Some(Property::$variant(val))
            })
        }
        if self.rest_properties == 0 {
            return None;
        }
        let type_code = try_opt!(self.read_u8());
        match type_code {
            // Boolean.
            b'C' => {
                let val = try_opt!(self.read_u8());
                if (val != b'T') && (val != b'Y') {
                    warn!("Expected 0x54 ('T') or 0x59 ('Y') as boolean property value, but got {:#x}", val);
                }
                self.rest_properties -= 1;
                Some(Property::Bool(val & 1 == 1))
            },
            // 2-byte signed integer.
            b'Y' => read_primitive_prop!(read_i16, I16),
            // 4-byte signed integer.
            b'I' => read_primitive_prop!(read_i32, I32),
            // 8-byte signed integer.
            b'L' => read_primitive_prop!(read_i64, I64),
            // 4-byte single-precision IEEE 754 floating-point number.
            b'F' => read_primitive_prop!(read_f32, F32),
            // 8-byte single-precision IEEE 754 floating-point number.
            b'D' => read_primitive_prop!(read_f64, F64),
            // String.
            b'S' => {
                let length = try_opt!(self.read_u32()) as usize;
                if self.buffer.len() < length {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                }
                let buf = &self.buffer[0..length];
                self.buffer = &self.buffer[length..];
                self.rest_properties -= 1;
                let strbuf = try_opt!(str::from_utf8(buf).map_err(|err| {
                    error!("Failed to decode a property of string type: {}", err);
                    self.rest_properties = 0;
                }).ok());
                Some(Property::String(strbuf))
            },
            // Raw binary.
            b'R' => {
                let length = try_opt!(self.read_u32()) as usize;
                if self.buffer.len() < length {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                }
                let buf = &self.buffer[0..length];
                self.buffer = &self.buffer[length..];
                self.rest_properties -= 1;
                Some(Property::Binary(buf))
            },
            b'b' | b'i' | b'l' | b'f' | b'd' => {
                let array_header = if let Some((header, length)) = ArrayHeader::from_binary(self.buffer) {
                    self.buffer = &self.buffer[length..];
                    header
                } else {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                };
                if self.buffer.len() < array_header.compressed_length {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                }
                let buf = &self.buffer[0..array_header.compressed_length];
                self.buffer = &self.buffer[array_header.compressed_length..];
                if let Some(val) = read_property_array(buf, &array_header, type_code) {
                    self.rest_properties -= 1;
                    Some(val)
                } else {
                    self.rest_properties = 0;
                    None
                }
            },
            _ => {
                error!("Unknown type code: {:#x}", type_code);
                self.rest_properties = 0;
                None
            },
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.rest_properties))
    }
}

/// Header of array type property value.
struct ArrayHeader {
    /// Number of values in the array, *NOT byte size*.
    num_elements: usize,
    /// Denotes whether data in stream is plain, or what algorithm it is compressed by.
    encoding: u32,
    /// Byte size of the compressed array value in the stream.
    compressed_length: usize,
}

impl ArrayHeader {
    /// Constructs `ArrayValueHeader` from the given binary.
    pub fn from_binary(source: &[u8]) -> Option<(Self, usize)> {
        const LENGTH: usize = 4 * 3;
        let mut buffer = source;
        if buffer.len() < LENGTH {
            return None;
        }
        // `buffer` has enough length of data. `read_u32()`s must success.
        let num_elements = buffer.read_u32::<LittleEndian>().unwrap() as usize;
        let encoding = buffer.read_u32::<LittleEndian>().unwrap();
        let compressed_length = buffer.read_u32::<LittleEndian>().unwrap() as usize;
        Some((ArrayHeader {
            num_elements: num_elements,
            encoding: encoding,
            compressed_length: compressed_length,
        }, LENGTH))
    }
}

#[derive(Debug)]
pub enum Property<'a> {
    /// Boolean.
    Bool(bool),
    /// 2-byte signed integer.
    I16(i16),
    /// 4-byte signed integer.
    I32(i32),
    /// 8-byte signed integer.
    I64(i64),
    /// 4-byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8-byte single-precision IEEE 754 floating-point number.
    F64(f64),
    /// String.
    String(&'a str),
    /// Raw binary.
    Binary(&'a [u8]),
    /// Array of boolean.
    VecBool(Vec<bool>),
    /// Array of 4-byte signed integer.
    VecI32(Vec<i32>),
    /// Array of 8-byte signed integer.
    VecI64(Vec<i64>),
    /// Array of 4-byte single-precision IEEE 754 number.
    VecF32(Vec<f32>),
    /// Array of 8-byte double-precision IEEE 754 number.
    VecF64(Vec<f64>),
}

fn read_property_array<'a>(mut buffer: &'a [u8], header: &ArrayHeader, type_code: u8) -> Option<Property<'static>> {
    match header.encoding {
        // 0: raw.
        0 => read_property_array_from_plain_stream(&mut buffer, header, type_code),
        // 1: zlib compressed.
        1 => read_property_array_from_plain_stream(&mut ZlibDecoder::new(buffer), header, type_code),
        // Unknown.
        e => {
            error!("Unknown property array encoding: encoding={}", e);
            None
        },
    }
}

fn read_property_array_from_plain_stream<R: Read>(reader: &mut R, header: &ArrayHeader, type_code: u8) -> Option<Property<'static>> {
    macro_rules! read_into_vec {
        ($t:ty, $read_fun:ident, $variant:ident) => ({
            let mut data = Vec::<$t>::with_capacity(header.num_elements);
            for _ in 0..header.num_elements {
                data.push(try_opt!(reader.$read_fun::<LittleEndian>().ok()));
            }
            Property::$variant(data)
        });
    }
    Some(match type_code {
        // Array of 4-byte signed integer.
        b'b' => {
            let mut data = Vec::<bool>::with_capacity(header.num_elements);
            // Don't check whether the values are 'T's and 'Y's.
            for _ in 0..header.num_elements {
                data.push(try_opt!(reader.read_u8().ok()) & 1 == 1);
            }
            Property::VecBool(data)
        },
        // Array of 4-byte signed integer.
        b'i' => read_into_vec!(i32, read_i32, VecI32),
        // Array of 8-byte signed integer.
        b'l' => read_into_vec!(i64, read_i64, VecI64),
        // Array of 4-byte single-precision IEEE 754 floating-point number.
        b'f' => read_into_vec!(f32, read_f32, VecF32),
        // Array of 8-byte single-precision IEEE 754 floating-point number.
        b'd' => read_into_vec!(f64, read_f64, VecF64),
        _ => unreachable!(),
    })
}
<commit_msg>Add utility methods to `Property` to get specific type property<commit_after>//! Contains node property related stuff.

use std::fmt;
use std::str;
use std::io::Read;
use byteorder::{LittleEndian, ReadBytesExt};
use flate2::read::ZlibDecoder;

macro_rules! try_opt {
    ($opt:expr) => (if let Some(val) = $opt {
        val
    } else {
        return None;
    });
}

#[derive(Clone)]
pub struct DelayedProperties {
    pub buffer: Vec<u8>,
    pub num_properties: usize,
}

impl DelayedProperties {
    pub fn from_vec_u8(vec: Vec<u8>, _version: i32, num_properties: usize) -> Self {
        DelayedProperties {
            buffer: vec,
            num_properties: num_properties,
        }
    }

    pub fn iter(&self) -> Iter {
        Iter {
            buffer: &self.buffer[..],
            rest_properties: self.num_properties,
        }
    }

    pub fn num_properties(&self) -> usize {
        self.num_properties
    }
}

impl fmt::Debug for DelayedProperties {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("DelayedProperties")
            .field("buffer_size", &self.buffer.len())
            .field("num_properties", &self.num_properties)
            .finish()
    }
}

pub struct Iter<'a> {
    buffer: &'a [u8],
    rest_properties: usize,
}

macro_rules! implement_iter_read {
    ($t:ty, $read_fun:ident, $size:expr) => (
        impl<'a> Iter<'a> {
            fn $read_fun(&mut self) -> Option<$t> {
                // TODO: Get size from `$t` at compile time.
                //const SIZE: usize = ::std::mem::size_of::<$t>(); // size_of() is not `const fn`.
                const SIZE: usize = $size;
                if self.buffer.len() < SIZE {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                }
                let val = self.buffer.$read_fun::<LittleEndian>().unwrap();
                Some(val)
            }
        }
    )
}

impl<'a> Iter<'a> {
    fn read_u8(&mut self) -> Option<u8> {
        const SIZE: usize = 1;
        if self.buffer.len() < SIZE {
            error!("Property data is too short");
            self.rest_properties = 0;
            return None;
        }
        let val = self.buffer.read_u8().unwrap();
        Some(val)
    }
}
implement_iter_read!(u32, read_u32, 4);
implement_iter_read!(i16, read_i16, 2);
implement_iter_read!(i32, read_i32, 4);
implement_iter_read!(i64, read_i64, 8);
implement_iter_read!(f32, read_f32, 4);
implement_iter_read!(f64, read_f64, 8);

impl<'a> Iterator for Iter<'a> {
    type Item = Property<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        macro_rules! read_primitive_prop {
            ($read_fun:ident, $variant:ident) => ({
                let val = try_opt!(self.$read_fun());
                self.rest_properties -= 1;
                Some(Property::$variant(val))
            })
        }
        if self.rest_properties == 0 {
            return None;
        }
        let type_code = try_opt!(self.read_u8());
        match type_code {
            // Boolean.
            b'C' => {
                let val = try_opt!(self.read_u8());
                if (val != b'T') && (val != b'Y') {
                    warn!("Expected 0x54 ('T') or 0x59 ('Y') as boolean property value, but got {:#x}", val);
                }
                self.rest_properties -= 1;
                Some(Property::Bool(val & 1 == 1))
            },
            // 2-byte signed integer.
            b'Y' => read_primitive_prop!(read_i16, I16),
            // 4-byte signed integer.
            b'I' => read_primitive_prop!(read_i32, I32),
            // 8-byte signed integer.
            b'L' => read_primitive_prop!(read_i64, I64),
            // 4-byte single-precision IEEE 754 floating-point number.
            b'F' => read_primitive_prop!(read_f32, F32),
            // 8-byte single-precision IEEE 754 floating-point number.
            b'D' => read_primitive_prop!(read_f64, F64),
            // String.
            b'S' => {
                let length = try_opt!(self.read_u32()) as usize;
                if self.buffer.len() < length {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                }
                let buf = &self.buffer[0..length];
                self.buffer = &self.buffer[length..];
                self.rest_properties -= 1;
                let strbuf = try_opt!(str::from_utf8(buf).map_err(|err| {
                    error!("Failed to decode a property of string type: {}", err);
                    self.rest_properties = 0;
                }).ok());
                Some(Property::String(strbuf))
            },
            // Raw binary.
            b'R' => {
                let length = try_opt!(self.read_u32()) as usize;
                if self.buffer.len() < length {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                }
                let buf = &self.buffer[0..length];
                self.buffer = &self.buffer[length..];
                self.rest_properties -= 1;
                Some(Property::Binary(buf))
            },
            b'b' | b'i' | b'l' | b'f' | b'd' => {
                let array_header = if let Some((header, length)) = ArrayHeader::from_binary(self.buffer) {
                    self.buffer = &self.buffer[length..];
                    header
                } else {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                };
                if self.buffer.len() < array_header.compressed_length {
                    error!("Property data is too short");
                    self.rest_properties = 0;
                    return None;
                }
                let buf = &self.buffer[0..array_header.compressed_length];
                self.buffer = &self.buffer[array_header.compressed_length..];
                if let Some(val) = read_property_array(buf, &array_header, type_code) {
                    self.rest_properties -= 1;
                    Some(val)
                } else {
                    self.rest_properties = 0;
                    None
                }
            },
            _ => {
                error!("Unknown type code: {:#x}", type_code);
                self.rest_properties = 0;
                None
            },
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.rest_properties))
    }
}

/// Header of array type property value.
struct ArrayHeader {
    /// Number of values in the array, *NOT byte size*.
    num_elements: usize,
    /// Denotes whether data in stream is plain, or what algorithm it is compressed by.
    encoding: u32,
    /// Byte size of the compressed array value in the stream.
    compressed_length: usize,
}

impl ArrayHeader {
    /// Constructs `ArrayValueHeader` from the given binary.
    pub fn from_binary(source: &[u8]) -> Option<(Self, usize)> {
        const LENGTH: usize = 4 * 3;
        let mut buffer = source;
        if buffer.len() < LENGTH {
            return None;
        }
        // `buffer` has enough length of data. `read_u32()`s must success.
        let num_elements = buffer.read_u32::<LittleEndian>().unwrap() as usize;
        let encoding = buffer.read_u32::<LittleEndian>().unwrap();
        let compressed_length = buffer.read_u32::<LittleEndian>().unwrap() as usize;
        Some((ArrayHeader {
            num_elements: num_elements,
            encoding: encoding,
            compressed_length: compressed_length,
        }, LENGTH))
    }
}

#[derive(Debug)]
pub enum Property<'a> {
    /// Boolean.
    Bool(bool),
    /// 2-byte signed integer.
    I16(i16),
    /// 4-byte signed integer.
    I32(i32),
    /// 8-byte signed integer.
    I64(i64),
    /// 4-byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8-byte single-precision IEEE 754 floating-point number.
    F64(f64),
    /// String.
    String(&'a str),
    /// Raw binary.
    Binary(&'a [u8]),
    /// Array of boolean.
    VecBool(Vec<bool>),
    /// Array of 4-byte signed integer.
    VecI32(Vec<i32>),
    /// Array of 8-byte signed integer.
    VecI64(Vec<i64>),
    /// Array of 4-byte single-precision IEEE 754 number.
    VecF32(Vec<f32>),
    /// Array of 8-byte double-precision IEEE 754 number.
    VecF64(Vec<f64>),
}

macro_rules! implement_property_value_getter {
    (primitive, $t:ty, $method_name:ident, $variant:ident) => (
        impl<'a> Property<'a> {
            /// Get property value without consuming self.
            ///
            /// Tries to get property value of specific type without type conversion.
            pub fn $method_name(&self) -> Option<$t> {
                match *self {
                    Property::$variant(v) => Some(v),
                    _ => None,
                }
            }
        }
    );
    (vec, $t:ty, $method_name:ident, $variant:ident) => (
        impl<'a> Property<'a> {
            /// Get property value without consuming self.
            ///
            /// Tries to get property value of specific type without type conversion.
            pub fn $method_name(&self) -> Option<&Vec<$t>> {
                match *self {
                    Property::$variant(ref v) => Some(v),
                    _ => None,
                }
            }
        }
    );
}

implement_property_value_getter!(primitive, bool, get_bool, Bool);
implement_property_value_getter!(primitive, i16, get_i16, I16);
implement_property_value_getter!(primitive, i32, get_i32, I32);
implement_property_value_getter!(primitive, i64, get_i64, I64);
implement_property_value_getter!(primitive, f32, get_f32, F32);
implement_property_value_getter!(primitive, f64, get_f64, F64);

implement_property_value_getter!(vec, bool, get_vec_bool, VecBool);
implement_property_value_getter!(vec, i32, get_vec_i32, VecI32);
implement_property_value_getter!(vec, i64, get_vec_i64, VecI64);
implement_property_value_getter!(vec, f32, get_vec_f32, VecF32);
implement_property_value_getter!(vec, f64, get_vec_f64, VecF64);

implement_property_value_getter!(primitive, &'a [u8], get_binary, Binary);
implement_property_value_getter!(primitive, &'a str, get_string, String);

macro_rules! implement_property_value_into {
    ($t:ty, $method_name:ident, $variant:ident) => (
        impl<'a> Property<'a> {
            /// Get property value consuming self.
            ///
            /// Tries to get property value of specific type without type conversion.
            pub fn $method_name(self) -> Result<$t, Self> {
                match self {
                    Property::$variant(v) => Ok(v),
                    s => Err(s),
                }
            }
        }
    );
}

implement_property_value_into!(bool, into_bool, Bool);
implement_property_value_into!(i16, into_i16, I16);
implement_property_value_into!(i32, into_i32, I32);
implement_property_value_into!(i64, into_i64, I64);
implement_property_value_into!(f32, into_f32, F32);
implement_property_value_into!(f64, into_f64, F64);
implement_property_value_into!(Vec<bool>, into_vec_bool, VecBool);
implement_property_value_into!(Vec<i32>, into_vec_i32, VecI32);
implement_property_value_into!(Vec<i64>, into_vec_i64, VecI64);
implement_property_value_into!(Vec<f32>, into_vec_f32, VecF32);
implement_property_value_into!(Vec<f64>, into_vec_f64, VecF64);

impl<'a> Property<'a> {
    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn as_i32(&self) -> Option<i32> {
        match *self {
            Property::I16(v) => Some(v as i32),
            Property::I32(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn as_i64(&self) -> Option<i64> {
        match *self {
            Property::I16(v) => Some(v as i64),
            Property::I32(v) => Some(v as i64),
            Property::I64(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type.
    pub fn as_f32(&self) -> Option<f32> {
        match *self {
            Property::F32(v) => Some(v),
            Property::F64(v) => Some(v as f32),
            _ => None,
        }
    }

    /// Safe conversion.
    ///
    /// Tries to convert property value into specific type.
    pub fn as_f64(&self) -> Option<f64> {
        match *self {
            Property::F32(v) => Some(v as f64),
            Property::F64(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion consuming self.
    ///
    /// Tries to convert property value into specific type without data loss.
    pub fn as_vec_i64(self) -> Option<Vec<i64>> {
        match self {
            Property::VecI32(v) => Some(v.into_iter().map(|v| v as i64).collect::<Vec<_>>()),
            Property::VecI64(v) => Some(v),
            _ => None,
        }
    }

    /// Safe conversion consuming self.
    ///
    /// Tries to convert property value into specific type.
    pub fn as_vec_f32(self) -> Option<Vec<f32>> {
        match self {
            Property::VecF32(v) => Some(v),
            Property::VecF64(v) => Some(v.into_iter().map(|v| v as f32).collect::<Vec<_>>()),
            _ => None,
        }
    }

    /// Safe conversion consuming self.
    ///
    /// Tries to convert property value into specific type.
    pub fn as_vec_f64(self) -> Option<Vec<f64>> {
        match self {
            Property::VecF32(v) => Some(v.into_iter().map(|v| v as f64).collect::<Vec<_>>()),
            Property::VecF64(v) => Some(v),
            _ => None,
        }
    }
}

fn read_property_array<'a>(mut buffer: &'a [u8], header: &ArrayHeader, type_code: u8) -> Option<Property<'static>> {
    match header.encoding {
        // 0: raw.
        0 => read_property_array_from_plain_stream(&mut buffer, header, type_code),
        // 1: zlib compressed.
        1 => read_property_array_from_plain_stream(&mut ZlibDecoder::new(buffer), header, type_code),
        // Unknown.
        e => {
            error!("Unknown property array encoding: encoding={}", e);
            None
        },
    }
}

fn read_property_array_from_plain_stream<R: Read>(reader: &mut R, header: &ArrayHeader, type_code: u8) -> Option<Property<'static>> {
    macro_rules! read_into_vec {
        ($t:ty, $read_fun:ident, $variant:ident) => ({
            let mut data = Vec::<$t>::with_capacity(header.num_elements);
            for _ in 0..header.num_elements {
                data.push(try_opt!(reader.$read_fun::<LittleEndian>().ok()));
            }
            Property::$variant(data)
        });
    }
    Some(match type_code {
        // Array of 4-byte signed integer.
        b'b' => {
            let mut data = Vec::<bool>::with_capacity(header.num_elements);
            // Don't check whether the values are 'T's and 'Y's.
            for _ in 0..header.num_elements {
                data.push(try_opt!(reader.read_u8().ok()) & 1 == 1);
            }
            Property::VecBool(data)
        },
        // Array of 4-byte signed integer.
        b'i' => read_into_vec!(i32, read_i32, VecI32),
        // Array of 8-byte signed integer.
        b'l' => read_into_vec!(i64, read_i64, VecI64),
        // Array of 4-byte single-precision IEEE 754 floating-point number.
        b'f' => read_into_vec!(f32, read_f32, VecF32),
        // Array of 8-byte single-precision IEEE 754 floating-point number.
        b'd' => read_into_vec!(f64, read_f64, VecF64),
        _ => unreachable!(),
    })
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::borrow::BorrowMut;
use gl;
use gl::types::*;
use context::ContextOf;
use image_data::{RenderbufferFormat};
use types::GLError;

pub struct Renderbuffer {
    gl_id: GLuint
}

impl Renderbuffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Renderbuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteRenderbuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

pub struct RenderbufferBuilder<'a, B, F, P, R, T>
    where B: 'a,
          F: 'a,
          P: 'a,
          R: 'a + BorrowMut<RenderbufferBinder>,
          T: 'a
{
    gl: &'a mut ContextOf<B, F, P, R, T>,
    storage_params: Option<(RenderbufferFormat, u32, u32)>
}

impl<'a, B, F, P, R, T> RenderbufferBuilder<'a, B, F, P, R, T>
    where B: 'a,
          F: 'a,
          P: 'a,
          R: 'a + BorrowMut<RenderbufferBinder>,
          T: 'a
{
    fn new(gl: &'a mut ContextOf<B, F, P, R, T>) -> Self {
        RenderbufferBuilder {
            gl: gl,
            storage_params: None
        }
    }

    pub fn storage(mut self,
                   format: RenderbufferFormat,
                   width: u32,
                   height: u32)
        -> Self
    {
        self.storage_params = Some((format, width, height));
        self
    }

    pub fn try_unwrap(self) -> Result<Renderbuffer, GLError> {
        let gl = self.gl.borrowed_mut();
        let mut rbo = unsafe { gl.gen_renderbuffer() };

        match self.storage_params {
            Some((format, width, height)) => {
                {
                    let (mut gl_rbo, _) = gl.bind_renderbuffer(&mut rbo);
                    gl_rbo.storage(format, width, height);
                }

                Ok(rbo)
            },
            None => {
                let msg = "Error building renderbuffer: no format or dimensions provided";
                Err(GLError::Message(msg.to_owned()))
            }
        }
    }

    pub fn unwrap(self) -> Renderbuffer {
        self.try_unwrap().unwrap()
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn build_renderbuffer<'a>(&'a mut self)
        -> RenderbufferBuilder<'a, B, F, P, R, T>
        where R: BorrowMut<RenderbufferBinder>
    {
        RenderbufferBuilder::new(self)
    }

    pub unsafe fn gen_renderbuffer(&self) -> Renderbuffer {
        let mut id : GLuint = 0;

        gl::GenRenderbuffers(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Renderbuffer {
            gl_id: id
        }
    }

    pub fn bind_renderbuffer<'a>(self, renderbuffer: &'a mut Renderbuffer)
        -> (
            RenderbufferBinding<'a>,
            ContextOf<B, F, P, (), T>
        )
        where R: BorrowMut<RenderbufferBinder>
    {
        let (mut renderbuffer_binder, gl) = self.split_renderbuffer();
        (renderbuffer_binder.borrow_mut().bind(renderbuffer), gl)
    }
}

gl_enum! {
    pub gl_enum RenderbufferTarget {
        Renderbuffer as RENDERBUFFER = gl::RENDERBUFFER
    }
}

pub struct RenderbufferBinding<'a> {
    phantom: PhantomData<&'a mut Renderbuffer>
}

impl<'a> RenderbufferBinding<'a> {
    fn target(&self) -> RenderbufferTarget {
        RenderbufferTarget::Renderbuffer
    }

    pub fn storage(&mut self,
                   format: RenderbufferFormat,
                   width: u32,
                   height: u32)
    {
        unsafe {
            gl::RenderbufferStorage(self.target().gl_enum(),
                                    format.gl_enum(),
                                    width as GLint,
                                    height as GLint);
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_RENDERBUFFER` or `internalformat` is not an accepted format",
                GLError::InvalidValue => "`width` or `height` is less than zero or greater than `GL_MAX_RENDERBUFFER_SIZE`",
                GLError::OutOfMemory => "Unable to allocate enough memory for requested size",
                GLError::InvalidOperation => "Renderbuffer object 0 is bound",
                _ => "Unknown error"
            }
        }
    }
}

pub struct RenderbufferBinder;
impl RenderbufferBinder {
    pub fn bind<'a>(&mut self, renderbuffer: &'a mut Renderbuffer)
        -> RenderbufferBinding<'a>
    {
        let binding = RenderbufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindRenderbuffer(binding.target().gl_enum(),
                                 renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_RENDERBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<commit_msg>Move `ContextOf.bind_renderbuffer()` into `RenderbufferContext` trait<commit_after>use std::marker::PhantomData;
use std::borrow::BorrowMut;
use gl;
use gl::types::*;
use context::ContextOf;
use image_data::{RenderbufferFormat};
use types::GLError;

pub struct Renderbuffer {
    gl_id: GLuint
}

impl Renderbuffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Renderbuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteRenderbuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

pub struct RenderbufferBuilder<'a, B, F, P, R, T>
    where B: 'a,
          F: 'a,
          P: 'a,
          R: 'a + BorrowMut<RenderbufferBinder>,
          T: 'a
{
    gl: &'a mut ContextOf<B, F, P, R, T>,
    storage_params: Option<(RenderbufferFormat, u32, u32)>
}

impl<'a, B, F, P, R, T> RenderbufferBuilder<'a, B, F, P, R, T>
    where B: 'a,
          F: 'a,
          P: 'a,
          R: 'a + BorrowMut<RenderbufferBinder>,
          T: 'a
{
    fn new(gl: &'a mut ContextOf<B, F, P, R, T>) -> Self {
        RenderbufferBuilder {
            gl: gl,
            storage_params: None
        }
    }

    pub fn storage(mut self,
                   format: RenderbufferFormat,
                   width: u32,
                   height: u32)
        -> Self
    {
        self.storage_params = Some((format, width, height));
        self
    }

    pub fn try_unwrap(self) -> Result<Renderbuffer, GLError> {
        let gl = self.gl.borrowed_mut();
        let mut rbo = unsafe { gl.gen_renderbuffer() };

        match self.storage_params {
            Some((format, width, height)) => {
                {
                    let (mut gl_rbo, _) = gl.bind_renderbuffer(&mut rbo);
                    gl_rbo.storage(format, width, height);
                }

                Ok(rbo)
            },
            None => {
                let msg = "Error building renderbuffer: no format or dimensions provided";
                Err(GLError::Message(msg.to_owned()))
            }
        }
    }

    pub fn unwrap(self) -> Renderbuffer {
        self.try_unwrap().unwrap()
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn build_renderbuffer<'a>(&'a mut self)
        -> RenderbufferBuilder<'a, B, F, P, R, T>
        where R: BorrowMut<RenderbufferBinder>
    {
        RenderbufferBuilder::new(self)
    }

    pub unsafe fn gen_renderbuffer(&self) -> Renderbuffer {
        let mut id : GLuint = 0;

        gl::GenRenderbuffers(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Renderbuffer {
            gl_id: id
        }
    }
}

pub trait RenderbufferContext {
    type Rest;

    fn bind_renderbuffer<'a>(self, rbo: &'a mut Renderbuffer)
        -> (RenderbufferBinding<'a>, Self::Rest);
}

impl<B, F, P, R, T> RenderbufferContext for ContextOf<B, F, P, R, T>
    where R: BorrowMut<RenderbufferBinder>
{
    type Rest = ContextOf<B, F, P, (), T>;

    fn bind_renderbuffer<'a>(self, rbo: &'a mut Renderbuffer)
        -> (RenderbufferBinding<'a>, Self::Rest)
    {
        let (mut rbo_binder, rest) = self.split_renderbuffer();
        (rbo_binder.borrow_mut().bind(rbo), rest)
    }
}

impl<'b, B, F, P, R, T> RenderbufferContext
    for &'b mut ContextOf<B, F, P, R, T>
    where R: BorrowMut<RenderbufferBinder>
{
    type Rest = ContextOf<&'b mut B, &'b mut F, &'b mut P, (), &'b mut T>;

    fn bind_renderbuffer<'a>(self, rbo: &'a mut Renderbuffer)
        -> (RenderbufferBinding<'a>, Self::Rest)
    {
        let gl = self.mut_into();
        let (rbo_binder, rest): (&mut R, _) = gl.split_renderbuffer();
        (rbo_binder.borrow_mut().bind(rbo), rest)
    }
}

gl_enum! {
    pub gl_enum RenderbufferTarget {
        Renderbuffer as RENDERBUFFER = gl::RENDERBUFFER
    }
}

pub struct RenderbufferBinding<'a> {
    phantom: PhantomData<&'a mut Renderbuffer>
}

impl<'a> RenderbufferBinding<'a> {
    fn target(&self) -> RenderbufferTarget {
        RenderbufferTarget::Renderbuffer
    }

    pub fn storage(&mut self,
                   format: RenderbufferFormat,
                   width: u32,
                   height: u32)
    {
        unsafe {
            gl::RenderbufferStorage(self.target().gl_enum(),
                                    format.gl_enum(),
                                    width as GLint,
                                    height as GLint);
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_RENDERBUFFER` or `internalformat` is not an accepted format",
                GLError::InvalidValue => "`width` or `height` is less than zero or greater than `GL_MAX_RENDERBUFFER_SIZE`",
                GLError::OutOfMemory => "Unable to allocate enough memory for requested size",
                GLError::InvalidOperation => "Renderbuffer object 0 is bound",
                _ => "Unknown error"
            }
        }
    }
}

pub struct RenderbufferBinder;
impl RenderbufferBinder {
    pub fn bind<'a>(&mut self, renderbuffer: &'a mut Renderbuffer)
        -> RenderbufferBinding<'a>
    {
        let binding = RenderbufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindRenderbuffer(binding.target().gl_enum(),
                                 renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_RENDERBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate glob;
extern crate log;

extern crate protobuf_codegen_pure;

extern crate protobuf_test_common;

use std::io::Read;
use std::io::Write;

use std::fs;
use std::path::Path;

use protobuf_test_common::build::*;

fn copy_test<P1: AsRef<Path>, P2: AsRef<Path>>(src: P1, dst: P2) {
    eprintln!("copy {:?} to {:?}", src.as_ref(), dst.as_ref());
    let mut content = Vec::new();
    fs::File::open(src.as_ref())
        .expect(&format!("open {}", src.as_ref().display()))
        .read_to_end(&mut content)
        .expect("read_to_end");

    let mut write = fs::File::create(dst).expect("create");
    writeln!(write, "// generated").expect("write");
    writeln!(write, "// copied from {}", src.as_ref().display()).expect("write");
    writeln!(write, "").expect("write");
    write.write_all(&content).expect("write_all");
    writeln!(write, "// generated").expect("write");
    write.flush().expect("flush");
}

fn copy_from_protobuf_test(path: &str) {
    copy_test(&format!("../protobuf-test/{}", path), &format!("{}", path))
}

enum FileNameClass {
    ModRs,
    TestRs,
    Proto,
    GeneratedRs,
    Ignore,
}

fn classify_file_name(name: &str) -> FileNameClass {
    if name.starts_with(".") || name.ends_with(".md") || name.ends_with(".sh") {
        FileNameClass::Ignore
    } else if name.ends_with(".pb_rs") || name.ends_with("_pb_proto3.rs") {
        FileNameClass::GeneratedRs
    } else if name == "mod.rs" {
        FileNameClass::ModRs
    } else if name.ends_with(".proto") || name.ends_with(".proto3") {
        FileNameClass::Proto
    } else if name.ends_with(".rs") {
        FileNameClass::TestRs
    } else {
        panic!("unknown test file: {}", name);
    }
}

// Copy tests from `protobuf-test` directory to the same directory here
fn copy_tests(dir: &str) {
    let src_dir = format!("../protobuf-test/{}", dir);
    for entry in fs::read_dir(&src_dir).expect(&format!("read_dir {}", src_dir)) {
        let file_name = entry.expect("entry").file_name().into_string().unwrap();

        match classify_file_name(&file_name) {
            FileNameClass::ModRs | FileNameClass::Ignore | FileNameClass::GeneratedRs => {}
            FileNameClass::TestRs | FileNameClass::Proto => {
                copy_from_protobuf_test(&format!("{}/{}", dir, file_name))
            }
        }
    }
}

fn gen_in_dir(dir: &str, include_dir: &str) {
    gen_in_dir_impl(
        dir,
        include_dir,
        |GenInDirArgs {
             out_dir,
             input,
             includes,
             customize,
         }| {
            protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
                out_dir,
                input,
                includes,
                customize,
            })
        },
    );
}

fn print_rerun_if_changed<P: AsRef<Path>>(path: P) {
    let path = path.as_ref();
    // Doesn't seem to do anything
    println!("rerun-if-changed={}", path.to_str().expect("to_str"));
    if path.is_dir() {
        for child in fs::read_dir(path).expect("read_dir") {
            let child = child.expect("child").path();
            print_rerun_if_changed(child);
        }
    }
}

fn generate_interop() {
    copy_from_protobuf_test("src/interop/mod.rs");
    copy_from_protobuf_test("src/interop/json.rs");

    protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
        out_dir: "src/interop",
        includes: &["../interop/cxx", "../proto"],
        input: &["../interop/cxx/interop_pb.proto"],
        customize: Default::default(),
    }).unwrap();
}

fn generate_pb_rs() {
    print_rerun_if_changed("../protobuf-test");

    copy_tests("src/v2");
    gen_in_dir("src/v2", "src/v2");

    copy_tests("src/v3");
    gen_in_dir("src/v3", "src/v3");

    copy_tests("src/common/v2");
    gen_in_dir("src/common/v2", "src/common/v2");

    copy_tests_v2_v3("src/common/v2", "src/common/v3");
    gen_in_dir("src/common/v3", "src/common/v3");

    copy_tests("src/google/protobuf");
    gen_in_dir("src/google/protobuf", "src");

    generate_interop();
}

fn main() {
    env_logger::init();

    cfg_serde();

    clean_old_files();
    generate_pb_rs();
}
<commit_msg>Fix protobuf-codegen-pure-test test codegen<commit_after>extern crate env_logger;
extern crate glob;
extern crate log;

extern crate protobuf_codegen_pure;

extern crate protobuf_test_common;

use std::io::Read;
use std::io::Write;

use std::fs;
use std::path::Path;

use protobuf_test_common::build::*;

fn copy_test<P1: AsRef<Path>, P2: AsRef<Path>>(src: P1, dst: P2) {
    eprintln!("copy {:?} to {:?}", src.as_ref(), dst.as_ref());
    let mut content = Vec::new();
    fs::File::open(src.as_ref())
        .expect(&format!("open {}", src.as_ref().display()))
        .read_to_end(&mut content)
        .expect("read_to_end");

    let mut write = fs::File::create(dst).expect("create");
    writeln!(write, "// generated").expect("write");
    writeln!(write, "// copied from {}", src.as_ref().display()).expect("write");
    writeln!(write, "").expect("write");
    write.write_all(&content).expect("write_all");
    writeln!(write, "// generated").expect("write");
    write.flush().expect("flush");
}

fn copy_from_protobuf_test(path: &str) {
    copy_test(&format!("../protobuf-test/{}", path), &format!("{}", path))
}

enum FileNameClass {
    ModRs,
    TestRs,
    Proto,
    GeneratedRs,
    Ignore,
}

fn classify_file_name(name: &str) -> FileNameClass {
    if name.starts_with(".") || name.ends_with(".md") || name.ends_with(".sh") {
        FileNameClass::Ignore
    } else if name.ends_with("_pb.rs") || name.ends_with("_pb_proto3.rs") {
        FileNameClass::GeneratedRs
    } else if name == "mod.rs" {
        FileNameClass::ModRs
    } else if name.ends_with(".proto") || name.ends_with(".proto3") {
        FileNameClass::Proto
    } else if name.ends_with(".rs") {
        FileNameClass::TestRs
    } else {
        panic!("unknown test file: {}", name);
    }
}

// Copy tests from `protobuf-test` directory to the same directory here
fn copy_tests(dir: &str) {
    let src_dir = format!("../protobuf-test/{}", dir);
    for entry in fs::read_dir(&src_dir).expect(&format!("read_dir {}", src_dir)) {
        let file_name = entry.expect("entry").file_name().into_string().unwrap();

        match classify_file_name(&file_name) {
            FileNameClass::ModRs | FileNameClass::Ignore | FileNameClass::GeneratedRs => {}
            FileNameClass::TestRs | FileNameClass::Proto => {
                copy_from_protobuf_test(&format!("{}/{}", dir, file_name))
            }
        }
    }
}

fn gen_in_dir(dir: &str, include_dir: &str) {
    gen_in_dir_impl(
        dir,
        include_dir,
        |GenInDirArgs {
             out_dir,
             input,
             includes,
             customize,
         }| {
            protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
                out_dir,
                input,
                includes,
                customize,
            })
        },
    );
}

fn print_rerun_if_changed<P: AsRef<Path>>(path: P) {
    let path = path.as_ref();
    // Doesn't seem to do anything
    println!("rerun-if-changed={}", path.to_str().expect("to_str"));
    if path.is_dir() {
        for child in fs::read_dir(path).expect("read_dir") {
            let child = child.expect("child").path();
            print_rerun_if_changed(child);
        }
    }
}

fn generate_interop() {
    copy_from_protobuf_test("src/interop/mod.rs");
    copy_from_protobuf_test("src/interop/json.rs");

    protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
        out_dir: "src/interop",
        includes: &["../interop/cxx", "../proto"],
        input: &["../interop/cxx/interop_pb.proto"],
        customize: Default::default(),
    }).unwrap();
}

fn generate_pb_rs() {
    print_rerun_if_changed("../protobuf-test");

    copy_tests("src/v2");
    gen_in_dir("src/v2", "src/v2");

    copy_tests("src/v3");
    gen_in_dir("src/v3", "src/v3");

    copy_tests("src/common/v2");
    gen_in_dir("src/common/v2", "src/common/v2");

    copy_tests_v2_v3("src/common/v2", "src/common/v3");
    gen_in_dir("src/common/v3", "src/common/v3");

    copy_tests("src/google/protobuf");
    gen_in_dir("src/google/protobuf", "src");

    generate_interop();
}

fn main() {
    env_logger::init();

    cfg_serde();

    clean_old_files();
    generate_pb_rs();
}
<|endoftext|>


<commit_before>use anyhow::Result;
use chrono::NaiveDate;
use mysql_async::{from_row, prelude::*, Pool};

use crate::post::SurveyPostData;

pub async fn survey_add(pool: &Pool, msg: SurveyPostData) -> Result<()> {
    let mut conn = pool.get_conn().await?;
    conn.exec_drop(
        "INSERT INTO `apis` (`time`,`api`) VALUES(NOW(),?)",
        (msg.api.clone(),),
    )
    .await?;
    Ok(())
}

pub async fn survey_overview(pool: &Pool, from: Option<NaiveDate>) -> Result<Vec<SurveyGetEntry>> {
    let mut conn = pool.get_conn().await?;
    let mut request = match from {
        Some(v) => {
            conn.exec_iter(
                r#"SELECT ma.api
                , COUNT(1) AS total
                , COUNT(1) / t.cnt * 100 AS `percentage`
            FROM apis ma
            CROSS JOIN (SELECT COUNT(1) AS cnt FROM apis mai
            WHERE mai.time > ?) t
            WHERE ma.time > ?
            GROUP BY ma.api
            ORDER BY ma.api DESC;"#,
                vec![v, v],
            )
            .await?
        }
        None => {
            conn.exec_iter(
                "SELECT ma.api
                , COUNT(1) AS total
                , COUNT(1) / t.cnt * 100 AS `percentage`
            FROM apis ma
            CROSS JOIN (SELECT COUNT(1) AS cnt FROM apis) t
            GROUP BY ma.api
            ORDER BY ma.api DESC;",
                (),
            )
            .await?
        }
    };
    let data: Vec<SurveyGetEntry> = request
        .map(|result| {
            let (api, _total, perc) = from_row::<(i32, i32, f64)>(result);
            SurveyGetEntry {
                api,
                percentage: perc,
            }
        })
        .await?;

    Ok(data)
}

// pub struct DbExecutor(pub Pool);

// impl Message for SurveyPostData {
//     type Result = Fallible<SurveyPostData>;
// }

// impl Message for SurveyGetData {
//     type Result = Fallible<Vec<SurveyGetEntry>>;
// }

#[derive(Debug, Serialize, Deserialize)]
pub struct SurveyGetEntry {
    pub api: i32,
    pub percentage: f64,
}

// impl Actor for DbExecutor {
//     type Context = SyncContext<Self>;
// }

// impl Handler<SurveyPostData> for DbExecutor {
//     type Result = Fallible<SurveyPostData>;

//     fn handle(&mut self, msg: SurveyPostData, _: &mut Self::Context) -> Self::Result {
//         self.0
//             .prep_exec(
//                 "INSERT INTO `apis` (`time`,`api`) VALUES(NOW(),?)",
//                 (msg.api.clone(),),
//             )
//             .map_err(|e| BackendError::DBQuery(e))?;
//         Ok(msg)
//     }
// }

// impl Handler<SurveyGetData> for DbExecutor {
//     type Result = Fallible<Vec<SurveyGetEntry>>;

//     fn handle(&mut self, msg: SurveyGetData, _: &mut Self::Context) -> Self::Result {
//         match self.handle_fallible(msg) {
//             Err(e) => {
//                 eprintln!("{}", e);
//                 Err(e)
//             }
//             Ok(v) => Ok(v),
//         }
//     }
// }

// impl DbExecutor {
//     fn handle_fallible(&mut self, msg: SurveyGetData) -> Fallible<Vec<SurveyGetEntry>> {
//         let request = match msg.from {
//             Some(v) => self.0.prep_exec(
//                 r#"SELECT ma.api
//                     , COUNT(1) AS total
//                     , COUNT(1) / t.cnt * 100 AS `percentage`
//                 FROM apis ma
//                 CROSS JOIN (SELECT COUNT(1) AS cnt FROM apis mai
//                 WHERE mai.time > ?) t
//                 WHERE ma.time > ?
//                 GROUP
//                     BY ma.api;"#,
//                 (v, v),
//             )?,
//             None => self.0.prep_exec(
//                 "SELECT ma.api
//                     , COUNT(1) AS total
//                     , COUNT(1) / t.cnt * 100 AS `percentage`
//                 FROM apis ma
//                 CROSS JOIN (SELECT COUNT(1) AS cnt FROM apis) t
//                 GROUP
//                     BY ma.api;",
//                 (),
//             )?,
//         };
//         let data: Fallible<Vec<SurveyGetEntry>> = request
//             .map(|result| {
//                 let (api, _total, perc) = from_row_opt::<(i32, i32, f64)>(result?)?;
//                 Ok(SurveyGetEntry {
//                     api,
//                     percentage: perc,
//                 })
//             })
//             .collect();
//         data
//     }
// }
<commit_msg>cleanup from survey backend rewrite<commit_after>use anyhow::Result;
use chrono::NaiveDate;
use mysql_async::{from_row, prelude::*, Pool};

use crate::post::SurveyPostData;

pub async fn survey_add(pool: &Pool, msg: SurveyPostData) -> Result<()> {
    let mut conn = pool.get_conn().await?;
    conn.exec_drop(
        "INSERT INTO `apis` (`time`,`api`) VALUES(NOW(),?)",
        (msg.api.clone(),),
    )
    .await?;
    Ok(())
}

pub async fn survey_overview(pool: &Pool, from: Option<NaiveDate>) -> Result<Vec<SurveyGetEntry>> {
    let mut conn = pool.get_conn().await?;
    let mut request = match from {
        Some(v) => {
            conn.exec_iter(
                r#"SELECT ma.api
                , COUNT(1) AS total
                , COUNT(1) / t.cnt * 100 AS `percentage`
            FROM apis ma
            CROSS JOIN (SELECT COUNT(1) AS cnt FROM apis mai
            WHERE mai.time > ?) t
            WHERE ma.time > ?
            GROUP BY ma.api
            ORDER BY ma.api DESC;"#,
                vec![v, v],
            )
            .await?
        }
        None => {
            conn.exec_iter(
                "SELECT ma.api
                , COUNT(1) AS total
                , COUNT(1) / t.cnt * 100 AS `percentage`
            FROM apis ma
            CROSS JOIN (SELECT COUNT(1) AS cnt FROM apis) t
            GROUP BY ma.api
            ORDER BY ma.api DESC;",
                (),
            )
            .await?
        }
    };
    let data: Vec<SurveyGetEntry> = request
        .map(|result| {
            let (api, _total, perc) = from_row::<(i32, i32, f64)>(result);
            SurveyGetEntry {
                api,
                percentage: perc,
            }
        })
        .await?;

    Ok(data)
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SurveyGetEntry {
    pub api: i32,
    pub percentage: f64,
}<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Literal, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::iter::FromIterator;
use std::str::FromStr;
use syn::{Lit, LitFloat, LitInt};

fn lit(s: &str) -> Lit {
    match TokenStream::from_str(s)
        .unwrap()
        .into_iter()
        .next()
        .unwrap()
    {
        TokenTree::Literal(lit) => Lit::new(lit),
        _ => panic!(),
    }
}

#[test]
fn strings() {
    fn test_string(s: &str, value: &str) {
        match lit(s) {
            Lit::Str(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_string(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_string("\"a\"", "a");
    test_string("\"\\n\"", "\n");
    test_string("\"\\r\"", "\r");
    test_string("\"\\t\"", "\t");
    test_string("\"🐕\"", "🐕"); // NOTE: This is an emoji
    test_string("\"\\\"\"", "\"");
    test_string("\"'\"", "'");
    test_string("\"\"", "");
    test_string("\"\\u{1F415}\"", "\u{1F415}");
    test_string(
        "\"contains\nnewlines\\\nescaped newlines\"",
        "contains\nnewlinesescaped newlines",
    );
    test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere");
    test_string("\"...\"q", "...");
    test_string("r\"...\"q", "...");
    test_string("r##\"...\"##q", "...");
}

#[test]
fn byte_strings() {
    fn test_byte_string(s: &str, value: &[u8]) {
        match lit(s) {
            Lit::ByteStr(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_byte_string(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_byte_string("b\"a\"", b"a");
    test_byte_string("b\"\\n\"", b"\n");
    test_byte_string("b\"\\r\"", b"\r");
    test_byte_string("b\"\\t\"", b"\t");
    test_byte_string("b\"\\\"\"", b"\"");
    test_byte_string("b\"'\"", b"'");
    test_byte_string("b\"\"", b"");
    test_byte_string(
        "b\"contains\nnewlines\\\nescaped newlines\"",
        b"contains\nnewlinesescaped newlines",
    );
    test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere");
    test_byte_string("b\"...\"q", b"...");
    test_byte_string("br\"...\"q", b"...");
    test_byte_string("br##\"...\"##q", b"...");
}

#[test]
fn bytes() {
    fn test_byte(s: &str, value: u8) {
        match lit(s) {
            Lit::Byte(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                assert_eq!(again, s);
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_byte("b'a'", b'a');
    test_byte("b'\\n'", b'\n');
    test_byte("b'\\r'", b'\r');
    test_byte("b'\\t'", b'\t');
    test_byte("b'\\''", b'\'');
    test_byte("b'\"'", b'"');
    test_byte("b'a'q", b'a');
}

#[test]
fn chars() {
    fn test_char(s: &str, value: char) {
        match lit(s) {
            Lit::Char(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_char(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_char("'a'", 'a');
    test_char("'\\n'", '\n');
    test_char("'\\r'", '\r');
    test_char("'\\t'", '\t');
    test_char("'🐕'", '🐕'); // NOTE: This is an emoji
    test_char("'\\''", '\'');
    test_char("'\"'", '"');
    test_char("'\\u{1F415}'", '\u{1F415}');
    test_char("'a'q", 'a');
}

#[test]
fn ints() {
    fn test_int(s: &str, value: u64, suffix: &str) {
        match lit(s) {
            Lit::Int(lit) => {
                assert_eq!(lit.base10_digits().parse::<u64>().unwrap(), value);
                assert_eq!(lit.suffix(), suffix);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_int(&again, value, suffix);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_int("5", 5, "");
    test_int("5u32", 5, "u32");
    test_int("5_0", 50, "");
    test_int("5_____0_____", 50, "");
    test_int("0x7f", 127, "");
    test_int("0x7F", 127, "");
    test_int("0b1001", 9, "");
    test_int("0o73", 59, "");
    test_int("0x7Fu8", 127, "u8");
    test_int("0b1001i8", 9, "i8");
    test_int("0o73u32", 59, "u32");
    test_int("0x__7___f_", 127, "");
    test_int("0x__7___F_", 127, "");
    test_int("0b_1_0__01", 9, "");
    test_int("0o_7__3", 59, "");
    test_int("0x_7F__u8", 127, "u8");
    test_int("0b__10__0_1i8", 9, "i8");
    test_int("0o__7__________________3u32", 59, "u32");
}

#[test]
fn floats() {
    #[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
    fn test_float(s: &str, value: f64, suffix: &str) {
        match lit(s) {
            Lit::Float(lit) => {
                assert_eq!(lit.base10_digits().parse::<f64>().unwrap(), value);
                assert_eq!(lit.suffix(), suffix);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_float(&again, value, suffix);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_float("5.5", 5.5, "");
    test_float("5.5E12", 5.5e12, "");
    test_float("5.5e12", 5.5e12, "");
    test_float("1.0__3e-12", 1.03e-12, "");
    test_float("1.03e+12", 1.03e12, "");
    test_float("9e99e99", 9e99, "e99");
}

#[test]
fn negative() {
    let span = Span::call_site();
    assert_eq!("-1", LitInt::new("-1", span).to_string());
    assert_eq!("-1i8", LitInt::new("-1i8", span).to_string());
    assert_eq!("-1i16", LitInt::new("-1i16", span).to_string());
    assert_eq!("-1i32", LitInt::new("-1i32", span).to_string());
    assert_eq!("-1i64", LitInt::new("-1i64", span).to_string());
    assert_eq!("-1.5", LitFloat::new("-1.5", span).to_string());
    assert_eq!("-1.5f32", LitFloat::new("-1.5f32", span).to_string());
    assert_eq!("-1.5f64", LitFloat::new("-1.5f64", span).to_string());
}

#[test]
fn negative_overflow() {
    assert!(syn::parse_str::<LitFloat>("-1.0e99f64").is_ok());
    assert!(syn::parse_str::<LitFloat>("-1.0e999f64").is_err());
}

#[test]
fn suffix() {
    fn get_suffix(token: &str) -> String {
        let lit = syn::parse_str::<Lit>(token).unwrap();
        match lit {
            Lit::Str(lit) => lit.suffix().to_owned(),
            Lit::ByteStr(lit) => lit.suffix().to_owned(),
            Lit::Byte(lit) => lit.suffix().to_owned(),
            Lit::Char(lit) => lit.suffix().to_owned(),
            Lit::Int(lit) => lit.suffix().to_owned(),
            Lit::Float(lit) => lit.suffix().to_owned(),
            _ => unimplemented!(),
        }
    }

    assert_eq!(get_suffix("\"\"s"), "s");
    assert_eq!(get_suffix("r\"\"r"), "r");
    assert_eq!(get_suffix("b\"\"b"), "b");
    assert_eq!(get_suffix("br\"\"br"), "br");
    assert_eq!(get_suffix("r#\"\"#r"), "r");
    assert_eq!(get_suffix("'c'c"), "c");
    assert_eq!(get_suffix("b'b'b"), "b");
    assert_eq!(get_suffix("1i32"), "i32");
    assert_eq!(get_suffix("1_i32"), "i32");
    assert_eq!(get_suffix("1.0f32"), "f32");
    assert_eq!(get_suffix("1.0_f32"), "f32");
}

#[test]
fn test_deep_group_empty() {
    let tokens = TokenStream::from_iter(vec![TokenTree::Group(Group::new(
        Delimiter::None,
        TokenStream::from_iter(vec![TokenTree::Group(Group::new(
            Delimiter::None,
            TokenStream::from_iter(vec![TokenTree::Literal(Literal::string("hi"))]),
        ))]),
    ))]);

    snapshot!(tokens as Lit, @r#""hi""# );
}
<commit_msg>Add test of hex digit suffix on a non-hex literal<commit_after>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Literal, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::iter::FromIterator;
use std::str::FromStr;
use syn::{Lit, LitFloat, LitInt};

fn lit(s: &str) -> Lit {
    match TokenStream::from_str(s)
        .unwrap()
        .into_iter()
        .next()
        .unwrap()
    {
        TokenTree::Literal(lit) => Lit::new(lit),
        _ => panic!(),
    }
}

#[test]
fn strings() {
    fn test_string(s: &str, value: &str) {
        match lit(s) {
            Lit::Str(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_string(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_string("\"a\"", "a");
    test_string("\"\\n\"", "\n");
    test_string("\"\\r\"", "\r");
    test_string("\"\\t\"", "\t");
    test_string("\"🐕\"", "🐕"); // NOTE: This is an emoji
    test_string("\"\\\"\"", "\"");
    test_string("\"'\"", "'");
    test_string("\"\"", "");
    test_string("\"\\u{1F415}\"", "\u{1F415}");
    test_string(
        "\"contains\nnewlines\\\nescaped newlines\"",
        "contains\nnewlinesescaped newlines",
    );
    test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere");
    test_string("\"...\"q", "...");
    test_string("r\"...\"q", "...");
    test_string("r##\"...\"##q", "...");
}

#[test]
fn byte_strings() {
    fn test_byte_string(s: &str, value: &[u8]) {
        match lit(s) {
            Lit::ByteStr(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_byte_string(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_byte_string("b\"a\"", b"a");
    test_byte_string("b\"\\n\"", b"\n");
    test_byte_string("b\"\\r\"", b"\r");
    test_byte_string("b\"\\t\"", b"\t");
    test_byte_string("b\"\\\"\"", b"\"");
    test_byte_string("b\"'\"", b"'");
    test_byte_string("b\"\"", b"");
    test_byte_string(
        "b\"contains\nnewlines\\\nescaped newlines\"",
        b"contains\nnewlinesescaped newlines",
    );
    test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere");
    test_byte_string("b\"...\"q", b"...");
    test_byte_string("br\"...\"q", b"...");
    test_byte_string("br##\"...\"##q", b"...");
}

#[test]
fn bytes() {
    fn test_byte(s: &str, value: u8) {
        match lit(s) {
            Lit::Byte(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                assert_eq!(again, s);
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_byte("b'a'", b'a');
    test_byte("b'\\n'", b'\n');
    test_byte("b'\\r'", b'\r');
    test_byte("b'\\t'", b'\t');
    test_byte("b'\\''", b'\'');
    test_byte("b'\"'", b'"');
    test_byte("b'a'q", b'a');
}

#[test]
fn chars() {
    fn test_char(s: &str, value: char) {
        match lit(s) {
            Lit::Char(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_char(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_char("'a'", 'a');
    test_char("'\\n'", '\n');
    test_char("'\\r'", '\r');
    test_char("'\\t'", '\t');
    test_char("'🐕'", '🐕'); // NOTE: This is an emoji
    test_char("'\\''", '\'');
    test_char("'\"'", '"');
    test_char("'\\u{1F415}'", '\u{1F415}');
    test_char("'a'q", 'a');
}

#[test]
fn ints() {
    fn test_int(s: &str, value: u64, suffix: &str) {
        match lit(s) {
            Lit::Int(lit) => {
                assert_eq!(lit.base10_digits().parse::<u64>().unwrap(), value);
                assert_eq!(lit.suffix(), suffix);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_int(&again, value, suffix);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_int("5", 5, "");
    test_int("5u32", 5, "u32");
    test_int("0o0A", 0, "A");
    test_int("5_0", 50, "");
    test_int("5_____0_____", 50, "");
    test_int("0x7f", 127, "");
    test_int("0x7F", 127, "");
    test_int("0b1001", 9, "");
    test_int("0o73", 59, "");
    test_int("0x7Fu8", 127, "u8");
    test_int("0b1001i8", 9, "i8");
    test_int("0o73u32", 59, "u32");
    test_int("0x__7___f_", 127, "");
    test_int("0x__7___F_", 127, "");
    test_int("0b_1_0__01", 9, "");
    test_int("0o_7__3", 59, "");
    test_int("0x_7F__u8", 127, "u8");
    test_int("0b__10__0_1i8", 9, "i8");
    test_int("0o__7__________________3u32", 59, "u32");
}

#[test]
fn floats() {
    #[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
    fn test_float(s: &str, value: f64, suffix: &str) {
        match lit(s) {
            Lit::Float(lit) => {
                assert_eq!(lit.base10_digits().parse::<f64>().unwrap(), value);
                assert_eq!(lit.suffix(), suffix);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_float(&again, value, suffix);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_float("5.5", 5.5, "");
    test_float("5.5E12", 5.5e12, "");
    test_float("5.5e12", 5.5e12, "");
    test_float("1.0__3e-12", 1.03e-12, "");
    test_float("1.03e+12", 1.03e12, "");
    test_float("9e99e99", 9e99, "e99");
}

#[test]
fn negative() {
    let span = Span::call_site();
    assert_eq!("-1", LitInt::new("-1", span).to_string());
    assert_eq!("-1i8", LitInt::new("-1i8", span).to_string());
    assert_eq!("-1i16", LitInt::new("-1i16", span).to_string());
    assert_eq!("-1i32", LitInt::new("-1i32", span).to_string());
    assert_eq!("-1i64", LitInt::new("-1i64", span).to_string());
    assert_eq!("-1.5", LitFloat::new("-1.5", span).to_string());
    assert_eq!("-1.5f32", LitFloat::new("-1.5f32", span).to_string());
    assert_eq!("-1.5f64", LitFloat::new("-1.5f64", span).to_string());
}

#[test]
fn negative_overflow() {
    assert!(syn::parse_str::<LitFloat>("-1.0e99f64").is_ok());
    assert!(syn::parse_str::<LitFloat>("-1.0e999f64").is_err());
}

#[test]
fn suffix() {
    fn get_suffix(token: &str) -> String {
        let lit = syn::parse_str::<Lit>(token).unwrap();
        match lit {
            Lit::Str(lit) => lit.suffix().to_owned(),
            Lit::ByteStr(lit) => lit.suffix().to_owned(),
            Lit::Byte(lit) => lit.suffix().to_owned(),
            Lit::Char(lit) => lit.suffix().to_owned(),
            Lit::Int(lit) => lit.suffix().to_owned(),
            Lit::Float(lit) => lit.suffix().to_owned(),
            _ => unimplemented!(),
        }
    }

    assert_eq!(get_suffix("\"\"s"), "s");
    assert_eq!(get_suffix("r\"\"r"), "r");
    assert_eq!(get_suffix("b\"\"b"), "b");
    assert_eq!(get_suffix("br\"\"br"), "br");
    assert_eq!(get_suffix("r#\"\"#r"), "r");
    assert_eq!(get_suffix("'c'c"), "c");
    assert_eq!(get_suffix("b'b'b"), "b");
    assert_eq!(get_suffix("1i32"), "i32");
    assert_eq!(get_suffix("1_i32"), "i32");
    assert_eq!(get_suffix("1.0f32"), "f32");
    assert_eq!(get_suffix("1.0_f32"), "f32");
}

#[test]
fn test_deep_group_empty() {
    let tokens = TokenStream::from_iter(vec![TokenTree::Group(Group::new(
        Delimiter::None,
        TokenStream::from_iter(vec![TokenTree::Group(Group::new(
            Delimiter::None,
            TokenStream::from_iter(vec![TokenTree::Literal(Literal::string("hi"))]),
        ))]),
    ))]);

    snapshot!(tokens as Lit, @r#""hi""# );
}
<|endoftext|>


<commit_before>use std::path::Path;

use config::Config;
use installation::{ Cache, PackageState };

/// Gets the config, fill it with default values, and return it.
fn get_config<P: AsRef<Path>>(path: P) -> Config {
    Config::read_from(path)
        .map(|x| x.fill_with_default())
        .unwrap()
}

/// Gets the cached repositories.
fn get_cache<P: AsRef<Path>>(path: P) -> Cache {
    Cache::read_from(path).unwrap()
}<commit_msg>Make functions public<commit_after>use std::path::{ Path, PathBuf };

use config::Config;
use installation::{ Cache, PackageState };
use repository::RepositoryList;

/// Gets the config, fill it with default values, and return it.
pub fn get_config<P: AsRef<Path>>(path: P) -> Config {
    Config::read_from(path)
        .map(|x| x.fill_with_default())
        .unwrap()
}

/// Gets the list of installed packages.
pub fn get_cache<P: AsRef<Path>>(path: P) -> Cache {
    Cache::read_from(path).unwrap()
}

pub fn get_repositories<P: AsRef<Path>>(path: P) -> RepositoryList {
    RepositoryList::read_from(path).unwrap()
}<|endoftext|>