<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.
use std::fmt::{Debug, Display, Formatter};
use regex::Error as RegexError;

// TODO(panhania@): Migrate to error kind design.
/// An error type for failures that can occur during a session.
#[derive(Debug)]
pub enum Error {
    /// Action-specific failure.
    Action(Box<dyn std::error::Error>),
    /// Attempted to call an unknown or not implemented action.
    Dispatch(String),
    /// An error occurred when encoding bytes of a proto message.
    // TODO: Determine whether we need this error type or we should just panic.
    Encode(protobuf::ProtobufError),
    /// An error occurred when parsing a proto message.
    Parse(crate::action::ParseArgsError),
}

impl Error {

    /// Converts an arbitrary action-issued error to a session error.
    ///
    /// This function should be used to construct session errors from action
    /// specific error types and propagate them further in the session pipeline.
    pub fn action<E>(error: E) -> Error
    where
        E: std::error::Error + 'static
    {
        Error::Action(Box::new(error))
    }
}

impl Display for Error {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            Action(ref error) => {
                write!(fmt, "action error: {}", error)
            }
            Dispatch(ref name) if name.is_empty() => {
                write!(fmt, "missing action")
            }
            Dispatch(ref name) => {
                write!(fmt, "unknown action: {}", name)
            }
            Encode(ref error) => {
                write!(fmt, "failure during encoding proto message: {}", error)
            }
            Parse(ref error) => {
                write!(fmt, "malformed proto message: {}", error)
            }
        }
    }
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            Action(ref error) => Some(error.as_ref()),
            Dispatch(_) => None,
            Encode(ref error) => Some(error),
            Parse(ref error) => Some(error),
        }
    }
}

impl From<protobuf::ProtobufError> for Error {

    fn from(error: protobuf::ProtobufError) -> Error {
        Error::Encode(error)
    }
}

impl From<crate::action::ParseArgsError> for Error {

    fn from(error: crate::action::ParseArgsError) -> Error {
        Error::Parse(error)
    }
}

/// An error type for failures that can occur when parsing proto messages.
#[derive(Debug)]
pub enum ParseError {
    /// An error occurred because the decoded proto message was malformed.
    Malformed(Box<dyn std::error::Error + Send + Sync>),
    /// An error occurred when decoding bytes of a proto message.
    Decode(protobuf::ProtobufError),
}

impl ParseError {

    /// Converts a detailed error indicating a malformed proto to `ParseError`.
    ///
    /// This is just a convenience function for lifting custom error types that
    /// contain more specific information to generic `ParseError`.
    pub fn malformed<E>(error: E) -> ParseError
    where
        E: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        ParseError::Malformed(error.into())
    }
}

impl Display for ParseError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use ParseError::*;

        match *self {
            Malformed(ref error) => {
                write!(fmt, "invalid proto message: {}", error)
            }
            Decode(ref error) => {
                write!(fmt, "failed to decode proto message: {}", error)
            }
        }
    }
}

impl std::error::Error for ParseError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use ParseError::*;

        match *self {
            Malformed(ref error) => Some(error.as_ref()),
            Decode(ref error) => Some(error),
        }
    }
}

impl From<protobuf::ProtobufError> for ParseError {

    fn from(error: protobuf::ProtobufError) -> ParseError {
        ParseError::Decode(error)
    }
}

/// An error type for situations where required proto field is missing.
#[derive(Debug)]
pub struct MissingFieldError {
    /// A name of the missing field.
    name: &'static str,
}

impl MissingFieldError {

    /// Creates a new error indicating that required field `name` is missing.
    pub fn new(name: &'static str) -> MissingFieldError {
        MissingFieldError {
            name: name,
        }
    }
}

impl Display for MissingFieldError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "required field '{}' is missing", self.name)
    }
}

impl std::error::Error for MissingFieldError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<MissingFieldError> for ParseError {

    fn from(error: MissingFieldError) -> ParseError {
        ParseError::malformed(error)
    }
}

/// An error type for situations where a given proto value is not supported.
#[derive(Debug)]
pub struct UnsupportedValueError<T> {
    /// A name of the field the value belongs to.
    pub name: &'static str,
    /// A value that is not supported.
    pub value: T,
}

impl<T: Debug> Display for UnsupportedValueError<T> {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "unsupported value for '{}': {:?}", self.name, self.value)
    }
}

impl<T: Debug> std::error::Error for UnsupportedValueError<T> {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

/// An error type for situations where time micros cannot be converted
/// to `std::time::SystemTime`.
#[derive(Debug)]
pub struct TimeMicrosConversionError {
    /// Time micros value causing the conversion error.
    pub micros: u64,
}

impl Display for TimeMicrosConversionError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "cannot convert micros to std::time::SystemTime: {}", self.micros)
    }
}

impl std::error::Error for TimeMicrosConversionError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<TimeMicrosConversionError> for ParseError {

    fn from(error: TimeMicrosConversionError) -> ParseError {
        ParseError::malformed(error)
    }
}

#[derive(Debug)]
pub struct RegexParseError {
    /// Raw data of the string which could not be converted to Regex.
    pub raw_data: Vec<u8>,
    /// Error message caught during the conversion.
    pub error: RegexError,
}

impl Display for RegexParseError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "Regex parse error happened on parsing '{:?}'. \
                     Regex error: '{}'",
               self.raw_data,
               self.error.to_string())
    }
}

impl std::error::Error for RegexParseError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<RegexParseError> for ParseError {

    fn from(error: RegexParseError) -> ParseError {
        ParseError::malformed(error)
    }
}

/// An error type for situations where proto enum has a value for which
/// the definition is not known.
#[derive(Debug)]
pub struct UnknownEnumValueError {
    /// A name of the enum field having unknown enum value.
    pub name: &'static str,

    /// An enum value, which definition is not known.
    pub value: i32,
}

impl Display for UnknownEnumValueError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "protobuf enum '{}' has unrecognised value: '{}'",
               self.name, self.value)
    }
}

impl std::error::Error for UnknownEnumValueError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<UnknownEnumValueError> for ParseError {

    fn from(error: UnknownEnumValueError) -> ParseError {
        ParseError::malformed(error)
    }
}
<commit_msg>Remove a no longer used session error variant.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.
use std::fmt::{Debug, Display, Formatter};
use regex::Error as RegexError;

// TODO(panhania@): Migrate to error kind design.
/// An error type for failures that can occur during a session.
#[derive(Debug)]
pub enum Error {
    /// Action-specific failure.
    Action(Box<dyn std::error::Error>),
    /// Attempted to call an unknown or not implemented action.
    Dispatch(String),
    /// An error occurred when parsing a proto message.
    Parse(crate::action::ParseArgsError),
}

impl Error {

    /// Converts an arbitrary action-issued error to a session error.
    ///
    /// This function should be used to construct session errors from action
    /// specific error types and propagate them further in the session pipeline.
    pub fn action<E>(error: E) -> Error
    where
        E: std::error::Error + 'static
    {
        Error::Action(Box::new(error))
    }
}

impl Display for Error {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            Action(ref error) => {
                write!(fmt, "action error: {}", error)
            }
            Dispatch(ref name) if name.is_empty() => {
                write!(fmt, "missing action")
            }
            Dispatch(ref name) => {
                write!(fmt, "unknown action: {}", name)
            }
            Parse(ref error) => {
                write!(fmt, "malformed proto message: {}", error)
            }
        }
    }
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            Action(ref error) => Some(error.as_ref()),
            Dispatch(_) => None,
            Parse(ref error) => Some(error),
        }
    }
}

impl From<crate::action::ParseArgsError> for Error {

    fn from(error: crate::action::ParseArgsError) -> Error {
        Error::Parse(error)
    }
}

/// An error type for failures that can occur when parsing proto messages.
#[derive(Debug)]
pub enum ParseError {
    /// An error occurred because the decoded proto message was malformed.
    Malformed(Box<dyn std::error::Error + Send + Sync>),
    /// An error occurred when decoding bytes of a proto message.
    Decode(protobuf::ProtobufError),
}

impl ParseError {

    /// Converts a detailed error indicating a malformed proto to `ParseError`.
    ///
    /// This is just a convenience function for lifting custom error types that
    /// contain more specific information to generic `ParseError`.
    pub fn malformed<E>(error: E) -> ParseError
    where
        E: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        ParseError::Malformed(error.into())
    }
}

impl Display for ParseError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use ParseError::*;

        match *self {
            Malformed(ref error) => {
                write!(fmt, "invalid proto message: {}", error)
            }
            Decode(ref error) => {
                write!(fmt, "failed to decode proto message: {}", error)
            }
        }
    }
}

impl std::error::Error for ParseError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use ParseError::*;

        match *self {
            Malformed(ref error) => Some(error.as_ref()),
            Decode(ref error) => Some(error),
        }
    }
}

impl From<protobuf::ProtobufError> for ParseError {

    fn from(error: protobuf::ProtobufError) -> ParseError {
        ParseError::Decode(error)
    }
}

/// An error type for situations where required proto field is missing.
#[derive(Debug)]
pub struct MissingFieldError {
    /// A name of the missing field.
    name: &'static str,
}

impl MissingFieldError {

    /// Creates a new error indicating that required field `name` is missing.
    pub fn new(name: &'static str) -> MissingFieldError {
        MissingFieldError {
            name: name,
        }
    }
}

impl Display for MissingFieldError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "required field '{}' is missing", self.name)
    }
}

impl std::error::Error for MissingFieldError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<MissingFieldError> for ParseError {

    fn from(error: MissingFieldError) -> ParseError {
        ParseError::malformed(error)
    }
}

/// An error type for situations where a given proto value is not supported.
#[derive(Debug)]
pub struct UnsupportedValueError<T> {
    /// A name of the field the value belongs to.
    pub name: &'static str,
    /// A value that is not supported.
    pub value: T,
}

impl<T: Debug> Display for UnsupportedValueError<T> {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "unsupported value for '{}': {:?}", self.name, self.value)
    }
}

impl<T: Debug> std::error::Error for UnsupportedValueError<T> {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

/// An error type for situations where time micros cannot be converted
/// to `std::time::SystemTime`.
#[derive(Debug)]
pub struct TimeMicrosConversionError {
    /// Time micros value causing the conversion error.
    pub micros: u64,
}

impl Display for TimeMicrosConversionError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "cannot convert micros to std::time::SystemTime: {}", self.micros)
    }
}

impl std::error::Error for TimeMicrosConversionError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<TimeMicrosConversionError> for ParseError {

    fn from(error: TimeMicrosConversionError) -> ParseError {
        ParseError::malformed(error)
    }
}

#[derive(Debug)]
pub struct RegexParseError {
    /// Raw data of the string which could not be converted to Regex.
    pub raw_data: Vec<u8>,
    /// Error message caught during the conversion.
    pub error: RegexError,
}

impl Display for RegexParseError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "Regex parse error happened on parsing '{:?}'. \
                     Regex error: '{}'",
               self.raw_data,
               self.error.to_string())
    }
}

impl std::error::Error for RegexParseError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<RegexParseError> for ParseError {

    fn from(error: RegexParseError) -> ParseError {
        ParseError::malformed(error)
    }
}

/// An error type for situations where proto enum has a value for which
/// the definition is not known.
#[derive(Debug)]
pub struct UnknownEnumValueError {
    /// A name of the enum field having unknown enum value.
    pub name: &'static str,

    /// An enum value, which definition is not known.
    pub value: i32,
}

impl Display for UnknownEnumValueError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        write!(fmt, "protobuf enum '{}' has unrecognised value: '{}'",
               self.name, self.value)
    }
}

impl std::error::Error for UnknownEnumValueError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<UnknownEnumValueError> for ParseError {

    fn from(error: UnknownEnumValueError) -> ParseError {
        ParseError::malformed(error)
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::thread;
use std::time::{Duration, Instant};

use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use sdl2::pixels::Color;
use sdl2::rect::Rect; // TODO: abstract my own drawtypes?
use sdl2::render::Texture;

use graphics::Display;
use input::Input;
use units::V2;

pub static COLOR_BG: Color  = Color::RGB(0,0,0);
pub static COLOR_FPS: Color = Color::RGB(255,255,0);
pub static COLOR_PEN: Color = Color::RGB(125, 0, 175);

#[derive(Copy, Clone, Debug)]
enum BrushMode {
    Normal,
    Squareish,
    WowSoEdgy,
}

struct Region {
    pub is_dirty: bool,
    pub texture:  Option<Texture>,
}

pub struct Engine {
    context:     sdl2::Sdl,
    controller:  Input,
    display:     Display,

    brush:   BrushMode,
    color:   (u8,u8,u8),
    cursor:  (i32,i32),
    scanbox: V2,
}

impl Engine {
    pub fn new(context: sdl2::Sdl) -> Engine {
        let video_renderer = Display::new(&context);

        Engine {
            context:    context,
            controller: Input::new(),
            display:    video_renderer,

            brush:   BrushMode::Squareish,
            color:   (125,0,175),
            cursor:  (0,0),
            scanbox: V2(0,0),
        }
    }

    pub fn run(&mut self) {
        let target_fps_ms  = Duration::from_millis(1000 / 120); // TODO: const fn?

        let mut event_pump = self.context.event_pump().unwrap();
        let mut is_running = true;

        let mut frame_start_at;
        let mut elapsed_time = Duration::from_millis(0);

        // init 9x9
        let mut regions = vec![];
        for _ in 0..9 {
            let mut txbuf = Some(self.display.get_texture(1280,720));
            regions.push(Region {
                is_dirty: true,
                texture:  txbuf,
            });
        }

        let mut mouse_clicked = false;
        let mut last_point = None;

        // init bitmap to good state
        //

        while is_running {
            frame_start_at  = Instant::now();

            // drain input event queue once per frame
            self.controller.begin_new_frame();
            for event in event_pump.poll_iter() {
                match event {
                    Event::KeyDown { keycode, .. } => {
                        self.controller.key_down_event(keycode.unwrap());
                    },

                    Event::KeyUp { keycode, .. } => {
                        self.controller.key_up_event(keycode.unwrap());
                    },

                    Event::MouseMotion { x, y, .. } => self.cursor = (x,y),

                    Event::MouseButtonDown { .. } => mouse_clicked = true,
                    Event::MouseButtonUp   { .. } => mouse_clicked = false,

                    _ => {},
                }
            }

            // handle exit game
            if self.controller.was_key_released(Keycode::Escape) { is_running = false; }

            // erase canvas
            if self.controller.was_key_released(Keycode::E) {
                for region in regions.iter_mut() {
                    Engine::with_texture(&mut self.display, &mut region.texture, |io| {
                        io.clear_buffer();
                        io.fill_rect(Rect::new(0,0,1280,5),   Color::RGB(255,0,0));  // top
                        io.fill_rect(Rect::new(0,715,1280,5), Color::RGB(255,0,0));  // bottom
                        io.fill_rect(Rect::new(0,0,5,720),    Color::RGB(255,0,0) ); // left
                        io.fill_rect(Rect::new(1275,0,5,720), Color::RGB(255,0,0));  // right
                    });
                }
            }

            // switch brush
            if self.controller.was_key_released(Keycode::B) {
                self.brush = match self.brush { // TODO: better cycle?
                    BrushMode::Normal    => BrushMode::Squareish,
                    BrushMode::Squareish => BrushMode::WowSoEdgy,
                    BrushMode::WowSoEdgy => BrushMode::Squareish,
                }
            }

            if self.controller.is_key_held(Keycode::I) {
                self.color.0 = self.color.0.wrapping_add(0x01);
            } else if self.controller.is_key_held(Keycode::O) {
                self.color.1 = self.color.1.wrapping_add(0x01);
            } else if self.controller.is_key_held(Keycode::P) {
                self.color.2 = self.color.2.wrapping_add(0x01);
            }

            if self.controller.is_key_held(Keycode::Up) {
                self.scanbox = self.scanbox - V2(0, 5);
            } else if self.controller.is_key_held(Keycode::Down) {
                self.scanbox = self.scanbox + V2(0, 5);
            } else if self.controller.is_key_held(Keycode::Left) {
                self.scanbox = self.scanbox - V2(5, 0);
            } else if self.controller.is_key_held(Keycode::Right) {
                self.scanbox = self.scanbox + V2(5, 0);
            }

            // blit current brush to appropriate region
            let brush_color = Color::RGB(self.color.0, self.color.1, self.color.2);
            if mouse_clicked {
                let (x2,y2) = self.cursor;

                if let Some((x1,y1)) = last_point {
                    let brush = self.brush;
                    let V2(ofs_x, ofs_y) = self.scanbox;

                    let x1 = x1 + ofs_x as i32;
                    let x2 = x2 + ofs_x as i32;
                    let y1 = y1 + ofs_y as i32;
                    let y2 = y2 + ofs_y as i32;

                    Engine::with_texture(&mut self.display, &mut regions[0].texture, |display| {
                        match brush {
                            BrushMode::WowSoEdgy => for i in 0..10 {
                                display.draw_line(x1+i, y1, x2, y2+i, brush_color);
                            },

                            BrushMode::Squareish => for i in 0..5 {
                                display.draw_line(x1+i, y1, x2+i, y2, brush_color);
                            },

                            BrushMode::Normal => {},
                        }
                    });

                    let pitch = (regions.len() as f64).sqrt() as i32;
                    if (x1 > 1280) || (y1 > 720) {
                        // compute ridx
                        let col  = x1 / 1280;
                        let row  = y1 / 720;
                        let ridx = (row * pitch) + col; // row * 3rows/col + col

                        //println!("[{}], row: {}, col: {}", ridx, row, col);
                        //println!("real ({},{})=>({},{})", x1, y1, x2, y2);
                        let (x1,x2) = if x1 > 1280 {
                            let x1 = x1 % (1280 * col+1);
                            let x2 = x2 % (1280 * col+1);
                            (x1,x2)
                        } else { (x1,x2) };

                        let (y1,y2) = if y1 > 720 {
                            let y1 = y1 % ( 720 * row+1);
                            let y2 = y2 % ( 720 * row+1);
                            (y1,y2)
                        } else { (y1,y2) };
                        //println!("adj ({},{})=>({},{})", x1, y1, x2, y2);

                        Engine::with_texture(&mut self.display, &mut regions[ridx as usize].texture, |display| {
                            match brush {
                                BrushMode::WowSoEdgy => for i in 0..10 {
                                    display.draw_line(x1+i, y1, x2, y2+i, brush_color);
                                },

                                BrushMode::Squareish => for i in 0..5 {
                                    display.draw_line(x1+i, y1, x2+i, y2, brush_color);
                                },

                                BrushMode::Normal => {},
                            }
                        });
                    }

                    // let diffx = x2 - x1;
                    // let diffy = y2 - y1;
                    // println!("delta ({},{}), mag: {}", diffx, diffy, diffy-diffx);
                } // NOTE: doesn't draw point if mouse held for single frame

                last_point = Some((x2,y2));
           } else { last_point = None; }

            // handle draw calls
            self.display.clear_buffer(); // clear back-buffer
            self.draw_regions(&mut regions);
            self.draw_cursor(brush_color);

            let V2(rx, ry) = self.scanbox + V2(1280,720);
            let region_sqrt = (regions.len() as f64).sqrt();
            if (rx as f64 > region_sqrt * 1280.0) || (ry as f64 > region_sqrt *  720.0) {
                println!("need to regrow right!");
                let pitch = (region_sqrt + 1.0) as usize;
                let next_square = pitch * pitch;

                // swap in the newly regrown buffer
                let mut buf = Vec::with_capacity(next_square);
                mem::swap(&mut regions, &mut buf);
                let mut old_drain = buf.into_iter();

                // copy old / allocate new
                for row in 0..pitch {
                    for col in 0..pitch {
                        let ridx = col + (row * 4);

                        if (row >= pitch - 1) || (col >= pitch - 1) {
                            // new region
                            let mut txbuf = Some(self.display.get_texture(1280,720));
                            regions.push(Region {
                                is_dirty: true,
                                texture:  txbuf,
                            });
                        } else {
                            regions.push(old_drain.next().expect("ran out of regions to copy during regrow!"));
                        }
                    }
                }
            }

            // if they pan left, trick them into thinking had canvases there
            if (self.scanbox.0 < 0) || (self.scanbox.1 < 0) {
                println!("need to regrow left!");
                let pitch = (region_sqrt + 1.0) as usize;
                let next_square = pitch * pitch;

                // swap in the newly regrown buffer
                let mut buf = Vec::with_capacity(next_square);
                mem::swap(&mut regions, &mut buf);
                let mut old_drain = buf.into_iter();

                // copy old / allocate new
                for row in 0..pitch {
                    for col in 0..pitch {
                        let ridx = col + (row * 4);

                        if (row == 0) || (col == 0) {
                            // new region
                            let mut txbuf = Some(self.display.get_texture(1280,720));

                            regions.push(Region {
                                is_dirty: true,
                                texture:  txbuf,
                            });
                        } else {
                            regions.push(old_drain.next().expect("ran out of regions to copy during regrow!"));
                        }
                    }
                }

                self.scanbox = V2(1280,720) + self.scanbox;
            }

            self.draw_debug(elapsed_time, regions.len());
            self.display.switch_buffers();

            // sleep for <target> - <draw time> and floor to zero
            elapsed_time = frame_start_at.elapsed();
            let sleep_time = if elapsed_time > target_fps_ms {
                Duration::from_millis(0)
            } else { target_fps_ms - elapsed_time };

            thread::sleep(sleep_time);
        }
    }

    // HACK: pulls texture out of an option and gives you a closure in which
    // you can use renderer calls to blit to it ...
    //
    fn with_texture<F>(io: &mut Display, target: &mut Option<Texture>, mut mutator: F)
        where F: FnMut(&mut Display) -> () {

        let _last = io.retarget().set(target.take().unwrap());
        mutator(io);
        *target = io.retarget().reset()
                        .ok().expect("did not get target back");
    }

    fn draw_cursor(&mut self, brush_color: Color) {
        self.display.fill_rect(Rect::new(self.cursor.0, self.cursor.1, 10, 10), brush_color);
    }

    fn draw_debug(&mut self, time: Duration, num_regions: usize) {
        let mut time_ms = time.as_secs() * 1000;        // -> millis
        time_ms += time.subsec_nanos() as u64 / (1000 * 1000); // /> micros /> millis

        let (hue_r, hue_g, hue_b) = self.color;
        let buf = format!("{}ms, # regions: {}, sb @ {:?}, \
                          e = erase all, b = brush ({:?}), hue(i,o,p) => ({:x},{:x},{:x})",
                          time_ms,
                          num_regions,
                          self.scanbox,
                          self.brush,
                          hue_r, hue_g, hue_b);
        self.display.blit_text(&buf[..], COLOR_FPS);
    }

    fn draw_regions(&mut self, regions: &mut Vec<Region>) {
        let V2(ofs_x, ofs_y) = self.scanbox;

        let pitch = (regions.len() as f64).sqrt() as usize;
        for row in 0..pitch {
            for col in 0..pitch {
                // (0,0), (0, 720)
                let x = (col * 1280) as i32;
                let y = (row *  720) as i32;
                let ridx = col + (row * pitch);

                if regions[ridx].is_dirty {
                    regions[ridx].is_dirty = false;
                    Engine::with_texture(&mut self.display, &mut regions[ridx].texture, |io| {
                        io.clear_buffer();
                        io.fill_rect(Rect::new(0,0,1280,5),   Color::RGB(255,0,0));  // top
                        io.fill_rect(Rect::new(0,715,1280,5), Color::RGB(255,0,0));  // bottom
                        io.fill_rect(Rect::new(0,0,5,720),    Color::RGB(255,0,0) ); // left
                        io.fill_rect(Rect::new(1275,0,5,720), Color::RGB(255,0,0));  // right
                    });
                }

                self.display.copy_t(regions[ridx].texture.as_ref().unwrap(),
                    Rect::new(0, 0, 1280, 720),
                    Rect::new(x - ofs_x as i32, y - ofs_y as i32, 1280, 720));
            }
        }
    }
}
<commit_msg>add simple eraser and clean up rendering special case<commit_after>use std::mem;
use std::thread;
use std::time::{Duration, Instant};

use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use sdl2::pixels::Color;
use sdl2::rect::Rect; // TODO: abstract my own drawtypes?
use sdl2::render::Texture;

use graphics::Display;
use input::Input;
use units::V2;

pub static COLOR_BG: Color  = Color::RGB(0,0,0);
pub static COLOR_FPS: Color = Color::RGB(255,255,0);
pub static COLOR_PEN: Color = Color::RGB(125, 0, 175);

#[derive(Copy, Clone, Debug)]
enum BrushMode {
    Normal,
    Squareish,
    WowSoEdgy,
    Eraser,
}

struct Region {
    pub is_dirty: bool,
    pub texture:  Option<Texture>,
}

pub struct Engine {
    context:     sdl2::Sdl,
    controller:  Input,
    display:     Display,

    brush:   BrushMode,
    color:   (u8,u8,u8),
    cursor:  (i32,i32),
    scanbox: V2,
}

impl Engine {
    pub fn new(context: sdl2::Sdl) -> Engine {
        let video_renderer = Display::new(&context);

        Engine {
            context:    context,
            controller: Input::new(),
            display:    video_renderer,

            brush:   BrushMode::Squareish,
            color:   (125,0,175),
            cursor:  (0,0),
            scanbox: V2(0,0),
        }
    }

    pub fn run(&mut self) {
        let target_fps_ms  = Duration::from_millis(1000 / 120); // TODO: const fn?

        let mut event_pump = self.context.event_pump().unwrap();
        let mut is_running = true;

        let mut frame_start_at;
        let mut elapsed_time = Duration::from_millis(0);

        // init 9x9
        let mut regions = vec![];
        for _ in 0..9 {
            let mut txbuf = Some(self.display.get_texture(1280,720));
            regions.push(Region {
                is_dirty: true,
                texture:  txbuf,
            });
        }

        let mut mouse_clicked = false;
        let mut last_point = None;

        // init bitmap to good state
        //

        while is_running {
            frame_start_at  = Instant::now();

            // drain input event queue once per frame
            self.controller.begin_new_frame();
            for event in event_pump.poll_iter() {
                match event {
                    Event::KeyDown { keycode, .. } => {
                        self.controller.key_down_event(keycode.unwrap());
                    },

                    Event::KeyUp { keycode, .. } => {
                        self.controller.key_up_event(keycode.unwrap());
                    },

                    Event::MouseMotion { x, y, .. } => self.cursor = (x,y),

                    Event::MouseButtonDown { .. } => mouse_clicked = true,
                    Event::MouseButtonUp   { .. } => mouse_clicked = false,

                    _ => {},
                }
            }

            // handle exit game
            if self.controller.was_key_released(Keycode::Escape) { is_running = false; }

            // erase canvas
            if self.controller.was_key_released(Keycode::E) {
                for region in regions.iter_mut() {
                    Engine::with_texture(&mut self.display, &mut region.texture, |io| {
                        io.clear_buffer();
                        io.fill_rect(Rect::new(0,0,1280,5),   Color::RGB(255,0,0));  // top
                        io.fill_rect(Rect::new(0,715,1280,5), Color::RGB(255,0,0));  // bottom
                        io.fill_rect(Rect::new(0,0,5,720),    Color::RGB(255,0,0) ); // left
                        io.fill_rect(Rect::new(1275,0,5,720), Color::RGB(255,0,0));  // right
                    });
                }
            }

            // switch brush
            if self.controller.was_key_released(Keycode::B) {
                self.brush = match self.brush { // TODO: better cycle?
                    BrushMode::Normal    => BrushMode::Squareish,
                    BrushMode::Squareish => BrushMode::WowSoEdgy,
                    BrushMode::WowSoEdgy => BrushMode::Eraser,
                    BrushMode::Eraser    => BrushMode::Normal,
                }
            }

            if self.controller.is_key_held(Keycode::I) {
                self.color.0 = self.color.0.wrapping_add(0x01);
            } else if self.controller.is_key_held(Keycode::O) {
                self.color.1 = self.color.1.wrapping_add(0x01);
            } else if self.controller.is_key_held(Keycode::P) {
                self.color.2 = self.color.2.wrapping_add(0x01);
            }

            if self.controller.is_key_held(Keycode::Up) {
                self.scanbox = self.scanbox - V2(0, 5);
            } else if self.controller.is_key_held(Keycode::Down) {
                self.scanbox = self.scanbox + V2(0, 5);
            } else if self.controller.is_key_held(Keycode::Left) {
                self.scanbox = self.scanbox - V2(5, 0);
            } else if self.controller.is_key_held(Keycode::Right) {
                self.scanbox = self.scanbox + V2(5, 0);
            }

            // blit current brush to appropriate region
            let brush_color = Color::RGB(self.color.0, self.color.1, self.color.2);
            if mouse_clicked {
                let (x2,y2) = self.cursor;

                if let Some((x1,y1)) = last_point {
                    let brush = self.brush;
                    let V2(ofs_x, ofs_y) = self.scanbox;

                    // cursor + scanbox origin => adjusted coordinate
                    let x1 = x1 + ofs_x as i32;
                    let x2 = x2 + ofs_x as i32;
                    let y1 = y1 + ofs_y as i32;
                    let y2 = y2 + ofs_y as i32;

                    // compute ridx of adjusted coordinate
                    let pitch = (regions.len() as f64).sqrt() as i32;
                    let col  = x1 / 1280;
                    let row  = y1 / 720;
                    let ridx = (row * pitch) + col; // row * 3rows/col + col

                    // blit in that region instead
                    println!("[{}], row: {}, col: {}", ridx, row, col);
                    println!("real ({},{})=>({},{})", x1, y1, x2, y2);
                    let (x1,x2) = if x1 > 1280 {
                        let x1 = x1 % (1280 * col+1);
                        let x2 = x2 % (1280 * col+1);
                        (x1,x2)
                    } else { (x1,x2) };

                    let (y1,y2) = if y1 > 720 {
                        let y1 = y1 % ( 720 * row+1);
                        let y2 = y2 % ( 720 * row+1);
                        (y1,y2)
                    } else { (y1,y2) };
                    println!("adj ({},{})=>({},{})", x1, y1, x2, y2);

                    if x1 + 5 < 1280 && x2 < 1280 && y1 < 720 && y2 + 10 < 720 {
                        Engine::with_texture(&mut self.display, &mut regions[ridx as usize].texture, |display| {
                            match brush {
                                BrushMode::WowSoEdgy => for i in 0..10 {
                                    display.draw_line(x1+i, y1, x2, y2+i, brush_color);
                                },

                                BrushMode::Squareish => for i in 0..5 {
                                    display.draw_line(x1+i, y1, x2+i, y2, brush_color);
                                },

                                BrushMode::Eraser => {
                                    display.fill_rect(Rect::new(x2,y2, 20, 20), Color::RGB(0,0,0));
                                },

                                BrushMode::Normal => {},
                            }
                        });
                    }

                    // let diffx = x2 - x1;
                    // let diffy = y2 - y1;
                    // println!("delta ({},{}), mag: {}", diffx, diffy, diffy-diffx);
                } // NOTE: doesn't draw point if mouse held for single frame

                last_point = Some((x2,y2));
           } else { last_point = None; }

            // handle draw calls
            self.display.clear_buffer(); // clear back-buffer
            self.draw_regions(&mut regions);
            self.draw_cursor(brush_color);

            let V2(rx, ry) = self.scanbox + V2(1280,720);
            let region_sqrt = (regions.len() as f64).sqrt();
            if (rx as f64 > region_sqrt * 1280.0) || (ry as f64 > region_sqrt *  720.0) {
                println!("need to regrow right!");
                let pitch = (region_sqrt + 1.0) as usize;
                let next_square = pitch * pitch;

                // swap in the newly regrown buffer
                let mut buf = Vec::with_capacity(next_square);
                mem::swap(&mut regions, &mut buf);
                let mut old_drain = buf.into_iter();

                // copy old / allocate new
                for row in 0..pitch {
                    for col in 0..pitch {
                        let ridx = col + (row * 4);

                        if (row >= pitch - 1) || (col >= pitch - 1) {
                            // new region
                            let mut txbuf = Some(self.display.get_texture(1280,720));
                            regions.push(Region {
                                is_dirty: true,
                                texture:  txbuf,
                            });
                        } else {
                            regions.push(old_drain.next().expect("ran out of regions to copy during regrow!"));
                        }
                    }
                }
            }

            // if they pan left, trick them into thinking had canvases there
            if (self.scanbox.0 < 0) || (self.scanbox.1 < 0) {
                println!("need to regrow left!");
                let pitch = (region_sqrt + 1.0) as usize;
                let next_square = pitch * pitch;

                // swap in the newly regrown buffer
                let mut buf = Vec::with_capacity(next_square);
                mem::swap(&mut regions, &mut buf);
                let mut old_drain = buf.into_iter();

                // copy old / allocate new
                for row in 0..pitch {
                    for col in 0..pitch {
                        let ridx = col + (row * 4);

                        if (row == 0) || (col == 0) {
                            // new region
                            let mut txbuf = Some(self.display.get_texture(1280,720));

                            regions.push(Region {
                                is_dirty: true,
                                texture:  txbuf,
                            });
                        } else {
                            regions.push(old_drain.next().expect("ran out of regions to copy during regrow!"));
                        }
                    }
                }

                self.scanbox = V2(1280,720) + self.scanbox;
            }

            self.draw_debug(elapsed_time, regions.len());
            self.display.switch_buffers();

            // sleep for <target> - <draw time> and floor to zero
            elapsed_time = frame_start_at.elapsed();
            let sleep_time = if elapsed_time > target_fps_ms {
                Duration::from_millis(0)
            } else { target_fps_ms - elapsed_time };

            thread::sleep(sleep_time);
        }
    }

    // HACK: pulls texture out of an option and gives you a closure in which
    // you can use renderer calls to blit to it ...
    //
    fn with_texture<F>(io: &mut Display, target: &mut Option<Texture>, mut mutator: F)
        where F: FnMut(&mut Display) -> () {

        let _last = io.retarget().set(target.take().unwrap());
        mutator(io);
        *target = io.retarget().reset()
                        .ok().expect("did not get target back");
    }

    fn draw_cursor(&mut self, brush_color: Color) {
        self.display.fill_rect(Rect::new(self.cursor.0, self.cursor.1, 10, 10), brush_color);
    }

    fn draw_debug(&mut self, time: Duration, num_regions: usize) {
        let mut time_ms = time.as_secs() * 1000;        // -> millis
        time_ms += time.subsec_nanos() as u64 / (1000 * 1000); // /> micros /> millis

        let (hue_r, hue_g, hue_b) = self.color;
        let buf = format!("{}ms, # regions: {}, sb @ {:?}, \
                          e = erase all, b = brush ({:?}), hue(i,o,p) => ({:x},{:x},{:x})",
                          time_ms,
                          num_regions,
                          self.scanbox,
                          self.brush,
                          hue_r, hue_g, hue_b);
        self.display.blit_text(&buf[..], COLOR_FPS);
    }

    fn draw_regions(&mut self, regions: &mut Vec<Region>) {
        let V2(ofs_x, ofs_y) = self.scanbox;

        let pitch = (regions.len() as f64).sqrt() as usize;
        for row in 0..pitch {
            for col in 0..pitch {
                // (0,0), (0, 720)
                let x = (col * 1280) as i32;
                let y = (row *  720) as i32;
                let ridx = col + (row * pitch);

                if regions[ridx].is_dirty {
                    regions[ridx].is_dirty = false;
                    Engine::with_texture(&mut self.display, &mut regions[ridx].texture, |io| {
                        io.clear_buffer();
                        io.fill_rect(Rect::new(0,0,1280,5),   Color::RGB(255,0,0));  // top
                        io.fill_rect(Rect::new(0,715,1280,5), Color::RGB(255,0,0));  // bottom
                        io.fill_rect(Rect::new(0,0,5,720),    Color::RGB(255,0,0) ); // left
                        io.fill_rect(Rect::new(1275,0,5,720), Color::RGB(255,0,0));  // right
                    });
                }

                self.display.copy_t(regions[ridx].texture.as_ref().unwrap(),
                    Rect::new(0, 0, 1280, 720),
                    Rect::new(x - ofs_x as i32, y - ofs_y as i32, 1280, 720));
            }
        }
    }
}
<|endoftext|>


<commit_before>use nom::multispace;
use std::fmt;
use std::str;

use common::{opt_multispace, statement_terminator};
use order::{order_clause, OrderClause};
use select::{limit_clause, nested_selection, LimitClause, SelectStatement};

#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub enum CompoundSelectOperator {
    Union,
    DistinctUnion,
    Intersect,
    Except,
}

impl fmt::Display for CompoundSelectOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CompoundSelectOperator::Union => write!(f, "UNION"),
            CompoundSelectOperator::DistinctUnion => write!(f, "UNION DISTINCT"),
            CompoundSelectOperator::Intersect => write!(f, "INTERSECT"),
            CompoundSelectOperator::Except => write!(f, "EXCEPT"),
        }
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub struct CompoundSelectStatement {
    pub selects: Vec<(Option<CompoundSelectOperator>, SelectStatement)>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

impl fmt::Display for CompoundSelectStatement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (ref op, ref sel) in &self.selects {
            if op.is_some() {
                write!(f, " {}", op.as_ref().unwrap())?;
            }
            write!(f, " {}", sel)?;
        }
        if self.order.is_some() {
            write!(f, " {}", self.order.as_ref().unwrap())?;
        }
        if self.limit.is_some() {
            write!(f, " {}", self.order.as_ref().unwrap())?;
        }
        Ok(())
    }
}

// Parse compound operator
named!(compound_op<&[u8], CompoundSelectOperator>,
    alt!(
          do_parse!(
              tag_no_case!("union") >>
              distinct: opt!(
                  preceded!(multispace,
                            alt!(  map!(tag_no_case!("all"), |_| { false })
                                          | map!(tag_no_case!("distinct"), |_| { true }))
                            )) >>
              (match distinct {
                  // DISTINCT is the default in both MySQL and SQLite
                  None => CompoundSelectOperator::DistinctUnion,
                  Some(d) => {
                      if d {
                          CompoundSelectOperator::DistinctUnion
                      } else {
                          CompoundSelectOperator::Union
                      }
                  },
              })
          )
        | map!(tag_no_case!("intersect"), |_| CompoundSelectOperator::Intersect)
        | map!(tag_no_case!("except"), |_| CompoundSelectOperator::Except)
    )
);

// Parse compound selection
named!(pub compound_selection<&[u8], CompoundSelectStatement>,
    do_parse!(
        first_select: delimited!(opt!(tag!("(")), nested_selection, opt!(tag!(")"))) >>
        other_selects: many1!(
            do_parse!(opt_multispace >>
                    op: compound_op >>
                    multispace >>
                    opt!(tag!("(")) >>
                    opt_multispace >>
                    select: nested_selection >>
                    opt_multispace >>
                    opt!(tag!(")")) >>
                    (Some(op), select)
            )
        ) >>
        opt_multispace >>
        order: opt!(order_clause) >>
        limit: opt!(limit_clause) >>
        statement_terminator >>
        ({
            let mut v = vec![(None, first_select)];
            v.extend(other_selects);

            CompoundSelectStatement {
                selects: v,
                order: order,
                limit: limit,
            }
        })
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use common::{FieldDefinitionExpression, FieldValueExpression, Literal};
    use table::Table;

    #[test]
    fn union() {
        let qstr = "SELECT id, 1 FROM Vote UNION SELECT id, stars from Rating;";
        let qstr2 = "(SELECT id, 1 FROM Vote) UNION (SELECT id, stars from Rating);";
        let res = compound_selection(&[u8](qstr.as_bytes()));
        let res2 = compound_selection(&[u8](qstr2.as_bytes()));

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::DistinctUnion), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
        assert_eq!(res2.unwrap().1, expected);
    }

    #[test]
    fn multi_union() {
        let qstr = "SELECT id, 1 FROM Vote \
                    UNION SELECT id, stars from Rating \
                    UNION DISTINCT SELECT 42, 5 FROM Vote;";
        let res = compound_selection(&[u8](qstr.as_bytes()));

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let third_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(42).into(),
                )),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(5).into(),
                )),
            ],
            ..Default::default()
        };

        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::DistinctUnion), second_select),
                (Some(CompoundSelectOperator::DistinctUnion), third_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }

    #[test]
    fn union_all() {
        let qstr = "SELECT id, 1 FROM Vote UNION ALL SELECT id, stars from Rating;";
        let res = compound_selection(&[u8](qstr.as_bytes()));

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::Union), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }
}
<commit_msg>Update `compond_select.rs`<commit_after>use nom::character::complete::multispace1;
use std::fmt;
use std::str;

use common::{opt_multispace, statement_terminator};
use order::{order_clause, OrderClause};
use select::{limit_clause, nested_selection, LimitClause, SelectStatement};

#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub enum CompoundSelectOperator {
    Union,
    DistinctUnion,
    Intersect,
    Except,
}

impl fmt::Display for CompoundSelectOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CompoundSelectOperator::Union => write!(f, "UNION"),
            CompoundSelectOperator::DistinctUnion => write!(f, "UNION DISTINCT"),
            CompoundSelectOperator::Intersect => write!(f, "INTERSECT"),
            CompoundSelectOperator::Except => write!(f, "EXCEPT"),
        }
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub struct CompoundSelectStatement {
    pub selects: Vec<(Option<CompoundSelectOperator>, SelectStatement)>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

impl fmt::Display for CompoundSelectStatement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (ref op, ref sel) in &self.selects {
            if op.is_some() {
                write!(f, " {}", op.as_ref().unwrap())?;
            }
            write!(f, " {}", sel)?;
        }
        if self.order.is_some() {
            write!(f, " {}", self.order.as_ref().unwrap())?;
        }
        if self.limit.is_some() {
            write!(f, " {}", self.order.as_ref().unwrap())?;
        }
        Ok(())
    }
}

// Parse compound operator
named!(compound_op<&[u8], CompoundSelectOperator>,
    alt!(
          do_parse!(
              tag_no_case!("union") >>
              distinct: opt!(
                  preceded!(multispace1,
                            alt!(  map!(tag_no_case!("all"), |_| { false })
                                          | map!(tag_no_case!("distinct"), |_| { true }))
                            )) >>
              (match distinct {
                  // DISTINCT is the default in both MySQL and SQLite
                  None => CompoundSelectOperator::DistinctUnion,
                  Some(d) => {
                      if d {
                          CompoundSelectOperator::DistinctUnion
                      } else {
                          CompoundSelectOperator::Union
                      }
                  },
              })
          )
        | map!(tag_no_case!("intersect"), |_| CompoundSelectOperator::Intersect)
        | map!(tag_no_case!("except"), |_| CompoundSelectOperator::Except)
    )
);

// Parse compound selection
named!(pub compound_selection<&[u8], CompoundSelectStatement>,
    do_parse!(
        first_select: delimited!(opt!(tag!("(")), nested_selection, opt!(tag!(")"))) >>
        other_selects: many1!(
            do_parse!(opt_multispace >>
                    op: compound_op >>
                    multispace1 >>
                    opt!(tag!("(")) >>
                    opt_multispace >>
                    select: nested_selection >>
                    opt_multispace >>
                    opt!(tag!(")")) >>
                    (Some(op), select)
            )
        ) >>
        opt_multispace >>
        order: opt!(order_clause) >>
        limit: opt!(limit_clause) >>
        statement_terminator >>
        ({
            let mut v = vec![(None, first_select)];
            v.extend(other_selects);

            CompoundSelectStatement {
                selects: v,
                order: order,
                limit: limit,
            }
        })
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use common::{FieldDefinitionExpression, FieldValueExpression, Literal};
    use table::Table;

    #[test]
    fn union() {
        let qstr = "SELECT id, 1 FROM Vote UNION SELECT id, stars from Rating;";
        let qstr2 = "(SELECT id, 1 FROM Vote) UNION (SELECT id, stars from Rating);";
        let res = compound_selection(qstr.as_bytes());
        let res2 = compound_selection(qstr2.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::DistinctUnion), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
        assert_eq!(res2.unwrap().1, expected);
    }

    #[test]
    fn multi_union() {
        let qstr = "SELECT id, 1 FROM Vote \
                    UNION SELECT id, stars from Rating \
                    UNION DISTINCT SELECT 42, 5 FROM Vote;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let third_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(42).into(),
                )),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(5).into(),
                )),
            ],
            ..Default::default()
        };

        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::DistinctUnion), second_select),
                (Some(CompoundSelectOperator::DistinctUnion), third_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }

    #[test]
    fn union_all() {
        let qstr = "SELECT id, 1 FROM Vote UNION ALL SELECT id, stars from Rating;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::Union), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }
}
<|endoftext|>


<commit_before>use concurrent_help::to_concurrent_on_section;
use num_cpus;
use primal_sieve;

pub fn prime_filter_concurrently(max_num: usize, threads: usize) -> Vec<bool>{
    prime_filter_section_concurrently(0, max_num, threads)
}
pub fn prime_filter_section_concurrently(min_num:usize, max_num: usize, threads: usize) -> Vec<bool>{
    to_concurrent_on_section(prime_filter_section_sequentially, min_num, max_num, threads, 12)
}

fn int_sqrt(n:usize) -> usize{
    if n < (1 << 53) {
        (n as f64).sqrt() as usize
    }else{
        let mut x = n;
            loop{
                x = match (x + n/x) >> 1 {
                    new_x if new_x == x => break,
                    new_x if new_x*new_x == n + 1 => {x = new_x - 1; break},
                    new_x => new_x,
                };
            }
        x
    }
}

fn ceil_sqrt(n:usize) -> usize{
    if n == 0{
        return 0;
    }
    match int_sqrt(n){
        sqrt if sqrt*sqrt == n => sqrt,
        sqrt => sqrt+1,
    }
}
pub fn prime_filter(max_num: usize) -> Vec<bool>{
    prime_filter_concurrently(max_num, num_cpus::get())
}

pub fn prime_filter_section(min_num:usize, max_num: usize) -> Vec<bool>{
    prime_filter_section_concurrently(min_num, max_num, num_cpus::get())
}

pub fn prime_filter_sequentially(max_num: usize) -> Vec<bool>{
    let ps = primal_sieve::Sieve::new(max_num);
    (0..max_num).map(|i| ps.is_prime(i)).collect()
}

pub fn prime_filter_section_sequentially(min_num:usize, max_num: usize) -> Vec<bool>{
    //Sieve of Atkin
    if min_num == 0{
        return prime_filter_sequentially(max_num);
    }
    assert!(min_num<max_num);
    let mut prime_filter = vec![false; max_num-min_num];

    set_true_if_in_range!(2, 3, 5 => prime_filter + min_num, min_num, max_num);
    //Macro equivilent:
    // if (min_num <= 2) & (max_num > 2) {prime_filter[2-min_num] = true;}
    // if (min_num <= 3) & (max_num > 3) {prime_filter[3-min_num] = true;}
    // if (min_num <= 5) & (max_num > 5) {prime_filter[5-min_num] = true;}

    let (mut y_sq, mut to_next_y_sq) = (1, 3);

    //O(sqrt(max_num)*(sqrt(max_num) - sqrt(min_num)))
    while y_sq<max_num {
        if y_sq%2 == 1 {
            //CASE 1
            //n_1 = 4x^2 + y^2 === 1 (mod 4)
            let (mut n_1, mut to_next_n_1) = match y_sq < min_num {
                false => (y_sq+4, 12),
                _ => {
                    let min_num_x = (ceil_sqrt(min_num - y_sq) +1)/2;
                    (4*min_num_x*min_num_x + y_sq, 8*min_num_x + 4)
                },
            };
            loop{
                //While n_1<max_num,
                //When n_1 % 60 === 1, 13, 17, 29, 37, 41, 49, or 53, do
                // prime_filter[n_1-min_num] ^= true
                do_if_mod_60_match_pat!( 1 | 13 | 17 | 29 | 37 | 41 | 49 | 53, n_1 < max_num,
                    prime_filter[n_1-min_num] ^= true);
                n_1 += to_next_n_1;
                to_next_n_1 += 8;
            };
        };
        if y_sq%3 == 1 {
            //CASE 2
            //n_2 = 3x^2 + y^2 === 1 (mod 6)
            let (mut n_2, mut to_next_n_2) = match y_sq < min_num {
                false => (y_sq+3, 9),
                _ => {
                    let min_num_x = (ceil_sqrt((min_num - y_sq)*3)+2)/3;
                    (3*min_num_x*min_num_x + y_sq, 6*min_num_x + 3)
                },
            };
            loop {
                //While n_2<max_num,
                //When n_2 % 60 === 7, 19, 31, or 43, do
                // prime_filter[n_2-min_num] ^= true
                do_if_mod_60_match_pat!(7 | 19 | 31 | 43, n_2 < max_num,
                    prime_filter[n_2-min_num] ^= true);
                n_2 += to_next_n_2;
                to_next_n_2 += 6;
            };
            //CASE 3
            //n_3 = 3x^2 - y^2 === 11 (mod 12)
            //Initially, we set x = y+1 -> n_3 = 3(y+1)^2 - y^2 = 2*y^2 + 6*y + 3
            //Amd then hop x by 2 each iteration.
            let (mut n_3, mut to_next_n_3) = match (y_sq << 1) < min_num {
                false => (2*y_sq+3*to_next_y_sq, 6*to_next_y_sq+18),
                _ => {
                    let min_num_x = match (ceil_sqrt((min_num + y_sq)*3) +2)/3{
                        mx if (mx+y_sq)%2 == 0 => mx + 1,
                        mx => mx,
                    };
                    (3*min_num_x*min_num_x - y_sq, 12*min_num_x + 12)
                },
            };
            loop {
                //While n_3<max_num,
                //When n_3 % 60 === 11, 23, 47, or 59, do
                // prime_filter[n_3-min_num] ^= true
                do_if_mod_60_match_pat!(11 | 23 | 47 | 59, n_3 < max_num,
                    prime_filter[n_3-min_num] ^= true);
                n_3 += to_next_n_3;
                to_next_n_3 += 24;
            };
        };
        do_while!({
            y_sq += to_next_y_sq;
            to_next_y_sq += 2;
        } y_sq%6 == 0 );
    };

    //Eliminate non-squarefree numbers

    //O(max_num - min_num + sqrt(max_num))

    //This is because the inner loop
    //will iterate floor((max_num - min_num)/n^2) + 1 times for each n
    //Since the number of n's is proportional to sqrt(max_num),
    //And since the series of 1/n^2 converges, we obtain the above complexity.

    let mut n_sq = 49; // 7^2
    let mut next_n_sq = 32; //9^2 - 7^2, skip even numbers.
    while n_sq < max_num {
        let mut non_sq_free =  n_sq * match min_num/n_sq{
            k if k%2 == 1 => k,
            k => k + 1,
        };
        while non_sq_free < max_num {
            if non_sq_free >= min_num {
                prime_filter[non_sq_free - min_num] = false;
            }
            do_while!({
                non_sq_free += n_sq + n_sq;
            } (non_sq_free%3==0) | (non_sq_free%5==0));

        };
        do_while!({
            n_sq += next_n_sq;
            next_n_sq += 8;
        }(n_sq%3==0) | (n_sq%5 == 0));
    }
    prime_filter
}

#[cfg(test)]
pub fn old_prime_filter(max_num: usize) -> Vec<bool>{
    slow_prime_filter(max_num)
}

#[test]
fn private_filter_test(){
    assert_eq!(5, ceil_sqrt(24));
    assert_eq!(2, int_sqrt(4));
    assert_eq!(4, int_sqrt(24));
    assert_eq!(10, int_sqrt(101));
    assert_eq!(1, int_sqrt(1));
    assert_eq!(10, int_sqrt(100));
    assert_eq!(3, int_sqrt(13));
}

#[cfg(test)]
fn slow_prime_filter(max_num: usize) -> Vec<bool>{
    if max_num < 5 {
         let mut ret = vec![false, false, true, true];
         ret.truncate(max_num);
         return ret
     }
    let mut prime_filter = vec![true; max_num];
    prime_filter[0] = false;
    prime_filter[1] = false;
    let mut cur_num = 2;
    'outer: loop{
        for i in (cur_num+1)..max_num{
            if 0 == i%cur_num { prime_filter[i] = false; }
        }
        cur_num += 1;
        while !prime_filter[cur_num]{
            if cur_num*cur_num > max_num {
                break 'outer
            }
            cur_num += 1;
        }
    };
    prime_filter
}
<commit_msg>Much faster sqrt for big numbers.<commit_after>use concurrent_help::to_concurrent_on_section;
use num_cpus;
use primal_sieve;

pub fn prime_filter_concurrently(max_num: usize, threads: usize) -> Vec<bool>{
    prime_filter_section_concurrently(0, max_num, threads)
}
pub fn prime_filter_section_concurrently(min_num:usize, max_num: usize, threads: usize) -> Vec<bool>{
    to_concurrent_on_section(prime_filter_section_sequentially, min_num, max_num, threads, 12)
}

fn int_sqrt(n:usize) -> usize{
    if n < (1 << 53) {
        (n as f64).sqrt() as usize
    }else{
        //We are trying to find n = (x+y)^2. Truncate the last third
        //(down to an even number) of the bits of n. Take the square root of this
        //and put half the bits removed back to make x. We can prove y^2 < x, so n%x = y^2.
        //Take the square root of that to derive sqrt(n) = x + y
        let third_log_2_n = match n.checked_next_power_of_two(){
            Some(n_power_of_two) => n_power_of_two.trailing_zeros()+1,
            None => (0 as usize).trailing_zeros()+1,
        }/3;
        let x = int_sqrt(n >> (third_log_2_n - (third_log_2_n%2))) << (third_log_2_n/2);
        int_sqrt(n%x) + x
    }
}

fn ceil_sqrt(n:usize) -> usize{
    if n == 0{
        return 0;
    }
    match int_sqrt(n){
        sqrt if sqrt*sqrt == n => sqrt,
        sqrt => sqrt+1,
    }
}
pub fn prime_filter(max_num: usize) -> Vec<bool>{
    prime_filter_concurrently(max_num, num_cpus::get())
}

pub fn prime_filter_section(min_num:usize, max_num: usize) -> Vec<bool>{
    prime_filter_section_concurrently(min_num, max_num, num_cpus::get())
}

pub fn prime_filter_sequentially(max_num: usize) -> Vec<bool>{
    let ps = primal_sieve::Sieve::new(max_num);
    (0..max_num).map(|i| ps.is_prime(i)).collect()
}

pub fn prime_filter_section_sequentially(min_num:usize, max_num: usize) -> Vec<bool>{
    //Sieve of Atkin
    if min_num == 0{
        return prime_filter_sequentially(max_num);
    }
    assert!(min_num<max_num);
    let mut prime_filter = vec![false; max_num-min_num];

    set_true_if_in_range!(2, 3, 5 => prime_filter + min_num, min_num, max_num);
    //Macro equivilent:
    // if (min_num <= 2) & (max_num > 2) {prime_filter[2-min_num] = true;}
    // if (min_num <= 3) & (max_num > 3) {prime_filter[3-min_num] = true;}
    // if (min_num <= 5) & (max_num > 5) {prime_filter[5-min_num] = true;}

    let (mut y_sq, mut to_next_y_sq) = (1, 3);

    //O(sqrt(max_num)*(sqrt(max_num) - sqrt(min_num)))
    while y_sq<max_num {
        if y_sq%2 == 1 {
            //CASE 1
            //n_1 = 4x^2 + y^2 === 1 (mod 4)
            let (mut n_1, mut to_next_n_1) = match y_sq < min_num {
                false => (y_sq+4, 12),
                _ => {
                    let min_num_x = (ceil_sqrt(min_num - y_sq) +1)/2;
                    (4*min_num_x*min_num_x + y_sq, 8*min_num_x + 4)
                },
            };
            loop{
                //While n_1<max_num,
                //When n_1 % 60 === 1, 13, 17, 29, 37, 41, 49, or 53, do
                // prime_filter[n_1-min_num] ^= true
                do_if_mod_60_match_pat!( 1 | 13 | 17 | 29 | 37 | 41 | 49 | 53, n_1 < max_num,
                    prime_filter[n_1-min_num] ^= true);
                n_1 += to_next_n_1;
                to_next_n_1 += 8;
            };
        };
        if y_sq%3 == 1 {
            //CASE 2
            //n_2 = 3x^2 + y^2 === 1 (mod 6)
            let (mut n_2, mut to_next_n_2) = match y_sq < min_num {
                false => (y_sq+3, 9),
                _ => {
                    let min_num_x = (ceil_sqrt((min_num - y_sq)*3)+2)/3;
                    (3*min_num_x*min_num_x + y_sq, 6*min_num_x + 3)
                },
            };
            loop {
                //While n_2<max_num,
                //When n_2 % 60 === 7, 19, 31, or 43, do
                // prime_filter[n_2-min_num] ^= true
                do_if_mod_60_match_pat!(7 | 19 | 31 | 43, n_2 < max_num,
                    prime_filter[n_2-min_num] ^= true);
                n_2 += to_next_n_2;
                to_next_n_2 += 6;
            };
            //CASE 3
            //n_3 = 3x^2 - y^2 === 11 (mod 12)
            //Initially, we set x = y+1 -> n_3 = 3(y+1)^2 - y^2 = 2*y^2 + 6*y + 3
            //Amd then hop x by 2 each iteration.
            let (mut n_3, mut to_next_n_3) = match (y_sq << 1) < min_num {
                false => (2*y_sq+3*to_next_y_sq, 6*to_next_y_sq+18),
                _ => {
                    let min_num_x = match (ceil_sqrt((min_num + y_sq)*3) +2)/3{
                        mx if (mx+y_sq)%2 == 0 => mx + 1,
                        mx => mx,
                    };
                    (3*min_num_x*min_num_x - y_sq, 12*min_num_x + 12)
                },
            };
            loop {
                //While n_3<max_num,
                //When n_3 % 60 === 11, 23, 47, or 59, do
                // prime_filter[n_3-min_num] ^= true
                do_if_mod_60_match_pat!(11 | 23 | 47 | 59, n_3 < max_num,
                    prime_filter[n_3-min_num] ^= true);
                n_3 += to_next_n_3;
                to_next_n_3 += 24;
            };
        };
        do_while!({
            y_sq += to_next_y_sq;
            to_next_y_sq += 2;
        } y_sq%6 == 0 );
    };

    //Eliminate non-squarefree numbers

    //O(max_num - min_num + sqrt(max_num))

    //This is because the inner loop
    //will iterate floor((max_num - min_num)/n^2) + 1 times for each n
    //Since the number of n's is proportional to sqrt(max_num),
    //And since the series of 1/n^2 converges, we obtain the above complexity.

    let mut n_sq = 49; // 7^2
    let mut next_n_sq = 32; //9^2 - 7^2, skip even numbers.
    while n_sq < max_num {
        let mut non_sq_free =  n_sq * match min_num/n_sq{
            k if k%2 == 1 => k,
            k => k + 1,
        };
        while non_sq_free < max_num {
            if non_sq_free >= min_num {
                prime_filter[non_sq_free - min_num] = false;
            }
            do_while!({
                non_sq_free += n_sq + n_sq;
            } (non_sq_free%3==0) | (non_sq_free%5==0));

        };
        do_while!({
            n_sq += next_n_sq;
            next_n_sq += 8;
        }(n_sq%3==0) | (n_sq%5 == 0));
    }
    prime_filter
}

#[cfg(test)]
pub fn old_prime_filter(max_num: usize) -> Vec<bool>{
    slow_prime_filter(max_num)
}

#[test]
fn private_filter_test(){
    assert_eq!(5, ceil_sqrt(24));
    assert_eq!(2, int_sqrt(4));
    assert_eq!(4, int_sqrt(24));
    assert_eq!(10, int_sqrt(101));
    assert_eq!(1, int_sqrt(1));
    assert_eq!(10, int_sqrt(100));
    assert_eq!(3, int_sqrt(13));
    assert_eq!(1_000_000_000, int_sqrt(10_00_000_000_000_000_000));
    assert_eq!(1<<27, ceil_sqrt((1<<54) - 1));
}

#[cfg(test)]
fn slow_prime_filter(max_num: usize) -> Vec<bool>{
    if max_num < 5 {
         let mut ret = vec![false, false, true, true];
         ret.truncate(max_num);
         return ret
     }
    let mut prime_filter = vec![true; max_num];
    prime_filter[0] = false;
    prime_filter[1] = false;
    let mut cur_num = 2;
    'outer: loop{
        for i in (cur_num+1)..max_num{
            if 0 == i%cur_num { prime_filter[i] = false; }
        }
        cur_num += 1;
        while !prime_filter[cur_num]{
            if cur_num*cur_num > max_num {
                break 'outer
            }
            cur_num += 1;
        }
    };
    prime_filter
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that the trace_macros feature gate is on.

fn main() {
    trace_macros!(); //~ ERROR `trace_macros` is not stable
    trace_macros!(1); //~ ERROR `trace_macros` is not stable
    trace_macros!(ident); //~ ERROR `trace_macros` is not stable
    trace_macros!(for); //~ ERROR `trace_macros` is not stable
    trace_macros!(true,); //~ ERROR `trace_macros` is not stable
    trace_macros!(false 1); //~ ERROR `trace_macros` is not stable

    // Errors are signalled early for the above, before expansion.
    // See trace_macros-gate2 and trace_macros-gate3. for examples
    // of the below being caught.

    macro_rules! expando {
        ($x: ident) => { trace_macros!($x) } //~ ERROR `trace_macros` is not stable
    }

    expando!(true); //~ NOTE in this expansion
                    //~^ NOTE in this expansion
}
<commit_msg>test: Remove NOTE assertions from trace_macros-gate<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that the trace_macros feature gate is on.

fn main() {
    trace_macros!(); //~ ERROR `trace_macros` is not stable
    trace_macros!(1); //~ ERROR `trace_macros` is not stable
    trace_macros!(ident); //~ ERROR `trace_macros` is not stable
    trace_macros!(for); //~ ERROR `trace_macros` is not stable
    trace_macros!(true,); //~ ERROR `trace_macros` is not stable
    trace_macros!(false 1); //~ ERROR `trace_macros` is not stable

    // Errors are signalled early for the above, before expansion.
    // See trace_macros-gate2 and trace_macros-gate3. for examples
    // of the below being caught.

    macro_rules! expando {
        ($x: ident) => { trace_macros!($x) } //~ ERROR `trace_macros` is not stable
    }

    expando!(true);
}
<|endoftext|>


<commit_before>use std::net::ToSocketAddrs;
use std::convert::AsRef;
use std::net;
use std::io::Write;
use rustc_serialize::Encodable;
use time;
use retry::retry_exponentially;
use record::Record;
use record::FluentError;
use retry_conf::RetryConf;
use forwardable::JsonForwardable;

#[derive(Debug, Clone, PartialEq)]
pub struct Fluent
    where A: ToSocketAddrs
{
    addr: A,
    tag: String,
    conf: RetryConf,
}

impl Fluent {
    /// Create Fluent type.
    ///
    /// ### Usage
    ///
    /// ```
    /// use fruently::fluent::Fluent;
    /// let fruently_with_str_tag = Fluent::new("0.0.0.0:24224", "test");
    /// let fruently_with_string_tag = Fluent::new("0.0.0.0:24224", "test".to_string());
    /// ```
    pub fn new<T>(addr: A, tag: T) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: RetryConf::new(),
        }
    }

    pub fn new_with_conf<T>(addr: A, tag: T, conf: RetryConf) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: conf,
        }
    }

    /// For internal usage.
    fn closure_send_data(addr: &A, message: String) -> Result<(), FluentError> {
        let mut stream = try!(net::TcpStream::connect(addr));
        let result = stream.write(&message.into_bytes());
        drop(stream);

        match result {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

impl JsonForwardable for Fluent {
        /// Post record into Fluentd. Without time version.
    fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.tag.clone(), time, record);
        let message = try!(record.make_forwardable_json());
        let addr = self.addr;
        let (max, multiplier) = self.conf.build();
        match retry_exponentially(max,
                    multiplier,
                    || Fluent::closure_send_data(&addr, message.clone()),
                    |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[cfg(feature="fluentd")]
    use time;
    use retry_conf::RetryConf;

    #[test]
    fn create_fruently() {
        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let expected = Fluent {
            addr: "0.0.0.0:24224",
            tag: "test".to_string(),
            conf: RetryConf::new(),
        };
        assert_eq!(expected, fruently);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post() {
        use std::collections::HashMap;
        use forwardable::JsonForwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let result = fruently.post(obj).is_ok();
        assert_eq!(true, result);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post_with_time() {
        use std::collections::HashMap;
        use forwardable::JsonForwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let time = time::now();
        let result = fruently.post_with_time(obj, time).is_ok();
        assert_eq!(true, result);
    }
}
<commit_msg>rustfmt<commit_after>use std::net::ToSocketAddrs;
use std::convert::AsRef;
use std::net;
use std::io::Write;
use rustc_serialize::Encodable;
use time;
use retry::retry_exponentially;
use record::Record;
use record::FluentError;
use retry_conf::RetryConf;
use forwardable::JsonForwardable;

#[derive(Debug, Clone, PartialEq)]
pub struct Fluent
    where A: ToSocketAddrs
{
    addr: A,
    tag: String,
    conf: RetryConf,
}

impl Fluent {
    /// Create Fluent type.
    ///
    /// ### Usage
    ///
    /// ```
    /// use fruently::fluent::Fluent;
    /// let fruently_with_str_tag = Fluent::new("0.0.0.0:24224", "test");
    /// let fruently_with_string_tag = Fluent::new("0.0.0.0:24224", "test".to_string());
    /// ```
    pub fn new<T>(addr: A, tag: T) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: RetryConf::new(),
        }
    }

    pub fn new_with_conf<T>(addr: A, tag: T, conf: RetryConf) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: conf,
        }
    }

    /// For internal usage.
    fn closure_send_data(addr: &A, message: String) -> Result<(), FluentError> {
        let mut stream = try!(net::TcpStream::connect(addr));
        let result = stream.write(&message.into_bytes());
        drop(stream);

        match result {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

impl JsonForwardable for Fluent {
    /// Post record into Fluentd. Without time version.
    fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.tag.clone(), time, record);
        let message = try!(record.make_forwardable_json());
        let addr = self.addr;
        let (max, multiplier) = self.conf.build();
        match retry_exponentially(max,
                                  multiplier,
                                  || Fluent::closure_send_data(&addr, message.clone()),
                                  |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[cfg(feature="fluentd")]
    use time;
    use retry_conf::RetryConf;

    #[test]
    fn create_fruently() {
        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let expected = Fluent {
            addr: "0.0.0.0:24224",
            tag: "test".to_string(),
            conf: RetryConf::new(),
        };
        assert_eq!(expected, fruently);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post() {
        use std::collections::HashMap;
        use forwardable::JsonForwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let result = fruently.post(obj).is_ok();
        assert_eq!(true, result);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post_with_time() {
        use std::collections::HashMap;
        use forwardable::JsonForwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let time = time::now();
        let result = fruently.post_with_time(obj, time).is_ok();
        assert_eq!(true, result);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-pass

#![feature(core_intrinsics)]
#![feature(untagged_unions)]

#![allow(unions_with_drop_fields)]
#![allow(dead_code)]

use std::intrinsics::needs_drop;

struct NeedDrop;

impl Drop for NeedDrop {
    fn drop(&mut self) {}
}

// Constant expressios allow `NoDrop` to go out of scope,
// unlike a value of the interior type implementing `Drop`.
static X: () = (NoDrop { inner: NeedDrop }, ()).1;

// A union that scrubs the drop glue from its inner type
union NoDrop<T> {inner: T}

// Copy currently can't be implemented on drop-containing unions,
// this may change later
// https://github.com/rust-lang/rust/pull/38934#issuecomment-271219289

// // We should be able to implement Copy for NoDrop
// impl<T> Copy for NoDrop<T> {}
// impl<T> Clone for NoDrop<T> {fn clone(&self) -> Self { *self }}

// // We should be able to implement Copy for things using NoDrop
// #[derive(Copy, Clone)]
struct Foo {
    x: NoDrop<Box<u8>>
}

struct Baz {
    x: NoDrop<Box<u8>>,
    y: Box<u8>,
}

union ActuallyDrop<T> {inner: T}

impl<T> Drop for ActuallyDrop<T> {
    fn drop(&mut self) {}
}

fn main() {
    unsafe {
        // NoDrop should not make needs_drop true
        assert!(!needs_drop::<Foo>());
        assert!(!needs_drop::<NoDrop<u8>>());
        assert!(!needs_drop::<NoDrop<Box<u8>>>());
        // presence of other drop types should still work
        assert!(needs_drop::<Baz>());
        // drop impl on union itself should work
        assert!(needs_drop::<ActuallyDrop<u8>>());
        assert!(needs_drop::<ActuallyDrop<Box<u8>>>());
    }
}
<commit_msg>Fix ui/run-pass/union/union-nodrop.rs test<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-pass

#![feature(core_intrinsics)]
#![feature(untagged_unions)]

#![allow(unions_with_drop_fields)]
#![allow(dead_code)]

use std::intrinsics::needs_drop;

struct NeedDrop;

impl Drop for NeedDrop {
    fn drop(&mut self) {}
}

// Constant expressios allow `NoDrop` to go out of scope,
// unlike a value of the interior type implementing `Drop`.
static X: () = (NoDrop { inner: NeedDrop }, ()).1;

// A union that scrubs the drop glue from its inner type
union NoDrop<T> {inner: T}

// Copy currently can't be implemented on drop-containing unions,
// this may change later
// https://github.com/rust-lang/rust/pull/38934#issuecomment-271219289

// // We should be able to implement Copy for NoDrop
// impl<T> Copy for NoDrop<T> {}
// impl<T> Clone for NoDrop<T> {fn clone(&self) -> Self { *self }}

// // We should be able to implement Copy for things using NoDrop
// #[derive(Copy, Clone)]
struct Foo {
    x: NoDrop<Box<u8>>
}

struct Baz {
    x: NoDrop<Box<u8>>,
    y: Box<u8>,
}

union ActuallyDrop<T> {inner: T}

impl<T> Drop for ActuallyDrop<T> {
    fn drop(&mut self) {}
}

fn main() {
    // NoDrop should not make needs_drop true
    assert!(!needs_drop::<Foo>());
    assert!(!needs_drop::<NoDrop<u8>>());
    assert!(!needs_drop::<NoDrop<Box<u8>>>());
    // presence of other drop types should still work
    assert!(needs_drop::<Baz>());
    // drop impl on union itself should work
    assert!(needs_drop::<ActuallyDrop<u8>>());
    assert!(needs_drop::<ActuallyDrop<Box<u8>>>());
}
<|endoftext|>