<commit_before>use block::ConcreteBlock;
use cocoa::base::{id, nil};
use cocoa::foundation::{NSString, NSUInteger};
use error::NSError;
use objc::runtime::YES;
use objc_bringup::NSArray;
use sys::{MTLCopyAllDevices, MTLCreateSystemDefaultDevice, MTLDevice};
use std::borrow::Cow;
use std::convert::From;
use std::error::Error;
use std::ffi::CStr;
use std::fmt::{self, Display, Formatter};
use std::path::Path;
use std::sync::mpsc;
use sys::MTLFeatureSet;
use {AsRaw, Buffer, CommandQueue, CommandQueueError, CompileOptions, DepthStencilState,
     DepthStencilStateDescriptor, FromRaw, FromRawError, Library, LibraryError, ResourceOptions,
     Size, Texture, TextureDescriptor};

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, DeviceError> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil { Ok(Device(device)) } else { Err(DeviceError::ConstructionFailed) }
    }

    pub fn enumerate_all_system_devices() -> Vec<Result<Self, DeviceError>> {
        let all_devices = unsafe { MTLCopyAllDevices() };
        let mut devices_vec = vec![];

        unsafe {
            for i in 0..all_devices.count() {
                let device = all_devices.objectAtIndex(i);
                if device != nil {
                    devices_vec.push(Ok(Device(device)));
                } else {
                    devices_vec.push(Err(DeviceError::ConstructionFailed));
                }
            }
        }

        devices_vec
    }

    pub fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
        unsafe { self.0.depth24Stencil8PixelFormatSupported() == YES }
    }

    pub fn is_headless(&self) -> bool {
        unsafe { self.0.headless() == YES }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() == YES }
    }

    pub fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    pub fn name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    pub fn supports_feature_set(&self, feature_set: FeatureSet) -> bool {
        unsafe { self.0.supportsFeatureSet(feature_set.into()) == YES }
    }

    pub fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) == YES }
    }

    pub fn new_command_queue(&mut self) -> Result<CommandQueue, CommandQueueError> {
        let command_queue = unsafe { self.0.newCommandQueue() };
        Ok(try!(FromRaw::from_raw(command_queue)))
    }

    pub fn new_command_queue_with_max_buffer_count(&mut self, max_command_buffer_count: usize)
                                                   -> Result<CommandQueue, CommandQueueError> {
        let command_queue = unsafe {
            self.0.newCommandQueueWithMaxCommandBufferCount(max_command_buffer_count as NSUInteger)
        };
        Ok(try!(FromRaw::from_raw(command_queue)))
    }

    // TODO(George): This will panic in the metal lib if not called from a binary in a bundle. Need
    // to add proper error checking
    pub fn new_default_library(&mut self) -> Result<Library, LibraryError> {
        unsafe {
            let library = self.0.newDefaultLibrary();
            Ok(try!(FromRaw::from_raw(library)))
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn new_library_with_file(&mut self, file_path: &Path) -> Result<Library, LibraryError> {
        unsafe {
            let path_string = match file_path.as_os_str().to_str() {
                None => unimplemented!(),
                Some(s) => s
            };
            let path = NSString::alloc(nil).init_str(path_string);
            let mut error = nil;
            let library = self.0.newLibraryWithFile_error(path, &mut error);
            if library == nil {
                Err(LibraryError::from(NSError::new(error)))
            } else {
                Ok(try!(FromRaw::from_raw(library)))
            }
        }
    }

    pub fn new_library_with_source(&mut self, source: &str, compile_options: &CompileOptions)
                                   -> Result<Library, LibraryError> {
        unsafe {
            let source = NSString::alloc(nil).init_str(source);
            let options = compile_options.mtl_compile_options();
            let mut error = nil;
            let library = self.0.newLibraryWithSource_options_error(source, options, &mut error);
            if library == nil {
                Err(LibraryError::from(NSError::new(error)))
            } else {
                Ok(try!(FromRaw::from_raw(library)))
            }
        }
    }

    pub fn new_library_with_source_async(&mut self, source: &str, compile_options: &CompileOptions)
                                         -> mpsc::Receiver<Result<Library, LibraryError>> {
        unsafe {
            let source = NSString::alloc(nil).init_str(source);
            let options = compile_options.mtl_compile_options();
            let (sender, receiver) = mpsc::channel();
            let block = ConcreteBlock::new(move |lib, err| {
                if lib != nil {
                    match FromRaw::from_raw(lib) {
                        Ok(library) => sender.send(Ok(library)).unwrap(),
                        Err(e) => sender.send(Err(LibraryError::from(e))).unwrap(),
                    }
                } else {
                    sender.send(Err(LibraryError::from(NSError::new(err)))).unwrap();
                }
            });
            self.0.newLibraryWithSource_options_completionHandler(source, options, &block.copy());
            receiver
        }
    }

    #[allow(unused_variables)]
    // TODO(burtonageo): `data` parameter should be of the correct type
    pub fn new_library_with_data(&mut self, data: ()) -> Result<Library, LibraryError> {
        unimplemented!();
    }

    pub fn new_buffer_with_length(&mut self, length: usize, options: ResourceOptions) -> Buffer {
        unsafe {
            FromRaw::from_raw(self.0.newBufferWithLength_options(length as NSUInteger,
                                                                 options.into()))
                .unwrap()
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn new_buffer_with_bytes(&mut self, bytes: &[u8], options: ResourceOptions)
                                 -> Buffer {
        let len = bytes.len() as NSUInteger;
        let bytes = bytes.as_ptr() as *const _;
        unsafe {
            FromRaw::from_raw(self.0.newBufferWithBytes_length_options(bytes, len, options.into())).unwrap()
        }
    }

    #[allow(unused_variables)]
    pub fn new_buffer_with_byes_no_copy<B, I>(&mut self, bytes: Vec<u8>, options: ResourceOptions)
                                              -> Buffer {
        unimplemented!();
    }

    pub fn new_texture(&mut self, descriptor: &TextureDescriptor) -> Result<Texture, FromRawError> {
        unsafe { FromRaw::from_raw(self.0.newTextureWithDescriptor(*descriptor.as_raw())) }
    }

    #[allow(unused_variables)]
    // TODO(burtonageo): Model types correctly
    pub fn new_sampler_state(&mut self, descriptor: ()) -> ! {
        unimplemented!();
    }

    #[allow(unused_variables)]
    pub fn new_depth_stencil_state(&mut self, descriptor: &DepthStencilStateDescriptor)
                                   -> Result<DepthStencilState, FromRawError> {
        unimplemented!();
    }
}

impl_from_into_raw!(Device, of protocol "MTLDevice");

#[cfg(target_os = "ios")]
convertible_enum! {
    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum FeatureSet: MTLFeatureSet {
        iOSGpuFamily1_v1 => MTLFeatureSet_iOS_GPUFamily1_v1,
        iOSGpuFamily2_v1 => MTLFeatureSet_iOS_GPUFamily2_v1,
        iOSGpuFamily1_v2 => MTLFeatureSet_iOS_GPUFamily1_v2,
        iOSGpuFamily2_v2 => MTLFeatureSet_iOS_GPUFamily2_v2,
        iOSGpuFamily3_v1 => MTLFeatureSet_iOS_GPUFamily3_v1
    }
}

#[cfg(target_os = "macos")]
convertible_enum! {
    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum FeatureSet: MTLFeatureSet {
        OsxGpuFamily1_v1 => MTLFeatureSet_OSX_GPUFamily1_v1,
        _non_unary_compile_dummy => _non_unary_compile_dummy
    }
}

#[derive(Clone, Debug)]
pub enum DeviceError {
    ConstructionFailed,
    RawError(FromRawError)
}

impl From<FromRawError> for DeviceError {
    fn from(error: FromRawError) -> Self {
        DeviceError::RawError(error)
    }
}

impl Display for DeviceError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let descr = match *self {
            DeviceError::ConstructionFailed => "DeviceError::ConstructionFailed",
            DeviceError::RawError(_) => "DeviceError::ConstructionFailed",
        };
        write!(f, "{}", descr)
    }
}

impl Error for DeviceError {
    fn description(&self) -> &str {
        match *self {
            DeviceError::ConstructionFailed => {
                "Could not create a default device. Please ensure that you are using at least OSX \
                 10.11 or iOS 8.0"
            }
            DeviceError::RawError(_) => "There was an error with the device pointer",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &DeviceError::ConstructionFailed => None,
            &DeviceError::RawError(ref raw_err) => Some(raw_err),
        }
    }
}
<commit_msg>Fix typo<commit_after>use block::ConcreteBlock;
use cocoa::base::{id, nil};
use cocoa::foundation::{NSString, NSUInteger};
use error::NSError;
use objc::runtime::YES;
use objc_bringup::NSArray;
use sys::{MTLCopyAllDevices, MTLCreateSystemDefaultDevice, MTLDevice};
use std::borrow::Cow;
use std::convert::From;
use std::error::Error;
use std::ffi::CStr;
use std::fmt::{self, Display, Formatter};
use std::path::Path;
use std::sync::mpsc;
use sys::MTLFeatureSet;
use {AsRaw, Buffer, CommandQueue, CommandQueueError, CompileOptions, DepthStencilState,
     DepthStencilStateDescriptor, FromRaw, FromRawError, Library, LibraryError, ResourceOptions,
     Size, Texture, TextureDescriptor};

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, DeviceError> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil { Ok(Device(device)) } else { Err(DeviceError::ConstructionFailed) }
    }

    pub fn enumerate_all_system_devices() -> Vec<Result<Self, DeviceError>> {
        let all_devices = unsafe { MTLCopyAllDevices() };
        let mut devices_vec = vec![];

        unsafe {
            for i in 0..all_devices.count() {
                let device = all_devices.objectAtIndex(i);
                if device != nil {
                    devices_vec.push(Ok(Device(device)));
                } else {
                    devices_vec.push(Err(DeviceError::ConstructionFailed));
                }
            }
        }

        devices_vec
    }

    pub fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
        unsafe { self.0.depth24Stencil8PixelFormatSupported() == YES }
    }

    pub fn is_headless(&self) -> bool {
        unsafe { self.0.headless() == YES }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() == YES }
    }

    pub fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    pub fn name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    pub fn supports_feature_set(&self, feature_set: FeatureSet) -> bool {
        unsafe { self.0.supportsFeatureSet(feature_set.into()) == YES }
    }

    pub fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) == YES }
    }

    pub fn new_command_queue(&mut self) -> Result<CommandQueue, CommandQueueError> {
        let command_queue = unsafe { self.0.newCommandQueue() };
        Ok(try!(FromRaw::from_raw(command_queue)))
    }

    pub fn new_command_queue_with_max_buffer_count(&mut self, max_command_buffer_count: usize)
                                                   -> Result<CommandQueue, CommandQueueError> {
        let command_queue = unsafe {
            self.0.newCommandQueueWithMaxCommandBufferCount(max_command_buffer_count as NSUInteger)
        };
        Ok(try!(FromRaw::from_raw(command_queue)))
    }

    // TODO(George): This will panic in the metal lib if not called from a binary in a bundle. Need
    // to add proper error checking
    pub fn new_default_library(&mut self) -> Result<Library, LibraryError> {
        unsafe {
            let library = self.0.newDefaultLibrary();
            Ok(try!(FromRaw::from_raw(library)))
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn new_library_with_file(&mut self, file_path: &Path) -> Result<Library, LibraryError> {
        unsafe {
            let path_string = match file_path.as_os_str().to_str() {
                None => unimplemented!(),
                Some(s) => s
            };
            let path = NSString::alloc(nil).init_str(path_string);
            let mut error = nil;
            let library = self.0.newLibraryWithFile_error(path, &mut error);
            if library == nil {
                Err(LibraryError::from(NSError::new(error)))
            } else {
                Ok(try!(FromRaw::from_raw(library)))
            }
        }
    }

    pub fn new_library_with_source(&mut self, source: &str, compile_options: &CompileOptions)
                                   -> Result<Library, LibraryError> {
        unsafe {
            let source = NSString::alloc(nil).init_str(source);
            let options = compile_options.mtl_compile_options();
            let mut error = nil;
            let library = self.0.newLibraryWithSource_options_error(source, options, &mut error);
            if library == nil {
                Err(LibraryError::from(NSError::new(error)))
            } else {
                Ok(try!(FromRaw::from_raw(library)))
            }
        }
    }

    pub fn new_library_with_source_async(&mut self, source: &str, compile_options: &CompileOptions)
                                         -> mpsc::Receiver<Result<Library, LibraryError>> {
        unsafe {
            let source = NSString::alloc(nil).init_str(source);
            let options = compile_options.mtl_compile_options();
            let (sender, receiver) = mpsc::channel();
            let block = ConcreteBlock::new(move |lib, err| {
                if lib != nil {
                    match FromRaw::from_raw(lib) {
                        Ok(library) => sender.send(Ok(library)).unwrap(),
                        Err(e) => sender.send(Err(LibraryError::from(e))).unwrap(),
                    }
                } else {
                    sender.send(Err(LibraryError::from(NSError::new(err)))).unwrap();
                }
            });
            self.0.newLibraryWithSource_options_completionHandler(source, options, &block.copy());
            receiver
        }
    }

    #[allow(unused_variables)]
    // TODO(burtonageo): `data` parameter should be of the correct type
    pub fn new_library_with_data(&mut self, data: ()) -> Result<Library, LibraryError> {
        unimplemented!();
    }

    pub fn new_buffer_with_length(&mut self, length: usize, options: ResourceOptions) -> Buffer {
        unsafe {
            FromRaw::from_raw(self.0.newBufferWithLength_options(length as NSUInteger,
                                                                 options.into()))
                .unwrap()
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn new_buffer_with_bytes(&mut self, bytes: &[u8], options: ResourceOptions)
                                 -> Buffer {
        let len = bytes.len() as NSUInteger;
        let bytes = bytes.as_ptr() as *const _;
        unsafe {
            FromRaw::from_raw(self.0.newBufferWithBytes_length_options(bytes, len, options.into())).unwrap()
        }
    }

    #[allow(unused_variables)]
    pub fn new_buffer_with_bytes_no_copy<B, I>(&mut self, bytes: Vec<u8>, options: ResourceOptions)
                                               -> Buffer {
        unimplemented!();
    }

    pub fn new_texture(&mut self, descriptor: &TextureDescriptor) -> Result<Texture, FromRawError> {
        unsafe { FromRaw::from_raw(self.0.newTextureWithDescriptor(*descriptor.as_raw())) }
    }

    #[allow(unused_variables)]
    // TODO(burtonageo): Model types correctly
    pub fn new_sampler_state(&mut self, descriptor: ()) -> ! {
        unimplemented!();
    }

    #[allow(unused_variables)]
    pub fn new_depth_stencil_state(&mut self, descriptor: &DepthStencilStateDescriptor)
                                   -> Result<DepthStencilState, FromRawError> {
        unimplemented!();
    }
}

impl_from_into_raw!(Device, of protocol "MTLDevice");

#[cfg(target_os = "ios")]
convertible_enum! {
    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum FeatureSet: MTLFeatureSet {
        iOSGpuFamily1_v1 => MTLFeatureSet_iOS_GPUFamily1_v1,
        iOSGpuFamily2_v1 => MTLFeatureSet_iOS_GPUFamily2_v1,
        iOSGpuFamily1_v2 => MTLFeatureSet_iOS_GPUFamily1_v2,
        iOSGpuFamily2_v2 => MTLFeatureSet_iOS_GPUFamily2_v2,
        iOSGpuFamily3_v1 => MTLFeatureSet_iOS_GPUFamily3_v1
    }
}

#[cfg(target_os = "macos")]
convertible_enum! {
    #[allow(non_camel_case_types)]
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum FeatureSet: MTLFeatureSet {
        OsxGpuFamily1_v1 => MTLFeatureSet_OSX_GPUFamily1_v1,
        _non_unary_compile_dummy => _non_unary_compile_dummy
    }
}

#[derive(Clone, Debug)]
pub enum DeviceError {
    ConstructionFailed,
    RawError(FromRawError)
}

impl From<FromRawError> for DeviceError {
    fn from(error: FromRawError) -> Self {
        DeviceError::RawError(error)
    }
}

impl Display for DeviceError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let descr = match *self {
            DeviceError::ConstructionFailed => "DeviceError::ConstructionFailed",
            DeviceError::RawError(_) => "DeviceError::ConstructionFailed",
        };
        write!(f, "{}", descr)
    }
}

impl Error for DeviceError {
    fn description(&self) -> &str {
        match *self {
            DeviceError::ConstructionFailed => {
                "Could not create a default device. Please ensure that you are using at least OSX \
                 10.11 or iOS 8.0"
            }
            DeviceError::RawError(_) => "There was an error with the device pointer",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &DeviceError::ConstructionFailed => None,
            &DeviceError::RawError(ref raw_err) => Some(raw_err),
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]

use std::path::Path;
use serde_json;
use book::bookconfig::*;

#[test]
fn it_parses_json_config() {
    let text = r#"
{
    "title": "mdBook Documentation",
    "description": "Create book from markdown files. Like Gitbook but implemented in Rust",
    "author": "Mathieu David"
}"#;

    // TODO don't require path argument, take pwd
    let mut config = BookConfig::new(Path::new("."));

    config.parse_from_json_string(&text.to_string());

    let expected = r#"BookConfig {
    root: ".",
    dest: "./book",
    src: "./src",
    theme_path: "./theme",
    title: "mdBook Documentation",
    author: "Mathieu David",
    description: "Create book from markdown files. Like Gitbook but implemented in Rust",
    indent_spaces: 4,
    multilingual: false
}"#;

    assert_eq!(format!("{:#?}", config), expected);
}

#[test]
fn it_parses_toml_config() {
    let text = r#"
title = "mdBook Documentation"
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
author = "Mathieu David"
"#;

    // TODO don't require path argument, take pwd
    let mut config = BookConfig::new(Path::new("."));

    config.parse_from_toml_string(&text.to_string());

    println!("{:#?}", config);

    let expected = r#"BookConfig {
    root: ".",
    dest: "./book",
    src: "./src",
    theme_path: "./theme",
    title: "mdBook Documentation",
    author: "Mathieu David",
    description: "Create book from markdown files. Like Gitbook but implemented in Rust",
    indent_spaces: 4,
    multilingual: false
}"#;

    assert_eq!(format!("{:#?}", config), expected);
}

#[test]
fn it_parses_json_nested_array_to_toml() {

    // Example from:
    // toml-0.2.1/tests/valid/arrays-nested.json

    let text = r#"
{
    "nest": {
        "type": "array",
        "value": [
            {"type": "array", "value": [
                {"type": "string", "value": "a"}
            ]},
            {"type": "array", "value": [
                {"type": "string", "value": "b"}
            ]}
        ]
    }
}"#;

    let c: serde_json::Value = serde_json::from_str(&text).unwrap();

    let result = json_object_to_btreemap(&c.as_object().unwrap());

    let expected = r#"{
    "nest": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "array"
                            ),
                            "value": Array(
                                [
                                    Table(
                                        {
                                            "type": String(
                                                "string"
                                            ),
                                            "value": String(
                                                "a"
                                            )
                                        }
                                    )
                                ]
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "array"
                            ),
                            "value": Array(
                                [
                                    Table(
                                        {
                                            "type": String(
                                                "string"
                                            ),
                                            "value": String(
                                                "b"
                                            )
                                        }
                                    )
                                ]
                            )
                        }
                    )
                ]
            )
        }
    )
}"#;

    assert_eq!(format!("{:#?}", result), expected);
}

#[test]
fn it_parses_json_arrays_to_toml() {

    // Example from:
    // toml-0.2.1/tests/valid/arrays.json

    let text = r#"
{
    "ints": {
        "type": "array",
        "value": [
            {"type": "integer", "value": "1"},
            {"type": "integer", "value": "2"},
            {"type": "integer", "value": "3"}
        ]
    },
    "floats": {
        "type": "array",
        "value": [
            {"type": "float", "value": "1.1"},
            {"type": "float", "value": "2.1"},
            {"type": "float", "value": "3.1"}
        ]
    },
    "strings": {
        "type": "array",
        "value": [
            {"type": "string", "value": "a"},
            {"type": "string", "value": "b"},
            {"type": "string", "value": "c"}
        ]
    },
    "dates": {
        "type": "array",
        "value": [
            {"type": "datetime", "value": "1987-07-05T17:45:00Z"},
            {"type": "datetime", "value": "1979-05-27T07:32:00Z"},
            {"type": "datetime", "value": "2006-06-01T11:00:00Z"}
        ]
    }
}"#;

    let c: serde_json::Value = serde_json::from_str(&text).unwrap();

    let result = json_object_to_btreemap(&c.as_object().unwrap());

    let expected = r#"{
    "dates": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "1987-07-05T17:45:00Z"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "1979-05-27T07:32:00Z"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "2006-06-01T11:00:00Z"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "floats": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "1.1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "2.1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "3.1"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "ints": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "2"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "3"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "strings": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "a"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "b"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "c"
                            )
                        }
                    )
                ]
            )
        }
    )
}"#;

    assert_eq!(format!("{:#?}", result), expected);
}
<commit_msg>upd example<commit_after>#[cfg(test)]

use std::path::Path;
use serde_json;
use book::bookconfig::*;

#[test]
fn it_parses_json_config() {
    let text = r#"
{
    "title": "mdBook Documentation",
    "description": "Create book from markdown files. Like Gitbook but implemented in Rust",
    "author": "Mathieu David"
}"#;

    // TODO don't require path argument, take pwd
    let mut config = BookConfig::new(Path::new("."));

    config.parse_from_json_string(&text.to_string());

    let expected = r#"BookConfig {
    root: ".",
    dest: "book",
    src: "src",
    theme_path: "theme",
    title: "mdBook Documentation",
    author: "Mathieu David",
    description: "Create book from markdown files. Like Gitbook but implemented in Rust",
    indent_spaces: 4,
    multilingual: false
}"#;

    assert_eq!(format!("{:#?}", config), expected);
}

#[test]
fn it_parses_toml_config() {
    let text = r#"
title = "mdBook Documentation"
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
author = "Mathieu David"
"#;

    // TODO don't require path argument, take pwd
    let mut config = BookConfig::new(Path::new("."));

    config.parse_from_toml_string(&text.to_string());

    let expected = r#"BookConfig {
    root: ".",
    dest: "book",
    src: "src",
    theme_path: "theme",
    title: "mdBook Documentation",
    author: "Mathieu David",
    description: "Create book from markdown files. Like Gitbook but implemented in Rust",
    indent_spaces: 4,
    multilingual: false
}"#;

    assert_eq!(format!("{:#?}", config), expected);
}

#[test]
fn it_parses_json_nested_array_to_toml() {

    // Example from:
    // toml-0.2.1/tests/valid/arrays-nested.json

    let text = r#"
{
    "nest": {
        "type": "array",
        "value": [
            {"type": "array", "value": [
                {"type": "string", "value": "a"}
            ]},
            {"type": "array", "value": [
                {"type": "string", "value": "b"}
            ]}
        ]
    }
}"#;

    let c: serde_json::Value = serde_json::from_str(&text).unwrap();

    let result = json_object_to_btreemap(&c.as_object().unwrap());

    let expected = r#"{
    "nest": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "array"
                            ),
                            "value": Array(
                                [
                                    Table(
                                        {
                                            "type": String(
                                                "string"
                                            ),
                                            "value": String(
                                                "a"
                                            )
                                        }
                                    )
                                ]
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "array"
                            ),
                            "value": Array(
                                [
                                    Table(
                                        {
                                            "type": String(
                                                "string"
                                            ),
                                            "value": String(
                                                "b"
                                            )
                                        }
                                    )
                                ]
                            )
                        }
                    )
                ]
            )
        }
    )
}"#;

    assert_eq!(format!("{:#?}", result), expected);
}

#[test]
fn it_parses_json_arrays_to_toml() {

    // Example from:
    // toml-0.2.1/tests/valid/arrays.json

    let text = r#"
{
    "ints": {
        "type": "array",
        "value": [
            {"type": "integer", "value": "1"},
            {"type": "integer", "value": "2"},
            {"type": "integer", "value": "3"}
        ]
    },
    "floats": {
        "type": "array",
        "value": [
            {"type": "float", "value": "1.1"},
            {"type": "float", "value": "2.1"},
            {"type": "float", "value": "3.1"}
        ]
    },
    "strings": {
        "type": "array",
        "value": [
            {"type": "string", "value": "a"},
            {"type": "string", "value": "b"},
            {"type": "string", "value": "c"}
        ]
    },
    "dates": {
        "type": "array",
        "value": [
            {"type": "datetime", "value": "1987-07-05T17:45:00Z"},
            {"type": "datetime", "value": "1979-05-27T07:32:00Z"},
            {"type": "datetime", "value": "2006-06-01T11:00:00Z"}
        ]
    }
}"#;

    let c: serde_json::Value = serde_json::from_str(&text).unwrap();

    let result = json_object_to_btreemap(&c.as_object().unwrap());

    let expected = r#"{
    "dates": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "1987-07-05T17:45:00Z"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "1979-05-27T07:32:00Z"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "2006-06-01T11:00:00Z"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "floats": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "1.1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "2.1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "3.1"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "ints": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "2"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "3"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "strings": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "a"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "b"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "c"
                            )
                        }
                    )
                ]
            )
        }
    )
}"#;

    assert_eq!(format!("{:#?}", result), expected);
}
<|endoftext|>


<commit_before>extern crate libc;

use self::libc::{c_char, c_uchar};

#[no_mangle]
pub extern fn anoncreds_create_master_secret(client_id: i32, command_id: i32,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           master_secret: *const c_char)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_create_key_pair(client_id: i32, command_id: i32, schema: *const c_uchar,
                                        cb: extern fn(xcommand_id: i32, err: i32,
                                                      pk: *const c_char, sk: *const c_char,
                                                      pnrk: *const c_char, snrk: *const c_char)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_issue_accumulator(client_id: i32, command_id: i32, schema: *const c_uchar,
                                          accumulator_id: *const c_uchar,
                                          max_claims: *const c_uchar,
                                          public_key_non_revocation: *const c_uchar,
                                          cb: extern fn(xcommand_id: i32, err: i32,
                                                        acc: *const c_char, tails: *const c_char,
                                                        acc_pk: *const c_char, acc_sk: *const c_char
                                          )) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_issue_claim(client_id: i32, command_id: i32, attributes: *const c_uchar,
                                    accumulator: *const c_uchar, sequence_number: *const c_uchar,
                                    claim_request: *const c_uchar, public_key: *const c_uchar,
                                    secret_key: *const c_uchar,
                                    public_key_non_revocation: *const c_uchar,
                                    secret_key_non_revocation: *const c_uchar,
                                    tails: *const c_uchar, secret_key_accumulator: *const c_uchar,
                                    cb: extern fn(xcommand_id: i32, err: i32, claim: *const c_char)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_create_claim_request(client_id: i32, command_id: i32, master_secret: *const c_uchar,
                                             public_key: *const c_uchar,
                                             public_key_non_revocation: *const c_uchar,
                                             request_non_revocation: *const c_uchar,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           claim_req: *const c_char)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_create_proof(proof_input: *const c_uchar, nonce: *const c_uchar,
                                     claims: *const c_uchar,
                                     public_key_non_revocation: *const c_uchar,
                                     accumulator: *const c_uchar, public_key: *const c_uchar,
                                     master_secret: *const c_uchar,
                                     cb: extern fn(xcommand_id: i32, err: i32,
                                                   proof: *const c_char, attrs: *const c_char)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_verify_proof(proof_input: *const c_uchar, proof: *const c_uchar,
                                     revealed_attributes: *const c_uchar, nonce: *const c_uchar,
                                     public_key_non_revocation: *const c_uchar,
                                     accumulator: *const c_uchar,
                                     public_key_accumulator: *const c_uchar,
                                     public_key: *const c_uchar, attributes: *const c_uchar,
                                     cb: extern fn(xcommand_id: i32, err: i32)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_create_nonce(cb: extern fn(client_id: i32, command_id: i32, err: i32, nonce: *const c_char)) {
    unimplemented!();
}<commit_msg>refactoring<commit_after>extern crate libc;

use self::libc::{c_char, c_uchar};

#[no_mangle]
pub extern fn anoncreds_create_claim(client_id: i32, command_id: i32,
                                     schema_id: *const c_char, attributes: *const c_char,
                                     claim_request: *const c_char,
                                     cb: extern fn(xcommand_id: i32, err: i32, claim: *const c_char)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_create_claim_request(client_id: i32, command_id: i32,
                                             schema_id: *const c_char,
                                             request_non_revocation: bool,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           claim_req: *const c_char)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_create_proof(client_id: i32, command_id: i32,
                                     proof_input: *const c_char,
                                     nonce: *const c_uchar,
                                     cb: extern fn(xcommand_id: i32, err: i32,
                                                   proof: *const c_char, attrs: *const c_char)) {
    unimplemented!();
}

#[no_mangle]
pub extern fn anoncreds_verify_proof(client_id: i32, command_id: i32,
                                     proof_input: *const c_char,
                                     proof: *const c_uchar,
                                     revealed_attributes: *const c_uchar,
                                     nonce: *const c_uchar,
                                     cb: extern fn(xcommand_id: i32, err: i32)) {
    unimplemented!();
}<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap, HashSet};

use super::types::ConflictReason;
use core::resolver::Context;
use core::{Dependency, PackageId};

enum ConflictStore {
    Con(BTreeMap<PackageId, ConflictReason>),
    Map(HashMap<PackageId, ConflictStore>),
}

impl ConflictStore {
    /// Finds any known set of conflicts, if any,
    /// which are activated in `cx` and pass the `filter` specified?
    pub fn find_conflicting<F>(
        &self,
        cx: &Context,
        filter: &F,
    ) -> Option<&BTreeMap<PackageId, ConflictReason>>
    where
        for<'r> F: Fn(&'r &BTreeMap<PackageId, ConflictReason>) -> bool,
    {
        match self {
            ConflictStore::Con(c) => {
                if filter(&c) {
                    Some(c)
                } else {
                    None
                }
            }
            ConflictStore::Map(m) => {
                for (pid, store) in m {
                    if cx.is_active(pid) {
                        if let Some(o) = store.find_conflicting(cx, filter) {
                            return Some(o);
                        }
                    }
                }
                None
            }
        }
    }

    pub fn insert<'a>(
        &mut self,
        mut iter: impl Iterator<Item = &'a PackageId>,
        con: BTreeMap<PackageId, ConflictReason>,
    ) {
        if let Some(pid) = iter.next() {
            if let ConflictStore::Map(p) = self {
                p.entry(pid.clone())
                    .or_insert_with(|| ConflictStore::Map(HashMap::new()))
                    .insert(iter, con);
            }
            // else, We already have a subset of this in the ConflictStore
        } else {
            *self = ConflictStore::Con(con)
        }
    }
}

pub(super) struct ConflictCache {
    // `con_from_dep` is a cache of the reasons for each time we
    // backtrack. For example after several backtracks we may have:
    //
    //  con_from_dep[`foo = "^1.0.2"`] = map!{
    //      `foo=1.0.1`: map!{`foo=1.0.1`: Semver},
    //      `foo=1.0.0`: map!{`foo=1.0.0`: Semver},
    //  };
    //
    // This can be read as "we cannot find a candidate for dep `foo = "^1.0.2"`
    // if either `foo=1.0.1` OR `foo=1.0.0` are activated".
    //
    // Another example after several backtracks we may have:
    //
    //  con_from_dep[`foo = ">=0.8.2, <=0.9.3"`] = map!{
    //      `foo=0.8.1`: map!{
    //          `foo=0.9.4`: map!{`foo=0.8.1`: Semver, `foo=0.9.4`: Semver},
    //      }
    //  };
    //
    // This can be read as "we cannot find a candidate for dep `foo = ">=0.8.2,
    // <=0.9.3"` if both `foo=0.8.1` AND `foo=0.9.4` are activated".
    //
    // This is used to make sure we don't queue work we know will fail. See the
    // discussion in https://github.com/rust-lang/cargo/pull/5168 for why this
    // is so important. The nested HashMaps act as a kind of btree, that lets us
    // look up a witch entry's are still active without
    // linearly scanning through the full list.
    //
    // Also, as a final note, this map is *not* ever removed from. This remains
    // as a global cache which we never delete from. Any entry in this map is
    // unconditionally true regardless of our resolution history of how we got
    // here.
    con_from_dep: HashMap<Dependency, ConflictStore>,
    // `dep_from_pid` is an inverse-index of `con_from_dep`.
    // For every `PackageId` this lists the `Dependency`s that mention it in `dep_from_pid`.
    dep_from_pid: HashMap<PackageId, HashSet<Dependency>>,
}

impl ConflictCache {
    pub fn new() -> ConflictCache {
        ConflictCache {
            con_from_dep: HashMap::new(),
            dep_from_pid: HashMap::new(),
        }
    }
    /// Finds any known set of conflicts, if any,
    /// which are activated in `cx` and pass the `filter` specified?
    pub fn find_conflicting<F>(
        &self,
        cx: &Context,
        dep: &Dependency,
        filter: F,
    ) -> Option<&BTreeMap<PackageId, ConflictReason>>
    where
        for<'r> F: Fn(&'r &BTreeMap<PackageId, ConflictReason>) -> bool,
    {
        self.con_from_dep.get(dep)?.find_conflicting(cx, &filter)
    }
    pub fn conflicting(
        &self,
        cx: &Context,
        dep: &Dependency,
    ) -> Option<&BTreeMap<PackageId, ConflictReason>> {
        self.find_conflicting(cx, dep, |_| true)
    }

    /// Add to the cache a conflict of the form:
    /// `dep` is known to be unresolvable if
    /// all the `PackageId` entries are activated
    pub fn insert(&mut self, dep: &Dependency, con: &BTreeMap<PackageId, ConflictReason>) {
        self.con_from_dep
            .entry(dep.clone())
            .or_insert_with(|| ConflictStore::Map(HashMap::new()))
            .insert(con.keys(), con.clone());

        trace!(
            "{} = \"{}\" adding a skip {:?}",
            dep.package_name(),
            dep.version_req(),
            con
        );

        for c in con.keys() {
            self.dep_from_pid
                .entry(c.clone())
                .or_insert_with(HashSet::new)
                .insert(dep.clone());
        }
    }
    pub fn dependencies_conflicting_with(&self, pid: &PackageId) -> Option<&HashSet<Dependency>> {
        self.dep_from_pid.get(pid)
    }
}
<commit_msg>add comments and pick better names<commit_after>use std::collections::{BTreeMap, HashMap, HashSet};

use super::types::ConflictReason;
use core::resolver::Context;
use core::{Dependency, PackageId};

/// This is a data structure for storing a large number of Sets designed to
/// efficiently see if any of the stored Sets are a subset of a search Set.
enum ConflictStore {
    /// a Leaf is one of the stored Sets.
    Leaf(BTreeMap<PackageId, ConflictReason>),
    /// a Node is a map from an element to a subset of the stored data
    /// where all the Sets in the subset contains that element.
    Node(HashMap<PackageId, ConflictStore>),
}

impl ConflictStore {
    /// Finds any known set of conflicts, if any,
    /// which are activated in `cx` and pass the `filter` specified?
    fn find_conflicting<F>(
        &self,
        cx: &Context,
        filter: &F,
    ) -> Option<&BTreeMap<PackageId, ConflictReason>>
    where
        for<'r> F: Fn(&'r &BTreeMap<PackageId, ConflictReason>) -> bool,
    {
        match self {
            ConflictStore::Leaf(c) => {
                if filter(&c) {
                    Some(c)
                } else {
                    None
                }
            }
            ConflictStore::Node(m) => {
                for (pid, store) in m {
                    // if the key is active then we need to check all of the corresponding subset,
                    // but if it is not active then there is no way any of the corresponding subset
                    // will be conflicting.
                    if cx.is_active(pid) {
                        if let Some(o) = store.find_conflicting(cx, filter) {
                            debug_assert!(cx.is_conflicting(None, o));
                            // is_conflicting checks that all the elements are active,
                            // but we have checked each one by the recursion of this function.
                            return Some(o);
                        }
                    }
                }
                None
            }
        }
    }

    fn insert<'a>(
        &mut self,
        mut iter: impl Iterator<Item = &'a PackageId>,
        con: BTreeMap<PackageId, ConflictReason>,
    ) {
        if let Some(pid) = iter.next() {
            if let ConflictStore::Node(p) = self {
                p.entry(pid.clone())
                    .or_insert_with(|| ConflictStore::Node(HashMap::new()))
                    .insert(iter, con);
            } // else, We already have a subset of this in the ConflictStore
        } else {
            // we are at the end of the set we are adding, there are 3 cases for what to do next:
            // 1. self is a empty dummy Node inserted by `or_insert_with`
            //      in witch case we should replace it with `Leaf(con)`.
            // 2. self is a Node because we previously inserted a superset of
            //      the thing we are working on (I don't know if this happens in practice)
            //      but the subset that we are working on will
            //      always match any time the larger set would have
            //      in witch case we can replace it with `Leaf(con)`.
            // 3. self is a Leaf that is in the same spot in the structure as
            //      the thing we are working on. So it is equivalent.
            //      We can replace it with `Leaf(con)`.
            *self = ConflictStore::Leaf(con)
        }
    }
}

pub(super) struct ConflictCache {
    // `con_from_dep` is a cache of the reasons for each time we
    // backtrack. For example after several backtracks we may have:
    //
    //  con_from_dep[`foo = "^1.0.2"`] = map!{
    //      `foo=1.0.1`: map!{`foo=1.0.1`: Semver},
    //      `foo=1.0.0`: map!{`foo=1.0.0`: Semver},
    //  };
    //
    // This can be read as "we cannot find a candidate for dep `foo = "^1.0.2"`
    // if either `foo=1.0.1` OR `foo=1.0.0` are activated".
    //
    // Another example after several backtracks we may have:
    //
    //  con_from_dep[`foo = ">=0.8.2, <=0.9.3"`] = map!{
    //      `foo=0.8.1`: map!{
    //          `foo=0.9.4`: map!{`foo=0.8.1`: Semver, `foo=0.9.4`: Semver},
    //      }
    //  };
    //
    // This can be read as "we cannot find a candidate for dep `foo = ">=0.8.2,
    // <=0.9.3"` if both `foo=0.8.1` AND `foo=0.9.4` are activated".
    //
    // This is used to make sure we don't queue work we know will fail. See the
    // discussion in https://github.com/rust-lang/cargo/pull/5168 for why this
    // is so important. The nested HashMaps act as a kind of btree, that lets us
    // look up which entries are still active without
    // linearly scanning through the full list.
    //
    // Also, as a final note, this map is *not* ever removed from. This remains
    // as a global cache which we never delete from. Any entry in this map is
    // unconditionally true regardless of our resolution history of how we got
    // here.
    con_from_dep: HashMap<Dependency, ConflictStore>,
    // `dep_from_pid` is an inverse-index of `con_from_dep`.
    // For every `PackageId` this lists the `Dependency`s that mention it in `dep_from_pid`.
    dep_from_pid: HashMap<PackageId, HashSet<Dependency>>,
}

impl ConflictCache {
    pub fn new() -> ConflictCache {
        ConflictCache {
            con_from_dep: HashMap::new(),
            dep_from_pid: HashMap::new(),
        }
    }
    /// Finds any known set of conflicts, if any,
    /// which are activated in `cx` and pass the `filter` specified?
    pub fn find_conflicting<F>(
        &self,
        cx: &Context,
        dep: &Dependency,
        filter: F,
    ) -> Option<&BTreeMap<PackageId, ConflictReason>>
    where
        for<'r> F: Fn(&'r &BTreeMap<PackageId, ConflictReason>) -> bool,
    {
        self.con_from_dep.get(dep)?.find_conflicting(cx, &filter)
    }
    pub fn conflicting(
        &self,
        cx: &Context,
        dep: &Dependency,
    ) -> Option<&BTreeMap<PackageId, ConflictReason>> {
        self.find_conflicting(cx, dep, |_| true)
    }

    /// Add to the cache a conflict of the form:
    /// `dep` is known to be unresolvable if
    /// all the `PackageId` entries are activated
    pub fn insert(&mut self, dep: &Dependency, con: &BTreeMap<PackageId, ConflictReason>) {
        self.con_from_dep
            .entry(dep.clone())
            .or_insert_with(|| ConflictStore::Node(HashMap::new()))
            .insert(con.keys(), con.clone());

        trace!(
            "{} = \"{}\" adding a skip {:?}",
            dep.package_name(),
            dep.version_req(),
            con
        );

        for c in con.keys() {
            self.dep_from_pid
                .entry(c.clone())
                .or_insert_with(HashSet::new)
                .insert(dep.clone());
        }
    }
    pub fn dependencies_conflicting_with(&self, pid: &PackageId) -> Option<&HashSet<Dependency>> {
        self.dep_from_pid.get(pid)
    }
}
<|endoftext|>


<commit_before>#[link(name = "word_count", vers = "1.0")];
#[crate_type = "lib"];

use std::hashmap::HashMap;

mod word_count;

#[test]
#[ignore]
fn test_no_words() {
    assert_eq!(word_count::word_count(""), HashMap::new());
    assert_eq!(word_count::word_count("-!@#$ $#() @@@"), HashMap::new());
}

#[test]
#[ignore]
fn test_count_one_word() {
    let m = word_count::word_count("word");
    assert_eq!(m.find(&~"word").unwrap(), &1);
}

#[test]
#[ignore]
fn test_count_one_of_each() {
    let m = word_count::word_count("one of each");
    assert_eq!(m.find(&~"one").unwrap(), &1);
    assert_eq!(m.find(&~"of").unwrap(), &1);
    assert_eq!(m.find(&~"each").unwrap(), &1);
}

#[test]
#[ignore]
fn test_count_multiple_occurrences() {
    let m = word_count::word_count("one fish two fish red fish blue fish");
    assert_eq!(m.find(&~"one").unwrap(), &1);
    assert_eq!(m.find(&~"fish").unwrap(), &4);
    assert_eq!(m.find(&~"two").unwrap(), &1);
    assert_eq!(m.find(&~"red").unwrap(), &1);
    assert_eq!(m.find(&~"blue").unwrap(), &1);
}

#[test]
#[ignore]
fn test_ignore_punctuation() {
    let m = word_count::word_count("car : carpet as java : javascript!!&@$%^&");
    assert_eq!(m.find(&~"car").unwrap(), &1);
    assert_eq!(m.find(&~"carpet").unwrap(), &1);
    assert_eq!(m.find(&~"as").unwrap(), &1);
    assert_eq!(m.find(&~"java").unwrap(), &1);
    assert_eq!(m.find(&~"javascript").unwrap(), &1);
}

#[test]
#[ignore]
fn test_include_numbers() {
    let m = word_count::word_count("testing, 1, 2 testing");
    assert_eq!(m.find(&~"testing").unwrap(), &2);
    assert_eq!(m.find(&~"1").unwrap(), &1);
    assert_eq!(m.find(&~"2").unwrap(), &1);
}

#[test]
#[ignore]
fn test_normalize_case() {
    let m = word_count::word_count("go Go GO");
    assert_eq!(m.find(&~"go").unwrap(), &3);
}

#[test]
#[ignore]
fn test_prefix_punctuation() {
    let m = word_count::word_count("!%%#testing, 1, 2 testing");
    assert_eq!(m.find(&~"testing").unwrap(), &2);
    assert_eq!(m.find(&~"1").unwrap(), &1);
    assert_eq!(m.find(&~"2").unwrap(), &1);
}

#[test]
#[ignore]
fn test_symbols_are_separators() {
    let m = word_count::word_count("hey,my_spacebar_is_broken.");
    assert_eq!(m.find(&~"hey").unwrap(), &1);
    assert_eq!(m.find(&~"my").unwrap(), &1);
    assert_eq!(m.find(&~"spacebar").unwrap(), &1);
    assert_eq!(m.find(&~"is").unwrap(), &1);
    assert_eq!(m.find(&~"broken").unwrap(), &1);
}
<commit_msg>rust - refactor word_count tests<commit_after>#[link(name = "word_count", vers = "1.0")];
#[crate_type = "lib"];

use std::hashmap::HashMap;

mod word_count;

fn check_word_count(s: &str, pairs: &[(&str, uint)]) {
    let mut m: HashMap<~str, uint> = word_count::word_count(s);
    for &(k, v) in pairs.iter() {
        assert_eq!((k, m.pop(&k.to_owned()).unwrap()), (k, v));
    }
    assert_eq!(m.iter().to_owned_vec(), ~[]);
}

#[test]
#[ignore]
fn test_no_words() {
    check_word_count("", []);
    check_word_count("-!@#$ $#() @@@", []);
}

#[test]
#[ignore]
fn test_count_one_word() {
    check_word_count("word", [("word", 1)]);
}

#[test]
#[ignore]
fn test_count_one_of_each() {
    check_word_count(
        "one of each",
        [("one", 1),
         ("of", 1),
         ("each", 1)]);
}

#[test]
#[ignore]
fn test_count_multiple_occurrences() {
    check_word_count(
        "one fish two fish red fish blue fish",
        [("one", 1),
         ("fish", 4),
         ("two", 1),
         ("red", 1),
         ("blue", 1)]);
}

#[test]
#[ignore]
fn test_ignore_punctuation() {
    check_word_count(
        "car : carpet as java : javascript!!&@$%^&",
        [("car", 1),
         ("carpet", 1),
         ("as", 1),
         ("java", 1),
         ("javascript", 1)]);
}

#[test]
#[ignore]
fn test_include_numbers() {
    check_word_count(
        "testing, 1, 2 testing",
        [("testing", 2),
         ("1", 1),
         ("2", 1)]);
}

#[test]
#[ignore]
fn test_normalize_case() {
    check_word_count(
        "go Go GO",
        [("go", 3)]);
}

#[test]
#[ignore]
fn test_prefix_punctuation() {
    check_word_count(
        "!%%#testing, 1, 2 testing",
        [("testing", 2),
         ("1", 1),
         ("2", 1)]);
}

#[test]
#[ignore]
fn test_symbols_are_separators() {
    check_word_count(
        "hey,my_spacebar_is_broken.",
        [("hey", 1),
         ("my", 1),
         ("spacebar", 1),
         ("is", 1),
         ("broken", 1)]);
}
<|endoftext|>


<commit_before>use rusqlite as rs;
use slack_api as slack;

use chrono::prelude::{Utc, DateTime};

use tokio::sync::mpsc;

use crate::bot::parser::karma::Karma;
use crate::bot::parser::reacji_to_karma;

use crate::bot::query::santizer;
use crate::bot::query::{KarmaName, ReacjiAction};

use crate::core::cache;

use crate::core::database::DbResult;
use crate::core::database::Query;
use crate::core::database::send_query;

fn fix<T>(input: Result<Option<T>, String>) -> Result<T, String> {
    input.map_or_else(
        |e| Err(e),
        |v| v.ok_or("NONE RESULT".to_string())
    )
}

pub async fn add_reacji<R>(
    sql_tx: &mut mpsc::Sender<Query>,
    cache: &cache::Cache<R>,
    input: &str,
    user_id: String,
    channel_id: String,
    ts: String,
    action: ReacjiAction,
)
where
    R: slack::requests::SlackWebRequestSender + std::clone::Clone
{
    match reacji_to_karma(input) {
        Some(karma) => {
            let message_id = fix(query_reacji_message(
                sql_tx,
                channel_id.clone(),
                ts.clone()
            ).await);

            let message_id = match message_id {
                Err(e) => {
                    eprintln!("ERROR: [User Event] Querying for reacji failed: {:?}", e);

                    fix(match cache.get_message(&channel_id, &ts).await {
                        Some(cache::ConversationHistoryMessage::Message { text, user_id: Some(user_id) }) => {
                            // We have the message content, insert it into the table and
                            // get its row id
                            let santized_text = santizer(&text, &cache).await;

                            match (
                                cache.get_username(&user_id).await,
                                cache.get_user_real_name(&user_id).await,
                            ) {
                                (Some(ud), Some(rn)) => {
                                    add_reacji_message(
                                        sql_tx,
                                        user_id,
                                        KarmaName::new(&ud),
                                        KarmaName::new(&rn),
                                        channel_id.clone(),
                                        ts.clone(),
                                        santized_text
                                    ).await
                                },
                                e => Err(format!("ERROR: [User Event] Querying for user/name failed: {:?}", e)),
                            }
                        },
                        // This should already have been logged by the api call function
                        e => Err(format!("ERROR: [User Event] IDK here: {:?}", e)),
                    })
                },
                Ok(mid) => Ok(mid),
            };

            match message_id {
                Err(e) => {
                    eprintln!("ERROR: [User Event] Wasn't able to get/store an reactji message, vote isn't recorded");
                    eprintln!("ERROR: [User Event] Returned error: {:?}", e);
                },
                Ok(mid) => {
                    match (
                        cache.get_username(&user_id).await,
                        cache.get_user_real_name(&user_id).await,
                    ) {
                        (Some(ud), Some(rn)) => {
                            let e = add_reacji_query(
                                sql_tx,
                                Utc::now(),
                                user_id,
                                KarmaName::new(&ud),
                                KarmaName::new(&rn),
                                action,
                                mid,
                                karma,
                            ).await;

                            if e.is_err() {
                                eprintln!("ERROR: [User Event] Query failed: {:?}", e);
                            }
                        },
                        e => eprintln!("ERROR: [User Event] Querying for user/name failed: {:?}", e),
                    }
                },
            }
        },
        None => (),
    }
}

async fn query_reacji_message(
    sql_tx: &mut mpsc::Sender<Query>,
    channel_id: String,
    message_ts: String,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let channel_id: Option<i64> = {
                let mut stmt = conn.prepare("SELECT id FROM chan_metadata WHERE channel = ?")?;
                let mut rows = stmt.query(rs::params![channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0).ok()
                } else {
                    None
                }
            };

            if let Some(channel_id) = channel_id {
                // We good let's proceed, otherwise abort since if channel id isn't here its
                // not going to be in reacji_message either
                let mut stmt = conn.prepare("SELECT id FROM reacji_message WHERE ts = ? AND chan_id = ?")?;
                let mut rows = stmt.query(rs::params![message_ts, channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    let msg_id: Option<i64> = row.get(0).ok();
                    Ok(msg_id)
                } else {
                    Ok(None)
                }
            } else {
                Ok(None)
            }
        })
    ).await
}

async fn add_reacji_message(
    sql_tx: &mut mpsc::Sender<Query>,
    user_id: String,
    username: KarmaName,
    real_name: KarmaName,
    channel_id: String,
    message_ts: String,
    message: String,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let nick_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM nick_metadata WHERE username = ?")?;
                let mut rows = stmt.query(rs::params![user_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare(
                        "INSERT INTO nick_metadata (cleaned_nick, full_name, username, hostmask) VALUES (?, ?, ?, ?)"
                    )?;
                    stmt.insert(rs::params![username, real_name, user_id, "SlackServer"])?
                }
            };

            let channel_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM chan_metadata WHERE channel = ?")?;
                let mut rows = stmt.query(rs::params![channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare("INSERT INTO chan_metadata (channel) VALUES (?)")?;
                    stmt.insert(rs::params![channel_id])?
                }
            };

            // Insert the reacji_message content now
            let mut stmt = conn.prepare(
                "INSERT INTO reacji_message (ts, chan_id, nick_id, message) VALUES (?, ?, ?, ?)"
            )?;

            Ok(
                Some(stmt.insert(rs::params![message_ts, channel_id, nick_id, message])?)
            )
        })
    ).await
}

async fn add_reacji_query(
    sql_tx: &mut mpsc::Sender<Query>,
    timestamp: DateTime<Utc>,
    user_id: String,
    username: KarmaName,
    real_name: KarmaName,
    action: ReacjiAction,
    message_id: i64,
    amount: Karma,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let nick_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM nick_metadata WHERE username = ?")?;
                let mut rows = stmt.query(rs::params![user_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare(
                        "INSERT INTO nick_metadata (cleaned_nick, full_name, username, hostmask) VALUES (?, ?, ?, ?)"
                    )?;

                    stmt.insert(rs::params![username, real_name, user_id, "SlackServer"])?
                }
            };

            let ts = timestamp.to_rfc3339();
            let ts = ts.trim_end_matches("+00:00");

            // Insert the reacji into the database
            let mut stmt = conn.prepare(
                "INSERT INTO reacji_votes
                    (voted_at, by_whom_name, action, reacji_message_id, amount, nick_id)
                VALUES
                    (?, ?, ?, ?, ?, ?)"
            )?;

            stmt.insert(rs::params![ts, username, action, message_id, amount, nick_id])?;

            Ok(None)
        })
    ).await
}
<commit_msg>Slack are bad at api, quietly ignore bad messages<commit_after>use rusqlite as rs;
use slack_api as slack;

use chrono::prelude::{Utc, DateTime};

use tokio::sync::mpsc;

use crate::bot::parser::karma::Karma;
use crate::bot::parser::reacji_to_karma;

use crate::bot::query::santizer;
use crate::bot::query::{KarmaName, ReacjiAction};

use crate::core::cache;

use crate::core::database::DbResult;
use crate::core::database::Query;
use crate::core::database::send_query;

pub async fn add_reacji<R>(
    sql_tx: &mut mpsc::Sender<Query>,
    cache: &cache::Cache<R>,
    input: &str,
    user_id: String,
    channel_id: String,
    ts: String,
    action: ReacjiAction,
)
where
    R: slack::requests::SlackWebRequestSender + std::clone::Clone
{
    match reacji_to_karma(input) {
        Some(karma) => {
            let message_id = query_reacji_message(
                sql_tx,
                channel_id.clone(),
                ts.clone()
            ).await.map_or_else(
                |e| Err(e),
                |v| v.ok_or("NONE".to_string())
            );

            let message_id = match message_id {
                Err(_) => match cache.get_message(&channel_id, &ts).await {
                    Some(cache::ConversationHistoryMessage::Message { text, user_id: Some(user_id) }) => {
                        // We have the message content, insert it into the table and
                        // get its row id
                        let santized_text = santizer(&text, &cache).await;

                        match (
                            cache.get_username(&user_id).await,
                            cache.get_user_real_name(&user_id).await,
                        ) {
                            (Some(ud), Some(rn)) => {
                                add_reacji_message(
                                    sql_tx,
                                    user_id,
                                    KarmaName::new(&ud),
                                    KarmaName::new(&rn),
                                    channel_id.clone(),
                                    ts.clone(),
                                    santized_text
                                ).await
                            },
                            e => Err(format!("ERROR: [User Event] Querying for user/name failed: {:?}", e)),
                        }
                    },

                    // This happens when there is no user_id (is none)
                    // This shouldn't happen but .... slack....
                    Some(cache::ConversationHistoryMessage::Message { user_id: None, .. }) => Ok(None),

                    e => Err(format!("ERROR: [User Event] IDK here: {:?}", e)),
                },
                Ok(mid) => Ok(Some(mid)),
            };

            match message_id {
                Err(e) => {
                    eprintln!("ERROR: [User Event] Wasn't able to get/store an reactji message, vote isn't recorded");
                    eprintln!("ERROR: [User Event] Returned error: {:?}", e);
                },
                Ok(None) => (), // These are expected error, drop
                Ok(Some(mid)) => {
                    match (
                        cache.get_username(&user_id).await,
                        cache.get_user_real_name(&user_id).await,
                    ) {
                        (Some(ud), Some(rn)) => {
                            let e = add_reacji_query(
                                sql_tx,
                                Utc::now(),
                                user_id,
                                KarmaName::new(&ud),
                                KarmaName::new(&rn),
                                action,
                                mid,
                                karma,
                            ).await;

                            if e.is_err() {
                                eprintln!("ERROR: [User Event] Query failed: {:?}", e);
                            }
                        },
                        e => eprintln!("ERROR: [User Event] Querying for user/name failed: {:?}", e),
                    }
                },
            }
        },
        None => (),
    }
}

async fn query_reacji_message(
    sql_tx: &mut mpsc::Sender<Query>,
    channel_id: String,
    message_ts: String,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let channel_id: Option<i64> = {
                let mut stmt = conn.prepare("SELECT id FROM chan_metadata WHERE channel = ?")?;
                let mut rows = stmt.query(rs::params![channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0).ok()
                } else {
                    None
                }
            };

            if let Some(channel_id) = channel_id {
                // We good let's proceed, otherwise abort since if channel id isn't here its
                // not going to be in reacji_message either
                let mut stmt = conn.prepare("SELECT id FROM reacji_message WHERE ts = ? AND chan_id = ?")?;
                let mut rows = stmt.query(rs::params![message_ts, channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    let msg_id: Option<i64> = row.get(0).ok();
                    Ok(msg_id)
                } else {
                    Ok(None)
                }
            } else {
                Ok(None)
            }
        })
    ).await
}

async fn add_reacji_message(
    sql_tx: &mut mpsc::Sender<Query>,
    user_id: String,
    username: KarmaName,
    real_name: KarmaName,
    channel_id: String,
    message_ts: String,
    message: String,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let nick_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM nick_metadata WHERE username = ?")?;
                let mut rows = stmt.query(rs::params![user_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare(
                        "INSERT INTO nick_metadata (cleaned_nick, full_name, username, hostmask) VALUES (?, ?, ?, ?)"
                    )?;
                    stmt.insert(rs::params![username, real_name, user_id, "SlackServer"])?
                }
            };

            let channel_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM chan_metadata WHERE channel = ?")?;
                let mut rows = stmt.query(rs::params![channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare("INSERT INTO chan_metadata (channel) VALUES (?)")?;
                    stmt.insert(rs::params![channel_id])?
                }
            };

            // Insert the reacji_message content now
            let mut stmt = conn.prepare(
                "INSERT INTO reacji_message (ts, chan_id, nick_id, message) VALUES (?, ?, ?, ?)"
            )?;

            Ok(
                Some(stmt.insert(rs::params![message_ts, channel_id, nick_id, message])?)
            )
        })
    ).await
}

async fn add_reacji_query(
    sql_tx: &mut mpsc::Sender<Query>,
    timestamp: DateTime<Utc>,
    user_id: String,
    username: KarmaName,
    real_name: KarmaName,
    action: ReacjiAction,
    message_id: i64,
    amount: Karma,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let nick_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM nick_metadata WHERE username = ?")?;
                let mut rows = stmt.query(rs::params![user_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare(
                        "INSERT INTO nick_metadata (cleaned_nick, full_name, username, hostmask) VALUES (?, ?, ?, ?)"
                    )?;

                    stmt.insert(rs::params![username, real_name, user_id, "SlackServer"])?
                }
            };

            let ts = timestamp.to_rfc3339();
            let ts = ts.trim_end_matches("+00:00");

            // Insert the reacji into the database
            let mut stmt = conn.prepare(
                "INSERT INTO reacji_votes
                    (voted_at, by_whom_name, action, reacji_message_id, amount, nick_id)
                VALUES
                    (?, ?, ?, ?, ?, ?)"
            )?;

            stmt.insert(rs::params![ts, username, action, message_id, amount, nick_id])?;

            Ok(None)
        })
    ).await
}
<|endoftext|>


<commit_before>extern crate libc;

#[macro_use]
extern crate apache2;

use libc::{c_void, c_char};
use apache2::{Request, Status, ffi};

#[allow(unused_variables)]
pub extern "C" fn cmd(parms: *mut ffi::cmd_parms, mconfig: *mut c_void, w: *const c_char) -> *const c_char {
   std::ptr::null()
}

const SOME_CMD: ffi::command_rec = ffi::command_rec {
   name: b"SomeCmd\0" as *const u8 as *const c_char,
   func: ffi::cmd_func {
      _bindgen_data_: [cmd as u64]
   },
   cmd_data: 0 as *mut c_void,
   req_override: apache2::ffi::RSRC_CONF,
   args_how: apache2::ffi::TAKE1,
   errmsg: b"Error message\0" as *const u8 as *const c_char
};

const EXAMPLE_DIRECTIVES: [*const ffi::command_rec; 2] = [
   &SOME_CMD,
   0 as *const ffi::command_rec
];

AP_DECLARE_MODULE!(
   conf_module,
   b"mod_conf\0",
   None,
   None,
   None,
   None,
   EXAMPLE_DIRECTIVES[0],
   Some(c_module_hooks)
);

extern "C" fn c_module_hooks(_: *mut apache2::ffi::apr_pool_t) {
   unsafe {
      apache2::ffi::ap_hook_handler(
         Some(c_conf_handler),
         std::ptr::null(),
         std::ptr::null(),
         apache2::HookOrder::MIDDLE.into()
      );
   }
}

#[no_mangle]
pub extern "C" fn c_conf_handler(r: *mut apache2::ffi::request_rec) -> apache2::c_int {
   match apache2::httpd::Request::from_raw_ptr(r) {
      Err(_) => apache2::httpd::Status::DECLINED.into(),
      Ok(mut request) => match conf_handler(&mut request) {
         Ok(status) => status,
         Err(_) => apache2::httpd::Status::HTTP_INTERNAL_SERVER_ERROR
      }.into()
   }
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   r.set_content_type("text/plain; charset=utf-8");

   try!(r.write("CONF: *****"));

   Ok(Status::OK)
}
<commit_msg>More progress on working through the config directives ffi support.<commit_after>extern crate libc;

#[macro_use]
extern crate apache2;

use libc::{c_void, c_char};
use apache2::{Request, Status, ffi};

#[allow(unused_variables)]
pub extern "C" fn cmd(parms: *mut ffi::cmd_parms, mconfig: *mut c_void, w: *const c_char) -> *const c_char {
   std::ptr::null()
}

#[no_mangle]
pub static mut SOME_CMD: ffi::command_rec = ffi::command_rec {
   name: b"SomeCmd\0" as *const u8 as *const c_char,
   func: ffi::cmd_func {
      _bindgen_data_: [cmd as u64]
   },
   cmd_data: 0 as *mut c_void,
   req_override: apache2::ffi::RSRC_CONF,
   args_how: apache2::ffi::TAKE1,
   errmsg: b"Error message\0" as *const u8 as *const c_char
};

#[no_mangle]
pub static mut EXAMPLE_DIRECTIVES: [*const ffi::command_rec; 2] = [
   &ffi::command_rec {
      name: b"SomeCmd\0" as *const u8 as *const c_char,
      func: ffi::cmd_func {
         _bindgen_data_: [cmd as u64]
      },
      cmd_data: 0 as *mut c_void,
      req_override: apache2::ffi::RSRC_CONF,
      args_how: apache2::ffi::TAKE1,
      errmsg: b"Error message\0" as *const u8 as *const c_char
   },
   0 as *const ffi::command_rec
];

AP_DECLARE_MODULE!(
   conf_module,
   b"mod_conf\0",
   None,
   None,
   None,
   None,
   unsafe { &EXAMPLE_DIRECTIVES as *const *const ffi::command_rec },
   Some(c_module_hooks)
);

extern "C" fn c_module_hooks(_: *mut apache2::ffi::apr_pool_t) {
   unsafe {
      apache2::ffi::ap_hook_handler(
         Some(c_conf_handler),
         std::ptr::null(),
         std::ptr::null(),
         apache2::HookOrder::MIDDLE.into()
      );
   }
}

#[no_mangle]
pub extern "C" fn c_conf_handler(r: *mut apache2::ffi::request_rec) -> apache2::c_int {
   match apache2::httpd::Request::from_raw_ptr(r) {
      Err(_) => apache2::httpd::Status::DECLINED.into(),
      Ok(mut request) => match conf_handler(&mut request) {
         Ok(status) => status,
         Err(_) => apache2::httpd::Status::HTTP_INTERNAL_SERVER_ERROR
      }.into()
   }
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "conf" {
      return Ok(Status::DECLINED)
   }

   r.set_content_type("text/plain; charset=utf-8");

   try!(r.write("CONF: *****"));

   Ok(Status::OK)
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Result, Write};

use crate::document::Document;
use crate::inline_table::DEFAULT_INLINE_KEY_DECOR;
use crate::key::Key;
use crate::repr::{DecorDisplay, Formatted, Repr};
use crate::table::{DEFAULT_KEY_DECOR, DEFAULT_TABLE_DECOR};
use crate::value::DEFAULT_VALUE_DECOR;
use crate::{Array, InlineTable, Item, Table, Value};

impl<'d, D: Display> Display for DecorDisplay<'d, D> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(
            f,
            "{}{}{}",
            self.decor.prefix().unwrap_or(self.default.0),
            self.inner,
            self.decor.suffix().unwrap_or(self.default.1)
        )
    }
}

impl Display for Repr {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        self.as_raw().fmt(f)
    }
}

impl<T> Display for Formatted<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "{}", self.decor.display(&self.repr, DEFAULT_VALUE_DECOR))
    }
}

impl Display for Key {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        self.repr().fmt(f)
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        match *self {
            Value::String(ref repr) => write!(f, "{}", repr),
            Value::Integer(ref repr) => write!(f, "{}", repr),
            Value::Float(ref repr) => write!(f, "{}", repr),
            Value::Boolean(ref repr) => write!(f, "{}", repr),
            Value::OffsetDateTime(ref repr) => write!(f, "{}", repr),
            Value::LocalDateTime(ref repr) => write!(f, "{}", repr),
            Value::LocalDate(ref repr) => write!(f, "{}", repr),
            Value::LocalTime(ref repr) => write!(f, "{}", repr),
            Value::Array(ref array) => write!(f, "{}", array),
            Value::InlineTable(ref table) => write!(f, "{}", table),
        }
    }
}

impl Display for Array {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(
            f,
            "{}[",
            self.decor.prefix().unwrap_or(DEFAULT_VALUE_DECOR.0)
        )?;
        join(f, self.iter(), ",")?;
        if self.trailing_comma {
            write!(f, ",")?;
        }
        write!(f, "{}", self.trailing)?;
        write!(
            f,
            "]{}",
            self.decor.suffix().unwrap_or(DEFAULT_VALUE_DECOR.1)
        )
    }
}

impl Display for InlineTable {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(
            f,
            "{}{{",
            self.decor.prefix().unwrap_or(DEFAULT_VALUE_DECOR.0)
        )?;
        write!(f, "{}", self.preamble)?;
        for (i, (key, value)) in self
            .items
            .iter()
            .filter(|&(_, kv)| kv.value.is_value())
            .map(|(_, kv)| {
                (
                    kv.key_decor.display(&kv.key_repr, DEFAULT_INLINE_KEY_DECOR),
                    kv.value.as_value().unwrap(),
                )
            })
            .enumerate()
        {
            if i > 0 {
                write!(f, ",")?;
            }
            write!(f, "{}={}", key, value)?;
        }
        write!(
            f,
            "}}{}",
            self.decor.suffix().unwrap_or(DEFAULT_VALUE_DECOR.1)
        )
    }
}

impl Table {
    fn visit_nested_tables<'t, F>(
        &'t self,
        path: &mut Vec<&'t str>,
        is_array_of_tables: bool,
        callback: &mut F,
    ) -> Result
    where
        F: FnMut(&Table, &Vec<&'t str>, bool) -> Result,
    {
        callback(self, path, is_array_of_tables)?;

        for kv in self.items.values() {
            match kv.value {
                Item::Table(ref t) => {
                    path.push(kv.key_repr.as_raw());
                    t.visit_nested_tables(path, false, callback)?;
                    path.pop();
                }
                Item::ArrayOfTables(ref a) => {
                    for t in a.iter() {
                        path.push(kv.key_repr.as_raw());
                        t.visit_nested_tables(path, true, callback)?;
                        path.pop();
                    }
                }
                _ => {}
            }
        }
        Ok(())
    }
}

fn visit_table(
    f: &mut dyn Write,
    table: &Table,
    path: &[&str],
    is_array_of_tables: bool,
) -> Result {
    if path.is_empty() {
        // don't print header for the root node
    } else if is_array_of_tables {
        write!(
            f,
            "{}[[",
            table.decor.prefix().unwrap_or(DEFAULT_TABLE_DECOR.0)
        )?;
        write!(f, "{}", path.join("."))?;
        writeln!(
            f,
            "]]{}",
            table.decor.suffix().unwrap_or(DEFAULT_TABLE_DECOR.1)
        )?;
    } else if !(table.implicit && table.values_len() == 0) {
        write!(
            f,
            "{}[",
            table.decor.prefix().unwrap_or(DEFAULT_TABLE_DECOR.0)
        )?;
        write!(f, "{}", path.join("."))?;
        writeln!(
            f,
            "]{}",
            table.decor.suffix().unwrap_or(DEFAULT_TABLE_DECOR.1)
        )?;
    }
    // print table body
    for kv in table.items.values() {
        if let Item::Value(ref value) = kv.value {
            writeln!(
                f,
                "{}={}",
                kv.key_decor.display(&kv.key_repr, DEFAULT_KEY_DECOR),
                value
            )?;
        }
    }
    Ok(())
}

impl Display for Table {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let mut path = Vec::new();

        self.visit_nested_tables(&mut path, false, &mut |t, path, is_array| {
            visit_table(f, t, path, is_array)
        })?;
        Ok(())
    }
}

impl Document {
    /// Returns a string representation of the TOML document, attempting to keep
    /// the table headers in their original order.
    fn to_string_in_original_order(&self) -> String {
        let mut string = String::new();
        let mut path = Vec::new();
        let mut last_position = 0;
        let mut tables = Vec::new();
        self.as_table()
            .visit_nested_tables(&mut path, false, &mut |t, p, is_array| {
                if let Some(pos) = t.position {
                    last_position = pos;
                }
                let mut s = String::new();
                visit_table(&mut s, t, p, is_array)?;
                tables.push((last_position, s));
                Ok(())
            })
            .unwrap();

        tables.sort_by_key(|&(id, _)| id);
        for (_, table) in tables {
            string.push_str(&table);
        }
        string.push_str(&self.trailing);
        string
    }
}

impl Display for Document {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let s = self.to_string_in_original_order();
        s.fmt(f)
    }
}

fn join<D, I>(f: &mut Formatter<'_>, iter: I, sep: &str) -> Result
where
    D: Display,
    I: Iterator<Item = D>,
{
    for (i, v) in iter.enumerate() {
        if i > 0 {
            write!(f, "{}", sep)?;
        }
        write!(f, "{}", v)?;
    }
    Ok(())
}
<commit_msg>perf: Lazily `Display` a document (#149)<commit_after>use std::fmt::{Display, Formatter, Result, Write};

use crate::document::Document;
use crate::inline_table::DEFAULT_INLINE_KEY_DECOR;
use crate::key::Key;
use crate::repr::{DecorDisplay, Formatted, Repr};
use crate::table::{DEFAULT_KEY_DECOR, DEFAULT_TABLE_DECOR};
use crate::value::DEFAULT_VALUE_DECOR;
use crate::{Array, InlineTable, Item, Table, Value};

impl<'d, D: Display> Display for DecorDisplay<'d, D> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(
            f,
            "{}{}{}",
            self.decor.prefix().unwrap_or(self.default.0),
            self.inner,
            self.decor.suffix().unwrap_or(self.default.1)
        )
    }
}

impl Display for Repr {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        self.as_raw().fmt(f)
    }
}

impl<T> Display for Formatted<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "{}", self.decor.display(&self.repr, DEFAULT_VALUE_DECOR))
    }
}

impl Display for Key {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        self.repr().fmt(f)
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        match *self {
            Value::String(ref repr) => write!(f, "{}", repr),
            Value::Integer(ref repr) => write!(f, "{}", repr),
            Value::Float(ref repr) => write!(f, "{}", repr),
            Value::Boolean(ref repr) => write!(f, "{}", repr),
            Value::OffsetDateTime(ref repr) => write!(f, "{}", repr),
            Value::LocalDateTime(ref repr) => write!(f, "{}", repr),
            Value::LocalDate(ref repr) => write!(f, "{}", repr),
            Value::LocalTime(ref repr) => write!(f, "{}", repr),
            Value::Array(ref array) => write!(f, "{}", array),
            Value::InlineTable(ref table) => write!(f, "{}", table),
        }
    }
}

impl Display for Array {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(
            f,
            "{}[",
            self.decor.prefix().unwrap_or(DEFAULT_VALUE_DECOR.0)
        )?;
        join(f, self.iter(), ",")?;
        if self.trailing_comma {
            write!(f, ",")?;
        }
        write!(f, "{}", self.trailing)?;
        write!(
            f,
            "]{}",
            self.decor.suffix().unwrap_or(DEFAULT_VALUE_DECOR.1)
        )
    }
}

impl Display for InlineTable {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(
            f,
            "{}{{",
            self.decor.prefix().unwrap_or(DEFAULT_VALUE_DECOR.0)
        )?;
        write!(f, "{}", self.preamble)?;
        for (i, (key, value)) in self
            .items
            .iter()
            .filter(|&(_, kv)| kv.value.is_value())
            .map(|(_, kv)| {
                (
                    kv.key_decor.display(&kv.key_repr, DEFAULT_INLINE_KEY_DECOR),
                    kv.value.as_value().unwrap(),
                )
            })
            .enumerate()
        {
            if i > 0 {
                write!(f, ",")?;
            }
            write!(f, "{}={}", key, value)?;
        }
        write!(
            f,
            "}}{}",
            self.decor.suffix().unwrap_or(DEFAULT_VALUE_DECOR.1)
        )
    }
}

impl Table {
    fn visit_nested_tables<'t, F>(
        &'t self,
        path: &mut Vec<&'t str>,
        is_array_of_tables: bool,
        callback: &mut F,
    ) -> Result
    where
        F: FnMut(&'t Table, &Vec<&'t str>, bool) -> Result,
    {
        callback(self, path, is_array_of_tables)?;

        for kv in self.items.values() {
            match kv.value {
                Item::Table(ref t) => {
                    path.push(kv.key_repr.as_raw());
                    t.visit_nested_tables(path, false, callback)?;
                    path.pop();
                }
                Item::ArrayOfTables(ref a) => {
                    for t in a.iter() {
                        path.push(kv.key_repr.as_raw());
                        t.visit_nested_tables(path, true, callback)?;
                        path.pop();
                    }
                }
                _ => {}
            }
        }
        Ok(())
    }
}

fn visit_table(
    f: &mut dyn Write,
    table: &Table,
    path: &[&str],
    is_array_of_tables: bool,
) -> Result {
    if path.is_empty() {
        // don't print header for the root node
    } else if is_array_of_tables {
        write!(
            f,
            "{}[[",
            table.decor.prefix().unwrap_or(DEFAULT_TABLE_DECOR.0)
        )?;
        write!(f, "{}", path.join("."))?;
        writeln!(
            f,
            "]]{}",
            table.decor.suffix().unwrap_or(DEFAULT_TABLE_DECOR.1)
        )?;
    } else if !(table.implicit && table.values_len() == 0) {
        write!(
            f,
            "{}[",
            table.decor.prefix().unwrap_or(DEFAULT_TABLE_DECOR.0)
        )?;
        write!(f, "{}", path.join("."))?;
        writeln!(
            f,
            "]{}",
            table.decor.suffix().unwrap_or(DEFAULT_TABLE_DECOR.1)
        )?;
    }
    // print table body
    for kv in table.items.values() {
        if let Item::Value(ref value) = kv.value {
            writeln!(
                f,
                "{}={}",
                kv.key_decor.display(&kv.key_repr, DEFAULT_KEY_DECOR),
                value
            )?;
        }
    }
    Ok(())
}

impl Display for Table {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let mut path = Vec::new();

        self.visit_nested_tables(&mut path, false, &mut |t, path, is_array| {
            visit_table(f, t, path, is_array)
        })?;
        Ok(())
    }
}

impl Display for Document {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let mut path = Vec::new();
        let mut last_position = 0;
        let mut tables = Vec::new();
        self.as_table()
            .visit_nested_tables(&mut path, false, &mut |t, p, is_array| {
                if let Some(pos) = t.position {
                    last_position = pos;
                }
                tables.push((last_position, t, p.clone(), is_array));
                Ok(())
            })
            .unwrap();

        tables.sort_by_key(|&(id, _, _, _)| id);
        for (_, table, path, is_array) in tables {
            visit_table(f, table, &path, is_array)?;
        }
        self.trailing.fmt(f)
    }
}

fn join<D, I>(f: &mut Formatter<'_>, iter: I, sep: &str) -> Result
where
    D: Display,
    I: Iterator<Item = D>,
{
    for (i, v) in iter.enumerate() {
        if i > 0 {
            write!(f, "{}", sep)?;
        }
        write!(f, "{}", v)?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>#![cfg(feature = "encoding")]

#![feature(test)]
extern crate test;

#[macro_use]
extern crate lambda_calculus as lambda;

use test::Bencher;
use lambda::parigot::numerals::*;
use lambda::*;

#[bench]
fn parigot_succ(b: &mut Bencher) {
    b.iter(|| { beta(app!(succ(), 1.into_parigot()), HAP, 0) } );
}

#[bench]
fn parigot_pred(b: &mut Bencher) {
    b.iter(|| { beta(app!(pred(), 1.into_parigot()), HAP, 0) } );
}

#[bench]
fn parigot_add(b: &mut Bencher) {
    b.iter(|| { beta(app!(add(), 1.into_parigot(), 2.into_parigot()), HAP, 0) } );
}
<commit_msg>benchmark parigot::mult, unify ::add's arguments with other benches<commit_after>#![cfg(feature = "encoding")]

#![feature(test)]
extern crate test;

#[macro_use]
extern crate lambda_calculus as lambda;

use test::Bencher;
use lambda::parigot::numerals::*;
use lambda::*;

#[bench]
fn parigot_succ(b: &mut Bencher) {
    b.iter(|| { beta(app!(succ(), 1.into_parigot()), HAP, 0) } );
}

#[bench]
fn parigot_pred(b: &mut Bencher) {
    b.iter(|| { beta(app!(pred(), 1.into_parigot()), HAP, 0) } );
}

#[bench]
fn parigot_add(b: &mut Bencher) {
    b.iter(|| { beta(app!(add(), 2.into_parigot(), 2.into_parigot()), HAP, 0) } );
}

#[bench]
fn parigot_mult(b: &mut Bencher) {
    b.iter(|| { beta(app!(mult(), 2.into_parigot(), 2.into_parigot()), HAP, 0) } );
}
<|endoftext|>