<commit_before>#![cfg(target_os = "macos")]

use CreationError;
use CreationError::OsError;
use ContextError;
use GlAttributes;
use GlContext;
use PixelFormat;
use PixelFormatRequirements;
use Robustness;
use WindowAttributes;
use os::macos::ActivationPolicy;

use objc::runtime::{BOOL, NO};

use cgl::{CGLEnable, kCGLCECrashOnRemovedFunctions};

use cocoa::base::{id, nil};
use cocoa::foundation::NSAutoreleasePool;
use cocoa::appkit::{self, NSOpenGLContext, NSOpenGLPixelFormat};

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};

use std::str::FromStr;
use std::ops::Deref;

use libc;

use winit;
use winit::os::macos::WindowExt;
pub use winit::{MonitorId, NativeMonitorId, get_available_monitors, get_primary_monitor};
pub use self::headless::HeadlessContext;
pub use self::headless::PlatformSpecificHeadlessBuilderAttributes;

mod headless;
mod helpers;

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub activation_policy: ActivationPolicy,
}

pub struct Window {
    context: IdRef,
    pixel_format: PixelFormat,
    winit_window: winit::Window,
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
    winit_iterator: winit::WaitEventsIterator<'a>,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = winit::Event;

    fn next(&mut self) -> Option<winit::Event> {
        let event = self.winit_iterator.next();
        match event {
            Some(winit::Event::Resized(_, _)) => self.window.update_context(),
            _ => {},
        }
        event
    }
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
    winit_iterator: winit::PollEventsIterator<'a>,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = winit::Event;

    fn next(&mut self) -> Option<winit::Event> {
        let event = self.winit_iterator.next();
        match event {
            Some(winit::Event::Resized(_, _)) => self.window.update_context(),
            _ => {},
        }
        event
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl Window {
    pub fn new(win_attribs: &WindowAttributes,
               pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>,
               _pl_attribs: &PlatformSpecificWindowBuilderAttributes,
               winit_builder: winit::WindowBuilder)
               -> Result<Window, CreationError> {
        if opengl.sharing.is_some() {
            unimplemented!()
        }

        match opengl.robustness {
            Robustness::RobustNoResetNotification |
            Robustness::RobustLoseContextOnReset => {
                return Err(CreationError::RobustnessNotSupported);
            }
            _ => (),
        }

        let winit_window = winit_builder.build().unwrap();
        let view = winit_window.get_nsview() as id;
        let (context, pf) = match Window::create_context(view, pf_reqs, opengl) {
            Ok((context, pf)) => (context, pf),
            Err(e) => {
                return Err(OsError(format!("Couldn't create OpenGL context: {}", e)));
            }
        };

        let window = Window {
            context: context,
            pixel_format: pf,
            winit_window: winit_window,
        };

        Ok(window)
    }

    fn create_context(view: id,
                      pf_reqs: &PixelFormatRequirements,
                      opengl: &GlAttributes<&Window>)
                      -> Result<(IdRef, PixelFormat), CreationError> {
        let attributes = try!(helpers::build_nsattributes(pf_reqs, opengl));
        unsafe {
            let pixelformat = IdRef::new(NSOpenGLPixelFormat::alloc(nil)
                .initWithAttributes_(&attributes));

            if let Some(pixelformat) = pixelformat.non_nil() {

                // TODO: Add context sharing
                let context = IdRef::new(NSOpenGLContext::alloc(nil)
                    .initWithFormat_shareContext_(*pixelformat, nil));

                if let Some(cxt) = context.non_nil() {
                    let pf = {
                        let get_attr = |attrib: appkit::NSOpenGLPixelFormatAttribute| -> i32 {
                            let mut value = 0;

                            NSOpenGLPixelFormat::getValues_forAttribute_forVirtualScreen_(
                                *pixelformat,
                                &mut value,
                                attrib,
                                NSOpenGLContext::currentVirtualScreen(*cxt));

                            value
                        };

                        PixelFormat {
                            hardware_accelerated: get_attr(appkit::NSOpenGLPFAAccelerated) != 0,
                            color_bits: (get_attr(appkit::NSOpenGLPFAColorSize) - get_attr(appkit::NSOpenGLPFAAlphaSize)) as u8,
                            alpha_bits: get_attr(appkit::NSOpenGLPFAAlphaSize) as u8,
                            depth_bits: get_attr(appkit::NSOpenGLPFADepthSize) as u8,
                            stencil_bits: get_attr(appkit::NSOpenGLPFAStencilSize) as u8,
                            stereoscopy: get_attr(appkit::NSOpenGLPFAStereo) != 0,
                            double_buffer: get_attr(appkit::NSOpenGLPFADoubleBuffer) != 0,
                            multisampling: if get_attr(appkit::NSOpenGLPFAMultisample) > 0 {
                                Some(get_attr(appkit::NSOpenGLPFASamples) as u16)
                            } else {
                                None
                            },
                            srgb: true,
                        }
                    };

                    cxt.setView_(view);
                    let value = if opengl.vsync { 1 } else { 0 };
                    cxt.setValues_forParameter_(&value, appkit::NSOpenGLContextParameter::NSOpenGLCPSwapInterval);

                    CGLEnable(cxt.CGLContextObj() as *mut _, kCGLCECrashOnRemovedFunctions);

                    Ok((cxt, pf))
                } else {
                    Err(CreationError::NotSupported)
                }
            } else {
                Err(CreationError::NoAvailablePixelFormat)
            }
        }
    }

    fn update_context(&self) {
        unsafe {
            self.context.update()
        }
    }

    pub fn set_title(&self, title: &str) {
        self.winit_window.set_title(title)
    }

    #[inline]
    pub fn as_winit_window(&self) -> &winit::Window {
        &self.winit_window
    }

    #[inline]
    pub fn as_winit_window_mut(&mut self) -> &mut winit::Window {
        &mut self.winit_window
    }

    pub fn show(&self) {
        self.winit_window.show()
    }

    pub fn hide(&self) {
        self.winit_window.hide()
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        self.winit_window.get_position()
    }

    pub fn set_position(&self, x: i32, y: i32) {
        self.winit_window.set_position(x, y)
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size()
    }

    pub fn get_inner_size_points(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size()
    }

    pub fn get_inner_size_pixels(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size().map(|(x, y)| {
            let hidpi = self.hidpi_factor();
            ((x as f32 * hidpi) as u32, (y as f32 * hidpi) as u32)
        })
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.winit_window.get_outer_size()
    }

    pub fn set_inner_size(&self, x: u32, y: u32) {
        self.winit_window.set_inner_size(x, y)
    }

    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self,
            winit_iterator: self.winit_window.poll_events()
        }
    }

    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self,
            winit_iterator: self.winit_window.wait_events()
        }
    }

    pub unsafe fn platform_display(&self) -> *mut libc::c_void {
        self.winit_window.platform_display()
    }

    pub unsafe fn platform_window(&self) -> *mut libc::c_void {
        self.winit_window.platform_window()
    }

    pub fn create_window_proxy(&self) -> winit::WindowProxy {
        self.winit_window.create_window_proxy()
    }

    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        self.winit_window.set_window_resize_callback(callback);
    }

    pub fn set_cursor(&self, cursor: winit::MouseCursor) {
        self.winit_window.set_cursor(cursor);
    }

    pub fn hidpi_factor(&self) -> f32 {
        self.winit_window.hidpi_factor()
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        self.winit_window.set_cursor_position(x, y)
    }

    pub fn set_cursor_state(&self, state: winit::CursorState) -> Result<(), String> {
        self.winit_window.set_cursor_state(state)
    }
}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        let _: () = msg_send![*self.context, update];
        self.context.makeCurrentContext();
        Ok(())
    }

    #[inline]
    fn is_current(&self) -> bool {
        unsafe {
            let current = NSOpenGLContext::currentContext(nil);
            if current != nil {
                let is_equal: BOOL = msg_send![current, isEqual:*self.context];
                is_equal != NO
            } else {
                false
            }
        }
    }

    fn get_proc_address(&self, addr: &str) -> *const () {
        let symbol_name: CFString = FromStr::from_str(addr).unwrap();
        let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap();
        let framework =
            unsafe { CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const _
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        unsafe {
            let pool = NSAutoreleasePool::new(nil);
            self.context.flushBuffer();
            let _: () = msg_send![pool, release];
        }
        Ok(())
    }

    #[inline]
    fn get_api(&self) -> ::Api {
        ::Api::OpenGl
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.pixel_format.clone()
    }
}

struct IdRef(id);

impl IdRef {
    fn new(i: id) -> IdRef {
        IdRef(i)
    }

    #[allow(dead_code)]
    fn retain(i: id) -> IdRef {
        if i != nil {
            let _: id = unsafe { msg_send![i, retain] };
        }
        IdRef(i)
    }

    fn non_nil(self) -> Option<IdRef> {
        if self.0 == nil { None } else { Some(self) }
    }
}

impl Drop for IdRef {
    fn drop(&mut self) {
        if self.0 != nil {
            let _: () = unsafe { msg_send![self.0, release] };
        }
    }
}

impl Deref for IdRef {
    type Target = id;
    fn deref<'a>(&'a self) -> &'a id {
        &self.0
    }
}

impl Clone for IdRef {
    fn clone(&self) -> IdRef {
        if self.0 != nil {
            let _: id = unsafe { msg_send![self.0, retain] };
        }
        IdRef(self.0)
    }
}
<commit_msg>Remove `update_context` helper.<commit_after>#![cfg(target_os = "macos")]

use CreationError;
use CreationError::OsError;
use ContextError;
use GlAttributes;
use GlContext;
use PixelFormat;
use PixelFormatRequirements;
use Robustness;
use WindowAttributes;
use os::macos::ActivationPolicy;

use objc::runtime::{BOOL, NO};

use cgl::{CGLEnable, kCGLCECrashOnRemovedFunctions};

use cocoa::base::{id, nil};
use cocoa::foundation::NSAutoreleasePool;
use cocoa::appkit::{self, NSOpenGLContext, NSOpenGLPixelFormat};

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};

use std::str::FromStr;
use std::ops::Deref;

use libc;

use winit;
use winit::os::macos::WindowExt;
pub use winit::{MonitorId, NativeMonitorId, get_available_monitors, get_primary_monitor};
pub use self::headless::HeadlessContext;
pub use self::headless::PlatformSpecificHeadlessBuilderAttributes;

mod headless;
mod helpers;

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub activation_policy: ActivationPolicy,
}

pub struct Window {
    context: IdRef,
    pixel_format: PixelFormat,
    winit_window: winit::Window,
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
    winit_iterator: winit::WaitEventsIterator<'a>,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = winit::Event;

    fn next(&mut self) -> Option<winit::Event> {
        let event = self.winit_iterator.next();
        match event {
            Some(winit::Event::Resized(_, _)) => unsafe { self.window.context.update() },
            _ => {},
        }
        event
    }
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
    winit_iterator: winit::PollEventsIterator<'a>,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = winit::Event;

    fn next(&mut self) -> Option<winit::Event> {
        let event = self.winit_iterator.next();
        match event {
            Some(winit::Event::Resized(_, _)) => unsafe { self.window.context.update() },
            _ => {},
        }
        event
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl Window {
    pub fn new(win_attribs: &WindowAttributes,
               pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>,
               _pl_attribs: &PlatformSpecificWindowBuilderAttributes,
               winit_builder: winit::WindowBuilder)
               -> Result<Window, CreationError> {
        if opengl.sharing.is_some() {
            unimplemented!()
        }

        match opengl.robustness {
            Robustness::RobustNoResetNotification |
            Robustness::RobustLoseContextOnReset => {
                return Err(CreationError::RobustnessNotSupported);
            }
            _ => (),
        }

        let winit_window = winit_builder.build().unwrap();
        let view = winit_window.get_nsview() as id;
        let (context, pf) = match Window::create_context(view, pf_reqs, opengl) {
            Ok((context, pf)) => (context, pf),
            Err(e) => {
                return Err(OsError(format!("Couldn't create OpenGL context: {}", e)));
            }
        };

        let window = Window {
            context: context,
            pixel_format: pf,
            winit_window: winit_window,
        };

        Ok(window)
    }

    fn create_context(view: id,
                      pf_reqs: &PixelFormatRequirements,
                      opengl: &GlAttributes<&Window>)
                      -> Result<(IdRef, PixelFormat), CreationError> {
        let attributes = try!(helpers::build_nsattributes(pf_reqs, opengl));
        unsafe {
            let pixelformat = IdRef::new(NSOpenGLPixelFormat::alloc(nil)
                .initWithAttributes_(&attributes));

            if let Some(pixelformat) = pixelformat.non_nil() {

                // TODO: Add context sharing
                let context = IdRef::new(NSOpenGLContext::alloc(nil)
                    .initWithFormat_shareContext_(*pixelformat, nil));

                if let Some(cxt) = context.non_nil() {
                    let pf = {
                        let get_attr = |attrib: appkit::NSOpenGLPixelFormatAttribute| -> i32 {
                            let mut value = 0;

                            NSOpenGLPixelFormat::getValues_forAttribute_forVirtualScreen_(
                                *pixelformat,
                                &mut value,
                                attrib,
                                NSOpenGLContext::currentVirtualScreen(*cxt));

                            value
                        };

                        PixelFormat {
                            hardware_accelerated: get_attr(appkit::NSOpenGLPFAAccelerated) != 0,
                            color_bits: (get_attr(appkit::NSOpenGLPFAColorSize) - get_attr(appkit::NSOpenGLPFAAlphaSize)) as u8,
                            alpha_bits: get_attr(appkit::NSOpenGLPFAAlphaSize) as u8,
                            depth_bits: get_attr(appkit::NSOpenGLPFADepthSize) as u8,
                            stencil_bits: get_attr(appkit::NSOpenGLPFAStencilSize) as u8,
                            stereoscopy: get_attr(appkit::NSOpenGLPFAStereo) != 0,
                            double_buffer: get_attr(appkit::NSOpenGLPFADoubleBuffer) != 0,
                            multisampling: if get_attr(appkit::NSOpenGLPFAMultisample) > 0 {
                                Some(get_attr(appkit::NSOpenGLPFASamples) as u16)
                            } else {
                                None
                            },
                            srgb: true,
                        }
                    };

                    cxt.setView_(view);
                    let value = if opengl.vsync { 1 } else { 0 };
                    cxt.setValues_forParameter_(&value, appkit::NSOpenGLContextParameter::NSOpenGLCPSwapInterval);

                    CGLEnable(cxt.CGLContextObj() as *mut _, kCGLCECrashOnRemovedFunctions);

                    Ok((cxt, pf))
                } else {
                    Err(CreationError::NotSupported)
                }
            } else {
                Err(CreationError::NoAvailablePixelFormat)
            }
        }
    }

    pub fn set_title(&self, title: &str) {
        self.winit_window.set_title(title)
    }

    #[inline]
    pub fn as_winit_window(&self) -> &winit::Window {
        &self.winit_window
    }

    #[inline]
    pub fn as_winit_window_mut(&mut self) -> &mut winit::Window {
        &mut self.winit_window
    }

    pub fn show(&self) {
        self.winit_window.show()
    }

    pub fn hide(&self) {
        self.winit_window.hide()
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        self.winit_window.get_position()
    }

    pub fn set_position(&self, x: i32, y: i32) {
        self.winit_window.set_position(x, y)
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size()
    }

    pub fn get_inner_size_points(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size()
    }

    pub fn get_inner_size_pixels(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size().map(|(x, y)| {
            let hidpi = self.hidpi_factor();
            ((x as f32 * hidpi) as u32, (y as f32 * hidpi) as u32)
        })
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.winit_window.get_outer_size()
    }

    pub fn set_inner_size(&self, x: u32, y: u32) {
        self.winit_window.set_inner_size(x, y)
    }

    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self,
            winit_iterator: self.winit_window.poll_events()
        }
    }

    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self,
            winit_iterator: self.winit_window.wait_events()
        }
    }

    pub unsafe fn platform_display(&self) -> *mut libc::c_void {
        self.winit_window.platform_display()
    }

    pub unsafe fn platform_window(&self) -> *mut libc::c_void {
        self.winit_window.platform_window()
    }

    pub fn create_window_proxy(&self) -> winit::WindowProxy {
        self.winit_window.create_window_proxy()
    }

    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        self.winit_window.set_window_resize_callback(callback);
    }

    pub fn set_cursor(&self, cursor: winit::MouseCursor) {
        self.winit_window.set_cursor(cursor);
    }

    pub fn hidpi_factor(&self) -> f32 {
        self.winit_window.hidpi_factor()
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        self.winit_window.set_cursor_position(x, y)
    }

    pub fn set_cursor_state(&self, state: winit::CursorState) -> Result<(), String> {
        self.winit_window.set_cursor_state(state)
    }
}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        let _: () = msg_send![*self.context, update];
        self.context.makeCurrentContext();
        Ok(())
    }

    #[inline]
    fn is_current(&self) -> bool {
        unsafe {
            let current = NSOpenGLContext::currentContext(nil);
            if current != nil {
                let is_equal: BOOL = msg_send![current, isEqual:*self.context];
                is_equal != NO
            } else {
                false
            }
        }
    }

    fn get_proc_address(&self, addr: &str) -> *const () {
        let symbol_name: CFString = FromStr::from_str(addr).unwrap();
        let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap();
        let framework =
            unsafe { CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const _
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        unsafe {
            let pool = NSAutoreleasePool::new(nil);
            self.context.flushBuffer();
            let _: () = msg_send![pool, release];
        }
        Ok(())
    }

    #[inline]
    fn get_api(&self) -> ::Api {
        ::Api::OpenGl
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.pixel_format.clone()
    }
}

struct IdRef(id);

impl IdRef {
    fn new(i: id) -> IdRef {
        IdRef(i)
    }

    #[allow(dead_code)]
    fn retain(i: id) -> IdRef {
        if i != nil {
            let _: id = unsafe { msg_send![i, retain] };
        }
        IdRef(i)
    }

    fn non_nil(self) -> Option<IdRef> {
        if self.0 == nil { None } else { Some(self) }
    }
}

impl Drop for IdRef {
    fn drop(&mut self) {
        if self.0 != nil {
            let _: () = unsafe { msg_send![self.0, release] };
        }
    }
}

impl Deref for IdRef {
    type Target = id;
    fn deref<'a>(&'a self) -> &'a id {
        &self.0
    }
}

impl Clone for IdRef {
    fn clone(&self) -> IdRef {
        if self.0 != nil {
            let _: id = unsafe { msg_send![self.0, retain] };
        }
        IdRef(self.0)
    }
}
<|endoftext|>


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

use any_pointer;
use MessageSize;
use capability::{Params, Promise, Request, RemotePromise, Results};

pub trait ResponseHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

pub trait RequestHook {
    fn get<'a>(&'a mut self) -> any_pointer::Builder<'a>;
    fn get_brand(&self) -> usize;
    fn send<'a>(self: Box<Self>) -> RemotePromise<any_pointer::Owned>;
    fn tail_send(self: Box<Self>)
                 -> Option<(u32, ::capability::Promise<(), ::Error>, Box<PipelineHook>)>;
}

pub trait ClientHook {
    fn add_ref(&self) -> Box<ClientHook>;
    fn new_call(&self,
                interface_id: u64,
                method_id: u16,
                size_hint: Option<MessageSize>)
                -> Request<any_pointer::Owned, any_pointer::Owned>;

    fn call(&self, interface_id: u64, method_id: u16,
            params: Box<ParamsHook>, results: Box<ResultsHook>)
            -> ::capability::Promise<(), ::Error>;

    fn get_brand(&self) -> usize;
    fn get_ptr(&self) -> usize;

    /// If this ClientHook is a promise that has already resolved, returns the inner, resolved version
    /// of the capability.  The caller may permanently replace this client with the resolved one if
    /// desired.  Returns null if the client isn't a promise or hasn't resolved yet -- use
    /// `whenMoreResolved()` to distinguish between them.
    fn get_resolved(&self) -> Option<Box<ClientHook>>;

    /// If this client is a settled reference (not a promise), return nullptr.  Otherwise, return a
    /// promise that eventually resolves to a new client that is closer to being the final, settled
    /// client (i.e. the value eventually returned by `getResolved()`).  Calling this repeatedly
    /// should eventually produce a settled client.
    fn when_more_resolved(&self) -> Option<::capability::Promise<Box<ClientHook>, ::Error>>;

    /// Repeatedly calls whenMoreResolved() until it returns nullptr.
    #[cfg(feature = "rpc")]
    fn when_resolved(&self) -> Promise<(), ::Error> {
        use futures::Future;

        match self.when_more_resolved() {
            Some(promise) => {
                Promise::from_future(promise.and_then(|resolution| {
                    resolution.when_resolved()
                }))
            }
            None => {
                Promise::ok(())
            }
        }
    }
}

impl Clone for Box<ClientHook> {
    fn clone(&self) -> Box<ClientHook> {
        self.add_ref()
    }
}

pub trait ServerHook: 'static {
    fn new_client(server: Box<::capability::Server>) -> ::capability::Client;
}

pub trait ResultsHook {
    fn get<'a>(&'a mut self) -> ::Result<any_pointer::Builder<'a>>;
    fn allow_cancellation(&self);
    fn tail_call(self: Box<Self>, request: Box<RequestHook>) -> Promise<(), ::Error>;
    fn direct_tail_call(self: Box<Self>, request: Box<RequestHook>) ->
        (::capability::Promise<(), ::Error>, Box<PipelineHook>);
}

pub trait ResultsDoneHook {
    fn add_ref(&self) -> Box<ResultsDoneHook>;
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

impl Clone for Box<ResultsDoneHook> {
    fn clone(&self) -> Box<ResultsDoneHook> {
        self.add_ref()
    }
}

pub trait ParamsHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

// Where should this live?
pub fn internal_get_typed_params<T>(typeless: Params<any_pointer::Owned>) -> Params<T> {
    Params { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_typed_results<T>(typeless: Results<any_pointer::Owned>) -> Results<T> {
    Results { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_untyped_results<T>(typeful: Results<T>) -> Results<any_pointer::Owned> {
    Results { hook: typeful.hook, marker: ::std::marker::PhantomData }
}

pub trait PipelineHook {
    fn add_ref(&self) -> Box<PipelineHook>;
    fn get_pipelined_cap(&self, ops: &[PipelineOp]) -> Box<ClientHook>;

    /// Version of get_pipelined_cap() passing the array by move. May avoid a copy in some cases.
    /// Default implementation just calls the other version.
    fn get_pipelined_cap_move(&self, ops: Vec<PipelineOp>) -> Box<ClientHook> {
        self.get_pipelined_cap(&ops)
    }
}

impl Clone for Box<PipelineHook> {
    fn clone(&self) -> Box<PipelineHook> {
        self.add_ref()
    }
}

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

use any_pointer;
use MessageSize;
use capability::{Params, Promise, Request, RemotePromise, Results};

pub trait ResponseHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

pub trait RequestHook {
    fn get<'a>(&'a mut self) -> any_pointer::Builder<'a>;
    fn get_brand(&self) -> usize;
    fn send<'a>(self: Box<Self>) -> RemotePromise<any_pointer::Owned>;
    fn tail_send(self: Box<Self>)
                 -> Option<(u32, ::capability::Promise<(), ::Error>, Box<PipelineHook>)>;
}

pub trait ClientHook {
    fn add_ref(&self) -> Box<ClientHook>;
    fn new_call(&self,
                interface_id: u64,
                method_id: u16,
                size_hint: Option<MessageSize>)
                -> Request<any_pointer::Owned, any_pointer::Owned>;

    fn call(&self, interface_id: u64, method_id: u16,
            params: Box<ParamsHook>, results: Box<ResultsHook>)
            -> ::capability::Promise<(), ::Error>;

    fn get_brand(&self) -> usize;
    fn get_ptr(&self) -> usize;

    /// If this ClientHook is a promise that has already resolved, returns the inner, resolved version
    /// of the capability.  The caller may permanently replace this client with the resolved one if
    /// desired.  Returns null if the client isn't a promise or hasn't resolved yet -- use
    /// `whenMoreResolved()` to distinguish between them.
    fn get_resolved(&self) -> Option<Box<ClientHook>>;

    /// If this client is a settled reference (not a promise), return nullptr.  Otherwise, return a
    /// promise that eventually resolves to a new client that is closer to being the final, settled
    /// client (i.e. the value eventually returned by `getResolved()`).  Calling this repeatedly
    /// should eventually produce a settled client.
    fn when_more_resolved(&self) -> Option<::capability::Promise<Box<ClientHook>, ::Error>>;

    /// Repeatedly calls whenMoreResolved() until it returns nullptr.
    #[cfg(feature = "rpc")]
    fn when_resolved(&self) -> Promise<(), ::Error> {
        use futures::Future;

        match self.when_more_resolved() {
            Some(promise) => {
                Promise::from_future(promise.and_then(|resolution| {
                    resolution.when_resolved()
                }))
            }
            None => {
                Promise::ok(())
            }
        }
    }
}

impl Clone for Box<ClientHook> {
    fn clone(&self) -> Box<ClientHook> {
        self.add_ref()
    }
}

pub trait ServerHook: 'static {
    fn new_client(server: Box<::capability::Server>) -> ::capability::Client;
}

pub trait ResultsHook {
    fn get<'a>(&'a mut self) -> ::Result<any_pointer::Builder<'a>>;
    fn allow_cancellation(&self);
    fn tail_call(self: Box<Self>, request: Box<RequestHook>) -> Promise<(), ::Error>;
    fn direct_tail_call(self: Box<Self>, request: Box<RequestHook>) ->
        (::capability::Promise<(), ::Error>, Box<PipelineHook>);
}

pub trait ParamsHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

// Where should this live?
pub fn internal_get_typed_params<T>(typeless: Params<any_pointer::Owned>) -> Params<T> {
    Params { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_typed_results<T>(typeless: Results<any_pointer::Owned>) -> Results<T> {
    Results { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_untyped_results<T>(typeful: Results<T>) -> Results<any_pointer::Owned> {
    Results { hook: typeful.hook, marker: ::std::marker::PhantomData }
}

pub trait PipelineHook {
    fn add_ref(&self) -> Box<PipelineHook>;
    fn get_pipelined_cap(&self, ops: &[PipelineOp]) -> Box<ClientHook>;

    /// Version of get_pipelined_cap() passing the array by move. May avoid a copy in some cases.
    /// Default implementation just calls the other version.
    fn get_pipelined_cap_move(&self, ops: Vec<PipelineOp>) -> Box<ClientHook> {
        self.get_pipelined_cap(&ops)
    }
}

impl Clone for Box<PipelineHook> {
    fn clone(&self) -> Box<PipelineHook> {
        self.add_ref()
    }
}

#[derive(Clone, Copy)]
pub enum PipelineOp {
    Noop,
    GetPointerField(u16),
}
<|endoftext|>


<commit_before>use reader::lexer::rdf_lexer::RdfLexer;
use reader::lexer::token::Token;
use reader::input_reader::InputReader;
use std::io::Read;
use error::{Error, ErrorType};
use Result;

pub struct TurtleLexer<R: Read> {
  input_reader: InputReader<R>,
  peeked_token: Option<Token>
}

impl<R: Read> RdfLexer<R> for TurtleLexer<R> {
  /// Constructor for `TurtleLexer`.
  ///
  /// # Example
  ///
  /// ```
  /// use rdf_rs::reader::lexer::rdf_lexer::RdfLexer;
  /// use rdf_rs::reader::lexer::turtle_lexer::TurtleLexer;
  ///
  /// let input = "<example.org/a>".as_bytes();
  ///
  /// TurtleLexer::new(input);
  /// ```
  fn new(input: R) -> TurtleLexer<R> {
    TurtleLexer {
      input_reader: InputReader::new(input),
      peeked_token: None
    }
  }

  /// Determines the next token from the input.
  /// todo
  ///
  /// # Example
  ///
  /// ```
  /// use rdf_rs::reader::lexer::rdf_lexer::RdfLexer;
  /// use rdf_rs::reader::lexer::turtle_lexer::TurtleLexer;
  /// use rdf_rs::reader::lexer::token::Token;
  ///
  /// let input = "_:auto <example.org/b> \"test\" .".as_bytes();
  ///
  /// let mut lexer = TurtleLexer::new(input);
  ///
  /// assert_eq!(lexer.get_next_token().unwrap(), Token::BlankNode("auto".to_string()));
  /// assert_eq!(lexer.get_next_token().unwrap(), Token::Uri("example.org/b".to_string()));
  /// assert_eq!(lexer.get_next_token().unwrap(), Token::Literal("test".to_string()));
  /// assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  /// ```
  fn get_next_token(&mut self) -> Result<Token> {
    match self.peeked_token.clone() {
      Some(token) => {
        self.peeked_token = None;
        return Ok(token)
      },
      None => { }
    }

    match try!(self.input_reader.peek_next_char_discard_leading_spaces()) {
      Some('#') => self.get_comment(),
      Some('@') => self.get_base_or_prefix(),
      Some('"') => self.get_literal(),
      Some('<') => self.get_uri(),
      Some('_') => self.get_blank_node(),
      Some('.') => {
        self.consume_next_char();  // consume '.'
        Ok(Token::TripleDelimiter)
      },
      Some(',') => {
        self.consume_next_char();  // consume ','
        Ok(Token::ObjectListDelimiter)
      },
      Some(';') => {
        self.consume_next_char();  // consume ';'
        Ok(Token::PredicateListDelimiter)
      },
      Some(_) => self.get_qname(),
      None => Ok(Token::EndOfInput)
    }
  }

  /// Determines the next token without consuming it.
  ///
  /// # Examples
  ///
  /// todo
  ///
  fn peek_next_token(&mut self) -> Result<Token> {
    match self.peeked_token.clone() {
      Some(token) => Ok(token),
      None => {
        match self.get_next_token() {
          Ok(next) => {
            self.peeked_token = Some(next.clone());
            return Ok(next)
          },
          Err(err) => return Err(err)
        }
      }
    }
  }
}

impl<R: Read> TurtleLexer<R> {
  /// Consumes the next character of the input reader.
  fn consume_next_char(&mut self) {
    let _ = self.input_reader.get_next_char();
  }

  /// Parses the base or prefix definition.
  fn get_base_or_prefix(&mut self) -> Result<Token> {
    self.consume_next_char(); // consume '@'

    match try!(self.input_reader.get_next_char()) {
      Some('b') => {
        self.get_base_directive()
      },
      Some('p') => {
        self.get_prefix_directive()
      },
      None | Some(_) => Err(Error::new(ErrorType::InvalidReaderInput,
                             "Invalid input while trying to parse base or prefix definition."))
    }
  }

  /// Parses the base directive.
  fn get_base_directive(&mut self) -> Result<Token> {
    let _ = self.input_reader.get_until(|c| c == '<');  // consume '@base'

    match try!(self.get_uri()) {
      Token::Uri(base_uri) => {
        Ok(Token::BaseDirective(base_uri))
      },
      _ => Err(Error::new(ErrorType::InvalidReaderInput,
                          "Invalid URI for Turtle base directive."))
    }
  }

  /// Parses the prefix directive.
  fn get_prefix_directive(&mut self) -> Result<Token> {
    let _ = self.input_reader.get_until(|c| c == ' ');  // consume '@prefix'

    // get prefix name including ':'
    let mut name = try!(self.input_reader.get_until_discard_leading_spaces(|c| c == ':'));
    name.push(':');

    let _ = self.input_reader.get_until(|c| c == '<');  // consume characters until URI begin

    match try!(self.get_uri()) {
      Token::Uri(prefix_uri) => {
        Ok(Token::PrefixDirective(name, prefix_uri))
      },
      _ => Err(Error::new(ErrorType::InvalidReaderInput,
                          "Invalid URI for Turtle prefix directive."))
    }
  }

  /// Parses the comment from the input and returns it as token.
  fn get_comment(&mut self) -> Result<Token> {
    self.consume_next_char();    // consume '#'

    match self.input_reader.get_until_discard_leading_spaces(|c| c == '\n' || c == '\r') {
      Ok(str) => {
        self.consume_next_char();  // consume comment delimiter
        Ok(Token::Comment(str))
      },
      Err(err) => {
        match err.error_type() {
          &ErrorType::EndOfInput(ref str) => Ok(Token::Comment(str.clone())),
          _ => Err(Error::new(ErrorType::InvalidReaderInput,
                              "Invalid input for Turtle lexer while parsing comment."))
        }
      }
    }
  }

  /// Parses the language specification from the input and returns it as token.
  fn get_language_specification(&mut self) -> Result<String> {
    match self.input_reader.get_until(|c| c == '\n' || c == '\r' || c == ' ' || c == '.') {
      Ok(str) => Ok(str),
      Err(err) => {
        match err.error_type() {
          &ErrorType::EndOfInput(ref str) => Ok(str.clone()),
          _ => Err(Error::new(ErrorType::InvalidReaderInput,
                              "Invalid input for Turtle lexer while parsing language specification."))
        }
      }
    }
  }

  /// Parses a literal from the input and returns it as token.
  fn get_literal(&mut self) -> Result<Token> {
    self.consume_next_char();  // consume '"'
    let literal = try!(self.input_reader.get_until(|c| c == '"'));
    self.consume_next_char(); // consume '"'

    match try!(self.input_reader.peek_next_char()) {
      Some('@') => {
        self.consume_next_char(); // consume '@'
        let language = try!(self.get_language_specification());
        Ok(Token::LiteralWithLanguageSpecification(literal, language))
      },
      Some('^') => {
        self.consume_next_char(); // consume '^'
        self.consume_next_char(); // consume '^'

        match try!(self.input_reader.peek_next_char()) {
          Some('<') => {    // data type is an URI (NTriples allows only URI data types)
            match try!(self.get_uri()) {
              Token::Uri(datatype_uri) => {
                Ok(Token::LiteralWithUrlDatatype(literal, datatype_uri))
              },
              _ => Err(Error::new(ErrorType::InvalidReaderInput,
                                  "Invalid data type URI for Turtle literal."))
            }
          },
          Some(_) => {
            match try!(self.get_qname()) {
              Token::QName(prefix, path) => Ok(Token::LiteralWithQNameDatatype(literal, prefix, path)),
              _ => Err(Error::new(ErrorType::InvalidReaderInput, "Invalid Turtle input for parsing QName data type."))
            }
          },
          None => Err(Error::new(ErrorType::InvalidReaderInput, "Invalid Turtle input."))
        }
      },
      _ => {
        self.consume_next_char(); // consume '"'
        Ok(Token::Literal(literal))
      }
    }
  }

  /// Parses a URI from the input and returns it as token.
  fn get_uri(&mut self) -> Result<Token> {
    self.consume_next_char();    // consume '<'
    let str = try!(self.input_reader.get_until(|c| c == '>'));
    self.consume_next_char();    // consume '>'
    Ok(Token::Uri(str))
  }

  /// Parses a blank node ID from the input and returns it as token.
  fn get_blank_node(&mut self) -> Result<Token> {
    self.consume_next_char();    // consume '_'

    // get colon after under score
    match try!(self.input_reader.get_next_char()) {
      Some(':') => { }
      Some(c) => return Err(Error::new(ErrorType::InvalidReaderInput,
                                       "Invalid character while parsing Turtle blank node: ".to_string() + &c.to_string())),
      None => return Err(Error::new(ErrorType::InvalidReaderInput,
                                    "Error while parsing Turtle blank node."))
    }

    match self.input_reader.get_until(|c| c == '\n' || c == '\r' || c == ' ' || c == '.') {
      Ok(str) => Ok(Token::BlankNode(str)),
      Err(err) => {
        match err.error_type() {
          &ErrorType::EndOfInput(ref str) => Ok(Token::BlankNode(str.clone())),
          _ => Err(Error::new(ErrorType::InvalidReaderInput,
                              "Invalid input for Turtle lexer while parsing blank node."))
        }
      }
    }
  }

  /// Parses a QName.
  fn get_qname(&mut self) -> Result<Token> {
    let mut prefix = try!(self.input_reader.get_until(|c| c == ':'));
    prefix.push(':');     // ':' is part of prefix name
    self.consume_next_char();    // consume ':'

    match self.input_reader.get_until(|c| c == '\n' || c == '\r' || c == ' ' || c == '.') {
      Ok(str) => Ok(Token::QName(prefix, str)),
      Err(err) => {
        match err.error_type() {
          &ErrorType::EndOfInput(ref str) => Ok(Token::QName(prefix, str.clone())),
          _ => Err(Error::new(ErrorType::InvalidReaderInput,
                              "Invalid input for Turtle lexer while parsing QName."))
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use reader::lexer::rdf_lexer::RdfLexer;
  use reader::lexer::turtle_lexer::TurtleLexer;
  use reader::lexer::token::Token;

  #[test]
  fn parse_base_directive() {
    let input = "@base <http://example.org/> .".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::BaseDirective("http://example.org/".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  }

  #[test]
  fn parse_prefix_directive() {
    let input = "@prefix foaf: <http://xmlns.com/foaf/0.1/> .".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::PrefixDirective("foaf:".to_string(), "http://xmlns.com/foaf/0.1/".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  }

  #[test]
  fn parse_comment() {
    let input = "# Hello World!\n# Foo".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::Comment("Hello World!".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::Comment("Foo".to_string()));
  }

  #[test]
  fn parse_literal() {
    let input = "\"a\"".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::Literal("a".to_string()));
  }

  #[test]
  fn parse_uri() {
    let input = "<example.org/a>".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::Uri("example.org/a".to_string()));
  }

  #[test]
  fn parse_literal_with_language_specification() {
    let input = "\"a\"@abc".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::LiteralWithLanguageSpecification("a".to_string(), "abc".to_string()));
  }

  #[test]
  fn parse_blank_node() {
    let input = "_:auto".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::BlankNode("auto".to_string()));
  }

  #[test]
  fn parse_qname() {
    let input = "abc:def:ghij".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::QName("abc:".to_string(), "def:ghij".to_string()));
  }

  #[test]
  fn parse_literal_with_data_type() {
    let input = "\"a\"^^<example.org/abc>".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::LiteralWithUrlDatatype("a".to_string(), "example.org/abc".to_string()));
  }

  #[test]
  fn parse_literal_with_qname_data_type() {
    let input = "\"a\"^^ex:abc:asdf".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::LiteralWithQNameDatatype("a".to_string(), "ex:".to_string(), "abc:asdf".to_string()));
  }

  #[test]
  fn parse_triple_delimiter() {
    let input = ".   \"a\"   .".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
    assert_eq!(lexer.get_next_token().unwrap(), Token::Literal("a".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  }
}
<commit_msg>Support SPARQL base and prefix definitions<commit_after>use reader::lexer::rdf_lexer::RdfLexer;
use reader::lexer::token::Token;
use reader::input_reader::InputReader;
use std::io::Read;
use error::{Error, ErrorType};
use Result;

pub struct TurtleLexer<R: Read> {
  input_reader: InputReader<R>,
  peeked_token: Option<Token>
}

impl<R: Read> RdfLexer<R> for TurtleLexer<R> {
  /// Constructor for `TurtleLexer`.
  ///
  /// # Example
  ///
  /// ```
  /// use rdf_rs::reader::lexer::rdf_lexer::RdfLexer;
  /// use rdf_rs::reader::lexer::turtle_lexer::TurtleLexer;
  ///
  /// let input = "<example.org/a>".as_bytes();
  ///
  /// TurtleLexer::new(input);
  /// ```
  fn new(input: R) -> TurtleLexer<R> {
    TurtleLexer {
      input_reader: InputReader::new(input),
      peeked_token: None
    }
  }

  /// Determines the next token from the input.
  /// todo
  ///
  /// # Example
  ///
  /// ```
  /// use rdf_rs::reader::lexer::rdf_lexer::RdfLexer;
  /// use rdf_rs::reader::lexer::turtle_lexer::TurtleLexer;
  /// use rdf_rs::reader::lexer::token::Token;
  ///
  /// let input = "_:auto <example.org/b> \"test\" .".as_bytes();
  ///
  /// let mut lexer = TurtleLexer::new(input);
  ///
  /// assert_eq!(lexer.get_next_token().unwrap(), Token::BlankNode("auto".to_string()));
  /// assert_eq!(lexer.get_next_token().unwrap(), Token::Uri("example.org/b".to_string()));
  /// assert_eq!(lexer.get_next_token().unwrap(), Token::Literal("test".to_string()));
  /// assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  /// ```
  fn get_next_token(&mut self) -> Result<Token> {
    match self.peeked_token.clone() {
      Some(token) => {
        self.peeked_token = None;
        return Ok(token)
      },
      None => { }
    }

    match try!(self.input_reader.peek_next_char_discard_leading_spaces()) {
      Some('#') => return self.get_comment(),
      Some('@') => {
        self.consume_next_char();   // consume '@'
        return self.get_base_or_prefix();
      },
      Some('"') => return self.get_literal(),      // todo: ''
      Some('<') => return self.get_uri(),
      Some('_') => return self.get_blank_node(),
      Some('.') => {
        self.consume_next_char();  // consume '.'
        return Ok(Token::TripleDelimiter);
      },
      Some(',') => {
        self.consume_next_char();  // consume ','
        return Ok(Token::ObjectListDelimiter);
      },
      Some(';') => {
        self.consume_next_char();  // consume ';'
        return Ok(Token::PredicateListDelimiter);
      },
      Some('P') | Some('B') => {
        match self.get_base_or_prefix() {
          Ok(token) => return Ok(token),
          _ => {}     // continue, because it could still be a QName
        }
      },
//      Some('t') | Some('f') => self.get_boolean(),
//      // todo: boolean, numbers, ....
      Some(_) => {},
      None => return Ok(Token::EndOfInput)
    }

    self.get_qname()
  }

  /// Determines the next token without consuming it.
  ///
  /// # Examples
  ///
  /// todo
  ///
  fn peek_next_token(&mut self) -> Result<Token> {
    match self.peeked_token.clone() {
      Some(token) => Ok(token),
      None => {
        match self.get_next_token() {
          Ok(next) => {
            self.peeked_token = Some(next.clone());
            return Ok(next)
          },
          Err(err) => return Err(err)
        }
      }
    }
  }
}

impl<R: Read> TurtleLexer<R> {
  /// Consumes the next character of the input reader.
  fn consume_next_char(&mut self) {
    let _ = self.input_reader.get_next_char();
  }

  /// Parses the base or prefix definition.
  fn get_base_or_prefix(&mut self) -> Result<Token> {
    match try!(self.input_reader.peek_next_char()) {
      Some('b') | Some('B') => {
        self.get_base_directive()
      },
      Some('p') | Some('P') => {
        self.get_prefix_directive()
      },
      None | Some(_) => Err(Error::new(ErrorType::InvalidReaderInput,
                             "Invalid input while trying to parse base or prefix definition."))
    }
  }

  /// Parses the base directive.
  fn get_base_directive(&mut self) -> Result<Token> {
    let base_directive: Vec<Option<char>> = try!(self.input_reader.peek_next_k_chars(5));
    let base_directive_string: String = base_directive.into_iter().flat_map(|c| c).collect();

    if base_directive_string.to_lowercase() != "base " {
      return Err(Error::new(ErrorType::InvalidReaderInput,
                           "Invalid URI for Turtle base directive."));
    }

    let _ = self.input_reader.get_until(|c| c == '<');  // consume 'base'

    match try!(self.get_uri()) {
      Token::Uri(base_uri) => {
        Ok(Token::BaseDirective(base_uri))
      },
      _ => Err(Error::new(ErrorType::InvalidReaderInput,
                          "Invalid URI for Turtle base directive."))
    }
  }

  /// Parses the prefix directive.
  fn get_prefix_directive(&mut self) -> Result<Token> {
    let prefix_directive: Vec<Option<char>> = try!(self.input_reader.peek_next_k_chars(7));
    let prefix_directive_string: String = prefix_directive.into_iter().flat_map(|c| c).collect();

    if prefix_directive_string.to_lowercase() != "prefix " {
      return Err(Error::new(ErrorType::InvalidReaderInput,
                            "Invalid URI for Turtle base directive."));
    }

    let _ = self.input_reader.get_until(|c| c == ' ');  // consume 'prefix'

    // get prefix name including ':'
    let mut name = try!(self.input_reader.get_until_discard_leading_spaces(|c| c == ':'));
    name.push(':');

    let _ = self.input_reader.get_until(|c| c == '<');  // consume characters until URI begin

    match try!(self.get_uri()) {
      Token::Uri(prefix_uri) => {
        Ok(Token::PrefixDirective(name, prefix_uri))
      },
      _ => Err(Error::new(ErrorType::InvalidReaderInput,
                          "Invalid URI for Turtle prefix directive."))
    }
  }

  /// Parses the comment from the input and returns it as token.
  fn get_comment(&mut self) -> Result<Token> {
    self.consume_next_char();    // consume '#'

    match self.input_reader.get_until_discard_leading_spaces(|c| c == '\n' || c == '\r') {
      Ok(str) => {
        self.consume_next_char();  // consume comment delimiter
        Ok(Token::Comment(str))
      },
      Err(err) => {
        match err.error_type() {
          &ErrorType::EndOfInput(ref str) => Ok(Token::Comment(str.clone())),
          _ => Err(Error::new(ErrorType::InvalidReaderInput,
                              "Invalid input for Turtle lexer while parsing comment."))
        }
      }
    }
  }

  /// Parses the language specification from the input and returns it as token.
  fn get_language_specification(&mut self) -> Result<String> {
    match self.input_reader.get_until(|c| c == '\n' || c == '\r' || c == ' ' || c == '.') {
      Ok(str) => Ok(str),
      Err(err) => {
        match err.error_type() {
          &ErrorType::EndOfInput(ref str) => Ok(str.clone()),
          _ => Err(Error::new(ErrorType::InvalidReaderInput,
                              "Invalid input for Turtle lexer while parsing language specification."))
        }
      }
    }
  }

  /// Parses a literal from the input and returns it as token.
  fn get_literal(&mut self) -> Result<Token> {
    self.consume_next_char();  // consume '"'
    let literal = try!(self.input_reader.get_until(|c| c == '"'));
    self.consume_next_char(); // consume '"'

    match try!(self.input_reader.peek_next_char()) {
      Some('@') => {
        self.consume_next_char(); // consume '@'
        let language = try!(self.get_language_specification());
        Ok(Token::LiteralWithLanguageSpecification(literal, language))
      },
      Some('^') => {
        self.consume_next_char(); // consume '^'
        self.consume_next_char(); // consume '^'

        match try!(self.input_reader.peek_next_char()) {
          Some('<') => {    // data type is an URI (NTriples allows only URI data types)
            match try!(self.get_uri()) {
              Token::Uri(datatype_uri) => {
                Ok(Token::LiteralWithUrlDatatype(literal, datatype_uri))
              },
              _ => Err(Error::new(ErrorType::InvalidReaderInput,
                                  "Invalid data type URI for Turtle literal."))
            }
          },
          Some(_) => {
            match try!(self.get_qname()) {
              Token::QName(prefix, path) => Ok(Token::LiteralWithQNameDatatype(literal, prefix, path)),
              _ => Err(Error::new(ErrorType::InvalidReaderInput, "Invalid Turtle input for parsing QName data type."))
            }
          },
          None => Err(Error::new(ErrorType::InvalidReaderInput, "Invalid Turtle input."))
        }
      },
      _ => {
        self.consume_next_char(); // consume '"'
        Ok(Token::Literal(literal))
      }
    }
  }

  /// Parses a URI from the input and returns it as token.
  fn get_uri(&mut self) -> Result<Token> {
    self.consume_next_char();    // consume '<'
    let str = try!(self.input_reader.get_until(|c| c == '>'));
    self.consume_next_char();    // consume '>'
    Ok(Token::Uri(str))
  }

  /// Parses a blank node ID from the input and returns it as token.
  fn get_blank_node(&mut self) -> Result<Token> {
    self.consume_next_char();    // consume '_'

    // get colon after under score
    match try!(self.input_reader.get_next_char()) {
      Some(':') => { }
      Some(c) => return Err(Error::new(ErrorType::InvalidReaderInput,
                                       "Invalid character while parsing Turtle blank node: ".to_string() + &c.to_string())),
      None => return Err(Error::new(ErrorType::InvalidReaderInput,
                                    "Error while parsing Turtle blank node."))
    }

    match self.input_reader.get_until(|c| c == '\n' || c == '\r' || c == ' ' || c == '.') {
      Ok(str) => Ok(Token::BlankNode(str)),
      Err(err) => {
        match err.error_type() {
          &ErrorType::EndOfInput(ref str) => Ok(Token::BlankNode(str.clone())),
          _ => Err(Error::new(ErrorType::InvalidReaderInput,
                              "Invalid input for Turtle lexer while parsing blank node."))
        }
      }
    }
  }

  /// Parses a QName.
  fn get_qname(&mut self) -> Result<Token> {
    let mut prefix = try!(self.input_reader.get_until(|c| c == ':'));
    prefix.push(':');     // ':' is part of prefix name
    self.consume_next_char();    // consume ':'

    match self.input_reader.get_until(|c| c == '\n' || c == '\r' || c == ' ' || c == '.') {
      Ok(str) => Ok(Token::QName(prefix, str)),
      Err(err) => {
        match err.error_type() {
          &ErrorType::EndOfInput(ref str) => Ok(Token::QName(prefix, str.clone())),
          _ => Err(Error::new(ErrorType::InvalidReaderInput,
                              "Invalid input for Turtle lexer while parsing QName."))
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use reader::lexer::rdf_lexer::RdfLexer;
  use reader::lexer::turtle_lexer::TurtleLexer;
  use reader::lexer::token::Token;

  #[test]
  fn parse_base_directive() {
    let input = "@base <http://example.org/> .".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::BaseDirective("http://example.org/".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  }

  #[test]
  fn parse_sparql_base_directive() {
    let input = "BASE <http://example.org/> .".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::BaseDirective("http://example.org/".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  }

  #[test]
  fn parse_prefix_directive() {
    let input = "@prefix foaf: <http://xmlns.com/foaf/0.1/> .".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::PrefixDirective("foaf:".to_string(), "http://xmlns.com/foaf/0.1/".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  }

  #[test]
  fn parse_sparql_prefix_directive() {
    let input = "PREFIX foaf: <http://xmlns.com/foaf/0.1/> .".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::PrefixDirective("foaf:".to_string(), "http://xmlns.com/foaf/0.1/".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  }

  #[test]
  fn parse_comment() {
    let input = "# Hello World!\n# Foo".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::Comment("Hello World!".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::Comment("Foo".to_string()));
  }

  #[test]
  fn parse_literal() {
    let input = "\"a\"".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::Literal("a".to_string()));
  }

  #[test]
  fn parse_uri() {
    let input = "<example.org/a>".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::Uri("example.org/a".to_string()));
  }

  #[test]
  fn parse_literal_with_language_specification() {
    let input = "\"a\"@abc".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::LiteralWithLanguageSpecification("a".to_string(), "abc".to_string()));
  }

  #[test]
  fn parse_blank_node() {
    let input = "_:auto".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::BlankNode("auto".to_string()));
  }

  #[test]
  fn parse_qname() {
    let input = "abc:def:ghij".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::QName("abc:".to_string(), "def:ghij".to_string()));
  }

  #[test]
  fn parse_literal_with_data_type() {
    let input = "\"a\"^^<example.org/abc>".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::LiteralWithUrlDatatype("a".to_string(), "example.org/abc".to_string()));
  }

  #[test]
  fn parse_literal_with_qname_data_type() {
    let input = "\"a\"^^ex:abc:asdf".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::LiteralWithQNameDatatype("a".to_string(), "ex:".to_string(), "abc:asdf".to_string()));
  }

  #[test]
  fn parse_triple_delimiter() {
    let input = ".   \"a\"   .".as_bytes();

    let mut lexer = TurtleLexer::new(input);

    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
    assert_eq!(lexer.get_next_token().unwrap(), Token::Literal("a".to_string()));
    assert_eq!(lexer.get_next_token().unwrap(), Token::TripleDelimiter);
  }
}
<|endoftext|>


<commit_before>use std::io::{self, Read, Take};
use std::str;
use std::result;

use byteorder::{ReadBytesExt, LittleEndian};

use types::Result;
use utils::ReadExt;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct ChunkId([u8; 4]);

impl ChunkId {
    #[inline]
    pub fn as_str(&self) -> Option<&str> {
        str::from_utf8(&self.0).ok()
    }

    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
}

pub struct RiffReader<R: Read> {
    source: R
}

impl<R: Read> RiffReader<R> {
    pub fn new(source: R) -> RiffReader<R> {
        RiffReader {
            source: source
        }
    }

    pub fn root(&mut self) -> Result<RiffChunk> {
        let (id, len) = match try!(read_id_and_len(&mut self.source)) {
            Some(t) => t,
            None => return Err(unexpected_eof!())
        };

        if id.as_bytes() != b"RIFF" {
            return Err(invalid_format!("RIFF file header is invalid"));
        }

        Ok(RiffChunk {
            data: Counter {
                delegate: (&mut self.source as &mut Read).take(len as u64),
                counter: None
            },
            tainted: false,
            chunk_id: id,
            len: len
        })
    }
}

struct Counter<'a, R> {
    delegate: R,
    counter: Option<&'a mut u32>
}

impl<'a, R: Read> Read for Counter<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.delegate.read(buf).map(|n| {
            if let Some(ref mut counter) = self.counter {
                **counter += n as u32;
            }
            n
        })
    }
}

pub struct RiffChunk<'a> {
    chunk_id: ChunkId,
    len: u32,
    tainted: bool,
    data: Counter<'a, Take<&'a mut Read>>
}

impl<'a> RiffChunk<'a> {
    #[inline]
    pub fn chunk_id(&self) -> ChunkId { self.chunk_id }

    #[inline]
    pub fn len(&self) -> u32 { self.len }

    #[inline]
    pub fn contents(&mut self) -> &mut Read {
        self.tainted = true;
        &mut self.data
    }

    #[inline]
    pub fn can_have_subchunks(&self) -> bool {
        !self.tainted && match &self.chunk_id.0 {
            b"RIFF" | b"LIST" => true,
            _ => false
        }
    }

    #[inline]
    pub fn into_list(self) -> result::Result<Result<RiffListChunk<'a>>, RiffChunk<'a>> {
        if self.can_have_subchunks() {
            Ok(self.into_list_unchecked())
        } else {
            Err(self)
        }
    }

    fn into_list_unchecked(mut self) -> Result<RiffListChunk<'a>> {
        let mut chunk_type = [0u8; 4];

        if try!(self.data.read_exact(&mut chunk_type)) != 4 {
            return Err(unexpected_eof!());
        }

        Ok(RiffListChunk {
            chunk_id: self.chunk_id,
            len: self.len,
            chunk_type: ChunkId(chunk_type),
            data: self.data,
            cur_chunk_len: 0,
            cur_chunk_read: 0
        })
    }
}

pub struct RiffListChunk<'a> {
    chunk_id: ChunkId,
    len: u32,
    chunk_type: ChunkId,
    data: Counter<'a, Take<&'a mut Read>>,
    cur_chunk_len: u32,
    cur_chunk_read: u32
}

impl<'a> RiffListChunk<'a> {
    #[inline]
    pub fn chunk_id(&self) -> ChunkId { self.chunk_id }

    #[inline]
    pub fn len(&self) -> u32 { self.len }

    #[inline]
    pub fn chunk_type(&self) -> ChunkId { self.chunk_type }

    #[inline]
    pub fn next(&mut self) -> Option<Result<RiffChunk>> {
        if self.cur_chunk_len < self.cur_chunk_read {
            let to_skip = (self.cur_chunk_len - self.cur_chunk_read) as u64;
            match self.data.skip_exact_0(to_skip) {
                Ok(n) if n == to_skip => {}
                Ok(_) => return Some(Err(unexpected_eof!())),
                Err(e) => return Some(Err(e.into()))
            }
        }

        let (id, len) = match read_id_and_len(&mut self.data) {
            Ok(Some(t)) => t,
            Ok(None) => return None,
            Err(e) => return Some(Err(e.into()))
        };

        self.cur_chunk_read = 0;
        self.cur_chunk_len = len;

        Some(Ok(RiffChunk {
            chunk_id: id,
            len: len,
            tainted: false,
            data: Counter {
                delegate: (&mut self.data as &mut Read).take(len as u64),
                counter: Some(&mut self.cur_chunk_read)
            }
        }))
    }
}

fn read_id_and_len<R: Read>(source: &mut R) -> Result<Option<(ChunkId, u32)>> {
    let mut id = [0u8; 4];

    match try!(source.read_exact(&mut id)) {
        0 => return Ok(None),
        4 => {}
        _ => return Err(unexpected_eof!())
    }

    let len = try!(source.read_u32::<LittleEndian>());

    Ok(Some((ChunkId(id), len)))
}

#[cfg(test)]
mod tests {
    use std::io::Write;

    use byteorder::{WriteBytesExt, LittleEndian};

    use utils::ReadExt;

    use super::{RiffReader, RiffListChunk, ChunkId};

    macro_rules! build {
        ($($arg:expr),+) => {{
            let mut data = Vec::new();
            $(data.write($arg).unwrap();)+
            data
        }}
    }

    fn n(n: u32) -> [u8; 4] {
        let mut r = [0u8; 4];
        (&mut r as &mut [u8]).write_u32::<LittleEndian>(n).unwrap();
        r
    }

    fn check_next_chunk<'a>(cl: &mut RiffListChunk<'a>, id: ChunkId, len: u32, data: &[u8]) {
        let chunk = cl.next();
        let mut chunk = chunk.unwrap().unwrap();

        assert_eq!(chunk.chunk_id(), id);
        assert_eq!(chunk.len(), len);
        let contents = chunk.contents().read_to_vec().unwrap();
        assert_eq!(&*contents, data);
        assert!(!chunk.can_have_subchunks());
    }

    #[test]
    fn test_invalid_header() {
        let mut data = b"XXXX\x04abcd" as &[u8];

        let mut r = RiffReader::new(&mut data);

        let root = r.root();
        assert!(root.is_err());
    }

    #[test]
    fn test_flat_chunks() {
        let data = build! {
            b"RIFF", &n(37), b"abcd",
            b"A   ", &n(4), b"1234",
            b"B   ", &n(5), b"56789"
        };
        let mut data: &[u8] = &data;

        let mut r = RiffReader::new(&mut data);

        let mut root = r.root().unwrap();

        assert_eq!(root.chunk_id(), ChunkId(*b"RIFF"));
        assert_eq!(root.len(), 37);
        assert!(root.can_have_subchunks());

        let root = root.into_list();
        assert!(root.is_ok());
        let mut root = root.ok().unwrap().unwrap();

        assert_eq!(root.chunk_type(), ChunkId(*b"abcd"));

        check_next_chunk(&mut root, ChunkId(*b"A   "), 4, b"1234");
        check_next_chunk(&mut root, ChunkId(*b"B   "), 5, b"56789");

        assert!(root.next().is_none());
    }

    #[test]
    fn test_nested_chunks() {
        let data = build! {
            b"RIFF", &n(77), b"abcd",
            b"A   ", &n(1), b"z",
            b"LIST", &n(56), b"wxyz",
                b" B  ", &n(3), b"123",
                b"LIST", &n(22), b"hi  ",
                    b"  C ", &n(0),
                    b"   D", &n(2), b"op",
                b"E   ", &n(3), b"fuz"
        };
        let mut data: &[u8] = &data;

        let mut r = RiffReader::new(&mut data);

        let mut root = r.root().unwrap();

        assert_eq!(root.chunk_id(), ChunkId(*b"RIFF"));
        assert_eq!(root.len(), 77);
        assert!(root.can_have_subchunks());

        let root = root.into_list();
        assert!(root.is_ok());
        let mut root = root.ok().unwrap().unwrap();

        assert_eq!(root.chunk_type(), ChunkId(*b"abcd"));

        check_next_chunk(&mut root, ChunkId(*b"A   "), 1, b"z");

        {
            let chunk = root.next().unwrap().unwrap();
            assert_eq!(chunk.chunk_id(), ChunkId(*b"LIST"));
            assert_eq!(chunk.len(), 56);
            assert!(chunk.can_have_subchunks());

            let chunk = chunk.into_list();
            assert!(chunk.is_ok());
            let mut chunk = chunk.ok().unwrap().unwrap();

            check_next_chunk(&mut chunk, ChunkId(*b" B  "), 3, b"123");

            {
                let sublist = chunk.next().unwrap().unwrap();
                assert_eq!(sublist.chunk_id(), ChunkId(*b"LIST"));
                assert_eq!(sublist.len(), 22);
                assert!(sublist.can_have_subchunks());

                let sublist = sublist.into_list();
                assert!(sublist.is_ok());
                let mut sublist = sublist.ok().unwrap().unwrap();

                check_next_chunk(&mut sublist, ChunkId(*b"  C "), 0, b"");
                check_next_chunk(&mut sublist, ChunkId(*b"   D"), 2, b"op");
            }

            check_next_chunk(&mut chunk, ChunkId(*b"E   "), 3, b"fuz");
        }

    }
}
<commit_msg>Added more tests<commit_after>use std::io::{self, Read, Take};
use std::str;
use std::result;

use byteorder::{ReadBytesExt, LittleEndian};

use types::Result;
use utils::ReadExt;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct ChunkId([u8; 4]);

impl ChunkId {
    #[inline]
    pub fn as_str(&self) -> Option<&str> {
        str::from_utf8(&self.0).ok()
    }

    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
}

pub struct RiffReader<R: Read> {
    source: R
}

impl<R: Read> RiffReader<R> {
    pub fn new(source: R) -> RiffReader<R> {
        RiffReader {
            source: source
        }
    }

    pub fn root(&mut self) -> Result<RiffChunk> {
        let (id, len) = match try!(read_id_and_len(&mut self.source)) {
            Some(t) => t,
            None => return Err(unexpected_eof!())
        };

        if id.as_bytes() != b"RIFF" {
            return Err(invalid_format!("RIFF file header is invalid"));
        }

        Ok(RiffChunk {
            data: Counter {
                delegate: (&mut self.source as &mut Read).take(len as u64),
                counter: None
            },
            tainted: false,
            chunk_id: id,
            len: len
        })
    }
}

struct Counter<'a, R> {
    delegate: R,
    counter: Option<&'a mut u32>
}

impl<'a, R: Read> Read for Counter<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.delegate.read(buf).map(|n| {
            if let Some(ref mut counter) = self.counter {
                **counter += n as u32;
            }
            n
        })
    }
}

pub struct RiffChunk<'a> {
    chunk_id: ChunkId,
    len: u32,
    tainted: bool,
    data: Counter<'a, Take<&'a mut Read>>
}

impl<'a> RiffChunk<'a> {
    #[inline]
    pub fn chunk_id(&self) -> ChunkId { self.chunk_id }

    #[inline]
    pub fn len(&self) -> u32 { self.len }

    #[inline]
    pub fn contents(&mut self) -> &mut Read {
        self.tainted = true;
        &mut self.data
    }

    #[inline]
    pub fn can_have_subchunks(&self) -> bool {
        !self.tainted && match &self.chunk_id.0 {
            b"RIFF" | b"LIST" => true,
            _ => false
        }
    }

    #[inline]
    pub fn into_list(self) -> result::Result<Result<RiffListChunk<'a>>, RiffChunk<'a>> {
        if self.can_have_subchunks() {
            Ok(self.into_list_unchecked())
        } else {
            Err(self)
        }
    }

    fn into_list_unchecked(mut self) -> Result<RiffListChunk<'a>> {
        let mut chunk_type = [0u8; 4];

        if try!(self.data.read_exact(&mut chunk_type)) != 4 {
            return Err(unexpected_eof!());
        }

        Ok(RiffListChunk {
            chunk_id: self.chunk_id,
            len: self.len,
            chunk_type: ChunkId(chunk_type),
            data: self.data,
            cur_chunk_len: 0,
            cur_chunk_read: 0
        })
    }
}

pub struct RiffListChunk<'a> {
    chunk_id: ChunkId,
    len: u32,
    chunk_type: ChunkId,
    data: Counter<'a, Take<&'a mut Read>>,
    cur_chunk_len: u32,
    cur_chunk_read: u32
}

impl<'a> RiffListChunk<'a> {
    #[inline]
    pub fn chunk_id(&self) -> ChunkId { self.chunk_id }

    #[inline]
    pub fn len(&self) -> u32 { self.len }

    #[inline]
    pub fn chunk_type(&self) -> ChunkId { self.chunk_type }

    #[inline]
    pub fn next(&mut self) -> Option<Result<RiffChunk>> {
        if self.cur_chunk_read < self.cur_chunk_len {
            let to_skip = (self.cur_chunk_len - self.cur_chunk_read) as u64;
            match self.data.skip_exact_0(to_skip) {
                Ok(n) if n == to_skip => {}
                Ok(_) => return Some(Err(unexpected_eof!())),
                Err(e) => return Some(Err(e.into()))
            }
        }

        let (id, len) = match read_id_and_len(&mut self.data) {
            Ok(Some(t)) => t,
            Ok(None) => return None,
            Err(e) => return Some(Err(e.into()))
        };

        self.cur_chunk_read = 0;
        self.cur_chunk_len = len;

        Some(Ok(RiffChunk {
            chunk_id: id,
            len: len,
            tainted: false,
            data: Counter {
                delegate: (&mut self.data as &mut Read).take(len as u64),
                counter: Some(&mut self.cur_chunk_read)
            }
        }))
    }
}

fn read_id_and_len<R: Read>(source: &mut R) -> Result<Option<(ChunkId, u32)>> {
    let mut id = [0u8; 4];

    match try!(source.read_exact(&mut id)) {
        0 => return Ok(None),
        4 => {}
        _ => return Err(unexpected_eof!())
    }

    let len = try!(source.read_u32::<LittleEndian>());

    Ok(Some((ChunkId(id), len)))
}

#[cfg(test)]
mod tests {
    use std::io::{Read, Write};

    use byteorder::{WriteBytesExt, LittleEndian};

    use utils::ReadExt;

    use super::{RiffReader, RiffListChunk, ChunkId};

    macro_rules! build {
        ($($arg:expr),+) => {{
            let mut data = Vec::new();
            $(data.write($arg).unwrap();)+
            data
        }}
    }

    fn n(n: u32) -> [u8; 4] {
        let mut r = [0u8; 4];
        (&mut r as &mut [u8]).write_u32::<LittleEndian>(n).unwrap();
        r
    }

    fn check_next_chunk<'a>(cl: &mut RiffListChunk<'a>, id: ChunkId, len: u32, data: &[u8]) {
        let chunk = cl.next();
        let mut chunk = chunk.unwrap().unwrap();

        assert_eq!(chunk.chunk_id(), id);
        assert_eq!(chunk.len(), len);
        let contents = chunk.contents().read_to_vec().unwrap();
        assert_eq!(&*contents, data);
        assert!(!chunk.can_have_subchunks());
    }

    #[test]
    fn test_invalid_header() {
        let mut data = b"XXXX\x04abcd" as &[u8];

        let mut r = RiffReader::new(&mut data);

        let root = r.root();
        assert!(root.is_err());
    }

    #[test]
    fn test_flat_chunks() {
        let data = build! {
            b"RIFF", &n(37), b"abcd",
            b"A   ", &n(4), b"1234",
            b"B   ", &n(5), b"56789"
        };
        let mut data: &[u8] = &data;

        let mut r = RiffReader::new(&mut data);

        let mut root = r.root().unwrap();

        assert_eq!(root.chunk_id(), ChunkId(*b"RIFF"));
        assert_eq!(root.len(), 37);
        assert!(root.can_have_subchunks());

        let root = root.into_list();
        assert!(root.is_ok());
        let mut root = root.ok().unwrap().unwrap();

        assert_eq!(root.chunk_type(), ChunkId(*b"abcd"));

        check_next_chunk(&mut root, ChunkId(*b"A   "), 4, b"1234");
        check_next_chunk(&mut root, ChunkId(*b"B   "), 5, b"56789");

        assert!(root.next().is_none());
    }

    #[test]
    fn test_nested_chunks() {
        let data = build! {
            b"RIFF", &n(77), b"abcd",
            b"A   ", &n(1), b"z",
            b"LIST", &n(56), b"wxyz",
                b" B  ", &n(3), b"123",
                b"LIST", &n(22), b"hi  ",
                    b"  C ", &n(0),
                    b"   D", &n(2), b"op",
                b"E   ", &n(3), b"fuz"
        };
        let mut data: &[u8] = &data;

        let mut r = RiffReader::new(&mut data);

        let mut root = r.root().unwrap();

        assert_eq!(root.chunk_id(), ChunkId(*b"RIFF"));
        assert_eq!(root.len(), 77);
        assert!(root.can_have_subchunks());

        let root = root.into_list();
        assert!(root.is_ok());
        let mut root = root.ok().unwrap().unwrap();

        assert_eq!(root.chunk_type(), ChunkId(*b"abcd"));

        check_next_chunk(&mut root, ChunkId(*b"A   "), 1, b"z");

        {
            let chunk = root.next().unwrap().unwrap();
            assert_eq!(chunk.chunk_id(), ChunkId(*b"LIST"));
            assert_eq!(chunk.len(), 56);
            assert!(chunk.can_have_subchunks());

            let chunk = chunk.into_list();
            assert!(chunk.is_ok());
            let mut chunk = chunk.ok().unwrap().unwrap();

            check_next_chunk(&mut chunk, ChunkId(*b" B  "), 3, b"123");

            {
                let sublist = chunk.next().unwrap().unwrap();
                assert_eq!(sublist.chunk_id(), ChunkId(*b"LIST"));
                assert_eq!(sublist.len(), 22);
                assert!(sublist.can_have_subchunks());

                let sublist = sublist.into_list();
                assert!(sublist.is_ok());
                let mut sublist = sublist.ok().unwrap().unwrap();

                check_next_chunk(&mut sublist, ChunkId(*b"  C "), 0, b"");
                check_next_chunk(&mut sublist, ChunkId(*b"   D"), 2, b"op");
            }

            check_next_chunk(&mut chunk, ChunkId(*b"E   "), 3, b"fuz");

            assert!(chunk.next().is_none());
        }

        assert!(root.next().is_none());
    }

    #[test]
    fn test_skip_chunk_data() {
        let data = build! {
            b"RIFF", &n(77), b"abcd",
            b"A   ", &n(10), b"abcdefghij",
            b" B  ", &n(12), b"123456789012",
            b"  C ", &n(8),  b"ABCDEFGH"
        };
        let mut data: &[u8] = &data;

        let mut r = RiffReader::new(&mut data);

        let root = r.root().unwrap();
        let mut root = root.into_list().ok().unwrap().unwrap();

        {
            let mut chunk = root.next().unwrap().unwrap();
            assert_eq!(chunk.chunk_id(), ChunkId(*b"A   "));
            assert_eq!(chunk.len(), 10);
            assert_eq!(
                (&mut chunk.contents() as &mut Read).take(5).read_to_vec().unwrap(),
                b"abcde".to_owned()
            );
        }

        {
            let chunk = root.next().unwrap().unwrap();
            assert_eq!(chunk.chunk_id(), ChunkId(*b" B  "));
            assert_eq!(chunk.len(), 12);
        }

        {
            let mut chunk = root.next().unwrap().unwrap();
            assert_eq!(chunk.chunk_id(), ChunkId(*b"  C "));
            assert_eq!(chunk.len(), 8);
            assert_eq!(chunk.contents().read_to_vec().unwrap(), b"ABCDEFGH".to_owned());
        }

        assert!(root.next().is_none());
    }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::cmp::min;
use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64 {
    // Stein's binary GCD algorithm
    // Base cases: gcd(n, 0) = gcd(0, n) = n
    if u == 0 {
        return v;
    } else if v == 0 {
        return u;
    }

    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
    // 2ᵏ is the greatest power of two that divides both u and v
    let k = {
        let i = u.trailing_zeros();
        let j = v.trailing_zeros();
        u >>= i;
        v >>= j;
        min(i, j)
    };

    loop {
        // Loop invariant: u and v are odd
        debug_assert!(u % 2 == 1, "u = {} is even", u);
        debug_assert!(v % 2 == 1, "v = {} is even", v);

        // gcd(u, v) = gcd(|u - v|, min(u, v))
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;

        if v == 0 {
            // Reached the base case; gcd is 2ᵏ u
            return u << k;
        }

        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
        v >>= v.trailing_zeros();
    }
}

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

    quickcheck! {
        fn euclidean(a: u64, b: u64) -> bool {
            // Test against the Euclidean algorithm
            let g = {
                let (mut a, mut b) = (a, b);
                while b > 0 {
                    a %= b;
                    swap(&mut a, &mut b);
                }
                a
            };
            gcd(a, b) == g
        }

        fn one(a: u64) -> bool {
            gcd(1, a) == 1
        }

        fn divisor(a: u64, b: u64) -> bool {
            // Test that gcd(a, b) divides a and b
            let g = gcd(a, b);
            if g == 0 { return a == 0 && b == 0; }
            a % g == 0 && b % g == 0
        }

        fn commutative(a: u64, b: u64) -> bool {
            gcd(a, b) == gcd(b, a)
        }

        fn associative(a: u64, b: u64, c: u64) -> bool {
            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
        }

        fn scalar_mult(a: u64, b: u64, k: u64) -> bool {
            gcd(k * a, k * b) == k * gcd(a, b)
        }

        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
        }

        fn linearity(a: u64, b: u64, k: u64) -> bool {
            gcd(a + k * b, b) == gcd(a, b)
        }
    }
}
<commit_msg>factor::numeric::gcd: Exclude the 0 case from test `divisor`<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::cmp::min;
use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64 {
    // Stein's binary GCD algorithm
    // Base cases: gcd(n, 0) = gcd(0, n) = n
    if u == 0 {
        return v;
    } else if v == 0 {
        return u;
    }

    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
    // 2ᵏ is the greatest power of two that divides both u and v
    let k = {
        let i = u.trailing_zeros();
        let j = v.trailing_zeros();
        u >>= i;
        v >>= j;
        min(i, j)
    };

    loop {
        // Loop invariant: u and v are odd
        debug_assert!(u % 2 == 1, "u = {} is even", u);
        debug_assert!(v % 2 == 1, "v = {} is even", v);

        // gcd(u, v) = gcd(|u - v|, min(u, v))
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;

        if v == 0 {
            // Reached the base case; gcd is 2ᵏ u
            return u << k;
        }

        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
        v >>= v.trailing_zeros();
    }
}

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

    quickcheck! {
        fn euclidean(a: u64, b: u64) -> bool {
            // Test against the Euclidean algorithm
            let g = {
                let (mut a, mut b) = (a, b);
                while b > 0 {
                    a %= b;
                    swap(&mut a, &mut b);
                }
                a
            };
            gcd(a, b) == g
        }

        fn one(a: u64) -> bool {
            gcd(1, a) == 1
        }

        fn divisor(a: u64, b: u64) -> bool {
            // Test that gcd(a, b) divides a and b
            let g = gcd(a, b);
            (a == 0 && b == 0) || (a % g == 0 && b % g == 0)
        }

        fn commutative(a: u64, b: u64) -> bool {
            gcd(a, b) == gcd(b, a)
        }

        fn associative(a: u64, b: u64, c: u64) -> bool {
            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
        }

        fn scalar_mult(a: u64, b: u64, k: u64) -> bool {
            gcd(k * a, k * b) == k * gcd(a, b)
        }

        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
        }

        fn linearity(a: u64, b: u64, k: u64) -> bool {
            gcd(a + k * b, b) == gcd(a, b)
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::error;
use std::fmt;
use std::mem;

use {Value, Table};

#[cfg(feature = "rustc-serialize")] mod rustc_serialize;
#[cfg(feature = "serde")] mod serde;

/// A structure to transform Rust values into TOML values.
///
/// This encoder implements the serialization `Encoder` interface, allowing
/// `Encodable` rust types to be fed into the encoder. The output of this
/// encoder is a TOML `Table` structure. The resulting TOML can be stringified
/// if necessary.
///
/// # Example
///
/// ```
/// extern crate rustc_serialize;
/// extern crate toml;
///
/// # fn main() {
/// use toml::{Encoder, Value};
/// use rustc_serialize::Encodable;
///
/// #[derive(RustcEncodable)]
/// struct MyStruct { foo: isize, bar: String }
/// let my_struct = MyStruct { foo: 4, bar: "hello!".to_string() };
///
/// let mut e = Encoder::new();
/// my_struct.encode(&mut e).unwrap();
///
/// assert_eq!(e.toml.get(&"foo".to_string()), Some(&Value::Integer(4)))
/// # }
/// ```
#[derive(Default, Debug)]
pub struct Encoder {
    /// Output TOML that is emitted. The current version of this encoder forces
    /// the top-level representation of a structure to be a table.
    ///
    /// This field can be used to extract the return value after feeding a value
    /// into this `Encoder`.
    pub toml: Table,
    state: State,
}

/// Enumeration of errors which can occur while encoding a rust value into a
/// TOML value.
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub enum Error {
    /// Indication that a key was needed when a value was emitted, but no key
    /// was previously emitted.
    NeedsKey,
    /// Indication that a key was emitted, but no value was emitted.
    NoValue,
    /// Indicates that a map key was attempted to be emitted at an invalid
    /// location.
    InvalidMapKeyLocation,
    /// Indicates that a type other than a string was attempted to be used as a
    /// map key type.
    InvalidMapKeyType,
    /// A custom error type was generated
    Custom(String),
}

/// Internal state of the encoder when encoding transitions
#[derive(Debug)]
pub struct EncoderState {
    inner: State,
}

#[derive(PartialEq, Debug)]
enum State {
    Start,
    NextKey(String),
    NextArray(Vec<Value>),
    NextMapKey,
}

impl Default for State {
    fn default() -> State { State::Start }
}

impl Encoder {
    /// Constructs a new encoder which will emit to the given output stream.
    pub fn new() -> Encoder {
        Encoder { state: State::Start, toml: BTreeMap::new() }
    }

    fn emit_value(&mut self, v: Value) -> Result<(), Error> {
        match mem::replace(&mut self.state, State::Start) {
            State::NextKey(key) => { self.toml.insert(key, v); Ok(()) }
            State::NextArray(mut vec) => {
                // TODO: validate types
                vec.push(v);
                self.state = State::NextArray(vec);
                Ok(())
            }
            State::NextMapKey => {
                match v {
                    Value::String(s) => { self.state = State::NextKey(s); Ok(()) }
                    _ => Err(Error::InvalidMapKeyType)
                }
            }
            _ => Err(Error::NeedsKey)
        }
    }

    fn emit_none(&mut self) -> Result<(), Error> {
        match mem::replace(&mut self.state, State::Start) {
            State::Start => unreachable!(),
            State::NextKey(_) => Ok(()),
            State::NextArray(..) => panic!("how to encode None in an array?"),
            State::NextMapKey => Err(Error::InvalidMapKeyLocation),
        }
    }

    fn seq_begin(&mut self) -> Result<State, Error> {
        Ok(mem::replace(&mut self.state, State::NextArray(Vec::new())))
    }

    fn seq_end(&mut self, old: State) -> Result<(), Error> {
        match mem::replace(&mut self.state, old) {
            State::NextArray(v) => self.emit_value(Value::Array(v)),
            _ => unreachable!(),
        }
    }

    fn table_key<F>(&mut self, f: F) -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        match mem::replace(&mut self.state, State::NextMapKey) {
            State::Start => {}
            _ => return Err(Error::InvalidMapKeyLocation),
        }
        try!(f(self));
        match self.state {
            State::NextKey(_) => Ok(()),
            _ => Err(Error::InvalidMapKeyLocation),
        }
    }
}

/// Encodes an encodable value into a TOML value.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(feature = "rustc-serialize")]
pub fn encode<T: ::rustc_serialize::Encodable>(t: &T) -> Value {
    let mut e = Encoder::new();
    t.encode(&mut e).unwrap();
    Value::Table(e.toml)
}

/// Encodes an encodable value into a TOML value.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode<T: ::serde::Serialize>(t: &T) -> Value {
    let mut e = Encoder::new();
    t.serialize(&mut e).unwrap();
    Value::Table(e.toml)
}

/// Encodes an encodable value into a TOML string.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(feature = "rustc-serialize")]
pub fn encode_str<T: ::rustc_serialize::Encodable>(t: &T) -> String {
    encode(t).to_string()
}

/// Encodes an encodable value into a TOML string.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode_str<T: ::serde::Serialize>(t: &T) -> String {
    encode(t).to_string()
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::NeedsKey => write!(f, "need a key to encode"),
            Error::NoValue => write!(f, "no value to emit for a previous key"),
            Error::InvalidMapKeyLocation => write!(f, "a map cannot be emitted \
                                                       at this location"),
            Error::InvalidMapKeyType => write!(f, "only strings can be used as \
                                                   key types"),
            Error::Custom(ref s) => write!(f, "custom error: {}", s),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str { "TOML encoding error" }
}
<commit_msg>Return encoding errors for NaN and infinite<commit_after>use std::collections::BTreeMap;
use std::error;
use std::fmt;
use std::mem;

use {Value, Table};

#[cfg(feature = "rustc-serialize")] mod rustc_serialize;
#[cfg(feature = "serde")] mod serde;

/// A structure to transform Rust values into TOML values.
///
/// This encoder implements the serialization `Encoder` interface, allowing
/// `Encodable` rust types to be fed into the encoder. The output of this
/// encoder is a TOML `Table` structure. The resulting TOML can be stringified
/// if necessary.
///
/// # Example
///
/// ```
/// extern crate rustc_serialize;
/// extern crate toml;
///
/// # fn main() {
/// use toml::{Encoder, Value};
/// use rustc_serialize::Encodable;
///
/// #[derive(RustcEncodable)]
/// struct MyStruct { foo: isize, bar: String }
/// let my_struct = MyStruct { foo: 4, bar: "hello!".to_string() };
///
/// let mut e = Encoder::new();
/// my_struct.encode(&mut e).unwrap();
///
/// assert_eq!(e.toml.get(&"foo".to_string()), Some(&Value::Integer(4)))
/// # }
/// ```
#[derive(Default, Debug)]
pub struct Encoder {
    /// Output TOML that is emitted. The current version of this encoder forces
    /// the top-level representation of a structure to be a table.
    ///
    /// This field can be used to extract the return value after feeding a value
    /// into this `Encoder`.
    pub toml: Table,
    state: State,
}

/// Enumeration of errors which can occur while encoding a rust value into a
/// TOML value.
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub enum Error {
    /// Indication that a key was needed when a value was emitted, but no key
    /// was previously emitted.
    NeedsKey,
    /// Indication that a key was emitted, but no value was emitted.
    NoValue,
    /// Indicates that a map key was attempted to be emitted at an invalid
    /// location.
    InvalidMapKeyLocation,
    /// Indicates that a type other than a string was attempted to be used as a
    /// map key type.
    InvalidMapKeyType,
    /// An error returned whenever a `NaN` value for a float is attempted to be
    /// encoded
    NanEncoded,
    /// An error returned whenever an infinity value for a float is attempted to
    /// be encoded
    InfinityEncoded,
    /// A custom error type was generated
    Custom(String),
}

/// Internal state of the encoder when encoding transitions
#[derive(Debug)]
pub struct EncoderState {
    inner: State,
}

#[derive(PartialEq, Debug)]
enum State {
    Start,
    NextKey(String),
    NextArray(Vec<Value>),
    NextMapKey,
}

impl Default for State {
    fn default() -> State { State::Start }
}

impl Encoder {
    /// Constructs a new encoder which will emit to the given output stream.
    pub fn new() -> Encoder {
        Encoder { state: State::Start, toml: BTreeMap::new() }
    }

    fn emit_value(&mut self, v: Value) -> Result<(), Error> {
        match v {
            Value::Float(f) => {
                if f.is_nan() {
                    return Err(Error::NanEncoded)
                }
                if f.is_infinite() {
                    return Err(Error::InfinityEncoded)
                }
            }
            _ => {}
        }
        match mem::replace(&mut self.state, State::Start) {
            State::NextKey(key) => { self.toml.insert(key, v); Ok(()) }
            State::NextArray(mut vec) => {
                // TODO: validate types
                vec.push(v);
                self.state = State::NextArray(vec);
                Ok(())
            }
            State::NextMapKey => {
                match v {
                    Value::String(s) => { self.state = State::NextKey(s); Ok(()) }
                    _ => Err(Error::InvalidMapKeyType)
                }
            }
            _ => Err(Error::NeedsKey)
        }
    }

    fn emit_none(&mut self) -> Result<(), Error> {
        match mem::replace(&mut self.state, State::Start) {
            State::Start => unreachable!(),
            State::NextKey(_) => Ok(()),
            State::NextArray(..) => panic!("how to encode None in an array?"),
            State::NextMapKey => Err(Error::InvalidMapKeyLocation),
        }
    }

    fn seq_begin(&mut self) -> Result<State, Error> {
        Ok(mem::replace(&mut self.state, State::NextArray(Vec::new())))
    }

    fn seq_end(&mut self, old: State) -> Result<(), Error> {
        match mem::replace(&mut self.state, old) {
            State::NextArray(v) => self.emit_value(Value::Array(v)),
            _ => unreachable!(),
        }
    }

    fn table_key<F>(&mut self, f: F) -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        match mem::replace(&mut self.state, State::NextMapKey) {
            State::Start => {}
            _ => return Err(Error::InvalidMapKeyLocation),
        }
        try!(f(self));
        match self.state {
            State::NextKey(_) => Ok(()),
            _ => Err(Error::InvalidMapKeyLocation),
        }
    }
}

/// Encodes an encodable value into a TOML value.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(feature = "rustc-serialize")]
pub fn encode<T: ::rustc_serialize::Encodable>(t: &T) -> Value {
    let mut e = Encoder::new();
    t.encode(&mut e).unwrap();
    Value::Table(e.toml)
}

/// Encodes an encodable value into a TOML value.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode<T: ::serde::Serialize>(t: &T) -> Value {
    let mut e = Encoder::new();
    t.serialize(&mut e).unwrap();
    Value::Table(e.toml)
}

/// Encodes an encodable value into a TOML string.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(feature = "rustc-serialize")]
pub fn encode_str<T: ::rustc_serialize::Encodable>(t: &T) -> String {
    encode(t).to_string()
}

/// Encodes an encodable value into a TOML string.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode_str<T: ::serde::Serialize>(t: &T) -> String {
    encode(t).to_string()
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::NeedsKey => write!(f, "need a key to encode"),
            Error::NoValue => write!(f, "no value to emit for a previous key"),
            Error::InvalidMapKeyLocation => write!(f, "a map cannot be emitted \
                                                       at this location"),
            Error::InvalidMapKeyType => write!(f, "only strings can be used as \
                                                   key types"),
            Error::NanEncoded => write!(f, "cannot encode NaN"),
            Error::InfinityEncoded => write!(f, "cannot encode infinity"),
            Error::Custom(ref s) => write!(f, "custom error: {}", s),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str { "TOML encoding error" }
}
<|endoftext|>