<commit_before>// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use cocoa::base::id;
use cocoa::foundation::{NSUInteger};
use objc::runtime::{Object, BOOL, YES, NO};
use objc_foundation::{NSString, INSString};

use super::*;

use libc;

use block::{Block, ConcreteBlock};

use std::ffi::CStr;
use std::path::Path;
use std::ptr;

use foreign_types::ForeignType;

#[allow(non_camel_case_types)]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLFeatureSet {
    iOS_GPUFamily1_v1 = 0,
    iOS_GPUFamily2_v1 = 1,
    iOS_GPUFamily1_v2 = 2,
    iOS_GPUFamily2_v2 = 3,
    iOS_GPUFamily3_v1 = 4,
    iOS_GPUFamily1_v3 = 5,
    iOS_GPUFamily2_v3 = 6,
    iOS_GPUFamily3_v2 = 7,
    iOS_GPUFamily1_v4 = 8,
    iOS_GPUFamily2_v4 = 9,
    iOS_GPUFamily3_v3 = 10,
    tvOS_GPUFamily1_v1 = 30000,
    tvOS_GPUFamily1_v2 = 30001,
    tvOS_GPUFamily1_v3 = 30002,
    macOS_GPUFamily1_v1 = 10000,
    macOS_GPUFamily1_v2 = 10001,
    macOS_ReadWriteTextureTier2 = 10002,
    macOS_GPUFamily1_v3 = 10003,
}

#[allow(non_camel_case_types)]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLArgumentBuffersTier {
    tier1 = 0,
    tier2 = 1,
}

bitflags! {
    struct MTLPipelineOption: NSUInteger {
        const ArgumentInfo   = 1 << 0;
        const BufferTypeInfo = 1 << 1;
    }
}

#[link(name = "Metal", kind = "framework")]
extern {
    fn MTLCreateSystemDefaultDevice() -> *mut MTLDevice;
}

#[allow(non_camel_case_types)]
type dispatch_data_t = id;
#[allow(non_camel_case_types)]
type dispatch_queue_t = id;
#[allow(non_camel_case_types)]
type dispatch_block_t = *const Block<(), ()>;

#[cfg_attr(any(target_os = "macos", target_os = "ios"),
           link(name = "System", kind = "dylib"))]
#[cfg_attr(not(any(target_os = "macos", target_os = "ios")),
           link(name = "dispatch", kind = "dylib"))]
#[allow(improper_ctypes)]
extern {
    static _dispatch_main_q: dispatch_queue_t;

    fn dispatch_data_create(
        buffer: *const libc::c_void,
        size: libc::size_t,
        queue: dispatch_queue_t,
        destructor: dispatch_block_t
    ) -> dispatch_data_t;
}

/*type MTLNewLibraryCompletionHandler = extern fn(library: id, error: id);
type MTLNewRenderPipelineStateCompletionHandler = extern fn(renderPipelineState: id, error: id);
type MTLNewRenderPipelineStateWithReflectionCompletionHandler = extern fn(renderPipelineState: id, reflection: id, error: id);
type MTLNewComputePipelineStateCompletionHandler = extern fn(computePipelineState: id, error: id);
type MTLNewComputePipelineStateWithReflectionCompletionHandler = extern fn(computePipelineState: id, reflection: id, error: id);*/

pub enum MTLDevice {}

foreign_obj_type! {
    type CType = MTLDevice;
    pub struct Device;
    pub struct DeviceRef;
}

impl Device {
    pub fn system_default() -> Device {
        unsafe { Device(MTLCreateSystemDefaultDevice()) }
    }
}

impl DeviceRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, name];
            name.as_str()
        }
    }

    pub fn vendor(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, vendorName];
            name.as_str()
        }
    }

    pub fn family_name(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, familyName];
            name.as_str()
        }
    }

    pub fn registry_id(&self) -> u64 {
        unsafe {
            msg_send![self, registryID]
        }
    }

    pub fn max_threads_per_threadgroup(&self) -> MTLSize {
        unsafe {
            msg_send![self, maxThreadsPerThreadgroup]
        }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe {
            match msg_send![self, isLowPower] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn is_headless(&self) -> bool {
        unsafe {
            match msg_send![self, isHeadless] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn supports_feature_set(&self, feature: MTLFeatureSet) -> bool {
        unsafe {
            match msg_send![self, supportsFeatureSet:feature] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn supports_sample_count(&self, count: NSUInteger) -> bool {
        unsafe {
            match msg_send![self, supportsTextureSampleCount:count] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn d24_s8_supported(&self) -> bool {
        unsafe {
            match msg_send![self, isDepth24Stencil8PixelFormatSupported] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn new_command_queue(&self) -> CommandQueue {
        unsafe {
            msg_send![self, newCommandQueue]
        }
    }

    pub fn new_command_queue_with_max_command_buffer_count(&self, count: NSUInteger) -> CommandQueue {
        unsafe {
            msg_send![self, newCommandQueueWithMaxCommandBufferCount:count]
        }
    }

    pub fn new_default_library(&self) -> Library {
        unsafe {
            msg_send![self, newDefaultLibrary]
        }
    }

    pub fn new_library_with_source(&self, src: &str, options: &CompileOptionsRef) -> Result<Library, String> {
        use cocoa::foundation::NSString as cocoa_NSString;
        use cocoa::base::nil as cocoa_nil;

        unsafe {
            let source = cocoa_NSString::alloc(cocoa_nil).init_str(src);
            let mut err: *mut Object = ptr::null_mut();
            let library: *mut MTLLibrary = msg_send![self, newLibraryWithSource:source
                                                                        options:options
                                                                          error:&mut err];
            if !err.is_null() {
                let desc: *mut Object = msg_send![err, localizedDescription];
                let compile_error: *const libc::c_char = msg_send![desc, UTF8String];
                let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned();
                msg_send![err, release];
                if library.is_null() {
                    return Err(message);
                } else {
                    warn!("Shader warnings: {}", message);
                }
            }

            assert!(!library.is_null());
            Ok(Library::from_ptr(library))
        }
    }

    pub fn new_library_with_file<P: AsRef<Path>>(&self, file: P) -> Result<Library, String> {
        use cocoa::foundation::NSString as cocoa_NSString;
        use cocoa::base::nil as cocoa_nil;

        unsafe {
            let filename = cocoa_NSString::alloc(cocoa_nil)
                .init_str(file.as_ref().to_string_lossy().as_ref());

            let library: *mut MTLLibrary = try_objc!{ err =>
                msg_send![self, newLibraryWithFile:filename
                                             error:&mut err]
            };

            Ok(Library::from_ptr(library))
        }
    }

    pub fn new_library_with_data(&self, library_data: &[u8]) -> Result<Library, String> {
        unsafe {
            let destructor_block = ConcreteBlock::new(|| {}).copy();
            let data = dispatch_data_create(
                library_data.as_ptr() as *const libc::c_void,
                library_data.len() as libc::size_t,
                &_dispatch_main_q as *const _ as dispatch_queue_t,
                &*destructor_block.deref()
            );

            let library: *mut MTLLibrary = try_objc! { err =>
                 msg_send![self, newLibraryWithData:data
                                              error:&mut err]
            };

            Ok(Library::from_ptr(library))
        }
    }

    pub fn new_render_pipeline_state_with_reflection(&self, descriptor: &RenderPipelineDescriptorRef, reflection: &RenderPipelineReflectionRef) -> Result<RenderPipelineState, String> {
        unsafe {
            let reflection_options = MTLPipelineOption::ArgumentInfo | MTLPipelineOption::BufferTypeInfo;

            let pipeline_state: *mut MTLRenderPipelineState = try_objc!{ err =>
                msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                             options:reflection_options
                                                          reflection:reflection
                                                               error:&mut err]
            };

            Ok(RenderPipelineState::from_ptr(pipeline_state))
        }
    }

    pub fn new_render_pipeline_state(&self, descriptor: &RenderPipelineDescriptorRef) -> Result<RenderPipelineState, String> {
        unsafe {
            let pipeline_state: *mut MTLRenderPipelineState = try_objc!{ err =>
                msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                               error:&mut err]
            };

            Ok(RenderPipelineState::from_ptr(pipeline_state))
        }
    }

    pub fn new_compute_pipeline_state(&self, descriptor: &ComputePipelineDescriptorRef) -> Result<ComputePipelineState, String> {
        unsafe {
            let pipeline_state: *mut MTLComputePipelineState = try_objc!{ err =>
                msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                               error:&mut err]
            };

            Ok(ComputePipelineState::from_ptr(pipeline_state))
        }
    }

    pub fn new_buffer(&self, length: u64, options: MTLResourceOptions) -> Buffer {
        unsafe {
            msg_send![self, newBufferWithLength:length
                                        options:options]
        }
    }

    pub fn new_buffer_with_data(&self, bytes: *const libc::c_void, length: NSUInteger, options: MTLResourceOptions) -> Buffer {
        unsafe {
            msg_send![self, newBufferWithBytes:bytes
                                        length:length
                                       options:options]
        }
    }

    pub fn new_texture(&self, descriptor: &TextureDescriptorRef) -> Texture {
        unsafe {
            msg_send![self, newTextureWithDescriptor:descriptor]
        }
    }

    pub fn new_sampler(&self, descriptor: &SamplerDescriptorRef) -> SamplerState {
        unsafe {
            msg_send![self, newSamplerStateWithDescriptor:descriptor]
        }
    }

    pub fn new_depth_stencil_state(&self, descriptor: &DepthStencilDescriptorRef) -> DepthStencilState {
        unsafe {
            msg_send![self, newDepthStencilStateWithDescriptor:descriptor]
        }
    }

    pub fn argument_buffers_support(&self) -> Option<MTLArgumentBuffersTier> {
        unsafe {
            let has_arg_buffers: BOOL = msg_send![self, respondsToSelector: sel!(argumentBuffersSupport)];
            if has_arg_buffers == YES {
                Some(msg_send![self, argumentBuffersSupport])
            } else {
                None
            }
        }
    }

    pub fn new_argument_encoder(&self, arguments: &ArrayRef<ArgumentDescriptor>) -> ArgumentEncoder {
        unsafe {
            msg_send![self, newArgumentEncoderWithArguments:arguments]
        }
    }

    pub fn new_heap(&self, descriptor: &HeapDescriptorRef) -> Heap {
        unsafe {
            msg_send![self, newHeapWithDescriptor: descriptor]
        }
    }

    pub fn heap_buffer_size_and_align(&self, length: NSUInteger, options: MTLResourceOptions) -> MTLSizeAndAlign {
        unsafe {
            msg_send![self, heapBufferSizeAndAlignWithLength: length options: options]
        }
    }

    pub fn heap_texture_size_and_align(&self, descriptor: &TextureDescriptorRef) -> MTLSizeAndAlign {
        unsafe {
            msg_send![self, heapTextureSizeAndAlignWithDescriptor: descriptor]
        }
    }
}
<commit_msg>Adding missing MTLFeatureSets<commit_after>// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use cocoa::base::id;
use cocoa::foundation::{NSUInteger};
use objc::runtime::{Object, BOOL, YES, NO};
use objc_foundation::{NSString, INSString};

use super::*;

use libc;

use block::{Block, ConcreteBlock};

use std::ffi::CStr;
use std::path::Path;
use std::ptr;

use foreign_types::ForeignType;

#[allow(non_camel_case_types)]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLFeatureSet {
    iOS_GPUFamily1_v1 = 0,
    iOS_GPUFamily2_v1 = 1,
    iOS_GPUFamily1_v2 = 2,
    iOS_GPUFamily2_v2 = 3,
    iOS_GPUFamily3_v1 = 4,
    iOS_GPUFamily1_v3 = 5,
    iOS_GPUFamily2_v3 = 6,
    iOS_GPUFamily3_v2 = 7,
    iOS_GPUFamily1_v4 = 8,
    iOS_GPUFamily2_v4 = 9,
    iOS_GPUFamily3_v3 = 10,
    iOS_GPUFamily4_v1 = 11,
    tvOS_GPUFamily1_v1 = 30000,
    tvOS_GPUFamily1_v2 = 30001,
    tvOS_GPUFamily1_v3 = 30002,
    tvOS_GPUFamily2_v1 = 30003,
    macOS_GPUFamily1_v1 = 10000,
    macOS_GPUFamily1_v2 = 10001,
    macOS_ReadWriteTextureTier2 = 10002,
    macOS_GPUFamily1_v3 = 10003,
    macOS_GPUFamily1_v4 = 10004,
    macOS_GPUFamily2_v1 = 10005,
}

#[allow(non_camel_case_types)]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLArgumentBuffersTier {
    tier1 = 0,
    tier2 = 1,
}

bitflags! {
    struct MTLPipelineOption: NSUInteger {
        const ArgumentInfo   = 1 << 0;
        const BufferTypeInfo = 1 << 1;
    }
}

#[link(name = "Metal", kind = "framework")]
extern {
    fn MTLCreateSystemDefaultDevice() -> *mut MTLDevice;
}

#[allow(non_camel_case_types)]
type dispatch_data_t = id;
#[allow(non_camel_case_types)]
type dispatch_queue_t = id;
#[allow(non_camel_case_types)]
type dispatch_block_t = *const Block<(), ()>;

#[cfg_attr(any(target_os = "macos", target_os = "ios"),
           link(name = "System", kind = "dylib"))]
#[cfg_attr(not(any(target_os = "macos", target_os = "ios")),
           link(name = "dispatch", kind = "dylib"))]
#[allow(improper_ctypes)]
extern {
    static _dispatch_main_q: dispatch_queue_t;

    fn dispatch_data_create(
        buffer: *const libc::c_void,
        size: libc::size_t,
        queue: dispatch_queue_t,
        destructor: dispatch_block_t
    ) -> dispatch_data_t;
}

/*type MTLNewLibraryCompletionHandler = extern fn(library: id, error: id);
type MTLNewRenderPipelineStateCompletionHandler = extern fn(renderPipelineState: id, error: id);
type MTLNewRenderPipelineStateWithReflectionCompletionHandler = extern fn(renderPipelineState: id, reflection: id, error: id);
type MTLNewComputePipelineStateCompletionHandler = extern fn(computePipelineState: id, error: id);
type MTLNewComputePipelineStateWithReflectionCompletionHandler = extern fn(computePipelineState: id, reflection: id, error: id);*/

pub enum MTLDevice {}

foreign_obj_type! {
    type CType = MTLDevice;
    pub struct Device;
    pub struct DeviceRef;
}

impl Device {
    pub fn system_default() -> Device {
        unsafe { Device(MTLCreateSystemDefaultDevice()) }
    }
}

impl DeviceRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, name];
            name.as_str()
        }
    }

    pub fn vendor(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, vendorName];
            name.as_str()
        }
    }

    pub fn family_name(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, familyName];
            name.as_str()
        }
    }

    pub fn registry_id(&self) -> u64 {
        unsafe {
            msg_send![self, registryID]
        }
    }

    pub fn max_threads_per_threadgroup(&self) -> MTLSize {
        unsafe {
            msg_send![self, maxThreadsPerThreadgroup]
        }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe {
            match msg_send![self, isLowPower] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn is_headless(&self) -> bool {
        unsafe {
            match msg_send![self, isHeadless] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn supports_feature_set(&self, feature: MTLFeatureSet) -> bool {
        unsafe {
            match msg_send![self, supportsFeatureSet:feature] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn supports_sample_count(&self, count: NSUInteger) -> bool {
        unsafe {
            match msg_send![self, supportsTextureSampleCount:count] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn d24_s8_supported(&self) -> bool {
        unsafe {
            match msg_send![self, isDepth24Stencil8PixelFormatSupported] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn new_command_queue(&self) -> CommandQueue {
        unsafe {
            msg_send![self, newCommandQueue]
        }
    }

    pub fn new_command_queue_with_max_command_buffer_count(&self, count: NSUInteger) -> CommandQueue {
        unsafe {
            msg_send![self, newCommandQueueWithMaxCommandBufferCount:count]
        }
    }

    pub fn new_default_library(&self) -> Library {
        unsafe {
            msg_send![self, newDefaultLibrary]
        }
    }

    pub fn new_library_with_source(&self, src: &str, options: &CompileOptionsRef) -> Result<Library, String> {
        use cocoa::foundation::NSString as cocoa_NSString;
        use cocoa::base::nil as cocoa_nil;

        unsafe {
            let source = cocoa_NSString::alloc(cocoa_nil).init_str(src);
            let mut err: *mut Object = ptr::null_mut();
            let library: *mut MTLLibrary = msg_send![self, newLibraryWithSource:source
                                                                        options:options
                                                                          error:&mut err];
            if !err.is_null() {
                let desc: *mut Object = msg_send![err, localizedDescription];
                let compile_error: *const libc::c_char = msg_send![desc, UTF8String];
                let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned();
                msg_send![err, release];
                if library.is_null() {
                    return Err(message);
                } else {
                    warn!("Shader warnings: {}", message);
                }
            }

            assert!(!library.is_null());
            Ok(Library::from_ptr(library))
        }
    }

    pub fn new_library_with_file<P: AsRef<Path>>(&self, file: P) -> Result<Library, String> {
        use cocoa::foundation::NSString as cocoa_NSString;
        use cocoa::base::nil as cocoa_nil;

        unsafe {
            let filename = cocoa_NSString::alloc(cocoa_nil)
                .init_str(file.as_ref().to_string_lossy().as_ref());

            let library: *mut MTLLibrary = try_objc!{ err =>
                msg_send![self, newLibraryWithFile:filename
                                             error:&mut err]
            };

            Ok(Library::from_ptr(library))
        }
    }

    pub fn new_library_with_data(&self, library_data: &[u8]) -> Result<Library, String> {
        unsafe {
            let destructor_block = ConcreteBlock::new(|| {}).copy();
            let data = dispatch_data_create(
                library_data.as_ptr() as *const libc::c_void,
                library_data.len() as libc::size_t,
                &_dispatch_main_q as *const _ as dispatch_queue_t,
                &*destructor_block.deref()
            );

            let library: *mut MTLLibrary = try_objc! { err =>
                 msg_send![self, newLibraryWithData:data
                                              error:&mut err]
            };

            Ok(Library::from_ptr(library))
        }
    }

    pub fn new_render_pipeline_state_with_reflection(&self, descriptor: &RenderPipelineDescriptorRef, reflection: &RenderPipelineReflectionRef) -> Result<RenderPipelineState, String> {
        unsafe {
            let reflection_options = MTLPipelineOption::ArgumentInfo | MTLPipelineOption::BufferTypeInfo;

            let pipeline_state: *mut MTLRenderPipelineState = try_objc!{ err =>
                msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                             options:reflection_options
                                                          reflection:reflection
                                                               error:&mut err]
            };

            Ok(RenderPipelineState::from_ptr(pipeline_state))
        }
    }

    pub fn new_render_pipeline_state(&self, descriptor: &RenderPipelineDescriptorRef) -> Result<RenderPipelineState, String> {
        unsafe {
            let pipeline_state: *mut MTLRenderPipelineState = try_objc!{ err =>
                msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                               error:&mut err]
            };

            Ok(RenderPipelineState::from_ptr(pipeline_state))
        }
    }

    pub fn new_compute_pipeline_state(&self, descriptor: &ComputePipelineDescriptorRef) -> Result<ComputePipelineState, String> {
        unsafe {
            let pipeline_state: *mut MTLComputePipelineState = try_objc!{ err =>
                msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                               error:&mut err]
            };

            Ok(ComputePipelineState::from_ptr(pipeline_state))
        }
    }

    pub fn new_buffer(&self, length: u64, options: MTLResourceOptions) -> Buffer {
        unsafe {
            msg_send![self, newBufferWithLength:length
                                        options:options]
        }
    }

    pub fn new_buffer_with_data(&self, bytes: *const libc::c_void, length: NSUInteger, options: MTLResourceOptions) -> Buffer {
        unsafe {
            msg_send![self, newBufferWithBytes:bytes
                                        length:length
                                       options:options]
        }
    }

    pub fn new_texture(&self, descriptor: &TextureDescriptorRef) -> Texture {
        unsafe {
            msg_send![self, newTextureWithDescriptor:descriptor]
        }
    }

    pub fn new_sampler(&self, descriptor: &SamplerDescriptorRef) -> SamplerState {
        unsafe {
            msg_send![self, newSamplerStateWithDescriptor:descriptor]
        }
    }

    pub fn new_depth_stencil_state(&self, descriptor: &DepthStencilDescriptorRef) -> DepthStencilState {
        unsafe {
            msg_send![self, newDepthStencilStateWithDescriptor:descriptor]
        }
    }

    pub fn argument_buffers_support(&self) -> Option<MTLArgumentBuffersTier> {
        unsafe {
            let has_arg_buffers: BOOL = msg_send![self, respondsToSelector: sel!(argumentBuffersSupport)];
            if has_arg_buffers == YES {
                Some(msg_send![self, argumentBuffersSupport])
            } else {
                None
            }
        }
    }

    pub fn new_argument_encoder(&self, arguments: &ArrayRef<ArgumentDescriptor>) -> ArgumentEncoder {
        unsafe {
            msg_send![self, newArgumentEncoderWithArguments:arguments]
        }
    }

    pub fn new_heap(&self, descriptor: &HeapDescriptorRef) -> Heap {
        unsafe {
            msg_send![self, newHeapWithDescriptor: descriptor]
        }
    }

    pub fn heap_buffer_size_and_align(&self, length: NSUInteger, options: MTLResourceOptions) -> MTLSizeAndAlign {
        unsafe {
            msg_send![self, heapBufferSizeAndAlignWithLength: length options: options]
        }
    }

    pub fn heap_texture_size_and_align(&self, descriptor: &TextureDescriptorRef) -> MTLSizeAndAlign {
        unsafe {
            msg_send![self, heapTextureSizeAndAlignWithDescriptor: descriptor]
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains the common driver code. Specific implementations for
//! different drivers exist elsewhere.

use error::Error;
use value::*;
use query::Query;

/// Gets the driver from a URL string using the protocol. For example a URL
/// of `postgres://localhost:5432/test_db` would look for a
/// `ardite-driver-postgres` crate, download the crate if it did not already
/// exist in the file system, and then return an instance initialized with the
/// `connect` static trait function.
pub fn get_driver<D: Driver>(url: &str) -> D {
  // TODO: implement.
  // Used to quiet warnings.
  println!("{}", url);
  unimplemented!();
}

pub trait Driver {
  /// Connects to a driver and returns a driver instance. After calling this
  /// the driver is ready to roll!
  fn connect(url: &str) -> Result<&Self, Error>;

  /// Set a value at a certain point in the driver.
  fn set(&self, pointer: Pointer, value: Value) -> Result<(), Error>;

  /// Get a value from a certain point in the driver. An optional query may be
  /// performed for more complex data selection.
  fn get(&self, query: Query) -> Result<Value, Error>;

  /// Gets the schema for the driver. By default no schema is returned.
  fn get_schema(&self) -> Result<Schema, Error> {
    Ok(Schema::None)
  }
}
<commit_msg>refactor: add local "allow" attribute<commit_after>//! This module contains the common driver code. Specific implementations for
//! different drivers exist elsewhere.

use error::Error;
use value::*;
use query::Query;

/// Gets the driver from a URL string using the protocol. For example a URL
/// of `postgres://localhost:5432/test_db` would look for a
/// `ardite-driver-postgres` crate, download the crate if it did not already
/// exist in the file system, and then return an instance initialized with the
/// `connect` static trait function.
#[allow(unused_variables)]
pub fn get_driver<D: Driver>(url: &str) -> D {
  // TODO: implement.
  unimplemented!();
}

pub trait Driver {
  /// Connects to a driver and returns a driver instance. After calling this
  /// the driver is ready to roll!
  fn connect(url: &str) -> Result<&Self, Error>;

  /// Set a value at a certain point in the driver.
  fn set(&self, pointer: Pointer, value: Value) -> Result<(), Error>;

  /// Get a value from a certain point in the driver. An optional query may be
  /// performed for more complex data selection.
  fn get(&self, query: Query) -> Result<Value, Error>;

  /// Gets the schema for the driver. By default no schema is returned.
  fn get_schema(&self) -> Result<Schema, Error> {
    Ok(Schema::None)
  }
}
<|endoftext|>


<commit_before>use core::fmt;

/// Read the current value from `$cr4`.
pub fn read() -> Flags {
    let result: usize;
    unsafe {
        asm!(   "mov $0, cr4"
            :   "=r"(result)
            ::: "intel" );
    }
    Flags::from_bits_truncate(result)
}

/// Write a value to `$cr4`.
///
/// # Unsafe Because:
///  - Control registers should generally not be modified during normal
///    operation.
pub unsafe fn cr4_write(value: usize) {
    asm!(  "mov cr4, $0"
        :: "r"(value)
        :: "intel");
}

bitflags! {
    /// Bitflags present in `$cr4`
    ///
    /// Documentation taken from
    /// [wikipedia](https://en.wikipedia.org/wiki/Control_register#CR4).
    pub flags Flags: usize {
        /// Virtual 8086 Mode Extensions
        ///
        /// If set, enables support for the virtual interrupt flag (VIF) in
        /// virtual-8086 mode.
        const VME = 1 << 0
      , /// Protected-mode Virtual Interrupts
        ///
        /// If set, enables support for the virtual interrupt flag (VIF) in
        /// protected mode.
        const PVI = 1 << 1
      , /// If 1, the `RTDSC` instruction can only be executed in Ring 0
        const TSD = 1 << 2
      , /// Debugging Extensions
        ///
        /// If set, enables debug register based breaks on I/O space access
        const DE = 1 << 3
      , /// Page Size Extension
        ///
        /// If unset, page size is 4 KiB, else page size is increased to 4 MiB
        /// (if PAE is enabled or the processor is in Long Mode this bit is
        /// ignored).
        const PSE = 1 << 4
      , /// Physical Address Extension
        ///
        /// If set, changes page table layout to translate 32-bit virtual
        /// addresses into extended 36-bit physical addresses.
        const PAE = 1 << 5
      , /// Machine Check Exception
        ///
        /// If set, Machine Check exceptions are enabled.
        const MCE = 1 << 6
      , /// Page Global Enabled
        ///
        /// If set, address translations (PDE or PTE records) may be shared
        /// between address spaces.
        const PGE = 1 << 7
      , /// Performance-Monitoring Counter enable
        ///
        /// If set, the `RDPMC` instruction can be executed at any privilege
        /// level, else `RDPMC` can only be used in ring 0.
        const PCE = 1 << 8
      , /// Operating system support for `FXSAVE` and `FXRSTOR` instructions
        ///
        /// If set, enables SSE instructions and fast FPU save and restore.
        const OSFXSR = 1 << 9
      , /// Operating System Support for Unmasked SIMD Floating-Point Exceptions
        ///
        /// If set, enables unmasked SSE exceptions.
        const OSXMMEXCPT = 1 << 10
      , /// Virtual Machine Extensions Enable
        const VMXE = 1 << 13
      , /// Safer Mode Extensions Enable
        const SMXE = 1 << 14
      , /// Enables the instructions RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE.
        const FSGSBASE = 1 << 16
      , /// PCID Enable
        ///
        /// If set, enables process-context identifiers (PCIDs).
        const PCIDE = 1 << 17
      , /// `XSAVE` and Processor Extended States Enable
        const OSXSAVE = 1 << 18
      , /// Supervisor Mode Execution Protection Enable
        ///
        /// If set, execution of code in a higher ring generates a fault
        const SMEP = 1 << 20
      , /// Supervisor Mode Access Protection Enable
        ///
        /// If set, access of data in a higher ring generates a faul
        const SMAP = 1 << 21
      , /// Protection Key Enable
        const PKE = 1 << 22
    }
}

impl fmt::LowerHex for Flags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#08x}", self.bits)
    }
}
<commit_msg>[x86_all] %cr4 bit flags embetterment<commit_after>use core::fmt;

/// Read the current value from `$cr4`.
pub fn read() -> Flags {
    let result: usize;
    unsafe {
        asm!(   "mov $0, cr4"
            :   "=r"(result)
            ::: "intel" );
    }
    Flags { bits: result }
}

/// Write a value to `$cr4`.
///
/// # Unsafe Because:
///  - Control registers should generally not be modified during normal
///    operation.
pub unsafe fn write(flags: Flags) {
    asm!(  "mov cr4, $0"
        :: "r"(flags.bits)
        :: "intel");
}

bitflags! {
    /// Bitflags present in `$cr4`
    ///
    /// Documentation taken from
    /// [wikipedia](https://en.wikipedia.org/wiki/Control_register#CR4).
    pub flags Flags: usize {
        /// Virtual 8086 Mode Extensions
        ///
        /// If set, enables support for the virtual interrupt flag (VIF) in
        /// virtual-8086 mode.
        const VME = 1 << 0
      , /// Protected-mode Virtual Interrupts
        ///
        /// If set, enables support for the virtual interrupt flag (VIF) in
        /// protected mode.
        const PVI = 1 << 1
      , /// If 1, the `RTDSC` instruction can only be executed in Ring 0
        const TSD = 1 << 2
      , /// Debugging Extensions
        ///
        /// If set, enables debug register based breaks on I/O space access
        const DE = 1 << 3
      , /// Page Size Extension
        ///
        /// If unset, page size is 4 KiB, else page size is increased to 4 MiB
        /// (if PAE is enabled or the processor is in Long Mode this bit is
        /// ignored).
        const PSE = 1 << 4
      , /// Physical Address Extension
        ///
        /// If set, changes page table layout to translate 32-bit virtual
        /// addresses into extended 36-bit physical addresses.
        const PAE = 1 << 5
      , /// Machine Check Exception
        ///
        /// If set, Machine Check exceptions are enabled.
        const MCE = 1 << 6
      , /// Page Global Enabled
        ///
        /// If set, address translations (PDE or PTE records) may be shared
        /// between address spaces.
        const PGE = 1 << 7
      , /// Performance-Monitoring Counter enable
        ///
        /// If set, the `RDPMC` instruction can be executed at any privilege
        /// level, else `RDPMC` can only be used in ring 0.
        const PCE = 1 << 8
      , /// Operating system support for `FXSAVE` and `FXRSTOR` instructions
        ///
        /// If set, enables SSE instructions and fast FPU save and restore.
        const OSFXSR = 1 << 9
      , /// Operating System Support for Unmasked SIMD Floating-Point Exceptions
        ///
        /// If set, enables unmasked SSE exceptions.
        const OSXMMEXCPT = 1 << 10
      , /// Virtual Machine Extensions Enable
        const VMXE = 1 << 13
      , /// Safer Mode Extensions Enable
        const SMXE = 1 << 14
      , /// Enables the instructions RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE.
        const FSGSBASE = 1 << 16
      , /// PCID Enable
        ///
        /// If set, enables process-context identifiers (PCIDs).
        const PCIDE = 1 << 17
      , /// `XSAVE` and Processor Extended States Enable
        const OSXSAVE = 1 << 18
      , /// Supervisor Mode Execution Protection Enable
        ///
        /// If set, execution of code in a higher ring generates a fault
        const SMEP = 1 << 20
      , /// Supervisor Mode Access Protection Enable
        ///
        /// If set, access of data in a higher ring generates a faul
        const SMAP = 1 << 21
      , /// Protection Key Enable
        const PKE = 1 << 22
    }
}

impl fmt::LowerHex for Flags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#08x}", self.bits)
    }
}
<|endoftext|>


<commit_before>// TOML test suite for [1]
//
// [1]: https://github.com/BurntSushi/toml-test
//
// If given a path, it will perform the same tests like toml-test [1],
// so no need to install "go" :).

extern crate extra = "extra#0.10-pre";
extern crate collections = "collections#0.10-pre";
extern crate toml = "github.com/mneumann/rust-toml#toml:0.1";

use extra::json::{Json,String,List,Object};

use collections::treemap::TreeMap;
use std::os;
use std::path::Path;
use std::io::fs::walk_dir;
use std::io::File;

fn to_json_type(typ: ~str, val: Json) -> Json {
    let mut tree = ~TreeMap::new();
    tree.insert(~"type", String(typ));
    tree.insert(~"value", val);
    Object(tree)
}

fn format_float(f: f64) -> ~str {
    let str = format!("{:.15f}", f);
    let str = str.as_slice();
    let str = str.trim_right_chars(&'0');
    if str.ends_with(".") {
      str.to_owned() + "0"
    } else {
      str.to_owned()
    }
}

fn to_json(v: &toml::Value) -> Json {
    match v {
        &toml::NoValue => { fail!("Invalid toml document"); }
        &toml::Table(_, ref map) => {
            let mut tree = ~TreeMap::new();
            for (k, v) in map.iter() {
                tree.insert(k.clone(), to_json(v));
            }
            Object(tree)
        }
        &toml::TableArray(ref arr) => {
            List(arr.map(|i| to_json(i)))
        }
        &toml::Array(ref arr) => {
            let list = arr.map(|i| to_json(i));
            to_json_type(~"array", List(list))
        }
        &toml::Boolean(true) => { to_json_type(~"bool", String(~"true")) }
        &toml::Boolean(false) => { to_json_type(~"bool", String(~"false")) }
        &toml::PosInt(n) => { to_json_type(~"integer", String(n.to_str())) }
        &toml::NegInt(n) => { to_json_type(~"integer", String("-" + n.to_str())) }
        &toml::Float(n) => { to_json_type(~"float", String(format_float(n))) }
        &toml::String(ref str) => { to_json_type(~"string", String(str.clone())) }
        &toml::Datetime(y,m,d,h,mi,s) => {
            let s = format!("{:04u}-{:02u}-{:02u}T{:02u}:{:02u}:{:02u}Z", y,m,d,h,mi,s);
            to_json_type(~"datetime", String(s))
        }
    }
}

fn toml_test_runner() {
    let toml = toml::parse_from_bytes(std::io::stdin().read_to_end().unwrap()).unwrap();
    let json = to_json(&toml);
    println!("{:s}", json.to_pretty_str());
}

fn independent_test_runner(path: ~str) {
  let path = Path::new(path);
  let mut tests: int = 0;
  let mut failed: int = 0;
  let mut passed: int = 0;

  for filename in walk_dir(&path.join("invalid")).unwrap() {
    if filename.is_file() && filename.extension_str() == Some("toml") {
      println!("TEST/INVALID: {}", filename.filename_display());
      tests += 1;

      match toml::parse_from_path(&filename) {
          Err(_) => {
              passed += 1;
              println!("   [PASS]");
          }
          _ => {
              failed += 1;
              println!("   [FAIL]");
          }
      }
    }
  }

  for filename in walk_dir(&path.join("valid")).unwrap() {
    if filename.is_file() && filename.extension_str() == Some("toml") {
      let jsonfile = filename.with_extension("json");
      if !jsonfile.is_file() { fail!() }

      println!("TEST/VALID:   {}", filename.filename_display());

      let jsonbytes = File::open(&Path::new(jsonfile)).read_to_end().unwrap();
      let jsonstr = std::str::from_utf8(jsonbytes).unwrap();

      let result = extra::json::from_str(jsonstr);
      if result.is_err() { fail!() }

      tests += 1;

      let json = result.unwrap();
      let toml = toml::parse_from_path(&filename);
      let toml_json = toml.map(|t| to_json(&t));

      if Ok(&json) == toml_json.as_ref() {
          passed += 1;
          println!("   [PASS]");
      } else {
          println!("===============================================");
          println!("{:s}", json.to_pretty_str());
          println!("-----------------------------------------------");
          match toml_json {
              Ok(json) => println!("{:s}", json.to_pretty_str()),
              Err(toml::ParseError) => println!("(parse error)"),
              Err(toml::IOError(e)) => println!("({})", e)
          }
          println!("===============================================");
          failed += 1;
          println!("   [FAIL]");
      }
    }
  }

  println!("");
  println!("Tests/PASS/FAIL: {:d}/{:d}/{:d}", tests, passed, failed);
  if failed > 0 { fail!(); }
}

fn main() {
    match os::args().len() {
      1 => toml_test_runner(),
      2 => independent_test_runner(os::args()[1]),
      _ => fail!("USAGE: {:s} [path]", os::args()[0]),
    }
}
<commit_msg>json moved from extra to serialize<commit_after>// TOML test suite for [1]
//
// [1]: https://github.com/BurntSushi/toml-test
//
// If given a path, it will perform the same tests like toml-test [1],
// so no need to install "go" :).

extern crate serialize;
extern crate collections = "collections#0.10-pre";
extern crate toml = "github.com/mneumann/rust-toml#toml:0.1";

use serialize::json::{Json,String,List,Object};

use collections::treemap::TreeMap;
use std::os;
use std::path::Path;
use std::io::fs::walk_dir;
use std::io::File;

fn to_json_type(typ: ~str, val: Json) -> Json {
    let mut tree = ~TreeMap::new();
    tree.insert(~"type", String(typ));
    tree.insert(~"value", val);
    Object(tree)
}

fn format_float(f: f64) -> ~str {
    let str = format!("{:.15f}", f);
    let str = str.as_slice();
    let str = str.trim_right_chars(&'0');
    if str.ends_with(".") {
      str.to_owned() + "0"
    } else {
      str.to_owned()
    }
}

fn to_json(v: &toml::Value) -> Json {
    match v {
        &toml::NoValue => { fail!("Invalid toml document"); }
        &toml::Table(_, ref map) => {
            let mut tree = ~TreeMap::new();
            for (k, v) in map.iter() {
                tree.insert(k.clone(), to_json(v));
            }
            Object(tree)
        }
        &toml::TableArray(ref arr) => {
            List(arr.map(|i| to_json(i)))
        }
        &toml::Array(ref arr) => {
            let list = arr.map(|i| to_json(i));
            to_json_type(~"array", List(list))
        }
        &toml::Boolean(true) => { to_json_type(~"bool", String(~"true")) }
        &toml::Boolean(false) => { to_json_type(~"bool", String(~"false")) }
        &toml::PosInt(n) => { to_json_type(~"integer", String(n.to_str())) }
        &toml::NegInt(n) => { to_json_type(~"integer", String("-" + n.to_str())) }
        &toml::Float(n) => { to_json_type(~"float", String(format_float(n))) }
        &toml::String(ref str) => { to_json_type(~"string", String(str.clone())) }
        &toml::Datetime(y,m,d,h,mi,s) => {
            let s = format!("{:04u}-{:02u}-{:02u}T{:02u}:{:02u}:{:02u}Z", y,m,d,h,mi,s);
            to_json_type(~"datetime", String(s))
        }
    }
}

fn toml_test_runner() {
    let toml = toml::parse_from_bytes(std::io::stdin().read_to_end().unwrap()).unwrap();
    let json = to_json(&toml);
    println!("{:s}", json.to_pretty_str());
}

fn independent_test_runner(path: ~str) {
  let path = Path::new(path);
  let mut tests: int = 0;
  let mut failed: int = 0;
  let mut passed: int = 0;

  for filename in walk_dir(&path.join("invalid")).unwrap() {
    if filename.is_file() && filename.extension_str() == Some("toml") {
      println!("TEST/INVALID: {}", filename.filename_display());
      tests += 1;

      match toml::parse_from_path(&filename) {
          Err(_) => {
              passed += 1;
              println!("   [PASS]");
          }
          _ => {
              failed += 1;
              println!("   [FAIL]");
          }
      }
    }
  }

  for filename in walk_dir(&path.join("valid")).unwrap() {
    if filename.is_file() && filename.extension_str() == Some("toml") {
      let jsonfile = filename.with_extension("json");
      if !jsonfile.is_file() { fail!() }

      println!("TEST/VALID:   {}", filename.filename_display());

      let jsonbytes = File::open(&Path::new(jsonfile)).read_to_end().unwrap();
      let jsonstr = std::str::from_utf8(jsonbytes).unwrap();

      let result = extra::json::from_str(jsonstr);
      if result.is_err() { fail!() }

      tests += 1;

      let json = result.unwrap();
      let toml = toml::parse_from_path(&filename);
      let toml_json = toml.map(|t| to_json(&t));

      if Ok(&json) == toml_json.as_ref() {
          passed += 1;
          println!("   [PASS]");
      } else {
          println!("===============================================");
          println!("{:s}", json.to_pretty_str());
          println!("-----------------------------------------------");
          match toml_json {
              Ok(json) => println!("{:s}", json.to_pretty_str()),
              Err(toml::ParseError) => println!("(parse error)"),
              Err(toml::IOError(e)) => println!("({})", e)
          }
          println!("===============================================");
          failed += 1;
          println!("   [FAIL]");
      }
    }
  }

  println!("");
  println!("Tests/PASS/FAIL: {:d}/{:d}/{:d}", tests, passed, failed);
  if failed > 0 { fail!(); }
}

fn main() {
    match os::args().len() {
      1 => toml_test_runner(),
      2 => independent_test_runner(os::args()[1]),
      _ => fail!("USAGE: {:s} [path]", os::args()[0]),
    }
}
<|endoftext|>


<commit_before>//! Formatting helpers for the logger middleware.

use iron::{Request, Response};
use term::{self, color};
use iron::status::NotFound;

use std::default::Default;
use std::str::FromStr;
use std::str::Chars;
use std::vec::IntoIter;
use std::iter::Peekable;

use self::ColorOrAttr::{Color, Attr};
use self::FormatText::{Method, URI, Status, ResponseTime, RemoteAddr, TimeStamp};
use self::FormatColor::{ConstantColor, FunctionColor};
use self::FormatAttr::{ConstantAttrs, FunctionAttrs};

/// A formatting style for the `Logger`, consisting of multiple
/// `FormatUnit`s concatenated into one line.
#[derive(Clone)]
pub struct Format(pub Vec<FormatUnit>);

impl Default for Format {
    /// Return the default formatting style for the `Logger`:
    ///
    /// ```ignore
    /// @[bold]{method}@ {uri} @[bold]->@ @[C]{status}@ ({response-time})
    /// // This will be written as: {method} {uri} -> {status} ({response-time})
    /// // with certain style attributes.
    /// ```
    ///
    /// The method is in bold, and the response status is colored blue for 100s,
    /// green for 200s, yellow for 300s, red for 400s, and bright red for 500s.
    fn default() -> Format {
        fn status_color(_req: &Request, res: &Response) -> Option<color::Color> {
            use iron::status::StatusClass::*;

            match res.status.unwrap_or(NotFound).class() {
                Informational   => Some(color::BLUE),
                Success         => Some(color::GREEN),
                Redirection     => Some(color::YELLOW),
                ClientError     => Some(color::RED),
                ServerError     => Some(color::BRIGHT_RED),
                NoClass         => None
            }
        }

        Format::new("@[bold]{method}@ {uri} @[bold]->@ @[C]{status}@ ({response-time})",
           vec![FunctionColor(status_color)], vec![]).unwrap()
    }
}

impl Format {
    // TODO: Document the color/attribute tags.
    /// Create a `Format` from a format string, which can contain the fields
    /// `{method}`, `{uri}`, `{status}`, `{response-time}`, `{ip-addr}` and `timestamp`.
    ///
    /// Returns `None` if the format string syntax is incorrect.
    ///
    /// ---
    ///
    /// Colors and attributes can also be added to the format string within `@` delimiters,
    /// by specifying them in a space-delimited list within square brackets (`[bold italic]`).
    /// They can be made dependent on the request/response by passing `FunctionColor` and
    /// `FunctionAttr`s in as the `colors` and `attrs` vecs; these colors/attributes will
    /// be used sequentially when there is a `[C]` or `[A]` marker, respectively (`[bold C]`).
    ///
    /// For example: `@[bold C]{status}@` will be formatted based upon
    /// the first FormatColor constant or function in the `colors` vector,
    /// yielding a bold and colored response status.
    ///
    /// Available colors are:
    ///
    /// - `black`
    /// - `blue`
    /// - `brightblack`
    /// - `brightblue`
    /// - `brightcyan`
    /// - `brightgreen`
    /// - `brightmagenta`
    /// - `brightred`
    /// - `brightwhite`
    /// - `brightyellow`
    /// - `cyan`
    /// - `green`
    /// - `magenta`
    /// - `red`
    /// - `white`
    /// - `yellow`
    ///
    /// Available attributes are:
    ///
    /// - `bold`
    /// - `dim`
    /// - `italic`
    /// - `underline`
    /// - `blink`
    /// - `standout`
    /// - `reverse`
    /// - `secure`
    pub fn new(s: &str, colors: Vec<FormatColor>, attrs: Vec<FormatAttr>)
            -> Option<Format> {

        let parser = FormatParser::new(s.chars().peekable(),
                                       colors.into_iter(),
                                       attrs.into_iter());

        let mut results = Vec::new();

        for unit in parser {
            match unit {
                Some(unit) => results.push(unit),
                None => return None
            }
        }

        Some(Format(results))
    }
}

struct FormatParser<'a> {
    // The characters of the format string.
    chars: Peekable<Chars<'a>>,

    // Passed-in FormatColors
    colors: IntoIter<FormatColor>,

    // Passed-in FormatAttr
    attrs: IntoIter<FormatAttr>,

    // A reusable buffer for parsing style attributes.
    object_buffer: String,

    // A queue of waiting format units to avoid full-on
    // state-machine parsing.
    waitqueue: Vec<FormatUnit>,

    finished: bool
}

impl<'a> FormatParser<'a> {
    fn new(chars: Peekable<Chars>, colors: IntoIter<FormatColor>,
           attrs: IntoIter<FormatAttr>) -> FormatParser {
        FormatParser {
            chars: chars,
            colors: colors,
            attrs: attrs,

            // No attributes are longer than 14 characters, so we can avoid reallocating.
            object_buffer: String::with_capacity(14),

            waitqueue: vec![],
            finished: false
        }
    }
}

// Some(None) means there was a parse error and this FormatParser should be abandoned.
impl<'a> Iterator for FormatParser<'a> {
    type Item = Option<FormatUnit>;

    fn next(&mut self) -> Option<Option<FormatUnit>> {
        // If the parser has been cancelled or errored for some reason.
        if self.finished { return None }

        if self.waitqueue.len() != 0 {
            return Some(Some(self.waitqueue.remove(0)));
        }

        // Try to parse a new FormatUnit.
        match self.chars.next() {
            // Parse a recognized object.
            //
            // The allowed forms are:
            //   - {method}
            //   - {uri}
            //   - {status}
            //   - {response-time}
            //   - {ip-addr}
            //   - {timestamp}
            Some('{') => {
                self.object_buffer.clear();

                let mut chr = self.chars.next();
                while chr != None {
                    match chr.unwrap() {
                        // Finished parsing, parse buffer.
                        '}' => break,
                        c => self.object_buffer.push(c.clone())
                    }

                    chr = self.chars.next();
                }

                let text = match self.object_buffer.as_ref() {
                    "method" => Method,
                    "uri" => URI,
                    "status" => Status,
                    "response-time" => ResponseTime,
                    "ip-addr" => RemoteAddr,
                    "timestamp" => TimeStamp,
                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                };

                Some(Some(FormatUnit {
                    text: text,
                    color: ConstantColor(None),
                    attrs: ConstantAttrs(vec![])
                }))
            },

            // Parse an attribute and the thing it applies to.
            //
            // The form is:
            //   - @[attributes]target@
            Some('@') => {
                match self.chars.next() {
                    // Parse attributes
                    Some('[') => {
                        let mut buffer = String::new();

                        loop {
                            match self.chars.next() {
                                // Finished parsing into buffer.
                                Some(']') => break,
                                Some(c) => buffer.push(c),
                                // Error, so mark as finished.
                                None => {
                                    self.finished = true;
                                    return Some(None);
                                }
                            }
                        }

                        let mut attrs = ConstantAttrs(vec![]);
                        let mut color = ConstantColor(None);

                        // Collect the attributes into attrs and color, for use as properties
                        // of a FormatUnit.
                        for word in buffer.split(|c: char| c.is_whitespace()) {
                            match word {
                                "A" => attrs = self.attrs.next().unwrap_or(ConstantAttrs(vec![])),

                                "C" => color = self.colors.next().unwrap_or(ConstantColor(None)),

                                style => match style.parse() {
                                    Ok(Color(c)) => match color {
                                        ConstantColor(_) => { color = ConstantColor(Some(c)); },
                                        _ => {}
                                    },

                                    Ok(Attr(a)) => match attrs {
                                        ConstantAttrs(ref mut v) => { v.push(a); },
                                        _ => {}
                                    },

                                    _ => {}
                                }
                            }
                        }

                        // Nested attributes are not supported.
                        if self.chars.peek() == Some(&'@') {
                            self.finished = true;
                            return Some(None);
                        }

                        // Now we have the parsed attributes, so we can parse what they apply to.
                        let mut apply_to = vec![];

                        loop {
                            match self.next() {
                                Some(Some(unit)) => apply_to.push(unit),
                                _ => {
                                    self.finished = true;
                                    return Some(None);
                                }
                            };

                            if self.chars.peek() == Some(&'@') {
                                // Jump over the closing '@'
                                self.chars.next();
                                break;
                            }
                        }

                        self.waitqueue.extend(apply_to.into_iter().map(|unit| {
                            FormatUnit {
                                text: unit.text,
                                color: color.clone(),
                                attrs: attrs.clone()
                            }
                        }));

                        self.next()
                    },

                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                }
            },

            // Parse a regular string part of the format string.
            Some(c) => {
                let mut buffer = String::new();
                buffer.push(c);

                loop {
                    match self.chars.peek() {
                        // Done parsing.
                        Some(&'@') | Some(&'{') | None => {
                            return Some(Some(FormatUnit {
                                text: FormatText::Str(buffer),
                                color: ConstantColor(None),
                                attrs: ConstantAttrs(vec![])
                            }))
                        },

                        Some(_) => {
                            buffer.push(self.chars.next().unwrap())
                        }
                    }
                }
            },

            // Reached end of the format string.
            None => None
        }
    }
}

impl FromStr for ColorOrAttr {
    type Err = ();

    fn from_str(name: &str) -> Result<ColorOrAttr, ()> {
        match name {
            "black" => Ok(Color(color::BLACK)),
            "blue" => Ok(Color(color::BLUE)),
            "brightblack" => Ok(Color(color::BRIGHT_BLACK)),
            "brightblue" => Ok(Color(color::BRIGHT_BLUE)),
            "brightcyan" => Ok(Color(color::BRIGHT_CYAN)),
            "brightgreen" => Ok(Color(color::BRIGHT_GREEN)),
            "brightmagenta" => Ok(Color(color::BRIGHT_MAGENTA)),
            "brightred" => Ok(Color(color::BRIGHT_RED)),
            "brightwhite" => Ok(Color(color::BRIGHT_WHITE)),
            "brightyellow" => Ok(Color(color::BRIGHT_YELLOW)),
            "cyan" => Ok(Color(color::CYAN)),
            "green" => Ok(Color(color::GREEN)),
            "magenta" => Ok(Color(color::MAGENTA)),
            "red" => Ok(Color(color::RED)),
            "white" => Ok(Color(color::WHITE)),
            "yellow" => Ok(Color(color::YELLOW)),

            "bold" => Ok(Attr(term::Attr::Bold)),
            "dim" => Ok(Attr(term::Attr::Dim)),
            "italic" => Ok(Attr(term::Attr::Italic(true))),
            "underline" => Ok(Attr(term::Attr::Underline(true))),
            "blink" => Ok(Attr(term::Attr::Blink)),
            "standout" => Ok(Attr(term::Attr::Standout(true))),
            "reverse" => Ok(Attr(term::Attr::Reverse)),
            "secure" => Ok(Attr(term::Attr::Secure)),

            _ => Err(())
        }
    }
}

enum ColorOrAttr {
    Color(color::Color),
    Attr(term::Attr)
}

/// A representation of color in a `FormatUnit`.
#[derive(Copy)]
pub enum FormatColor {
    /// A constant color
    ConstantColor(Option<color::Color>),
    /// A variable color, dependent on the request/response
    ///
    /// This can be used to change the color depending on response status, &c.
    FunctionColor(fn(&Request, &Response) -> Option<color::Color>)
}

/// A representation of attributes in a `FormatUnit`.
pub enum FormatAttr {
    /// A constant attribute
    ConstantAttrs(Vec<term::Attr>),
    /// A variable attribute, dependent on the request/response
    ///
    /// This can be used to change the attribute depending on response status, &c.
    FunctionAttrs(fn(&Request, &Response) -> Vec<term::Attr>)
}

impl Clone for FormatColor {
    fn clone(&self) -> FormatColor { *self }
}

impl Clone for FormatAttr {
    fn clone(&self) -> FormatAttr {
        match *self {
            ConstantAttrs(ref attrs) => ConstantAttrs(attrs.iter().map(|&attr| attr).collect()),
            FunctionAttrs(f) => FunctionAttrs(f)
        }
    }
}

/// A string of text to be logged. This is either one of the data
/// fields supported by the `Logger`, or a custom `String`.
#[derive(Clone)]
#[doc(hidden)]
pub enum FormatText {
    Str(String),
    Method,
    URI,
    Status,
    ResponseTime,
    RemoteAddr,
    TimeStamp
}

/// A `FormatText` with associated style information.
#[derive(Clone)]
#[doc(hidden)]
pub struct FormatUnit {
    pub text: FormatText,
    pub color: FormatColor,
    pub attrs: FormatAttr
}
<commit_msg>(feat) Add timestamp to default format<commit_after>//! Formatting helpers for the logger middleware.

use iron::{Request, Response};
use term::{self, color};
use iron::status::NotFound;

use std::default::Default;
use std::str::FromStr;
use std::str::Chars;
use std::vec::IntoIter;
use std::iter::Peekable;

use self::ColorOrAttr::{Color, Attr};
use self::FormatText::{Method, URI, Status, ResponseTime, RemoteAddr, TimeStamp};
use self::FormatColor::{ConstantColor, FunctionColor};
use self::FormatAttr::{ConstantAttrs, FunctionAttrs};

/// A formatting style for the `Logger`, consisting of multiple
/// `FormatUnit`s concatenated into one line.
#[derive(Clone)]
pub struct Format(pub Vec<FormatUnit>);

impl Default for Format {
    /// Return the default formatting style for the `Logger`:
    ///
    /// ```ignore
    /// @[bold]{method}@ {uri} @[bold]->@ @[C]{status}@ ({response-time})
    /// // This will be written as: {method} {uri} -> {status} ({response-time})
    /// // with certain style attributes.
    /// ```
    ///
    /// The method is in bold, and the response status is colored blue for 100s,
    /// green for 200s, yellow for 300s, red for 400s, and bright red for 500s.
    fn default() -> Format {
        fn status_color(_req: &Request, res: &Response) -> Option<color::Color> {
            use iron::status::StatusClass::*;

            match res.status.unwrap_or(NotFound).class() {
                Informational   => Some(color::BLUE),
                Success         => Some(color::GREEN),
                Redirection     => Some(color::YELLOW),
                ClientError     => Some(color::RED),
                ServerError     => Some(color::BRIGHT_RED),
                NoClass         => None
            }
        }

        Format::new("[{timestamp}] @[bold]{method}@ {uri} @[bold]->@ @[C]{status}@ ({response-time})",
           vec![FunctionColor(status_color)], vec![]).unwrap()
    }
}

impl Format {
    // TODO: Document the color/attribute tags.
    /// Create a `Format` from a format string, which can contain the fields
    /// `{method}`, `{uri}`, `{status}`, `{response-time}`, `{ip-addr}` and `{timestamp}`.
    ///
    /// Returns `None` if the format string syntax is incorrect.
    ///
    /// ---
    ///
    /// Colors and attributes can also be added to the format string within `@` delimiters,
    /// by specifying them in a space-delimited list within square brackets (`[bold italic]`).
    /// They can be made dependent on the request/response by passing `FunctionColor` and
    /// `FunctionAttr`s in as the `colors` and `attrs` vecs; these colors/attributes will
    /// be used sequentially when there is a `[C]` or `[A]` marker, respectively (`[bold C]`).
    ///
    /// For example: `@[bold C]{status}@` will be formatted based upon
    /// the first FormatColor constant or function in the `colors` vector,
    /// yielding a bold and colored response status.
    ///
    /// Available colors are:
    ///
    /// - `black`
    /// - `blue`
    /// - `brightblack`
    /// - `brightblue`
    /// - `brightcyan`
    /// - `brightgreen`
    /// - `brightmagenta`
    /// - `brightred`
    /// - `brightwhite`
    /// - `brightyellow`
    /// - `cyan`
    /// - `green`
    /// - `magenta`
    /// - `red`
    /// - `white`
    /// - `yellow`
    ///
    /// Available attributes are:
    ///
    /// - `bold`
    /// - `dim`
    /// - `italic`
    /// - `underline`
    /// - `blink`
    /// - `standout`
    /// - `reverse`
    /// - `secure`
    pub fn new(s: &str, colors: Vec<FormatColor>, attrs: Vec<FormatAttr>)
            -> Option<Format> {

        let parser = FormatParser::new(s.chars().peekable(),
                                       colors.into_iter(),
                                       attrs.into_iter());

        let mut results = Vec::new();

        for unit in parser {
            match unit {
                Some(unit) => results.push(unit),
                None => return None
            }
        }

        Some(Format(results))
    }
}

struct FormatParser<'a> {
    // The characters of the format string.
    chars: Peekable<Chars<'a>>,

    // Passed-in FormatColors
    colors: IntoIter<FormatColor>,

    // Passed-in FormatAttr
    attrs: IntoIter<FormatAttr>,

    // A reusable buffer for parsing style attributes.
    object_buffer: String,

    // A queue of waiting format units to avoid full-on
    // state-machine parsing.
    waitqueue: Vec<FormatUnit>,

    finished: bool
}

impl<'a> FormatParser<'a> {
    fn new(chars: Peekable<Chars>, colors: IntoIter<FormatColor>,
           attrs: IntoIter<FormatAttr>) -> FormatParser {
        FormatParser {
            chars: chars,
            colors: colors,
            attrs: attrs,

            // No attributes are longer than 14 characters, so we can avoid reallocating.
            object_buffer: String::with_capacity(14),

            waitqueue: vec![],
            finished: false
        }
    }
}

// Some(None) means there was a parse error and this FormatParser should be abandoned.
impl<'a> Iterator for FormatParser<'a> {
    type Item = Option<FormatUnit>;

    fn next(&mut self) -> Option<Option<FormatUnit>> {
        // If the parser has been cancelled or errored for some reason.
        if self.finished { return None }

        if self.waitqueue.len() != 0 {
            return Some(Some(self.waitqueue.remove(0)));
        }

        // Try to parse a new FormatUnit.
        match self.chars.next() {
            // Parse a recognized object.
            //
            // The allowed forms are:
            //   - {method}
            //   - {uri}
            //   - {status}
            //   - {response-time}
            //   - {ip-addr}
            //   - {timestamp}
            Some('{') => {
                self.object_buffer.clear();

                let mut chr = self.chars.next();
                while chr != None {
                    match chr.unwrap() {
                        // Finished parsing, parse buffer.
                        '}' => break,
                        c => self.object_buffer.push(c.clone())
                    }

                    chr = self.chars.next();
                }

                let text = match self.object_buffer.as_ref() {
                    "method" => Method,
                    "uri" => URI,
                    "status" => Status,
                    "response-time" => ResponseTime,
                    "ip-addr" => RemoteAddr,
                    "timestamp" => TimeStamp,
                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                };

                Some(Some(FormatUnit {
                    text: text,
                    color: ConstantColor(None),
                    attrs: ConstantAttrs(vec![])
                }))
            },

            // Parse an attribute and the thing it applies to.
            //
            // The form is:
            //   - @[attributes]target@
            Some('@') => {
                match self.chars.next() {
                    // Parse attributes
                    Some('[') => {
                        let mut buffer = String::new();

                        loop {
                            match self.chars.next() {
                                // Finished parsing into buffer.
                                Some(']') => break,
                                Some(c) => buffer.push(c),
                                // Error, so mark as finished.
                                None => {
                                    self.finished = true;
                                    return Some(None);
                                }
                            }
                        }

                        let mut attrs = ConstantAttrs(vec![]);
                        let mut color = ConstantColor(None);

                        // Collect the attributes into attrs and color, for use as properties
                        // of a FormatUnit.
                        for word in buffer.split(|c: char| c.is_whitespace()) {
                            match word {
                                "A" => attrs = self.attrs.next().unwrap_or(ConstantAttrs(vec![])),

                                "C" => color = self.colors.next().unwrap_or(ConstantColor(None)),

                                style => match style.parse() {
                                    Ok(Color(c)) => match color {
                                        ConstantColor(_) => { color = ConstantColor(Some(c)); },
                                        _ => {}
                                    },

                                    Ok(Attr(a)) => match attrs {
                                        ConstantAttrs(ref mut v) => { v.push(a); },
                                        _ => {}
                                    },

                                    _ => {}
                                }
                            }
                        }

                        // Nested attributes are not supported.
                        if self.chars.peek() == Some(&'@') {
                            self.finished = true;
                            return Some(None);
                        }

                        // Now we have the parsed attributes, so we can parse what they apply to.
                        let mut apply_to = vec![];

                        loop {
                            match self.next() {
                                Some(Some(unit)) => apply_to.push(unit),
                                _ => {
                                    self.finished = true;
                                    return Some(None);
                                }
                            };

                            if self.chars.peek() == Some(&'@') {
                                // Jump over the closing '@'
                                self.chars.next();
                                break;
                            }
                        }

                        self.waitqueue.extend(apply_to.into_iter().map(|unit| {
                            FormatUnit {
                                text: unit.text,
                                color: color.clone(),
                                attrs: attrs.clone()
                            }
                        }));

                        self.next()
                    },

                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                }
            },

            // Parse a regular string part of the format string.
            Some(c) => {
                let mut buffer = String::new();
                buffer.push(c);

                loop {
                    match self.chars.peek() {
                        // Done parsing.
                        Some(&'@') | Some(&'{') | None => {
                            return Some(Some(FormatUnit {
                                text: FormatText::Str(buffer),
                                color: ConstantColor(None),
                                attrs: ConstantAttrs(vec![])
                            }))
                        },

                        Some(_) => {
                            buffer.push(self.chars.next().unwrap())
                        }
                    }
                }
            },

            // Reached end of the format string.
            None => None
        }
    }
}

impl FromStr for ColorOrAttr {
    type Err = ();

    fn from_str(name: &str) -> Result<ColorOrAttr, ()> {
        match name {
            "black" => Ok(Color(color::BLACK)),
            "blue" => Ok(Color(color::BLUE)),
            "brightblack" => Ok(Color(color::BRIGHT_BLACK)),
            "brightblue" => Ok(Color(color::BRIGHT_BLUE)),
            "brightcyan" => Ok(Color(color::BRIGHT_CYAN)),
            "brightgreen" => Ok(Color(color::BRIGHT_GREEN)),
            "brightmagenta" => Ok(Color(color::BRIGHT_MAGENTA)),
            "brightred" => Ok(Color(color::BRIGHT_RED)),
            "brightwhite" => Ok(Color(color::BRIGHT_WHITE)),
            "brightyellow" => Ok(Color(color::BRIGHT_YELLOW)),
            "cyan" => Ok(Color(color::CYAN)),
            "green" => Ok(Color(color::GREEN)),
            "magenta" => Ok(Color(color::MAGENTA)),
            "red" => Ok(Color(color::RED)),
            "white" => Ok(Color(color::WHITE)),
            "yellow" => Ok(Color(color::YELLOW)),

            "bold" => Ok(Attr(term::Attr::Bold)),
            "dim" => Ok(Attr(term::Attr::Dim)),
            "italic" => Ok(Attr(term::Attr::Italic(true))),
            "underline" => Ok(Attr(term::Attr::Underline(true))),
            "blink" => Ok(Attr(term::Attr::Blink)),
            "standout" => Ok(Attr(term::Attr::Standout(true))),
            "reverse" => Ok(Attr(term::Attr::Reverse)),
            "secure" => Ok(Attr(term::Attr::Secure)),

            _ => Err(())
        }
    }
}

enum ColorOrAttr {
    Color(color::Color),
    Attr(term::Attr)
}

/// A representation of color in a `FormatUnit`.
#[derive(Copy)]
pub enum FormatColor {
    /// A constant color
    ConstantColor(Option<color::Color>),
    /// A variable color, dependent on the request/response
    ///
    /// This can be used to change the color depending on response status, &c.
    FunctionColor(fn(&Request, &Response) -> Option<color::Color>)
}

/// A representation of attributes in a `FormatUnit`.
pub enum FormatAttr {
    /// A constant attribute
    ConstantAttrs(Vec<term::Attr>),
    /// A variable attribute, dependent on the request/response
    ///
    /// This can be used to change the attribute depending on response status, &c.
    FunctionAttrs(fn(&Request, &Response) -> Vec<term::Attr>)
}

impl Clone for FormatColor {
    fn clone(&self) -> FormatColor { *self }
}

impl Clone for FormatAttr {
    fn clone(&self) -> FormatAttr {
        match *self {
            ConstantAttrs(ref attrs) => ConstantAttrs(attrs.iter().map(|&attr| attr).collect()),
            FunctionAttrs(f) => FunctionAttrs(f)
        }
    }
}

/// A string of text to be logged. This is either one of the data
/// fields supported by the `Logger`, or a custom `String`.
#[derive(Clone)]
#[doc(hidden)]
pub enum FormatText {
    Str(String),
    Method,
    URI,
    Status,
    ResponseTime,
    RemoteAddr,
    TimeStamp
}

/// A `FormatText` with associated style information.
#[derive(Clone)]
#[doc(hidden)]
pub struct FormatUnit {
    pub text: FormatText,
    pub color: FormatColor,
    pub attrs: FormatAttr
}
<|endoftext|>


<commit_before>//! # CloneCell
//!
//! Variant of std::rc::Cell that works using cloning instead of copying.

use std::cell::*;

pub struct CloneCell<TContentType> {
    content: UnsafeCell<TContentType>
}

impl<TContentType:Clone> CloneCell<TContentType> {
    #[inline]
    pub fn new(value: TContentType) -> CloneCell<TContentType> {
        CloneCell { content: UnsafeCell::new(value.to_owned()) }
    }

    #[inline]
    pub fn get(&self) -> TContentType {
        unsafe { (*self.content.get()).to_owned() }
    }

    #[inline]
    pub fn set(&self, new_value: TContentType) {
        unsafe { *self.content.get() = new_value.to_owned() }
    }
}

impl<TContentType:Clone> Clone for CloneCell<TContentType> {
    fn clone(&self) -> CloneCell<TContentType> {
        CloneCell::new(self.get())
    }
}

#[cfg(test)]
mod clonecell_tests {
    use std::rc::*;
    use std::cell::*;
    use super::*;

    // This would be much easier to test if it was possible to read out the reference count for Rc (we could check it's behaving as expected)
    // However, that feature is considered 'not clearly useful' so we have to reimplement everything to make sure that reference counts
    // get updated properly.

    #[derive(Copy, Clone)]
    struct RefCount {
        count: i32
    }

    type RefCountRef = Rc<Cell<RefCount>>;

    impl RefCount {
        fn new() -> RefCount {
            RefCount { count: 0 }
        }

        fn inc(&self) -> RefCount {
            RefCount {  count: self.count+1 }
        }

        fn dec(&self) -> RefCount {
            RefCount { count: self.count-1 }
        }

        fn get(&self) -> i32 {
            self.count
        }
    }

    struct Droppable {
        counter: RefCountRef
    }

    impl Drop for Droppable {
        fn drop(&mut self) {
            (*self.counter).set(self.counter.get().dec());
        }
    }

    impl Clone for Droppable {
        fn clone(&self) -> Droppable {
            (*self.counter).set(self.counter.get().inc());
            Droppable { counter: self.counter.clone() }
        }
    }

    impl Droppable {
        fn new(counter: &RefCountRef) -> Droppable {
            (*counter).set((*counter).get().inc());
            Droppable { counter: counter.clone() }
        }
    }

    #[test]
    fn clonecell_update_rc() {
        let ref_count = Rc::new(Cell::new(RefCount::new()));
        let ref_count2 = Rc::new(Cell::new(RefCount::new()));

        assert!(ref_count.get().get() == 0);
        assert!(ref_count2.get().get() == 0);

        {
            let rc_standin = Droppable::new(&ref_count);

            assert!(ref_count.get().get() == 1);

            let arefcell = CloneCell::new(rc_standin.clone());
            assert!(ref_count.get().get() == 2);

            let rc_standin2 = Droppable::new(&ref_count2);

            assert!(ref_count2.get().get() == 1);

            arefcell.set(rc_standin2.clone());
            assert!(ref_count2.get().get() == 2);
            assert!(ref_count.get().get() == 1);
        }

        assert!(ref_count.get().get() == 0);
        assert!(ref_count2.get().get() == 0);
    }
}
<commit_msg>Add some docs for CloneCell<commit_after>//! # CloneCell
//!
//! Variant of std::rc::Cell that works using cloning instead of copying.

use std::cell::*;

///
/// CloneCell<T> is a variant of Cell<T> that works by cloning its content rather than copying it.
///
/// Mainly designed to allow for creating CloneCell<Rc<T>> objects, which are very useful for creating
/// graphs and trees without the need for runtime checking that RefCell<Rc<T>> would add in. Performance
/// is probably a wash for this reason: using CloneCell updates the reference count, but using RefCell
/// adds the overhead of checking and updating the usage count.
///
pub struct CloneCell<TContentType> {
    content: UnsafeCell<TContentType>
}

impl<TContentType:Clone> CloneCell<TContentType> {
    #[inline]
    pub fn new(value: TContentType) -> CloneCell<TContentType> {
        CloneCell { content: UnsafeCell::new(value.to_owned()) }
    }

    #[inline]
    pub fn get(&self) -> TContentType {
        unsafe { (*self.content.get()).to_owned() }
    }

    #[inline]
    pub fn set(&self, new_value: TContentType) {
        unsafe { *self.content.get() = new_value.to_owned() }
    }
}

impl<TContentType:Clone> Clone for CloneCell<TContentType> {
    fn clone(&self) -> CloneCell<TContentType> {
        CloneCell::new(self.get())
    }
}

#[cfg(test)]
mod clonecell_tests {
    use std::rc::*;
    use std::cell::*;
    use super::*;

    // This would be much easier to test if it was possible to read out the reference count for Rc (we could check it's behaving as expected)
    // However, that feature is considered 'not clearly useful' so we have to reimplement everything to make sure that reference counts
    // get updated properly.

    #[derive(Copy, Clone)]
    struct RefCount {
        count: i32
    }

    type RefCountRef = Rc<Cell<RefCount>>;

    impl RefCount {
        fn new() -> RefCount {
            RefCount { count: 0 }
        }

        fn inc(&self) -> RefCount {
            RefCount {  count: self.count+1 }
        }

        fn dec(&self) -> RefCount {
            RefCount { count: self.count-1 }
        }

        fn get(&self) -> i32 {
            self.count
        }
    }

    struct Droppable {
        counter: RefCountRef
    }

    impl Drop for Droppable {
        fn drop(&mut self) {
            (*self.counter).set(self.counter.get().dec());
        }
    }

    impl Clone for Droppable {
        fn clone(&self) -> Droppable {
            (*self.counter).set(self.counter.get().inc());
            Droppable { counter: self.counter.clone() }
        }
    }

    impl Droppable {
        fn new(counter: &RefCountRef) -> Droppable {
            (*counter).set((*counter).get().inc());
            Droppable { counter: counter.clone() }
        }
    }

    #[test]
    fn clonecell_update_rc() {
        let ref_count = Rc::new(Cell::new(RefCount::new()));
        let ref_count2 = Rc::new(Cell::new(RefCount::new()));

        assert!(ref_count.get().get() == 0);
        assert!(ref_count2.get().get() == 0);

        {
            let rc_standin = Droppable::new(&ref_count);

            assert!(ref_count.get().get() == 1);

            let arefcell = CloneCell::new(rc_standin.clone());
            assert!(ref_count.get().get() == 2);

            let rc_standin2 = Droppable::new(&ref_count2);

            assert!(ref_count2.get().get() == 1);

            arefcell.set(rc_standin2.clone());
            assert!(ref_count2.get().get() == 2);
            assert!(ref_count.get().get() == 1);
        }

        assert!(ref_count.get().get() == 0);
        assert!(ref_count2.get().get() == 0);
    }
}
<|endoftext|>


<commit_before>// Brief implementation of the 'node-google'
// node.js package.
use std::io::Read;

use super::hyper::Client;
use super::hyper::header::Connection;

use super::select::document::Document;
use super::select::predicate::Class;
use super::select::predicate::Name;
use super::select::predicate::And;

use super::regex::Regex;

#[derive(Debug)]
pub struct GoogleResult {
    pub link: String,
}

impl GoogleResult {
    pub fn new(link: &str) -> Self {
        GoogleResult { link: String::from(link) }
    }
}

#[derive(Debug)]
pub struct Google {
    per_page: usize,
    client: Client,
}

impl Default for Google {
    fn default() -> Self {
        Google {
            per_page: 10,
            client: Client::new(),
        }
    }
}

impl Google {
    pub fn new(results_per_page: usize) -> Self {
        let mut per_page = results_per_page;
        if per_page > 100 {
            per_page = 100;
        }

        Google {
            per_page: per_page,
            client: Client::new(),
        }
    }

    pub fn google(&self, query: &str) -> Vec<GoogleResult> {
        let body = self.request(query);
        self.get_links(&body)
    }

    fn request(&self, query: &str) -> String {
        let url = format!("https://www.google.\
                           com/search?hl=en&q={}&start=0&sa=N&num={}&ie=UTF-8&oe=UTF-8&gws_rd=ssl",
                          query,
                          self.per_page);

        let mut res = self.client
                          .get(&url)
                          .header(Connection::close())
                          .send()
                          .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }

    fn get_links(&self, body: &str) -> Vec<GoogleResult> {
        let doc = Document::from(body);

        let item_selector = And(Name("div"), Class("g"));
        let link_container_selector = And(Name("h3"), Class("r"));
        let link_selector = Name("a");
        let cleaning_regex = Regex::new(r"(/url\?q=)(?P<link>.*)&(sa=.*&?)(ved=.*&?)(usg=.*&?)")
                                 .unwrap();

        let mut results = Vec::new();

        for item in doc.find(item_selector).iter().take(self.per_page) {
            let link_container;
            match item.find(link_container_selector).first() {
                Some(container) => {
                    link_container = container;
                }
                None => {
                    continue;
                }
            };

            let link_node = link_container.find(link_selector).first().unwrap();
            let link_href = link_node.attr("href").unwrap();

            if link_href.contains("/search?q=") {
                continue;
            }

            let clean_link = cleaning_regex.captures(&link_href)
                                           .unwrap()
                                           .name("link")
                                           .unwrap();

            results.push(GoogleResult::new(&clean_link));
        }

        results
    }
}
<commit_msg>Removed unused code.<commit_after>// Brief implementation of the 'node-google'
// node.js package.
use std::io::Read;

use super::hyper::Client;
use super::hyper::header::Connection;

use super::select::document::Document;
use super::select::predicate::Class;
use super::select::predicate::Name;
use super::select::predicate::And;

use super::regex::Regex;

#[derive(Debug)]
pub struct GoogleResult {
    pub link: String,
}

impl GoogleResult {
    pub fn new(link: &str) -> Self {
        GoogleResult { link: String::from(link) }
    }
}

#[derive(Debug)]
pub struct Google {
    per_page: usize,
    client: Client,
}

impl Default for Google {
    fn default() -> Self {
        Google {
            per_page: 10,
            client: Client::new(),
        }
    }
}

impl Google {
    pub fn google(&self, query: &str) -> Vec<GoogleResult> {
        let body = self.request(query);
        self.get_links(&body)
    }

    fn request(&self, query: &str) -> String {
        let url = format!("https://www.google.\
                           com/search?hl=en&q={}&start=0&sa=N&num={}&ie=UTF-8&oe=UTF-8&gws_rd=ssl",
                          query,
                          self.per_page);

        let mut res = self.client
                          .get(&url)
                          .header(Connection::close())
                          .send()
                          .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }

    fn get_links(&self, body: &str) -> Vec<GoogleResult> {
        let doc = Document::from(body);

        let item_selector = And(Name("div"), Class("g"));
        let link_container_selector = And(Name("h3"), Class("r"));
        let link_selector = Name("a");
        let cleaning_regex = Regex::new(r"(/url\?q=)(?P<link>.*)&(sa=.*&?)(ved=.*&?)(usg=.*&?)")
                                 .unwrap();

        let mut results = Vec::new();

        for item in doc.find(item_selector).iter().take(self.per_page) {
            let link_container;
            match item.find(link_container_selector).first() {
                Some(container) => {
                    link_container = container;
                }
                None => {
                    continue;
                }
            };

            let link_node = link_container.find(link_selector).first().unwrap();
            let link_href = link_node.attr("href").unwrap();

            if link_href.contains("/search?q=") {
                continue;
            }

            let clean_link = cleaning_regex.captures(&link_href)
                                           .unwrap()
                                           .name("link")
                                           .unwrap();

            results.push(GoogleResult::new(&clean_link));
        }

        results
    }
}
<|endoftext|>


<commit_before>//! Int array virtual table.
use std::cell::RefCell;
use std::default::Default;
use std::mem;
use std::rc::Rc;
use libc;

use {Connection, Error, Result};
use ffi;
use vtab::{declare_vtab, escape_double_quote, VTab, VTabCursor};

/// Create a specific instance of an intarray object.
/// The new intarray object is returned.
///
/// Each intarray object corresponds to a virtual table in the TEMP table
/// with the specified `name`.
pub fn create_int_array(conn: &Connection, name: &str) -> Result<Rc<RefCell<Vec<i64>>>> {
    let array = Rc::new(RefCell::new(Vec::new()));
    try!(conn.create_module(name, &INT_ARRAY_MODULE, Some(array.clone())));
    try!(conn.execute_batch(&format!("CREATE VIRTUAL TABLE temp.\"{0}\" USING \"{0}\"",
                                     escape_double_quote(name))));
    Ok(array)
}

/// Destroy the intarray object by dropping the virtual table.
/// If not done explicitly by the application, the virtual table will be dropped implicitly
/// by the system when the database connection is closed.
pub fn drop_int_array(conn: &Connection, name: &str) -> Result<()> {
    conn.execute_batch(&format!("DROP TABLE temp.\"{0}\"", escape_double_quote(name)))
}

init_module!(INT_ARRAY_MODULE,
             IntArrayVTab,
             IntArrayVTabCursor,
             int_array_create,
             int_array_best_index,
             int_array_destroy,
             int_array_open,
             int_array_close,
             int_array_filter,
             int_array_next,
             int_array_eof,
             int_array_column,
             int_array_rowid);

#[repr(C)]
struct IntArrayVTab {
    /// Base class
    base: ffi::sqlite3_vtab,
    array: *const Rc<RefCell<Vec<i64>>>,
}

impl VTab<IntArrayVTabCursor> for IntArrayVTab {
    fn create(db: *mut ffi::sqlite3,
              aux: *mut libc::c_void,
              _args: &[*const libc::c_char])
              -> Result<IntArrayVTab> {
        let array = unsafe { mem::transmute(aux) };
        let vtab = IntArrayVTab {
            base: Default::default(),
            array: array,
        };
        try!(declare_vtab(db, "CREATE TABLE x(value INTEGER PRIMARY KEY)"));
        Ok(vtab)
    }

    fn best_index(&self, _info: *mut ffi::sqlite3_index_info) {}

    fn open(&self) -> Result<IntArrayVTabCursor> {
        Ok(IntArrayVTabCursor::new())
    }
}

#[derive(Default)]
#[repr(C)]
struct IntArrayVTabCursor {
    /// Base class
    base: ffi::sqlite3_vtab_cursor,
    /// Current cursor position
    i: usize,
}

impl IntArrayVTabCursor {
    fn new() -> IntArrayVTabCursor {
        IntArrayVTabCursor {
            base: Default::default(),
            i: 0,
        }
    }
}

impl VTabCursor<IntArrayVTab> for IntArrayVTabCursor {
    fn vtab(&self) -> &mut IntArrayVTab {
        unsafe { &mut *(self.base.pVtab as *mut IntArrayVTab) }
    }
    fn filter(&mut self,
              _idx_num: libc::c_int,
              _idx_str: *const libc::c_char,
              _argc: libc::c_int,
              _argv: *mut *mut ffi::sqlite3_value)
              -> Result<()> {
        self.i = 0;
        Ok(())
    }
    fn next(&mut self) -> Result<()> {
        self.i = self.i + 1;
        Ok(())
    }
    fn eof(&self) -> bool {
        let vtab = self.vtab();
        unsafe {
            let array = (*vtab.array).borrow();
            self.i >= array.len()
        }
    }
    fn column(&self, ctx: *mut ffi::sqlite3_context, _i: libc::c_int) -> Result<()> {
        use functions::ToResult;
        let vtab = self.vtab();
        unsafe {
            let array = (*vtab.array).borrow();
            array[self.i].set_result(ctx);
        }
        Ok(())
    }
    fn rowid(&self) -> Result<i64> {
        Ok(self.i as i64)
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use vtab::int_array;

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_int_array_module() {
        let db = Connection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE t1 (x INT);
                INSERT INTO t1 VALUES (1);
                INSERT INTO t1 VALUES (3);
                CREATE TABLE t2 (y INT);
                INSERT INTO t2 VALUES (11);
                CREATE TABLE t3 (z INT);
                INSERT INTO t3 VALUES (-5);").unwrap();
        let p1 = int_array::create_int_array(&db, "ex1").unwrap();
        let p2 = int_array::create_int_array(&db, "ex2").unwrap();
        let p3 = int_array::create_int_array(&db, "ex3").unwrap();

        let mut s = db.prepare("SELECT * FROM t1, t2, t3
                WHERE t1.x IN ex1
                AND t2.y IN ex2
                AND t3.z IN ex3").unwrap();

        p1.borrow_mut().append(&mut vec![1, 2, 3, 4]);
        p2.borrow_mut().append(&mut vec![5, 6, 7, 8, 9, 10, 11]);
        p3.borrow_mut().append(&mut vec![-1, -5, -10]);

        {
            let rows = s.query(&[]).unwrap();
            for row in rows {
                let row = row.unwrap();
                let i1: i64 = row.get(0);
                assert!(i1 == 1 || i1 == 3);
                assert_eq!(11, row.get(1));
                assert_eq!(-5, row.get(2));
            }
        }

        s.reset_if_needed();
        p1.borrow_mut().clear();
        p2.borrow_mut().clear();
        p3.borrow_mut().clear();
        p1.borrow_mut().append(&mut vec![1]);
        p2.borrow_mut().append(&mut vec![7, 11]);
        p3.borrow_mut().append(&mut vec![-5, -10]);

        {
            let row = s.query(&[]).unwrap().next().unwrap().unwrap();
            assert_eq!(1, row.get(0));
            assert_eq!(11, row.get(1));
            assert_eq!(-5, row.get(2));
        }

        s.reset_if_needed();
        p2.borrow_mut().clear();
        p3.borrow_mut().clear();
        p2.borrow_mut().append(&mut vec![3, 4, 5]);
        p3.borrow_mut().append(&mut vec![0, -5]);
        assert!(s.query(&[]).unwrap().next().is_none());

        int_array::drop_int_array(&db, "ex1").unwrap();
        int_array::drop_int_array(&db, "ex2").unwrap();
        int_array::drop_int_array(&db, "ex3").unwrap();
    }
}
<commit_msg>SQLite Modules cannot be destroyed.<commit_after>//! Int array virtual table.
use std::cell::RefCell;
use std::default::Default;
use std::mem;
use std::rc::Rc;
use libc;

use {Connection, Error, Result};
use ffi;
use vtab::{declare_vtab, escape_double_quote, VTab, VTabCursor};

/// Create a specific instance of an intarray object.
/// The new intarray object is returned.
///
/// Each intarray object corresponds to a virtual table in the TEMP table
/// with the specified `name`.
pub fn create_int_array(conn: &Connection, name: &str) -> Result<Rc<RefCell<Vec<i64>>>> {
    let array = Rc::new(RefCell::new(Vec::new()));
    try!(conn.create_module(name, &INT_ARRAY_MODULE, Some(array.clone())));
    try!(conn.execute_batch(&format!("CREATE VIRTUAL TABLE temp.\"{0}\" USING \"{0}\"",
                                     escape_double_quote(name))));
    Ok(array)
}

/// Destroy the intarray object by dropping the virtual table.
/// If not done explicitly by the application, the virtual table will be dropped implicitly
/// by the system when the database connection is closed.
/// In fact, the intarray is not destroy until the connection is closed
/// because there is no other way to destroy the associated module.
pub fn drop_int_array(conn: &Connection, name: &str) -> Result<()> {
    conn.execute_batch(&format!("DROP TABLE temp.\"{0}\"", escape_double_quote(name)))
    // http://www.mail-archive.com/sqlite-users%40mailinglists.sqlite.org/msg08423.html
    // "Once a virtual table module has been created, it cannot be modified or destroyed, except by closing the database connection."
    /*let aux: Option<()> = None;
    conn.create_module(name, ptr::null() as *const ffi::sqlite3_module, aux)*/
}

init_module!(INT_ARRAY_MODULE,
             IntArrayVTab,
             IntArrayVTabCursor,
             int_array_create,
             int_array_best_index,
             int_array_destroy,
             int_array_open,
             int_array_close,
             int_array_filter,
             int_array_next,
             int_array_eof,
             int_array_column,
             int_array_rowid);

#[repr(C)]
struct IntArrayVTab {
    /// Base class
    base: ffi::sqlite3_vtab,
    array: *const Rc<RefCell<Vec<i64>>>,
}

impl VTab<IntArrayVTabCursor> for IntArrayVTab {
    fn create(db: *mut ffi::sqlite3,
              aux: *mut libc::c_void,
              _args: &[*const libc::c_char])
              -> Result<IntArrayVTab> {
        let array = unsafe { mem::transmute(aux) };
        let vtab = IntArrayVTab {
            base: Default::default(),
            array: array,
        };
        try!(declare_vtab(db, "CREATE TABLE x(value INTEGER PRIMARY KEY)"));
        Ok(vtab)
    }

    fn best_index(&self, _info: *mut ffi::sqlite3_index_info) {}

    fn open(&self) -> Result<IntArrayVTabCursor> {
        Ok(IntArrayVTabCursor::new())
    }
}

#[derive(Default)]
#[repr(C)]
struct IntArrayVTabCursor {
    /// Base class
    base: ffi::sqlite3_vtab_cursor,
    /// Current cursor position
    i: usize,
}

impl IntArrayVTabCursor {
    fn new() -> IntArrayVTabCursor {
        IntArrayVTabCursor {
            base: Default::default(),
            i: 0,
        }
    }
}

impl VTabCursor<IntArrayVTab> for IntArrayVTabCursor {
    fn vtab(&self) -> &mut IntArrayVTab {
        unsafe { &mut *(self.base.pVtab as *mut IntArrayVTab) }
    }
    fn filter(&mut self,
              _idx_num: libc::c_int,
              _idx_str: *const libc::c_char,
              _argc: libc::c_int,
              _argv: *mut *mut ffi::sqlite3_value)
              -> Result<()> {
        self.i = 0;
        Ok(())
    }
    fn next(&mut self) -> Result<()> {
        self.i = self.i + 1;
        Ok(())
    }
    fn eof(&self) -> bool {
        let vtab = self.vtab();
        unsafe {
            let array = (*vtab.array).borrow();
            self.i >= array.len()
        }
    }
    fn column(&self, ctx: *mut ffi::sqlite3_context, _i: libc::c_int) -> Result<()> {
        use functions::ToResult;
        let vtab = self.vtab();
        unsafe {
            let array = (*vtab.array).borrow();
            array[self.i].set_result(ctx);
        }
        Ok(())
    }
    fn rowid(&self) -> Result<i64> {
        Ok(self.i as i64)
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use vtab::int_array;

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_int_array_module() {
        let db = Connection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE t1 (x INT);
                INSERT INTO t1 VALUES (1);
                INSERT INTO t1 VALUES (3);
                CREATE TABLE t2 (y INT);
                INSERT INTO t2 VALUES (11);
                CREATE TABLE t3 (z INT);
                INSERT INTO t3 VALUES (-5);").unwrap();
        let p1 = int_array::create_int_array(&db, "ex1").unwrap();
        let p2 = int_array::create_int_array(&db, "ex2").unwrap();
        let p3 = int_array::create_int_array(&db, "ex3").unwrap();

        let mut s = db.prepare("SELECT * FROM t1, t2, t3
                WHERE t1.x IN ex1
                AND t2.y IN ex2
                AND t3.z IN ex3").unwrap();

        p1.borrow_mut().append(&mut vec![1, 2, 3, 4]);
        p2.borrow_mut().append(&mut vec![5, 6, 7, 8, 9, 10, 11]);
        p3.borrow_mut().append(&mut vec![-1, -5, -10]);

        {
            let rows = s.query(&[]).unwrap();
            for row in rows {
                let row = row.unwrap();
                let i1: i64 = row.get(0);
                assert!(i1 == 1 || i1 == 3);
                assert_eq!(11, row.get(1));
                assert_eq!(-5, row.get(2));
            }
        }

        s.reset_if_needed();
        p1.borrow_mut().clear();
        p2.borrow_mut().clear();
        p3.borrow_mut().clear();
        p1.borrow_mut().append(&mut vec![1]);
        p2.borrow_mut().append(&mut vec![7, 11]);
        p3.borrow_mut().append(&mut vec![-5, -10]);

        {
            let row = s.query(&[]).unwrap().next().unwrap().unwrap();
            assert_eq!(1, row.get(0));
            assert_eq!(11, row.get(1));
            assert_eq!(-5, row.get(2));
        }

        s.reset_if_needed();
        p2.borrow_mut().clear();
        p3.borrow_mut().clear();
        p2.borrow_mut().append(&mut vec![3, 4, 5]);
        p3.borrow_mut().append(&mut vec![0, -5]);
        assert!(s.query(&[]).unwrap().next().is_none());

        int_array::drop_int_array(&db, "ex1").unwrap();
        int_array::drop_int_array(&db, "ex2").unwrap();
        int_array::drop_int_array(&db, "ex3").unwrap();
    }
}
<|endoftext|>