<commit_before>use std::os::raw::c_char;
use std::fmt;
use std::ffi::{CStr, CString};
use std::fmt::Display;
use std::str::Utf8Error;

use ffi::functions::*;

pub fn ptr_to_string(str_ptr: *const c_char) -> Result<String, Utf8Error> {
    let str_slice: &str = try!(unsafe { CStr::from_ptr(str_ptr) }.to_str());
    Ok(str_slice.to_string())
}

/// Possible error codes. You can print the
/// corresponding error message easily, because
/// this enum implements `Display`.
///
/// # Example
///
/// ```
/// use rsoundio::ffi::SioError;
/// println!("{}", SioError::SystemResources)
/// ```
#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u32)]
pub enum SioError {
    None = 0,
    /// Out of memory.
    NoMem = 1,
    /// The backend does not appear to be active or running.
    InitAudioBackend = 2,
    /// A system resource other than memory (Dummy) was not available.
    SystemResources = 3,
    /// Attempted to open a device and failed.
    OpeningDevice = 4,
    NoSuchDevice = 5,
    /// The programmer did not comply with the API.
    Invalid = 6,
    /// libsoundio was compiled without support for that backend.
    ///
    /// Currently there is no JACK support in Arch Linux until
    /// `jack2{,-dbus}1.9.10-4` is available. See [this](https://bugs.archlinux.org/task/47839)
    /// bug report for details.
    BackendUnavailable = 7,
    /// An open stream had an error that can only be recovered from by
    /// destroying the stream and creating it again.
    Streaming = 8,
    /// Attempted to use a device with parameters it cannot support.
    IncompatibleDevice = 9,
    /// When JACK returns `JackNoSuchClient`
    NoSuchClient = 10,
    /// Attempted to use parameters that the backend cannot support.
    IncompatibleBackend = 11,
    /// Backend server shutdown or became inactive.
    BackendDisconnected = 12,
    Interrupted = 13,
    /// Buffer underrun occurred.
    Underflow = 14,
    /// Unable to convert to or from UTF-8 to the native string format.
    EncodingString = 15,
}
impl Display for SioError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { soundio_strerror(*self) };
        write!(f, "{}", ptr_to_string(str_ptr).unwrap())
    }
}

/// Specifies where a channel is physically located.
#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u32)]
pub enum SioChannelId {
    Invalid = 0,
    /// First of the more commonly supported ids.
    FrontLeft = 1,
    FrontRight = 2,
    FrontCenter = 3,
    Lfe = 4,
    BackLeft = 5,
    BackRight = 6,
    FrontLeftCenter = 7,
    FrontRightCenter = 8,
    BackCenter = 9,
    SideLeft = 10,
    SideRight = 11,
    TopCenter = 12,
    TopFrontLeft = 13,
    TopFrontCenter = 14,
    TopFrontRight = 15,
    TopBackLeft = 16,
    TopBackCenter = 17,
    /// Last of the more commonly supported ids.
    TopBackRight = 18,
    /// First of the less commonly supported ids.
    BackLeftCenter = 19,
    BackRightCenter = 20,
    FrontLeftWide = 21,
    FrontRightWide = 22,
    FrontLeftHigh = 23,
    FrontCenterHigh = 24,
    FrontRightHigh = 25,
    TopFrontLeftCenter = 26,
    TopFrontRightCenter = 27,
    TopSideLeft = 28,
    TopSideRight = 29,
    LeftLfe = 30,
    RightLfe = 31,
    Lfe2 = 32,
    BottomCenter = 33,
    BottomLeftCenter = 34,
    BottomRightCenter = 35,
    /// Mid/side recording
    MsMid = 36,
    MsSide = 37,
    /// first order ambisonic channels
    AmbisonicW = 38,
    AmbisonicX = 39,
    AmbisonicY = 40,
    AmbisonicZ = 41,
    /// X-Y Recording
    XyX = 42,
    XyY = 43,
    /// First of the "other" channel ids
    HeadphonesLeft = 44,
    HeadphonesRight = 45,
    ClickTrack = 46,
    ForeignLanguage = 47,
    HearingImpaired = 48,
    Narration = 49,
    Haptic = 50,
    /// Last of the "other" channel ids
    DialogCentricMix = 51,
    Aux = 52,
    Aux0 = 53,
    Aux1 = 54,
    Aux2 = 55,
    Aux3 = 56,
    Aux4 = 57,
    Aux5 = 58,
    Aux6 = 59,
    Aux7 = 60,
    Aux8 = 61,
    Aux9 = 62,
    Aux10 = 63,
    Aux11 = 64,
    Aux12 = 65,
    Aux13 = 66,
    Aux14 = 67,
    Aux15 = 68,
}
impl Display for SioChannelId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { soundio_get_channel_name(*self) };
        write!(f, "{}", ptr_to_string(str_ptr).unwrap())
    }
}
impl From<String> for SioChannelId {
    fn from(id: String) -> Self {
        let str_len = id.len() as i32;
        let cstr = CString::new(id).unwrap();
        unsafe { soundio_parse_channel_id(cstr.as_ptr(), str_len) }
    }
}

/// Built-in channel layouts for convenience.
#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u32)]
pub enum SioChannelLayoutId {
    Mono = 0,
    Stereo = 1,
    TwoPointOne = 2,
    ThreePointZero = 3,
    ThreePointZeroBack = 4,
    ThreePointOne = 5,
    FourPointZero = 6,
    Quad = 7,
    QuadSide = 8,
    FourPointOne = 9,
    FivePointZeroBack = 10,
    FivePointZeroSide = 11,
    FivePointOne = 12,
    FivePointOneBack = 13,
    SixPointZeroSide = 14,
    SixPointZeroFront = 15,
    Hexagonal = 16,
    SixPointOne = 17,
    SixPointOneBack = 18,
    SixPointOneFront = 19,
    SevenPointZero = 20,
    SevenPointZeroFront = 21,
    SevenPointOne = 22,
    SevenPointOneWide = 23,
    SevenPointOneWideBack = 24,
    Octagonal = 25,
}

#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u32)]
pub enum SioBackend {
    None = 0,
    Jack = 1,
    PulseAudio = 2,
    Alsa = 3,
    CoreAudio = 4,
    Wasapi = 5,
    Dummy = 6,
}
impl Display for SioBackend {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { soundio_backend_name(*self) };
        write!(f, "{}", ptr_to_string(str_ptr).unwrap())
    }
}

#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u32)]
pub enum SioDeviceAim {
    /// capture/recording
    Input = 0,
    /// playback
    Output = 1,
}

/// Supported sound formats, each for little- and big-endian.
#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u32)]
pub enum SioFormat {
    Invalid = 0,
    /// Signed 8 bit
    S8 = 1,
    /// Unsigned 8 bit
    U8 = 2,
    /// Signed 16 bit little-endian
    S16LE = 3,
    /// Signed 16 bit big-endian
    S16BE = 4,
    /// Unsigned 16 bit little-endian
    U16LE = 5,
    /// Unsigned 16 bit big-endian
    U16BE = 6,
    /// The 24 bit types are not supported in rsoundio at the moment.
    /// Because there is no native number type that is 24 bits wide,
    /// (at least not in Rusts `std`) I had to use something like
    /// C unions in Rust to support them.
    /// This would probably be unsafe and working with
    /// 3 byte number types is also not too much fun.
    ///
    /// Signed 24 bit little-endian
    S24LE = 7,
    /// Signed 24 bit big-endian
    S24BE = 8,
    /// Unsigned 24 bit little-endian
    U24LE = 9,
    /// Unsigned 24 bit big-endian
    U24BE = 10,
    /// Signed 32 bit little-endian
    S32LE = 11,
    /// Signed 32 bit big-endian
    S32BE = 12,
    /// Unsigned 32 bit little-endian
    U32LE = 13,
    /// Unsigend 32 bit big-endian
    U32BE = 14,
    /// 32 bit float little-endian in [-1.0, 1.0]
    Float32LE = 15,
    /// 32 bit float big-endian in [-1.0, 1.0]
    Float32BE = 16,
    /// 64 bit float little-endian in [-1.0, 1.0]
    Float64LE = 17,
    /// 64 bit float big-endian in [-1.0, 1.0]
    Float64BE = 18,
}
impl Display for SioFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { soundio_format_string(*self) };
        write!(f, "{}", ptr_to_string(str_ptr).unwrap())
    }
}
impl SioFormat {
    /// Returns the number of bytes a sample takes in this format.
    pub fn get_bytes_per_sample(self) -> i32 {
        unsafe { soundio_get_bytes_per_sample(self) as i32 }
    }
}

//#[allow(dead_code,non_camel_case_types)]
//enum SoundIoRingBuffer { }
<commit_msg>Derive `Debug` and `PartialEq` for `SioBackend`<commit_after>use std::os::raw::c_char;
use std::fmt;
use std::ffi::{CStr, CString};
use std::fmt::Display;
use std::str::Utf8Error;

use ffi::functions::*;

pub fn ptr_to_string(str_ptr: *const c_char) -> Result<String, Utf8Error> {
    let str_slice: &str = try!(unsafe { CStr::from_ptr(str_ptr) }.to_str());
    Ok(str_slice.to_string())
}

/// Possible error codes. You can print the
/// corresponding error message easily, because
/// this enum implements `Display`.
///
/// # Example
///
/// ```
/// use rsoundio::ffi::SioError;
/// println!("{}", SioError::SystemResources)
/// ```
#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u32)]
pub enum SioError {
    None = 0,
    /// Out of memory.
    NoMem = 1,
    /// The backend does not appear to be active or running.
    InitAudioBackend = 2,
    /// A system resource other than memory (Dummy) was not available.
    SystemResources = 3,
    /// Attempted to open a device and failed.
    OpeningDevice = 4,
    NoSuchDevice = 5,
    /// The programmer did not comply with the API.
    Invalid = 6,
    /// libsoundio was compiled without support for that backend.
    ///
    /// Currently there is no JACK support in Arch Linux until
    /// `jack2{,-dbus}1.9.10-4` is available. See [this](https://bugs.archlinux.org/task/47839)
    /// bug report for details.
    BackendUnavailable = 7,
    /// An open stream had an error that can only be recovered from by
    /// destroying the stream and creating it again.
    Streaming = 8,
    /// Attempted to use a device with parameters it cannot support.
    IncompatibleDevice = 9,
    /// When JACK returns `JackNoSuchClient`
    NoSuchClient = 10,
    /// Attempted to use parameters that the backend cannot support.
    IncompatibleBackend = 11,
    /// Backend server shutdown or became inactive.
    BackendDisconnected = 12,
    Interrupted = 13,
    /// Buffer underrun occurred.
    Underflow = 14,
    /// Unable to convert to or from UTF-8 to the native string format.
    EncodingString = 15,
}
impl Display for SioError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { soundio_strerror(*self) };
        write!(f, "{}", ptr_to_string(str_ptr).unwrap())
    }
}

/// Specifies where a channel is physically located.
#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u32)]
pub enum SioChannelId {
    Invalid = 0,
    /// First of the more commonly supported ids.
    FrontLeft = 1,
    FrontRight = 2,
    FrontCenter = 3,
    Lfe = 4,
    BackLeft = 5,
    BackRight = 6,
    FrontLeftCenter = 7,
    FrontRightCenter = 8,
    BackCenter = 9,
    SideLeft = 10,
    SideRight = 11,
    TopCenter = 12,
    TopFrontLeft = 13,
    TopFrontCenter = 14,
    TopFrontRight = 15,
    TopBackLeft = 16,
    TopBackCenter = 17,
    /// Last of the more commonly supported ids.
    TopBackRight = 18,
    /// First of the less commonly supported ids.
    BackLeftCenter = 19,
    BackRightCenter = 20,
    FrontLeftWide = 21,
    FrontRightWide = 22,
    FrontLeftHigh = 23,
    FrontCenterHigh = 24,
    FrontRightHigh = 25,
    TopFrontLeftCenter = 26,
    TopFrontRightCenter = 27,
    TopSideLeft = 28,
    TopSideRight = 29,
    LeftLfe = 30,
    RightLfe = 31,
    Lfe2 = 32,
    BottomCenter = 33,
    BottomLeftCenter = 34,
    BottomRightCenter = 35,
    /// Mid/side recording
    MsMid = 36,
    MsSide = 37,
    /// first order ambisonic channels
    AmbisonicW = 38,
    AmbisonicX = 39,
    AmbisonicY = 40,
    AmbisonicZ = 41,
    /// X-Y Recording
    XyX = 42,
    XyY = 43,
    /// First of the "other" channel ids
    HeadphonesLeft = 44,
    HeadphonesRight = 45,
    ClickTrack = 46,
    ForeignLanguage = 47,
    HearingImpaired = 48,
    Narration = 49,
    Haptic = 50,
    /// Last of the "other" channel ids
    DialogCentricMix = 51,
    Aux = 52,
    Aux0 = 53,
    Aux1 = 54,
    Aux2 = 55,
    Aux3 = 56,
    Aux4 = 57,
    Aux5 = 58,
    Aux6 = 59,
    Aux7 = 60,
    Aux8 = 61,
    Aux9 = 62,
    Aux10 = 63,
    Aux11 = 64,
    Aux12 = 65,
    Aux13 = 66,
    Aux14 = 67,
    Aux15 = 68,
}
impl Display for SioChannelId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { soundio_get_channel_name(*self) };
        write!(f, "{}", ptr_to_string(str_ptr).unwrap())
    }
}
impl From<String> for SioChannelId {
    fn from(id: String) -> Self {
        let str_len = id.len() as i32;
        let cstr = CString::new(id).unwrap();
        unsafe { soundio_parse_channel_id(cstr.as_ptr(), str_len) }
    }
}

/// Built-in channel layouts for convenience.
#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u32)]
pub enum SioChannelLayoutId {
    Mono = 0,
    Stereo = 1,
    TwoPointOne = 2,
    ThreePointZero = 3,
    ThreePointZeroBack = 4,
    ThreePointOne = 5,
    FourPointZero = 6,
    Quad = 7,
    QuadSide = 8,
    FourPointOne = 9,
    FivePointZeroBack = 10,
    FivePointZeroSide = 11,
    FivePointOne = 12,
    FivePointOneBack = 13,
    SixPointZeroSide = 14,
    SixPointZeroFront = 15,
    Hexagonal = 16,
    SixPointOne = 17,
    SixPointOneBack = 18,
    SixPointOneFront = 19,
    SevenPointZero = 20,
    SevenPointZeroFront = 21,
    SevenPointOne = 22,
    SevenPointOneWide = 23,
    SevenPointOneWideBack = 24,
    Octagonal = 25,
}

#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u32)]
pub enum SioBackend {
    None = 0,
    Jack = 1,
    PulseAudio = 2,
    Alsa = 3,
    CoreAudio = 4,
    Wasapi = 5,
    Dummy = 6,
}
impl Display for SioBackend {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { soundio_backend_name(*self) };
        write!(f, "{}", ptr_to_string(str_ptr).unwrap())
    }
}

#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u32)]
pub enum SioDeviceAim {
    /// capture/recording
    Input = 0,
    /// playback
    Output = 1,
}

/// Supported sound formats, each for little- and big-endian.
#[allow(dead_code,non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u32)]
pub enum SioFormat {
    Invalid = 0,
    /// Signed 8 bit
    S8 = 1,
    /// Unsigned 8 bit
    U8 = 2,
    /// Signed 16 bit little-endian
    S16LE = 3,
    /// Signed 16 bit big-endian
    S16BE = 4,
    /// Unsigned 16 bit little-endian
    U16LE = 5,
    /// Unsigned 16 bit big-endian
    U16BE = 6,
    /// The 24 bit types are not supported in rsoundio at the moment.
    /// Because there is no native number type that is 24 bits wide,
    /// (at least not in Rusts `std`) I had to use something like
    /// C unions in Rust to support them.
    /// This would probably be unsafe and working with
    /// 3 byte number types is also not too much fun.
    ///
    /// Signed 24 bit little-endian
    S24LE = 7,
    /// Signed 24 bit big-endian
    S24BE = 8,
    /// Unsigned 24 bit little-endian
    U24LE = 9,
    /// Unsigned 24 bit big-endian
    U24BE = 10,
    /// Signed 32 bit little-endian
    S32LE = 11,
    /// Signed 32 bit big-endian
    S32BE = 12,
    /// Unsigned 32 bit little-endian
    U32LE = 13,
    /// Unsigend 32 bit big-endian
    U32BE = 14,
    /// 32 bit float little-endian in [-1.0, 1.0]
    Float32LE = 15,
    /// 32 bit float big-endian in [-1.0, 1.0]
    Float32BE = 16,
    /// 64 bit float little-endian in [-1.0, 1.0]
    Float64LE = 17,
    /// 64 bit float big-endian in [-1.0, 1.0]
    Float64BE = 18,
}
impl Display for SioFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { soundio_format_string(*self) };
        write!(f, "{}", ptr_to_string(str_ptr).unwrap())
    }
}
impl SioFormat {
    /// Returns the number of bytes a sample takes in this format.
    pub fn get_bytes_per_sample(self) -> i32 {
        unsafe { soundio_get_bytes_per_sample(self) as i32 }
    }
}

//#[allow(dead_code,non_camel_case_types)]
//enum SoundIoRingBuffer { }
<|endoftext|>


<commit_before>extern crate app_units;
extern crate webrender;
extern crate glutin;
extern crate gleam;
extern crate webrender_traits;
extern crate euclid;

use euclid::{Size2D, Point2D, Rect, Matrix4D};
use gleam::gl;
use std::path::PathBuf;
use std::ffi::CStr;
use webrender_traits::{PipelineId, StackingContextId, DisplayListId};
use webrender_traits::{AuxiliaryListsBuilder, Epoch, ColorF, GlyphInstance};
use webrender_traits::{ImageFormat, RendererKind};
use std::fs::File;
use std::io::Read;
use std::env;

fn _load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

pub struct WebRenderFrameBuilder {
    pub stacking_contexts: Vec<(StackingContextId, webrender_traits::StackingContext)>,
    pub display_lists: Vec<(DisplayListId, webrender_traits::BuiltDisplayList)>,
    pub auxiliary_lists_builder: AuxiliaryListsBuilder,
    pub root_pipeline_id: PipelineId,
    pub next_scroll_layer_id: usize,
}

impl WebRenderFrameBuilder {
    pub fn new(root_pipeline_id: PipelineId) -> WebRenderFrameBuilder {
        WebRenderFrameBuilder {
            stacking_contexts: vec![],
            display_lists: vec![],
            auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
            root_pipeline_id: root_pipeline_id,
            next_scroll_layer_id: 0,
        }
    }

    pub fn add_stacking_context(&mut self,
                                api: &mut webrender_traits::RenderApi,
                                pipeline_id: PipelineId,
                                stacking_context: webrender_traits::StackingContext)
                                -> StackingContextId {
        assert!(pipeline_id == self.root_pipeline_id);
        let id = api.next_stacking_context_id();
        self.stacking_contexts.push((id, stacking_context));
        id
    }

    pub fn add_display_list(&mut self,
                            api: &mut webrender_traits::RenderApi,
                            display_list: webrender_traits::BuiltDisplayList,
                            stacking_context: &mut webrender_traits::StackingContext)
                            -> DisplayListId {
        let id = api.next_display_list_id();
        stacking_context.display_lists.push(id);
        self.display_lists.push((id, display_list));
        id
    }

    pub fn next_scroll_layer_id(&mut self) -> webrender_traits::ScrollLayerId {
        let scroll_layer_id = webrender_traits::ServoScrollRootId(self.next_scroll_layer_id);
        self.next_scroll_layer_id += 1;
        webrender_traits::ScrollLayerId::new(self.root_pipeline_id, 0, scroll_layer_id)
    }

}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        self.window_proxy.wakeup_event_loop();
    }

    fn pipeline_size_changed(&mut self,
                             _: PipelineId,
                             _: Option<Size2D<f32>>) {
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("{} <shader path>", args[0]);
        return;
    }

    let res_path = &args[1];

    let window = glutin::WindowBuilder::new()
                .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::clear_color(0.3, 0.0, 0.0, 1.0);
    }

    let version = unsafe {
        let data = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes().to_vec();
        String::from_utf8(data).unwrap()
    };

    println!("OpenGL version {}", version);
    println!("Shader resource path: {}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        device_pixel_ratio: 1.0,
        resource_path: PathBuf::from(res_path),
        enable_aa: false,
        enable_msaa: false,
        enable_profiler: false,
        enable_recording: false,
        enable_scrollbars: false,
        debug: true,
        precache_shaders: true,
        renderer_kind: RendererKind::Native,
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);
    let mut api = sender.create_api();

//     let font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf";
//     let font_bytes = load_file(font_path);
//     let font_key = api.add_raw_font(font_bytes);

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let pipeline_id = PipelineId(0, 0);
    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id);
    let root_scroll_layer_id = frame_builder.next_scroll_layer_id();

    let bounds = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(width as f32, height as f32));
    let mut sc =
        webrender_traits::StackingContext::new(Some(root_scroll_layer_id),
                                               webrender_traits::ScrollPolicy::Scrollable,
                                               bounds,
                                               bounds,
                                               0,
                                               &Matrix4D::identity(),
                                               &Matrix4D::identity(),
                                               true,
                                               webrender_traits::MixBlendMode::Normal,
                                               Vec::new(),
                                               &mut frame_builder.auxiliary_lists_builder);

    let mut builder = webrender_traits::DisplayListBuilder::new();

    let clip_region = {
        let rect = Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0));
        let mask = webrender_traits::ImageMask {
            image: api.add_image(2, 2, ImageFormat::A8, vec![0,80, 180, 255]),
            rect: rect,
            repeat: false,
        };
        let radius = webrender_traits::BorderRadius::uniform(20.0);
        let complex = webrender_traits::ComplexClipRegion::new(rect, radius);

        webrender_traits::ClipRegion::new(&bounds,
                                          vec![complex],
                                          Some(mask),
                                          &mut frame_builder.auxiliary_lists_builder)
    };

    builder.push_rect(Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0)),
                      clip_region,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));

    let _text_bounds = Rect::new(Point2D::new(100.0, 200.0), Size2D::new(700.0, 300.0));

    let _glyphs = vec![
        GlyphInstance {
            index: 48,
            x: 100.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 68,
            x: 150.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 80,
            x: 200.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 82,
            x: 250.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 81,
            x: 300.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 3,
            x: 350.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 86,
            x: 400.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 79,
            x: 450.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 72,
            x: 500.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 83,
            x: 550.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 87,
            x: 600.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 17,
            x: 650.0,
            y: 100.0,
        },
    ];

//     builder.push_text(text_bounds,
//                       clip_region,
//                       glyphs,
//                       font_key,
//                       ColorF::new(1.0, 1.0, 0.0, 1.0),
//                       Au::from_px(32),
//                       Au::from_px(0),
//                       &mut frame_builder.auxiliary_lists_builder);

    frame_builder.add_display_list(&mut api, builder.finalize(), &mut sc);
    let sc_id = frame_builder.add_stacking_context(&mut api, pipeline_id, sc);

    api.set_root_stacking_context(sc_id,
                                  root_background_color,
                                  epoch,
                                  pipeline_id,
                                  Size2D::new(width as f32, height as f32),
                                  frame_builder.stacking_contexts,
                                  frame_builder.display_lists,
                                  frame_builder.auxiliary_lists_builder
                                               .finalize());

    api.set_root_pipeline(pipeline_id);

    for event in window.wait_events() {
        gl::clear(gl::COLOR_BUFFER_BIT);
        renderer.update();

        renderer.render(Size2D::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed => break,
            glutin::Event::KeyboardInput(_element_state, scan_code, _virtual_key_code) => {
                if scan_code == 9 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<commit_msg>Update wr-sample for API change.<commit_after>extern crate app_units;
extern crate webrender;
extern crate glutin;
extern crate gleam;
extern crate webrender_traits;
extern crate euclid;

use euclid::{Size2D, Point2D, Rect, Matrix4D};
use gleam::gl;
use std::path::PathBuf;
use std::ffi::CStr;
use webrender_traits::{PipelineId, StackingContextId, DisplayListId};
use webrender_traits::{AuxiliaryListsBuilder, Epoch, ColorF, GlyphInstance};
use webrender_traits::{ImageFormat, RendererKind};
use std::fs::File;
use std::io::Read;
use std::env;

fn _load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

pub struct WebRenderFrameBuilder {
    pub stacking_contexts: Vec<(StackingContextId, webrender_traits::StackingContext)>,
    pub display_lists: Vec<(DisplayListId, webrender_traits::BuiltDisplayList)>,
    pub auxiliary_lists_builder: AuxiliaryListsBuilder,
    pub root_pipeline_id: PipelineId,
    pub next_scroll_layer_id: usize,
}

impl WebRenderFrameBuilder {
    pub fn new(root_pipeline_id: PipelineId) -> WebRenderFrameBuilder {
        WebRenderFrameBuilder {
            stacking_contexts: vec![],
            display_lists: vec![],
            auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
            root_pipeline_id: root_pipeline_id,
            next_scroll_layer_id: 0,
        }
    }

    pub fn add_stacking_context(&mut self,
                                api: &mut webrender_traits::RenderApi,
                                pipeline_id: PipelineId,
                                stacking_context: webrender_traits::StackingContext)
                                -> StackingContextId {
        assert!(pipeline_id == self.root_pipeline_id);
        let id = api.next_stacking_context_id();
        self.stacking_contexts.push((id, stacking_context));
        id
    }

    pub fn add_display_list(&mut self,
                            api: &mut webrender_traits::RenderApi,
                            display_list: webrender_traits::BuiltDisplayList,
                            stacking_context: &mut webrender_traits::StackingContext)
                            -> DisplayListId {
        let id = api.next_display_list_id();
        stacking_context.display_lists.push(id);
        self.display_lists.push((id, display_list));
        id
    }

    pub fn next_scroll_layer_id(&mut self) -> webrender_traits::ScrollLayerId {
        let scroll_layer_id = webrender_traits::ServoScrollRootId(self.next_scroll_layer_id);
        self.next_scroll_layer_id += 1;
        webrender_traits::ScrollLayerId::new(self.root_pipeline_id, 0, scroll_layer_id)
    }

}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        self.window_proxy.wakeup_event_loop();
    }

    fn pipeline_size_changed(&mut self,
                             _: PipelineId,
                             _: Option<Size2D<f32>>) {
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("{} <shader path>", args[0]);
        return;
    }

    let res_path = &args[1];

    let window = glutin::WindowBuilder::new()
                .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::clear_color(0.3, 0.0, 0.0, 1.0);
    }

    let version = unsafe {
        let data = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes().to_vec();
        String::from_utf8(data).unwrap()
    };

    println!("OpenGL version {}", version);
    println!("Shader resource path: {}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        device_pixel_ratio: 1.0,
        resource_path: PathBuf::from(res_path),
        enable_aa: false,
        enable_msaa: false,
        enable_profiler: false,
        enable_recording: false,
        enable_scrollbars: false,
        debug: true,
        precache_shaders: true,
        renderer_kind: RendererKind::Native,
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);
    let mut api = sender.create_api();

//     let font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf";
//     let font_bytes = load_file(font_path);
//     let font_key = api.add_raw_font(font_bytes);

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let pipeline_id = PipelineId(0, 0);
    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id);
    let root_scroll_layer_id = frame_builder.next_scroll_layer_id();

    let bounds = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(width as f32, height as f32));
    let mut sc =
        webrender_traits::StackingContext::new(Some(root_scroll_layer_id),
                                               webrender_traits::ScrollPolicy::Scrollable,
                                               bounds,
                                               bounds,
                                               0,
                                               &Matrix4D::identity(),
                                               &Matrix4D::identity(),
                                               true,
                                               webrender_traits::MixBlendMode::Normal,
                                               Vec::new(),
                                               &mut frame_builder.auxiliary_lists_builder);

    let mut builder = webrender_traits::DisplayListBuilder::new();

    let clip_region = {
        let rect = Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0));
        let mask = webrender_traits::ImageMask {
            image: api.add_image(2, 2, None, ImageFormat::A8, vec![0,80, 180, 255]),
            rect: rect,
            repeat: false,
        };
        let radius = webrender_traits::BorderRadius::uniform(20.0);
        let complex = webrender_traits::ComplexClipRegion::new(rect, radius);

        webrender_traits::ClipRegion::new(&bounds,
                                          vec![complex],
                                          Some(mask),
                                          &mut frame_builder.auxiliary_lists_builder)
    };

    builder.push_rect(Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0)),
                      clip_region,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));

    let _text_bounds = Rect::new(Point2D::new(100.0, 200.0), Size2D::new(700.0, 300.0));

    let _glyphs = vec![
        GlyphInstance {
            index: 48,
            x: 100.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 68,
            x: 150.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 80,
            x: 200.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 82,
            x: 250.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 81,
            x: 300.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 3,
            x: 350.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 86,
            x: 400.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 79,
            x: 450.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 72,
            x: 500.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 83,
            x: 550.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 87,
            x: 600.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 17,
            x: 650.0,
            y: 100.0,
        },
    ];

//     builder.push_text(text_bounds,
//                       clip_region,
//                       glyphs,
//                       font_key,
//                       ColorF::new(1.0, 1.0, 0.0, 1.0),
//                       Au::from_px(32),
//                       Au::from_px(0),
//                       &mut frame_builder.auxiliary_lists_builder);

    frame_builder.add_display_list(&mut api, builder.finalize(), &mut sc);
    let sc_id = frame_builder.add_stacking_context(&mut api, pipeline_id, sc);

    api.set_root_stacking_context(sc_id,
                                  root_background_color,
                                  epoch,
                                  pipeline_id,
                                  Size2D::new(width as f32, height as f32),
                                  frame_builder.stacking_contexts,
                                  frame_builder.display_lists,
                                  frame_builder.auxiliary_lists_builder
                                               .finalize());

    api.set_root_pipeline(pipeline_id);

    for event in window.wait_events() {
        gl::clear(gl::COLOR_BUFFER_BIT);
        renderer.update();

        renderer.render(Size2D::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed => break,
            glutin::Event::KeyboardInput(_element_state, scan_code, _virtual_key_code) => {
                if scan_code == 9 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Mutex;

fn main() {
    let m = Mutex::new(5);

    {
        let mut num = m.lock().unwrap();
        *num = 6;
    }

    println!("m = {:?}", m);
}
<commit_msg>Use mutex with multiple threads and Arc<commit_after>use std::sync::{Mutex, Arc};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 1..10 {
        let counter = counter.clone();
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();

            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}
<|endoftext|>


<commit_before>use nom::{alphanumeric, digit, eof, is_alphanumeric, line_ending, multispace};
use nom::{IResult, Err, ErrorKind, Needed};
use std::fmt::{self, Display};
use std::str;
use std::str::FromStr;

use column::{Column, FunctionExpression};
use keywords::sql_keyword;
use table::Table;

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum SqlType {
    Char(u16),
    Varchar(u16),
    Int(u16),
    Bigint(u16),
    Tinyint(u16),
    Blob,
    Longblob,
    Mediumblob,
    Tinyblob,
    Double,
    Float,
    Real,
    Tinytext,
    Mediumtext,
    Text,
    Date,
    Timestamp,
    Varbinary(u16),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum Literal {
    Null,
    Integer(i64),
    String(String),
    Blob(Vec<u8>),
    CurrentTime,
    CurrentDate,
    CurrentTimestamp,
}

impl From<i64> for Literal {
    fn from(i: i64) -> Self {
        Literal::Integer(i)
    }
}

impl From<String> for Literal {
    fn from(s: String) -> Self {
        Literal::String(s)
    }
}

impl<'a> From<&'a str> for Literal {
    fn from(s: &'a str) -> Self {
        Literal::String(String::from(s))
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
pub enum Operator {
    Not,
    And,
    Or,
    Like,
    NotLike,
    Equal,
    NotEqual,
    Greater,
    GreaterOrEqual,
    Less,
    LessOrEqual,
}

impl Display for Operator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let op = match *self {
            Operator::Not => "not",
            Operator::And => "and",
            Operator::Or => "or",
            Operator::Like => "like",
            Operator::NotLike => "not_like",
            Operator::Equal => "=",
            Operator::NotEqual => "!=",
            Operator::Greater => ">",
            Operator::GreaterOrEqual => ">=",
            Operator::Less => "<",
            Operator::LessOrEqual => "<=",
        };
        write!(f, "{}", op)
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
pub enum TableKey {
    PrimaryKey(Vec<Column>),
    UniqueKey(Option<String>, Vec<Column>),
    FulltextKey(Option<String>, Vec<Column>),
    Key(String, Vec<Column>),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum FieldExpression {
    All,
    AllInTable(String),
    Col(Column),
}

impl Display for FieldExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FieldExpression::All => write!(f, "*"),
            FieldExpression::AllInTable(ref table) => write!(f, "{}.*", table),
            FieldExpression::Col(ref col) => write!(f, "{}", col.name.as_str()),
        }
    }
}

impl Default for FieldExpression {
    fn default() -> FieldExpression {
        FieldExpression::All
    }
}

#[inline]
pub fn is_sql_identifier(chr: u8) -> bool {
    is_alphanumeric(chr) || chr == '_' as u8
}

/// Parses the arguments for an agregation function, and also returns whether the distinct flag is
/// present.
named!(pub function_arguments<&[u8], (Column, bool)>,
       chain!(
           distinct: opt!(chain!(
               caseless_tag!("distinct") ~
               multispace,
               ||{}
           )) ~
           column: column_identifier_no_alias,
           || {
               (column, distinct.is_some())
           }
       )
);

named!(pub column_function<&[u8], FunctionExpression>,
    alt_complete!(
        chain!(
            caseless_tag!("count(*)"),
            || {
                FunctionExpression::CountStar
            }
        )
    |   chain!(
            caseless_tag!("count") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Count(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("sum") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Sum(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("avg") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Avg(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("max") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Max(args.0.clone())
            }
        )
    |   chain!(
            caseless_tag!("min") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Min(args.0.clone())
            }
        )
    |   chain!(
            caseless_tag!("group_concat") ~
            spec: delimited!(tag!("("),
                       complete!(chain!(
                               column: column_identifier_no_alias ~
                               seperator: opt!(
                                   chain!(
                                       multispace? ~
                                       caseless_tag!("separator") ~
                                       sep: delimited!(tag!("'"), opt!(alphanumeric), tag!("'")) ~
                                       multispace?,
                                       || { sep.unwrap_or("".as_bytes()) }
                                   )
                               ),
                               || { (column, seperator) }
                       )),
                       tag!(")")),
            || {
                let (ref col, ref sep) = spec;
                let sep = match *sep {
                    // default separator is a comma, see MySQL manual §5.7
                    None => String::from(","),
                    Some(s) => String::from_utf8(s.to_vec()).unwrap(),
                };

                FunctionExpression::GroupConcat(col.clone(), sep)
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier_no_alias<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function,
            || {
                Column {
                    name: format!("{}", function),
                    alias: None,
                    table: None,
                    function: Some(Box::new(function)),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8),
            || {
                Column {
                    name: String::from(column),
                    alias: None,
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: match alias {
                        None => format!("{}", function),
                        Some(a) => String::from(a),
                    },
                    alias: match alias {
                        None => None,
                        Some(a) => Some(String::from(a)),
                    },
                    table: None,
                    function: Some(Box::new(function)),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8) ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: String::from(column),
                    alias: match alias {
                        None => None,
                        Some(a) => Some(String::from(a)),
                    },
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL identifier (alphanumeric and "_").
named!(pub sql_identifier<&[u8], &[u8]>,
    alt_complete!(
          chain!(
                not!(peek!(sql_keyword)) ~
                ident: take_while1!(is_sql_identifier),
                || { ident }
          )
        | delimited!(tag!("`"), take_while1!(is_sql_identifier), tag!("`"))
        | delimited!(tag!("'"), take_while1!(is_sql_identifier), tag!("'"))
    )
);

/// Parse an unsigned integer.
named!(pub unsigned_number<&[u8], u64>,
    map_res!(
        map_res!(digit, str::from_utf8),
        FromStr::from_str
    )
);

/// Parse a terminator that ends a SQL statement.
named!(pub statement_terminator,
    delimited!(opt!(multispace),
               alt_complete!(tag!(";") | line_ending | eof),
               opt!(multispace)
    )
);

/// Parse binary comparison operators
named!(pub binary_comparison_operator<&[u8], Operator>,
    alt_complete!(
           map!(caseless_tag!("not_like"), |_| Operator::NotLike)
         | map!(caseless_tag!("like"), |_| Operator::Like)
         | map!(caseless_tag!("!="), |_| Operator::NotEqual)
         | map!(caseless_tag!("<>"), |_| Operator::NotEqual)
         | map!(caseless_tag!(">="), |_| Operator::GreaterOrEqual)
         | map!(caseless_tag!("<="), |_| Operator::LessOrEqual)
         | map!(caseless_tag!("="), |_| Operator::Equal)
         | map!(caseless_tag!("<"), |_| Operator::Less)
         | map!(caseless_tag!(">"), |_| Operator::Greater)
    )
);

/// Parse rule for AS-based aliases for SQL entities.
named!(pub as_alias<&[u8], &str>,
    complete!(
        chain!(
            multispace ~
            opt!(chain!(caseless_tag!("as") ~ multispace, ||{})) ~
            alias: map_res!(sql_identifier, str::from_utf8),
            || { alias }
        )
    )
);

/// Parse rule for a comma-separated list of fields without aliases.
named!(pub field_list<&[u8], Vec<Column> >,
       many0!(
           chain!(
               fieldname: column_identifier_no_alias ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { fieldname }
           )
       )
);

/// Parse list of column/field definitions.
/// XXX(malte): add support for named table notation
named!(pub field_definition_expr<&[u8], Vec<FieldExpression>>,
       many0!(
           chain!(
               field: alt_complete!(
                   chain!(
                       tag!("*"),
                       || {
                           FieldExpression::All
                       }
                   )
                 | chain!(
                     table: table_reference ~ tag!(".*"),
                     || {
                         FieldExpression::AllInTable(table.name.clone())
                     }
                 )
                 | chain!(
                     column: column_identifier,
                     || {
                         FieldExpression::Col(column)
                     }
                 )
               ) ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                           tag!(",") ~
                           multispace?,
                       ||{}
                   ))
               ),
               || { field }
           )
       )
);

/// Parse list of table names.
/// XXX(malte): add support for aliases
named!(pub table_list<&[u8], Vec<Table> >,
       many0!(
           chain!(
               table: table_reference ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       || {}
                   ))
               ),
               || { table }
           )
       )
);

/// Integer literal value
named!(pub integer_literal<&[u8], Literal>,
    chain!(
        val: delimited!(opt!(multispace), digit, opt!(multispace)),
        || {
            let intval = i64::from_str(str::from_utf8(val).unwrap()).unwrap();
            Literal::Integer(intval)
        }
    )
);

/// String literal value
named!(pub string_literal<&[u8], Literal>,
    chain!(
        val: delimited!(opt!(multispace),
                 alt_complete!(
                       delimited!(tag!("\""), opt!(take_until!("\"")), tag!("\""))
                     | delimited!(tag!("'"), opt!(take_until!("'")), tag!("'"))
                 ),
                 opt!(multispace)
              ),
        || {
            let val = val.unwrap_or("".as_bytes());
            let s = String::from(str::from_utf8(val).unwrap());
            Literal::String(s)
        }
    )
);

/// Any literal value.
named!(pub literal<&[u8], Literal>,
    alt_complete!(
          integer_literal
        | string_literal
        | chain!(caseless_tag!("NULL"), || Literal::Null)
        | chain!(caseless_tag!("CURRENT_TIMESTAMP"), || Literal::CurrentTimestamp)
        | chain!(caseless_tag!("CURRENT_DATE"), || Literal::CurrentDate)
        | chain!(caseless_tag!("CURRENT_TIME"), || Literal::CurrentTime)
//        | float_literal
    )
);

/// Parse a list of values (e.g., for INSERT syntax).
named!(pub value_list<&[u8], Vec<Literal> >,
       many0!(
           chain!(
               val: literal ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { val }
           )
       )
);

/// Parse a reference to a named table
/// XXX(malte): add support for schema.table notation
named!(pub table_reference<&[u8], Table>,
    chain!(
        table: map_res!(sql_identifier, str::from_utf8) ~
        alias: opt!(as_alias),
        || {
            Table {
                name: String::from(table),
                alias: match alias {
                    Some(a) => Some(String::from(a)),
                    None => None,
                }
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn sql_identifiers() {
        let id1 = b"foo";
        let id2 = b"f_o_o";
        let id3 = b"foo12";
        let id4 = b":fo oo";
        let id5 = b"primary ";
        let id6 = b"`primary`";

        assert!(sql_identifier(id1).is_done());
        assert!(sql_identifier(id2).is_done());
        assert!(sql_identifier(id3).is_done());
        assert!(sql_identifier(id4).is_err());
        assert!(sql_identifier(id5).is_err());
        assert!(sql_identifier(id6).is_done());
    }

    #[test]
    fn simple_column_function() {
        let qs = b"max(addr_id)";

        let res = column_identifier(qs);
        let expected = Column {
            name: String::from("max(addr_id)"),
            alias: None,
            table: None,
            function: Some(Box::new(FunctionExpression::Max(Column::from("addr_id")))),
        };
        assert_eq!(res.unwrap().1, expected);
    }
}
<commit_msg>String conversion for `Literal`s<commit_after>use nom::{alphanumeric, digit, eof, is_alphanumeric, line_ending, multispace};
use nom::{IResult, Err, ErrorKind, Needed};
use std::fmt::{self, Display};
use std::str;
use std::str::FromStr;

use column::{Column, FunctionExpression};
use keywords::sql_keyword;
use table::Table;

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum SqlType {
    Char(u16),
    Varchar(u16),
    Int(u16),
    Bigint(u16),
    Tinyint(u16),
    Blob,
    Longblob,
    Mediumblob,
    Tinyblob,
    Double,
    Float,
    Real,
    Tinytext,
    Mediumtext,
    Text,
    Date,
    Timestamp,
    Varbinary(u16),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum Literal {
    Null,
    Integer(i64),
    String(String),
    Blob(Vec<u8>),
    CurrentTime,
    CurrentDate,
    CurrentTimestamp,
}

impl From<i64> for Literal {
    fn from(i: i64) -> Self {
        Literal::Integer(i)
    }
}

impl From<String> for Literal {
    fn from(s: String) -> Self {
        Literal::String(s)
    }
}

impl<'a> From<&'a str> for Literal {
    fn from(s: &'a str) -> Self {
        Literal::String(String::from(s))
    }
}

impl ToString for Literal {
    fn to_string(&self) -> String {
        match *self {
            Literal::Null => "NULL".to_string(),
            Literal::Integer(ref i) => format!("{}", i),
            Literal::String(ref s) => s.clone(),
            Literal::Blob(ref bv) => {
                format!("{}",
                        bv.iter()
                            .map(|v| format!("{:x}", v))
                            .collect::<Vec<String>>()
                            .join(" "))
            }
            Literal::CurrentTime => "CURRENT_TIME".to_string(),
            Literal::CurrentDate => "CURRENT_DATE".to_string(),
            Literal::CurrentTimestamp => "CURRENT_TIMESTAMP".to_string(),
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
pub enum Operator {
    Not,
    And,
    Or,
    Like,
    NotLike,
    Equal,
    NotEqual,
    Greater,
    GreaterOrEqual,
    Less,
    LessOrEqual,
}

impl Display for Operator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let op = match *self {
            Operator::Not => "not",
            Operator::And => "and",
            Operator::Or => "or",
            Operator::Like => "like",
            Operator::NotLike => "not_like",
            Operator::Equal => "=",
            Operator::NotEqual => "!=",
            Operator::Greater => ">",
            Operator::GreaterOrEqual => ">=",
            Operator::Less => "<",
            Operator::LessOrEqual => "<=",
        };
        write!(f, "{}", op)
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
pub enum TableKey {
    PrimaryKey(Vec<Column>),
    UniqueKey(Option<String>, Vec<Column>),
    FulltextKey(Option<String>, Vec<Column>),
    Key(String, Vec<Column>),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum FieldExpression {
    All,
    AllInTable(String),
    Col(Column),
}

impl Display for FieldExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FieldExpression::All => write!(f, "*"),
            FieldExpression::AllInTable(ref table) => write!(f, "{}.*", table),
            FieldExpression::Col(ref col) => write!(f, "{}", col.name.as_str()),
        }
    }
}

impl Default for FieldExpression {
    fn default() -> FieldExpression {
        FieldExpression::All
    }
}

#[inline]
pub fn is_sql_identifier(chr: u8) -> bool {
    is_alphanumeric(chr) || chr == '_' as u8
}

/// Parses the arguments for an agregation function, and also returns whether the distinct flag is
/// present.
named!(pub function_arguments<&[u8], (Column, bool)>,
       chain!(
           distinct: opt!(chain!(
               caseless_tag!("distinct") ~
               multispace,
               ||{}
           )) ~
           column: column_identifier_no_alias,
           || {
               (column, distinct.is_some())
           }
       )
);

named!(pub column_function<&[u8], FunctionExpression>,
    alt_complete!(
        chain!(
            caseless_tag!("count(*)"),
            || {
                FunctionExpression::CountStar
            }
        )
    |   chain!(
            caseless_tag!("count") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Count(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("sum") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Sum(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("avg") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Avg(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("max") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Max(args.0.clone())
            }
        )
    |   chain!(
            caseless_tag!("min") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Min(args.0.clone())
            }
        )
    |   chain!(
            caseless_tag!("group_concat") ~
            spec: delimited!(tag!("("),
                       complete!(chain!(
                               column: column_identifier_no_alias ~
                               seperator: opt!(
                                   chain!(
                                       multispace? ~
                                       caseless_tag!("separator") ~
                                       sep: delimited!(tag!("'"), opt!(alphanumeric), tag!("'")) ~
                                       multispace?,
                                       || { sep.unwrap_or("".as_bytes()) }
                                   )
                               ),
                               || { (column, seperator) }
                       )),
                       tag!(")")),
            || {
                let (ref col, ref sep) = spec;
                let sep = match *sep {
                    // default separator is a comma, see MySQL manual §5.7
                    None => String::from(","),
                    Some(s) => String::from_utf8(s.to_vec()).unwrap(),
                };

                FunctionExpression::GroupConcat(col.clone(), sep)
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier_no_alias<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function,
            || {
                Column {
                    name: format!("{}", function),
                    alias: None,
                    table: None,
                    function: Some(Box::new(function)),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8),
            || {
                Column {
                    name: String::from(column),
                    alias: None,
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: match alias {
                        None => format!("{}", function),
                        Some(a) => String::from(a),
                    },
                    alias: match alias {
                        None => None,
                        Some(a) => Some(String::from(a)),
                    },
                    table: None,
                    function: Some(Box::new(function)),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8) ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: String::from(column),
                    alias: match alias {
                        None => None,
                        Some(a) => Some(String::from(a)),
                    },
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL identifier (alphanumeric and "_").
named!(pub sql_identifier<&[u8], &[u8]>,
    alt_complete!(
          chain!(
                not!(peek!(sql_keyword)) ~
                ident: take_while1!(is_sql_identifier),
                || { ident }
          )
        | delimited!(tag!("`"), take_while1!(is_sql_identifier), tag!("`"))
        | delimited!(tag!("'"), take_while1!(is_sql_identifier), tag!("'"))
    )
);

/// Parse an unsigned integer.
named!(pub unsigned_number<&[u8], u64>,
    map_res!(
        map_res!(digit, str::from_utf8),
        FromStr::from_str
    )
);

/// Parse a terminator that ends a SQL statement.
named!(pub statement_terminator,
    delimited!(opt!(multispace),
               alt_complete!(tag!(";") | line_ending | eof),
               opt!(multispace)
    )
);

/// Parse binary comparison operators
named!(pub binary_comparison_operator<&[u8], Operator>,
    alt_complete!(
           map!(caseless_tag!("not_like"), |_| Operator::NotLike)
         | map!(caseless_tag!("like"), |_| Operator::Like)
         | map!(caseless_tag!("!="), |_| Operator::NotEqual)
         | map!(caseless_tag!("<>"), |_| Operator::NotEqual)
         | map!(caseless_tag!(">="), |_| Operator::GreaterOrEqual)
         | map!(caseless_tag!("<="), |_| Operator::LessOrEqual)
         | map!(caseless_tag!("="), |_| Operator::Equal)
         | map!(caseless_tag!("<"), |_| Operator::Less)
         | map!(caseless_tag!(">"), |_| Operator::Greater)
    )
);

/// Parse rule for AS-based aliases for SQL entities.
named!(pub as_alias<&[u8], &str>,
    complete!(
        chain!(
            multispace ~
            opt!(chain!(caseless_tag!("as") ~ multispace, ||{})) ~
            alias: map_res!(sql_identifier, str::from_utf8),
            || { alias }
        )
    )
);

/// Parse rule for a comma-separated list of fields without aliases.
named!(pub field_list<&[u8], Vec<Column> >,
       many0!(
           chain!(
               fieldname: column_identifier_no_alias ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { fieldname }
           )
       )
);

/// Parse list of column/field definitions.
/// XXX(malte): add support for named table notation
named!(pub field_definition_expr<&[u8], Vec<FieldExpression>>,
       many0!(
           chain!(
               field: alt_complete!(
                   chain!(
                       tag!("*"),
                       || {
                           FieldExpression::All
                       }
                   )
                 | chain!(
                     table: table_reference ~ tag!(".*"),
                     || {
                         FieldExpression::AllInTable(table.name.clone())
                     }
                 )
                 | chain!(
                     column: column_identifier,
                     || {
                         FieldExpression::Col(column)
                     }
                 )
               ) ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                           tag!(",") ~
                           multispace?,
                       ||{}
                   ))
               ),
               || { field }
           )
       )
);

/// Parse list of table names.
/// XXX(malte): add support for aliases
named!(pub table_list<&[u8], Vec<Table> >,
       many0!(
           chain!(
               table: table_reference ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       || {}
                   ))
               ),
               || { table }
           )
       )
);

/// Integer literal value
named!(pub integer_literal<&[u8], Literal>,
    chain!(
        val: delimited!(opt!(multispace), digit, opt!(multispace)),
        || {
            let intval = i64::from_str(str::from_utf8(val).unwrap()).unwrap();
            Literal::Integer(intval)
        }
    )
);

/// String literal value
named!(pub string_literal<&[u8], Literal>,
    chain!(
        val: delimited!(opt!(multispace),
                 alt_complete!(
                       delimited!(tag!("\""), opt!(take_until!("\"")), tag!("\""))
                     | delimited!(tag!("'"), opt!(take_until!("'")), tag!("'"))
                 ),
                 opt!(multispace)
              ),
        || {
            let val = val.unwrap_or("".as_bytes());
            let s = String::from(str::from_utf8(val).unwrap());
            Literal::String(s)
        }
    )
);

/// Any literal value.
named!(pub literal<&[u8], Literal>,
    alt_complete!(
          integer_literal
        | string_literal
        | chain!(caseless_tag!("NULL"), || Literal::Null)
        | chain!(caseless_tag!("CURRENT_TIMESTAMP"), || Literal::CurrentTimestamp)
        | chain!(caseless_tag!("CURRENT_DATE"), || Literal::CurrentDate)
        | chain!(caseless_tag!("CURRENT_TIME"), || Literal::CurrentTime)
//        | float_literal
    )
);

/// Parse a list of values (e.g., for INSERT syntax).
named!(pub value_list<&[u8], Vec<Literal> >,
       many0!(
           chain!(
               val: literal ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { val }
           )
       )
);

/// Parse a reference to a named table
/// XXX(malte): add support for schema.table notation
named!(pub table_reference<&[u8], Table>,
    chain!(
        table: map_res!(sql_identifier, str::from_utf8) ~
        alias: opt!(as_alias),
        || {
            Table {
                name: String::from(table),
                alias: match alias {
                    Some(a) => Some(String::from(a)),
                    None => None,
                }
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn sql_identifiers() {
        let id1 = b"foo";
        let id2 = b"f_o_o";
        let id3 = b"foo12";
        let id4 = b":fo oo";
        let id5 = b"primary ";
        let id6 = b"`primary`";

        assert!(sql_identifier(id1).is_done());
        assert!(sql_identifier(id2).is_done());
        assert!(sql_identifier(id3).is_done());
        assert!(sql_identifier(id4).is_err());
        assert!(sql_identifier(id5).is_err());
        assert!(sql_identifier(id6).is_done());
    }

    #[test]
    fn simple_column_function() {
        let qs = b"max(addr_id)";

        let res = column_identifier(qs);
        let expected = Column {
            name: String::from("max(addr_id)"),
            alias: None,
            table: None,
            function: Some(Box::new(FunctionExpression::Max(Column::from("addr_id")))),
        };
        assert_eq!(res.unwrap().1, expected);
    }
}
<|endoftext|>


<commit_before>extern crate url;
use self::url::percent_encoding::from_hex;

/// Percent-decode the input string
///
/// Not using url::percent_decode because it does not throw an error for malformed percent encoding
/// such as %AK
pub fn percent_decode(input: &str) -> Result<Vec<u8>, String> {
    let mut output: Vec<u8> = Vec::new();

    let mut input_iterator = input.as_bytes().into_iter();
    while let Some(i) = input_iterator.next() {
        match i {
            &b'%' => {
                let hexdigit1 = input_iterator.next()
                    .and_then(|h| from_hex(h.clone()));
                let hexdigit2 = input_iterator.next()
                    .and_then(|h| from_hex(h.clone()));
                match (hexdigit1, hexdigit2) {
                    (Some(h1), Some(h2)) => {
                        output.push(h1 * 0x10 + h2);
                    },
                    _ => {
                        return Err("Invalid percent encoding".to_owned());
                    },
                }
            }
            _ => {
                output.push(i.clone());
            }
        }
    }

    return Ok(output);
}

#[test]
fn percent_decode_test() {
    // Successes
    assert_eq!(percent_decode("%1a").unwrap(), [26]);
    assert_eq!(percent_decode("%1A").unwrap(), [26]);
    assert_eq!(percent_decode("a").unwrap(), [97]);

    // Failures
    assert!(percent_decode("%").is_err()); //too short
    assert!(percent_decode("%a").is_err()); //too short
    assert!(percent_decode("%ak").is_err()); //not in [0-9a-f]
}

/// Converts bytes to a hexstring
///
/// Lowercase-hex
pub fn hexstring(input: &[u8]) -> String
{
    let mut output = String::new();

    for byte in input {
        output.push_str(&format!("{:02x}", byte));
    }

    return output;
}

#[test]
fn hexstring_test() {
    assert_eq!(hexstring(&[0x5, 0x6]), "0506");
    assert_eq!(hexstring(&[0x0B, 0xf1]), "0bf1");
}

/* The info hash is stored in mongo, which is not binary string safe apparently,
so it needs to be parsed to a hexadecimal string rather than a binary one. */
pub fn parse_info_hash(input: &str) -> Result<String, String> {
    let info_hash_binary = match percent_decode(input) {
        Ok(i) => i,
        Err(j) => return Err(j),
    };

    if info_hash_binary.len() != 20 {
        return Err("Info hash is invalid (too short).".to_owned());
    }

    return Ok(hexstring(&info_hash_binary));
}

#[test]
fn parse_info_hash_test() {
    // Success
    assert_eq!(parse_info_hash("%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A").unwrap(), "123456789abcdef123456789abcdef123456789a");

    // Failures
    assert!(parse_info_hash("%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx").is_err()); // too short
    assert!(parse_info_hash("%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vxab").is_err()); // too long
    assert!(parse_info_hash("%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%ZA").is_err()); // invalid percent encoding
}
<commit_msg>Dereference instead of clone<commit_after>extern crate url;
use self::url::percent_encoding::from_hex;

/// Percent-decode the input string
///
/// Not using url::percent_decode because it does not throw an error for malformed percent encoding
/// such as %AK
pub fn percent_decode(input: &str) -> Result<Vec<u8>, String> {
    let mut output: Vec<u8> = Vec::new();

    let mut input_iterator = input.as_bytes().into_iter();
    while let Some(i) = input_iterator.next() {
        match i {
            &b'%' => {
                let hexdigit1 = input_iterator.next()
                    .and_then(|h| from_hex(*h));
                let hexdigit2 = input_iterator.next()
                    .and_then(|h| from_hex(*h));
                match (hexdigit1, hexdigit2) {
                    (Some(h1), Some(h2)) => {
                        output.push(h1 * 0x10 + h2);
                    },
                    _ => {
                        return Err("Invalid percent encoding".to_owned());
                    },
                }
            }
            _ => {
                output.push(*i);
            }
        }
    }

    return Ok(output);
}

#[test]
fn percent_decode_test() {
    // Successes
    assert_eq!(percent_decode("%1a").unwrap(), [26]);
    assert_eq!(percent_decode("%1A").unwrap(), [26]);
    assert_eq!(percent_decode("a").unwrap(), [97]);

    // Failures
    assert!(percent_decode("%").is_err()); //too short
    assert!(percent_decode("%a").is_err()); //too short
    assert!(percent_decode("%ak").is_err()); //not in [0-9a-f]
}

/// Converts bytes to a hexstring
///
/// Lowercase-hex
pub fn hexstring(input: &[u8]) -> String
{
    let mut output = String::new();

    for byte in input {
        output.push_str(&format!("{:02x}", byte));
    }

    return output;
}

#[test]
fn hexstring_test() {
    assert_eq!(hexstring(&[0x5, 0x6]), "0506");
    assert_eq!(hexstring(&[0x0B, 0xf1]), "0bf1");
}

/* The info hash is stored in mongo, which is not binary string safe apparently,
so it needs to be parsed to a hexadecimal string rather than a binary one. */
pub fn parse_info_hash(input: &str) -> Result<String, String> {
    let info_hash_binary = match percent_decode(input) {
        Ok(i) => i,
        Err(j) => return Err(j),
    };

    if info_hash_binary.len() != 20 {
        return Err("Info hash is invalid (too short).".to_owned());
    }

    return Ok(hexstring(&info_hash_binary));
}

#[test]
fn parse_info_hash_test() {
    // Success
    assert_eq!(parse_info_hash("%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A").unwrap(), "123456789abcdef123456789abcdef123456789a");

    // Failures
    assert!(parse_info_hash("%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx").is_err()); // too short
    assert!(parse_info_hash("%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vxab").is_err()); // too long
    assert!(parse_info_hash("%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%ZA").is_err()); // invalid percent encoding
}
<|endoftext|>