<commit_before>use super::RootMove;
use super::super::MAX_THREADS;
use super::root_moves_list::{RootMoveList,RawRootMoveList};

use std::heap::{Alloc, Layout, Heap};
use std::ptr::Unique;
use std::sync::Arc;
use std::sync::atomic::{Ordering,AtomicUsize,fence,compiler_fence};
use std::mem;

use std::iter::{Iterator,IntoIterator};

use pleco::Board;
use pleco::board::movegen::{MoveGen,Legal};
use pleco::core::mono_traits::AllGenType;

//struct RawRmManager {
//    pub rms: [RawRootMoveList; MAX_THREADS]
//}
//
//impl RawRmManager {
//    pub fn new() -> Unique<RawRmManager> {
//        unsafe {
//            println!("Raw RMManager create: start");
//            let ptr = Heap.alloc_zeroed(Layout::array::<RawRootMoveList>(MAX_THREADS).unwrap());
//            println!("Raw RMManager create: created ptr");
//            let new_ptr = match ptr {
//                Ok(ptr) => ptr,
//                Err(err) => Heap.oom(err),
//            };
//            println!("Raw RMManager create: created new_ptr");
//            let raw = Unique::new(new_ptr as *mut RawRmManager).unwrap();
//            for x in 0..MAX_THREADS {
//                print!("Attempt {} :", x);
//                let mut list = mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(raw.as_ptr())
//                    .offset(x as isize);
//
//                let raw_list: &mut RawRootMoveList = (*raw.as_ptr()).rms.get_unchecked_mut(x);
//                print!(" raw_list ... ");
//                (*list).init();
//                raw_list.init();
//                println!("Made raw list");
//            }
////            println!("Raw RMManager create: Done!");
//            println!("Raw RMManager created raw ptr! Success");
//            raw
//        }
//    }
//}

pub type RawRmManager = [RawRootMoveList; MAX_THREADS];

pub struct RmManager {
    threads: Arc<AtomicUsize>,
    moves: Unique<RawRmManager>,
    ref_count: Arc<AtomicUsize>
}

unsafe impl Send for RmManager {}

impl Clone for RmManager {
    fn clone(&self) -> Self {
        let ref_count: Arc<AtomicUsize> = self.ref_count.clone();
        ref_count.fetch_add(1, Ordering::SeqCst);
        RmManager {
            threads: self.threads.clone(),
            moves: self.moves.clone(),
            ref_count
        }
    }
}

impl RmManager {
    pub fn new() -> Self {
        let mut rms = RmManager::init();
        rms.allocate();
        unsafe { rms.set_states();}
        rms
    }

    fn init() -> Self {
        RmManager {
            threads: Arc::new(AtomicUsize::new(0)),
            moves: Unique::empty(),
            ref_count: Arc::new(AtomicUsize::new(1))
        }
    }

    fn allocate(&mut self) {
        unsafe {
            let elem_size = mem::size_of::<RawRootMoveList>();
            let alloc_size = elem_size * MAX_THREADS;
            let align = mem::align_of::<RawRootMoveList>();
            let layout = Layout::from_size_align(alloc_size, align).unwrap();
            let result = Heap.alloc_zeroed(layout);
            let new_ptr = match result {
                Ok(ptr) => ptr,
                Err(err) => Heap.oom(err),
            };
            self.moves = Unique::new_unchecked(new_ptr as *mut RawRmManager);
        }
    }

    unsafe fn set_states(&mut self) {
        for x in 0..MAX_THREADS {
            print!("Attempt {} :", x);
            let mut raw_list = self.get_list_unchecked(x);
            print!(" raw_list ... ");
            raw_list.init();
            println!("Made raw list");
        }
    }

    pub fn threads(&self) -> usize {
        self.threads.load(Ordering::Relaxed)
    }

    pub fn add_thread(&mut self) -> Option<RootMoveList> {
        if self.threads() >= MAX_THREADS {
            None
        } else {
            let thread_idx = self.threads.fetch_add(1, Ordering::SeqCst);
            unsafe {
                Some(self.get_list_unchecked(thread_idx))
            }
        }
    }

    pub fn get_list(&self, num: usize) -> Option<RootMoveList> {
        if num >= self.threads() {
            None
        } else {
            unsafe {
                Some(self.get_list_unchecked(num))
            }
        }
    }

    pub unsafe fn get_list_unchecked(&self, num: usize) -> RootMoveList {
        RootMoveList {
            moves: self.as_raw_ptr().offset(num as isize)
        }
    }

    pub unsafe fn replace_moves(&mut self, board: &Board) {
        let legal_moves = MoveGen::generate::<Legal, AllGenType>(&board);
        let mut first = self.as_ptr();
        first.replace(&legal_moves);
        let num = self.threads();
        for i in 1..num {
            self.get_list_unchecked(i).clone_from_other(&first);
        }
    }

    pub unsafe fn as_ptr(&self) -> RootMoveList {
        RootMoveList {
            moves: mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(self.moves.as_ptr())
        }
    }

    unsafe fn as_raw_ptr(&self) -> *mut RawRootMoveList {
        mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(self.moves.as_ptr())
    }

    pub fn wait_for_finish(&self) {
        unsafe {
            for i in 0..self.threads() {
                fence(Ordering::AcqRel);
                compiler_fence(Ordering::AcqRel);
                let root_moves = self.get_list_unchecked(i).moves;
                (*root_moves).finished.await(true);
            }
        }
    }
    pub fn wait_for_start(&self) {
        unsafe {
            let num_threads = self.threads();
            for i in 0..num_threads {
                fence(Ordering::AcqRel);
                compiler_fence(Ordering::AcqRel);
                let root_moves = self.get_list_unchecked(i).moves;
                (*root_moves).finished.await(false);
            }
        }
    }

    pub fn reset_depths(&self) {
        unsafe {
            for i in 0..self.threads() {
                self.get_list_unchecked(i).set_depth_completed(0);
            }
        }
    }

    pub fn thread_best_move_and_depth(&self, thread_id: usize) -> (RootMove, u16) {
        unsafe {
            let mut thread = self.get_list_unchecked(thread_id);
            (thread.first().clone(), thread.depth_completed())
        }

    }

    pub fn best_rootmove(&self, use_stdout: bool) -> RootMove {
        let (mut best_root_move, mut depth_reached): (RootMove, u16) = self.thread_best_move_and_depth(0);
        if use_stdout {
            println!("id: 0, value: {}, prev_value: {}, depth: {}, depth_comp: {}, mov: {}", best_root_move.score, best_root_move.prev_score, best_root_move.depth_reached,depth_reached, best_root_move.bit_move);
        }

        for x in 1..self.threads() {
            let (thread_move, thread_depth): (RootMove, u16)  = self.thread_best_move_and_depth(x);
            let depth_diff = thread_depth as i32 - depth_reached as i32;
            let value_diff = thread_move.score - best_root_move.score;
            if x != 0 {
                // If it has a bigger value and greater or equal depth
                if value_diff > 0 && depth_diff >= 0 {
                    best_root_move = thread_move;
                    depth_reached = thread_depth;
                }
            }

            if use_stdout {
                println!("id: {}, value: {}, prev_value: {}, depth: {}, depth_comp: {}, mov: {}",x, thread_move.score, thread_move.prev_score, thread_move.depth_reached,thread_depth, thread_move.bit_move);
            }
        }
        best_root_move
    }
}

pub struct RootMovesIter<'a> {
    root_moves: &'a RmManager,
    threads: usize,
    idx: usize,
}

impl<'a> Iterator for RootMovesIter<'a> {
    type Item = RootMoveList;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.threads {
            None
        } else {
            unsafe {
                Some(self.root_moves.get_list_unchecked(self.idx))
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.threads - self.idx, Some(self.threads - self.idx))
    }
}

impl<'a> IntoIterator for &'a RmManager {
    type Item = RootMoveList;
    type IntoIter = RootMovesIter<'a>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        RootMovesIter {
            root_moves: &self,
            threads: self.threads(),
            idx: 0,
        }
    }
}

impl Drop for RmManager {
    fn drop(&mut self) {
        let num = self.ref_count.fetch_sub(1, Ordering::SeqCst);
        if num == 1 {
            unsafe {
                Heap.dealloc(self.as_raw_ptr() as *mut _,
                             Layout::array::<RawRootMoveList>(MAX_THREADS).unwrap());
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn rm_basic() {
        let mut rms = RmManager::new();
        assert_eq!(rms.threads(), 0);
        let moves_1 = rms.add_thread().unwrap();
        assert_eq!(rms.threads(), 1);
        assert_eq!(moves_1.len(), 0);
        let board = Board::default();
        unsafe {
            rms.replace_moves(&board);
            let moves_1_clone = rms.get_list_unchecked(0);
            assert_eq!(moves_1.len(), moves_1_clone.len());
            let moves_2 = rms.add_thread().unwrap();
            assert_eq!(rms.threads(), 2);
            rms.replace_moves(&board);
            let moves_2_clone = rms.get_list_unchecked(0);
            assert_eq!(moves_2.len(), moves_2_clone.len());
            assert_eq!(moves_1.len(), moves_2_clone.len());
        }
    }

    #[test]
    fn rm_cloning() {
        let mut rms = RmManager::new();
        let rmsc = rms.clone();
        rms.add_thread();
        rms.add_thread();
        assert_eq!(rms.threads(), rmsc.threads());
    }
}<commit_msg>Removed type println statements<commit_after>use super::RootMove;
use super::super::MAX_THREADS;
use super::root_moves_list::{RootMoveList,RawRootMoveList};

use std::heap::{Alloc, Layout, Heap};
use std::ptr::Unique;
use std::sync::Arc;
use std::sync::atomic::{Ordering,AtomicUsize,fence,compiler_fence};
use std::mem;

use std::iter::{Iterator,IntoIterator};

use pleco::Board;
use pleco::board::movegen::{MoveGen,Legal};
use pleco::core::mono_traits::AllGenType;

//struct RawRmManager {
//    pub rms: [RawRootMoveList; MAX_THREADS]
//}
//
//impl RawRmManager {
//    pub fn new() -> Unique<RawRmManager> {
//        unsafe {
//            println!("Raw RMManager create: start");
//            let ptr = Heap.alloc_zeroed(Layout::array::<RawRootMoveList>(MAX_THREADS).unwrap());
//            println!("Raw RMManager create: created ptr");
//            let new_ptr = match ptr {
//                Ok(ptr) => ptr,
//                Err(err) => Heap.oom(err),
//            };
//            println!("Raw RMManager create: created new_ptr");
//            let raw = Unique::new(new_ptr as *mut RawRmManager).unwrap();
//            for x in 0..MAX_THREADS {
//                print!("Attempt {} :", x);
//                let mut list = mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(raw.as_ptr())
//                    .offset(x as isize);
//
//                let raw_list: &mut RawRootMoveList = (*raw.as_ptr()).rms.get_unchecked_mut(x);
//                print!(" raw_list ... ");
//                (*list).init();
//                raw_list.init();
//                println!("Made raw list");
//            }
////            println!("Raw RMManager create: Done!");
//            println!("Raw RMManager created raw ptr! Success");
//            raw
//        }
//    }
//}

pub type RawRmManager = [RawRootMoveList; MAX_THREADS];

pub struct RmManager {
    threads: Arc<AtomicUsize>,
    moves: Unique<RawRmManager>,
    ref_count: Arc<AtomicUsize>
}

unsafe impl Send for RmManager {}

impl Clone for RmManager {
    fn clone(&self) -> Self {
        let ref_count: Arc<AtomicUsize> = self.ref_count.clone();
        ref_count.fetch_add(1, Ordering::SeqCst);
        RmManager {
            threads: self.threads.clone(),
            moves: self.moves.clone(),
            ref_count
        }
    }
}

impl RmManager {
    pub fn new() -> Self {
        let mut rms = RmManager::init();
        rms.allocate();
        unsafe { rms.set_states();}
        rms
    }

    fn init() -> Self {
        RmManager {
            threads: Arc::new(AtomicUsize::new(0)),
            moves: Unique::empty(),
            ref_count: Arc::new(AtomicUsize::new(1))
        }
    }

    fn allocate(&mut self) {
        unsafe {
            let elem_size = mem::size_of::<RawRootMoveList>();
            let alloc_size = elem_size * MAX_THREADS;
            let align = mem::align_of::<RawRootMoveList>();
            let layout = Layout::from_size_align(alloc_size, align).unwrap();
            let result = Heap.alloc_zeroed(layout);
            let new_ptr = match result {
                Ok(ptr) => ptr,
                Err(err) => Heap.oom(err),
            };
            self.moves = Unique::new_unchecked(new_ptr as *mut RawRmManager);
        }
    }

    unsafe fn set_states(&mut self) {
        for x in 0..MAX_THREADS {
            let mut raw_list = self.get_list_unchecked(x);
            raw_list.init();
        }
    }

    pub fn threads(&self) -> usize {
        self.threads.load(Ordering::Relaxed)
    }

    pub fn add_thread(&mut self) -> Option<RootMoveList> {
        if self.threads() >= MAX_THREADS {
            None
        } else {
            let thread_idx = self.threads.fetch_add(1, Ordering::SeqCst);
            unsafe {
                Some(self.get_list_unchecked(thread_idx))
            }
        }
    }

    pub fn get_list(&self, num: usize) -> Option<RootMoveList> {
        if num >= self.threads() {
            None
        } else {
            unsafe {
                Some(self.get_list_unchecked(num))
            }
        }
    }

    pub unsafe fn get_list_unchecked(&self, num: usize) -> RootMoveList {
        RootMoveList {
            moves: self.as_raw_ptr().offset(num as isize)
        }
    }

    pub unsafe fn replace_moves(&mut self, board: &Board) {
        let legal_moves = MoveGen::generate::<Legal, AllGenType>(&board);
        let mut first = self.as_ptr();
        first.replace(&legal_moves);
        let num = self.threads();
        for i in 1..num {
            self.get_list_unchecked(i).clone_from_other(&first);
        }
    }

    pub unsafe fn as_ptr(&self) -> RootMoveList {
        RootMoveList {
            moves: mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(self.moves.as_ptr())
        }
    }

    unsafe fn as_raw_ptr(&self) -> *mut RawRootMoveList {
        mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(self.moves.as_ptr())
    }

    pub fn wait_for_finish(&self) {
        unsafe {
            for i in 0..self.threads() {
                fence(Ordering::AcqRel);
                compiler_fence(Ordering::AcqRel);
                let root_moves = self.get_list_unchecked(i).moves;
                (*root_moves).finished.await(true);
            }
        }
    }
    pub fn wait_for_start(&self) {
        unsafe {
            let num_threads = self.threads();
            for i in 0..num_threads {
                fence(Ordering::AcqRel);
                compiler_fence(Ordering::AcqRel);
                let root_moves = self.get_list_unchecked(i).moves;
                (*root_moves).finished.await(false);
            }
        }
    }

    pub fn reset_depths(&self) {
        unsafe {
            for i in 0..self.threads() {
                self.get_list_unchecked(i).set_depth_completed(0);
            }
        }
    }

    pub fn thread_best_move_and_depth(&self, thread_id: usize) -> (RootMove, u16) {
        unsafe {
            let mut thread = self.get_list_unchecked(thread_id);
            (thread.first().clone(), thread.depth_completed())
        }

    }

    pub fn best_rootmove(&self, use_stdout: bool) -> RootMove {
        let (mut best_root_move, mut depth_reached): (RootMove, u16) = self.thread_best_move_and_depth(0);
        if use_stdout {
            println!("id: 0, value: {}, prev_value: {}, depth: {}, depth_comp: {}, mov: {}", best_root_move.score, best_root_move.prev_score, best_root_move.depth_reached,depth_reached, best_root_move.bit_move);
        }

        for x in 1..self.threads() {
            let (thread_move, thread_depth): (RootMove, u16)  = self.thread_best_move_and_depth(x);
            let depth_diff = thread_depth as i32 - depth_reached as i32;
            let value_diff = thread_move.score - best_root_move.score;
            if x != 0 {
                // If it has a bigger value and greater or equal depth
                if value_diff > 0 && depth_diff >= 0 {
                    best_root_move = thread_move;
                    depth_reached = thread_depth;
                }
            }

            if use_stdout {
                println!("id: {}, value: {}, prev_value: {}, depth: {}, depth_comp: {}, mov: {}",x, thread_move.score, thread_move.prev_score, thread_move.depth_reached,thread_depth, thread_move.bit_move);
            }
        }
        best_root_move
    }
}

pub struct RootMovesIter<'a> {
    root_moves: &'a RmManager,
    threads: usize,
    idx: usize,
}

impl<'a> Iterator for RootMovesIter<'a> {
    type Item = RootMoveList;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.threads {
            None
        } else {
            unsafe {
                Some(self.root_moves.get_list_unchecked(self.idx))
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.threads - self.idx, Some(self.threads - self.idx))
    }
}

impl<'a> IntoIterator for &'a RmManager {
    type Item = RootMoveList;
    type IntoIter = RootMovesIter<'a>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        RootMovesIter {
            root_moves: &self,
            threads: self.threads(),
            idx: 0,
        }
    }
}

impl Drop for RmManager {
    fn drop(&mut self) {
        let num = self.ref_count.fetch_sub(1, Ordering::SeqCst);
        if num == 1 {
            unsafe {
                Heap.dealloc(self.as_raw_ptr() as *mut _,
                             Layout::array::<RawRootMoveList>(MAX_THREADS).unwrap());
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn rm_basic() {
        let mut rms = RmManager::new();
        assert_eq!(rms.threads(), 0);
        let moves_1 = rms.add_thread().unwrap();
        assert_eq!(rms.threads(), 1);
        assert_eq!(moves_1.len(), 0);
        let board = Board::default();
        unsafe {
            rms.replace_moves(&board);
            let moves_1_clone = rms.get_list_unchecked(0);
            assert_eq!(moves_1.len(), moves_1_clone.len());
            let moves_2 = rms.add_thread().unwrap();
            assert_eq!(rms.threads(), 2);
            rms.replace_moves(&board);
            let moves_2_clone = rms.get_list_unchecked(0);
            assert_eq!(moves_2.len(), moves_2_clone.len());
            assert_eq!(moves_1.len(), moves_2_clone.len());
        }
    }

    #[test]
    fn rm_cloning() {
        let mut rms = RmManager::new();
        let rmsc = rms.clone();
        rms.add_thread();
        rms.add_thread();
        assert_eq!(rms.threads(), rmsc.threads());
    }
}<|endoftext|>


<commit_before>/*
 * PCG Random Number Generation for Rust
 *
 * Copyright 2015 John Brooks <robojeb@robojeb.xyz>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/// The types of numaric options that PCG needs to operate.
/// Some day this will be replaced with Num-traits when they support
/// wrapping opts for everything, and when extprim supports those traits as
/// well.
pub trait PcgOps {
    fn wrap_mul(&self, rhs : Self) -> Self;
    fn wrap_add(&self, rhs : Self) -> Self;
}

/// Convert a value to a usize don't care about overflow etc
pub trait AsUsize {
    fn as_usize(&self) -> usize;
}

/// A trait that determines how many bits are in a type.
pub trait BitSize {
    const BITS: usize;
}

/// Allows a type to become a type of a smaller value.
pub trait AsSmaller<T> {
    fn shrink(self) -> T;
}

//Implementations of the traits for basic types
macro_rules! basic_ops {
    ( $( $t:ty, $bits:expr);*) => {
        $(impl BitSize for $t {
            const BITS: usize = $bits;
        }

        impl AsUsize for $t {
            fn as_usize(&self) -> usize {
                *self as usize
            }
        }

        impl PcgOps for $t {
            #[inline]
            fn wrap_mul(&self, rhs : $t) -> $t {
                self.wrapping_mul(rhs)
            }

            #[inline]
            fn wrap_add(&self, rhs : $t) -> $t {
                self.wrapping_add(rhs)
            }
        }

        )*
    }
}

basic_ops!(
    u8, 8;
    u16, 16;
    u32, 32;
    u64, 64;
    u128, 128
);

macro_rules! smaller {
    ( $( $t:ty, $other:ty);*) => {
        $(
            impl AsSmaller<$other> for $t {
                fn shrink(self) -> $other {
                    self as $other
                }
            }
        )*
    }
}

smaller!(
    u128, u64;
    u128, u32;
    u128, u16;
    u128, u8;
    u64, u32;
    u64, u16;
    u64, u8;
    u32, u16;
    u32, u8;
    u16, u8
);

// impl PcgOps for u128 {
//     #[inline]
//     fn wrap_mul(&self, rhs : u128) -> u128 {
//         self.wrapping_mul(rhs)
//     }

//     #[inline]
//     fn wrap_add(&self, rhs : u128) -> u128 {
//         self.wrapping_add(rhs)
//     }
// }<commit_msg>Added inline hints for minor release performance gains<commit_after>/*
 * PCG Random Number Generation for Rust
 *
 * Copyright 2015 John Brooks <robojeb@robojeb.xyz>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/// The types of numaric options that PCG needs to operate.
/// Some day this will be replaced with Num-traits when they support
/// wrapping opts for everything, and when extprim supports those traits as
/// well.
pub trait PcgOps {
    fn wrap_mul(&self, rhs : Self) -> Self;
    fn wrap_add(&self, rhs : Self) -> Self;
}

/// Convert a value to a usize don't care about overflow etc
pub trait AsUsize {
    fn as_usize(&self) -> usize;
}

/// A trait that determines how many bits are in a type.
pub trait BitSize {
    const BITS: usize;
}

/// Allows a type to become a type of a smaller value.
pub trait AsSmaller<T> {
    fn shrink(self) -> T;
}

//Implementations of the traits for basic types
macro_rules! basic_ops {
    ( $( $t:ty, $bits:expr);*) => {
        $(impl BitSize for $t {
            const BITS: usize = $bits;
        }

        impl AsUsize for $t {
            #[inline]
            fn as_usize(&self) -> usize {
                *self as usize
            }
        }

        impl PcgOps for $t {
            #[inline]
            fn wrap_mul(&self, rhs : $t) -> $t {
                self.wrapping_mul(rhs)
            }

            #[inline]
            fn wrap_add(&self, rhs : $t) -> $t {
                self.wrapping_add(rhs)
            }
        }

        )*
    }
}

basic_ops!(
    u8, 8;
    u16, 16;
    u32, 32;
    u64, 64;
    u128, 128
);

macro_rules! smaller {
    ( $( $t:ty, $other:ty);*) => {
        $(
            impl AsSmaller<$other> for $t {
                #[inline]
                fn shrink(self) -> $other {
                    self as $other
                }
            }
        )*
    }
}

smaller!(
    u128, u64;
    u128, u32;
    u128, u16;
    u128, u8;
    u64, u32;
    u64, u16;
    u64, u8;
    u32, u16;
    u32, u8;
    u16, u8
);

// impl PcgOps for u128 {
//     #[inline]
//     fn wrap_mul(&self, rhs : u128) -> u128 {
//         self.wrapping_mul(rhs)
//     }

//     #[inline]
//     fn wrap_add(&self, rhs : u128) -> u128 {
//         self.wrapping_add(rhs)
//     }
// }<|endoftext|>


<commit_before>use std::io;
use std::result;

use byteorder::{BigEndian, WriteBytesExt};

use constants::*;
use job::*;
use queues::QueueHolder;

pub struct PacketType {
    pub name: &'static str,
    pub ptype: u32,
    pub nargs: i8,
}

#[derive(PartialEq)]
pub enum PacketMagic {
    UNKNOWN,
    REQ,
    RES,
}

pub struct Packet {
    pub magic: PacketMagic,
    pub ptype: u32,
    pub psize: u32,
    pub data: Box<Vec<u8>>,
    _field_byte_count: usize,
    _field_count: i8,
}

const READ_BUFFER_INIT_CAPACITY: usize = 2048;

impl Iterator for Packet {
    type Item = (usize, usize);
    fn next(&mut self) -> Option<(usize, usize)> {
        let nargs = PTYPES[self.ptype as usize].nargs;
        if self._field_count > nargs {
            return None
        }
        self._field_count += 1;
        println!("DEBUG: returning field #{}", self._field_count);
        if self._field_count == nargs {
            return Some((self._field_byte_count, self.data.len()))
        };
        let start = self._field_byte_count;
        for byte in &self.data[start..] {
            self._field_byte_count += 1;
            if *byte == '\0' as u8 {
                break
            }
        };
        Some((start, self._field_byte_count))
    }
}

pub struct ParseError {}

pub type Result<T> = result::Result<T, ParseError>;

impl Packet {
    pub fn new() -> Packet {
        Packet {
            magic: PacketMagic::UNKNOWN,
            ptype: 0,
            psize: 0,
            data: Box::new(Vec::with_capacity(READ_BUFFER_INIT_CAPACITY)),
            _field_byte_count: 0,
            _field_count: 0,
        }
    }

    pub fn process(&mut self, mut queues: QueueHolder) -> Result<Option<Packet>> {
        match self.ptype {
            SUBMIT_JOB => {
                match self.handleSubmitJob(queues)? {
                    None => Ok(None),
                    Some(p) => {
                        println!("Should send a packet here {}",
                                 PTYPES[p.ptype as usize].name);
                        Ok(None)
                    }
                }
            },
            _ => {
                println!("Unimplemented: processing packet");
                Ok(None)
            },
        }
    }

    fn nextField(&mut self) -> Result<Vec<u8>> {
        let (start, finish) = match self.next() {
            None => return Err(ParseError{}),
            Some((start, finish)) => (start, finish),
        };
        let mut r = Vec::with_capacity(finish - start);
        let new_size = r.capacity();
        r.resize(new_size, 0);
        r.clone_from_slice(&self.data[start..finish]);
        Ok(r)
    }

    fn handleSubmitJob(&mut self, mut queues: QueueHolder) -> Result<Option<Packet>> {
        let fname = self.nextField()?;
        let unique = self.nextField()?;
        let data = self.nextField()?;
        let j = Job::new(fname, unique, data);
        println!("Created job {:?}", j);
        queues.add_job(j);
        Ok(None)
    }

    pub fn to_byteslice(&self) -> Box<[u8]> {
        let len = 12 + self.psize;
        let mut buf = Vec::with_capacity(len as usize) as Vec<u8>;
        let magic = match self.magic {
            PacketMagic::UNKNOWN => panic!("Unknown packet magic cannot be sent"),
            PacketMagic::REQ => REQ,
            PacketMagic::RES => RES,
        };
        buf.extend(magic.iter());
        buf.write_u32::<BigEndian>(self.ptype);
        buf.write_u32::<BigEndian>(self.psize);
        buf.extend(self.data.iter());
        buf.into_boxed_slice()
    }
}

pub static PTYPES: [PacketType; 43] = [
    PacketType { name: "__UNUSED__", ptype: 0, nargs: -1 },
    PacketType { name: "CAN_DO", ptype: 1, nargs: 0 },
    PacketType { name: "CANT_DO", ptype: 2, nargs: 0 },
    PacketType { name: "RESET_ABILITIES", ptype: 3, nargs: -1 },
    PacketType { name: "PRE_SLEEP", ptype: 4, nargs: -1 },
    PacketType { name: "__UNUSED__", ptype: 5, nargs: -1 },
    PacketType { name: "NOOP", ptype: 6, nargs: -1 },
    PacketType { name: "SUBMIT_JOB", ptype: 7, nargs: 2 },
    PacketType { name: "JOB_CREATED", ptype: 8, nargs: 0 },
    PacketType { name: "GRAB_JOB", ptype: 9, nargs: -1 },
    PacketType { name: "NO_JOB", ptype: 10, nargs: -1 },
    PacketType { name: "JOB_ASSIGN", ptype: 11, nargs: 2 },
    PacketType { name: "WORK_STATUS", ptype: 12, nargs: 2 },
    PacketType { name: "WORK_COMPLETE", ptype: 13, nargs: 1 },
    PacketType { name: "WORK_FAIL", ptype: 14, nargs: 0 },
    PacketType { name: "GET_STATUS", ptype: 15, nargs: 0 },
    PacketType { name: "ECHO_REQ", ptype: 16, nargs: 0 },
    PacketType { name: "ECHO_RES", ptype: 17, nargs: 1 },
    PacketType { name: "SUBMIT_JOB_BG", ptype: 18, nargs: 2 },
    PacketType { name: "ERROR", ptype: 19, nargs: 1 },
    PacketType { name: "STATUS_RES", ptype: 20, nargs: 4 },
    PacketType { name: "SUBMIT_JOB_HIGH", ptype: 21, nargs: 2 },
    PacketType { name: "SET_CLIENT_ID", ptype: 22, nargs: 0 },
    PacketType { name: "CAN_DO_TIMEOUT", ptype: 23, nargs: 1 },
    PacketType { name: "ALL_YOURS", ptype: 24, nargs: -1 },
    PacketType { name: "WORK_EXCEPTION", ptype: 25, nargs: 1 },
    PacketType { name: "OPTION_REQ", ptype: 26, nargs: 0 },
    PacketType { name: "OPTION_RES", ptype: 27, nargs: 0 },
    PacketType { name: "WORK_DATA", ptype: 28, nargs: 1 },
    PacketType { name: "WORK_WARNING", ptype: 29, nargs: 1 },
    PacketType { name: "GRAB_JOB_UNIQ", ptype: 30, nargs: -1 },
    PacketType { name: "JOB_ASSIGN_UNIQ", ptype: 31, nargs: 3 },
    PacketType { name: "SUBMIT_JOB_HIGH_BG", ptype: 32, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_LOW", ptype: 33, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_LOW_BG", ptype: 34, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_SCHED", ptype: 35, nargs: 7 },
    PacketType { name: "SUBMIT_JOB_EPOCH", ptype: 36, nargs: 3 },
    PacketType { name: "SUBMIT_REDUCE_JOB", ptype: 37, nargs: 3 },
    PacketType { name: "SUBMIT_REDUCE_JOB_BACKGROUND", ptype: 38, nargs: 3 },
    PacketType { name: "GRAB_JOB_ALL", ptype: 39, nargs: -1 },
    PacketType { name: "JOB_ASSIGN_ALL", ptype: 40, nargs: 4 },
    PacketType { name: "GET_STATUS_UNIQUE", ptype: 41, nargs: 0 },
    PacketType { name: "STATUS_RES_UNIQUE", ptype: 42, nargs: 5 },
];
<commit_msg>responding with JOB_CREATED<commit_after>use std::fmt;
use std::io;
use std::result;

use byteorder::{BigEndian, WriteBytesExt};

use constants::*;
use job::*;
use queues::QueueHolder;

pub struct PacketType {
    pub name: &'static str,
    pub ptype: u32,
    pub nargs: i8,
}

#[derive(PartialEq)]
pub enum PacketMagic {
    UNKNOWN,
    REQ,
    RES,
}

pub struct Packet {
    pub magic: PacketMagic,
    pub ptype: u32,
    pub psize: u32,
    pub data: Box<Vec<u8>>,
    _field_byte_count: usize,
    _field_count: i8,
}

const READ_BUFFER_INIT_CAPACITY: usize = 2048;

impl Iterator for Packet {
    type Item = (usize, usize);
    fn next(&mut self) -> Option<(usize, usize)> {
        let nargs = PTYPES[self.ptype as usize].nargs;
        if self._field_count > nargs {
            return None
        }
        self._field_count += 1;
        println!("DEBUG: returning field #{}", self._field_count);
        if self._field_count == nargs {
            return Some((self._field_byte_count, self.data.len()))
        };
        let start = self._field_byte_count;
        for byte in &self.data[start..] {
            self._field_byte_count += 1;
            if *byte == '\0' as u8 {
                break
            }
        };
        Some((start, self._field_byte_count))
    }
}

pub struct ParseError {}

pub type Result<T> = result::Result<T, ParseError>;

impl Packet {
    pub fn new() -> Packet {
        Packet {
            magic: PacketMagic::UNKNOWN,
            ptype: 0,
            psize: 0,
            data: Box::new(Vec::with_capacity(READ_BUFFER_INIT_CAPACITY)),
            _field_byte_count: 0,
            _field_count: 0,
        }
    }

    pub fn new_res(ptype: u32, data: Box<Vec<u8>>) -> Packet {
        Packet {
            magic: PacketMagic::RES,
            ptype: ptype,
            psize: data.len() as u32,
            data: data,
            _field_byte_count: 0,
            _field_count: 0,
        }
    }

    pub fn process(&mut self, mut queues: QueueHolder) -> Result<Option<Packet>> {
        match self.ptype {
            SUBMIT_JOB => {
                match self.handleSubmitJob(queues)? {
                    None => Ok(None),
                    Some(p) => {
                        println!("Should send a packet here {:?}", p);
                        Ok(Some(p))
                    }
                }
            },
            _ => {
                println!("Unimplemented: processing packet");
                Ok(None)
            },
        }
    }

    fn nextField(&mut self) -> Result<Vec<u8>> {
        let (start, finish) = match self.next() {
            None => return Err(ParseError{}),
            Some((start, finish)) => (start, finish),
        };
        let mut r = Vec::with_capacity(finish - start);
        let new_size = r.capacity();
        r.resize(new_size, 0);
        r.clone_from_slice(&self.data[start..finish]);
        Ok(r)
    }

    fn handleSubmitJob(&mut self, mut queues: QueueHolder) -> Result<Option<Packet>> {
        let fname = self.nextField()?;
        let unique = self.nextField()?;
        let data = self.nextField()?;
        let j = Job::new(fname, unique, data);
        println!("Created job {:?}", j);
        let p = Packet::new_res(JOB_CREATED, Box::new(j.handle.clone()));
        queues.add_job(j);
        Ok(Some(p))
    }

    pub fn to_byteslice(&self) -> Box<[u8]> {
        let len = 12 + self.psize;
        let mut buf = Vec::with_capacity(len as usize) as Vec<u8>;
        let magic = match self.magic {
            PacketMagic::UNKNOWN => panic!("Unknown packet magic cannot be sent"),
            PacketMagic::REQ => REQ,
            PacketMagic::RES => RES,
        };
        buf.extend(magic.iter());
        buf.write_u32::<BigEndian>(self.ptype);
        buf.write_u32::<BigEndian>(self.psize);
        buf.extend(self.data.iter());
        buf.into_boxed_slice()
    }
}

impl fmt::Debug for Packet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Packet {{ magic: {:?}, ptype: {}, size: {} }}",
               match self.magic {
                   PacketMagic::REQ => "REQ",
                   PacketMagic::RES => "RES",
                   _ => "UNKNOWN",
               },
               PTYPES[self.ptype as usize].name,
               self.psize)
    }
}

pub static PTYPES: [PacketType; 43] = [
    PacketType { name: "__UNUSED__", ptype: 0, nargs: -1 },
    PacketType { name: "CAN_DO", ptype: 1, nargs: 0 },
    PacketType { name: "CANT_DO", ptype: 2, nargs: 0 },
    PacketType { name: "RESET_ABILITIES", ptype: 3, nargs: -1 },
    PacketType { name: "PRE_SLEEP", ptype: 4, nargs: -1 },
    PacketType { name: "__UNUSED__", ptype: 5, nargs: -1 },
    PacketType { name: "NOOP", ptype: 6, nargs: -1 },
    PacketType { name: "SUBMIT_JOB", ptype: 7, nargs: 2 },
    PacketType { name: "JOB_CREATED", ptype: 8, nargs: 0 },
    PacketType { name: "GRAB_JOB", ptype: 9, nargs: -1 },
    PacketType { name: "NO_JOB", ptype: 10, nargs: -1 },
    PacketType { name: "JOB_ASSIGN", ptype: 11, nargs: 2 },
    PacketType { name: "WORK_STATUS", ptype: 12, nargs: 2 },
    PacketType { name: "WORK_COMPLETE", ptype: 13, nargs: 1 },
    PacketType { name: "WORK_FAIL", ptype: 14, nargs: 0 },
    PacketType { name: "GET_STATUS", ptype: 15, nargs: 0 },
    PacketType { name: "ECHO_REQ", ptype: 16, nargs: 0 },
    PacketType { name: "ECHO_RES", ptype: 17, nargs: 1 },
    PacketType { name: "SUBMIT_JOB_BG", ptype: 18, nargs: 2 },
    PacketType { name: "ERROR", ptype: 19, nargs: 1 },
    PacketType { name: "STATUS_RES", ptype: 20, nargs: 4 },
    PacketType { name: "SUBMIT_JOB_HIGH", ptype: 21, nargs: 2 },
    PacketType { name: "SET_CLIENT_ID", ptype: 22, nargs: 0 },
    PacketType { name: "CAN_DO_TIMEOUT", ptype: 23, nargs: 1 },
    PacketType { name: "ALL_YOURS", ptype: 24, nargs: -1 },
    PacketType { name: "WORK_EXCEPTION", ptype: 25, nargs: 1 },
    PacketType { name: "OPTION_REQ", ptype: 26, nargs: 0 },
    PacketType { name: "OPTION_RES", ptype: 27, nargs: 0 },
    PacketType { name: "WORK_DATA", ptype: 28, nargs: 1 },
    PacketType { name: "WORK_WARNING", ptype: 29, nargs: 1 },
    PacketType { name: "GRAB_JOB_UNIQ", ptype: 30, nargs: -1 },
    PacketType { name: "JOB_ASSIGN_UNIQ", ptype: 31, nargs: 3 },
    PacketType { name: "SUBMIT_JOB_HIGH_BG", ptype: 32, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_LOW", ptype: 33, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_LOW_BG", ptype: 34, nargs: 2 },
    PacketType { name: "SUBMIT_JOB_SCHED", ptype: 35, nargs: 7 },
    PacketType { name: "SUBMIT_JOB_EPOCH", ptype: 36, nargs: 3 },
    PacketType { name: "SUBMIT_REDUCE_JOB", ptype: 37, nargs: 3 },
    PacketType { name: "SUBMIT_REDUCE_JOB_BACKGROUND", ptype: 38, nargs: 3 },
    PacketType { name: "GRAB_JOB_ALL", ptype: 39, nargs: -1 },
    PacketType { name: "JOB_ASSIGN_ALL", ptype: 40, nargs: 4 },
    PacketType { name: "GET_STATUS_UNIQUE", ptype: 41, nargs: 0 },
    PacketType { name: "STATUS_RES_UNIQUE", ptype: 42, nargs: 5 },
];
<|endoftext|>


<commit_before>use std::mem;
use std::num::from_str_radix;

use phf;
use unicode;

use datum::{Datum, cons};
use lexer::{Token, TokenWrapper, Lexer};
use error::{ParserError, ParserErrorKind};

/// Parser parses character stream into a Datum
pub struct Parser<'a> {
    lexer: Lexer<'a>,
    token_buf: Option<TokenWrapper>
}

fn unexpected_token(tok: &TokenWrapper, expected: String) -> ParserError {
    ParserError {
        line: tok.line,
        column: tok.column,
        kind: ParserErrorKind::UnexpectedToken(format!("{:?}", tok.token), expected)
    }
}

fn invalid_token(tok: &TokenWrapper) -> ParserError {
    ParserError {
        line: tok.line,
        column: tok.column,
        kind: ParserErrorKind::InvalidToken(format!("{:?}", tok.token))
    }
}

static CHAR_MAP: phf::Map<&'static str, char> = phf_map! {
    "nul" => '\0',
    "backspace" => '\x08',
    "tab" => '\t',
    "page" => '\x0c',
    "return" => '\r',
    "space" => ' ',
};

fn parse_char(ch: &str) -> Option<char> {
    match CHAR_MAP.get(ch) {
        Some(c) => return Some(*c),
        None => ()
    };

    if ch.chars().count() == 1 {
        Some(ch.char_at(0))
    } else if ch.starts_with("x") {
        from_str_radix(&ch[1..], 16).and_then(|c| unicode::char::from_u32(c))
    } else {
        None
    }
}

fn parse_numeric(rep: &str) -> Option<isize> {
    rep.parse()
}

impl <'a> Parser<'a> {
    /// Create new parser from io::Buffer
    pub fn new<'r>(stream: &'r mut Buffer) -> Parser<'r> {
        Parser {
            lexer: Lexer::new(stream),
            token_buf: None
        }
    }

    /// Parse next datum
    pub fn parse_datum<T>(&mut self) -> Result<Datum<T>, ParserError> {
        let tok = try!(self.consume_token());
        match tok.token {
            Token::Identifier(ident) => Ok(Datum::Sym(ident)),
            Token::OpenParen => self.parse_list(),
            Token::True => Ok(Datum::Bool(true)),
            Token::False => Ok(Datum::Bool(false)),
            Token::Character(ref ch) => match parse_char(ch.as_slice()) {
                Some(c) => Ok(Datum::Char(c)),
                None => Err(invalid_token(&tok))
            },
            Token::Numeric(ref rep) => match parse_numeric(rep.as_slice()) {
                Some(n) => Ok(Datum::Num(n)),
                None => Err(invalid_token(&tok))
            },
            _ => Err(unexpected_token(&tok, "Datum or OpenParen".to_string()))
        }
    }

    fn consume_token(&mut self) -> Result<TokenWrapper, ParserError> {
        let mut tok = None;
        mem::swap(&mut self.token_buf, &mut tok);
        match tok {
            Some(t) => Ok(t),
            None => self.lexer.lex_token()
        }
    }

    fn lookahead_token<'t>(&'t mut self) -> Result<&'t TokenWrapper, ParserError> {
        if self.token_buf.is_none() {
            self.token_buf = Some(try!(self.lexer.lex_token()));
        }

        Ok(self.token_buf.as_ref().unwrap())
    }

    fn consume_if(&mut self, tok: &Token) -> Result<bool, ParserError> {
        let res = self.lookahead_token().map(|t| t.token == *tok);
        if res == Ok(true) {
            self.token_buf = None;
        }
        res
    }

    fn expect(&mut self, tok: &Token) -> Result<(), ParserError> {
        let t = try!(self.consume_token());
        if t.token == *tok {
            Ok(())
        } else {
            Err(unexpected_token(&t, format!("{:?}", tok)))
        }
    }

    fn parse_list<T>(&mut self) -> Result<Datum<T>, ParserError> {
        if try!(self.consume_if(&Token::CloseParen)) {
            return Ok(Datum::Nil);
        }

        let head = try!(self.parse_datum());

        if try!(self.consume_if(&Token::Dot)) {
            let tail = try!(self.parse_datum());
            try!(self.expect(&Token::CloseParen));
            Ok(cons(head, tail))
        } else {
            let tail = try!(self.parse_list());
            Ok(cons(head, tail))
        }
    }
}

#[cfg(test)]
mod test {
    use std::io::BufReader;
    use std::borrow::Cow;
    use super::Parser;
    use super::super::datum::{Datum, cons};

    fn test_parse(source: &str, result: Datum<()>) {
        let mut reader = BufReader::new(source.as_bytes());
        let mut parser = Parser::new(&mut reader);

        assert_eq!(parser.parse_datum(), Ok(result))
    }

    #[test]
    fn test_sym() {
        test_parse("lambda", sym!("lambda"));
        test_parse("list->vector", sym!("list->vector"));
        test_parse("->vector", sym!("->vector"));
        test_parse("+", sym!("+"));
    }

    #[test]
    fn test_list() {
        test_parse("()", list!());
        test_parse("(a)", list!(sym!("a")));
        test_parse("(a b)", list!(sym!("a"), sym!("b")));
        test_parse("(a . b)", cons(sym!("a"), sym!("b")));
        test_parse("(a; comment!\nb)", list!(sym!("a"), sym!("b")));
    }

    #[test]
    fn test_simple_datum() {
        test_parse("#t", Datum::Bool(true));
        test_parse("#f", Datum::Bool(false));
        test_parse(r##"#\f"##, Datum::Char('f'));
        test_parse(r##"#\x3f"##, Datum::Char('\x3f'));
        test_parse(r##"#\space"##, Datum::Char(' '));
        test_parse(r##"#\nul"##, Datum::Char('\0'));
    }

    #[test]
    fn test_numeric() {
        test_parse("2", Datum::Num(2));
    }
}
<commit_msg>Add character notations<commit_after>use std::mem;
use std::num::from_str_radix;

use phf;
use unicode;

use datum::{Datum, cons};
use lexer::{Token, TokenWrapper, Lexer};
use error::{ParserError, ParserErrorKind};

/// Parser parses character stream into a Datum
pub struct Parser<'a> {
    lexer: Lexer<'a>,
    token_buf: Option<TokenWrapper>
}

fn unexpected_token(tok: &TokenWrapper, expected: String) -> ParserError {
    ParserError {
        line: tok.line,
        column: tok.column,
        kind: ParserErrorKind::UnexpectedToken(format!("{:?}", tok.token), expected)
    }
}

fn invalid_token(tok: &TokenWrapper) -> ParserError {
    ParserError {
        line: tok.line,
        column: tok.column,
        kind: ParserErrorKind::InvalidToken(format!("{:?}", tok.token))
    }
}

static CHAR_MAP: phf::Map<&'static str, char> = phf_map! {
    "nul" => '\0',
    "alarm" => '\x07',
    "backspace" => '\x08',
    "tab" => '\t',
    "newline" => '\n',
    "linefeed" => '\n',
    "vtab" => '\x0b',
    "page" => '\x0c',
    "return" => '\r',
    "esc" => '\x1b',
    "space" => ' ',
    "delete" => '\x7f'
};

fn parse_char(ch: &str) -> Option<char> {
    match CHAR_MAP.get(ch) {
        Some(c) => return Some(*c),
        None => ()
    };

    if ch.chars().count() == 1 {
        Some(ch.char_at(0))
    } else if ch.starts_with("x") {
        from_str_radix(&ch[1..], 16).and_then(|c| unicode::char::from_u32(c))
    } else {
        None
    }
}

fn parse_numeric(rep: &str) -> Option<isize> {
    rep.parse()
}

impl <'a> Parser<'a> {
    /// Create new parser from io::Buffer
    pub fn new<'r>(stream: &'r mut Buffer) -> Parser<'r> {
        Parser {
            lexer: Lexer::new(stream),
            token_buf: None
        }
    }

    /// Parse next datum
    pub fn parse_datum<T>(&mut self) -> Result<Datum<T>, ParserError> {
        let tok = try!(self.consume_token());
        match tok.token {
            Token::Identifier(ident) => Ok(Datum::Sym(ident)),
            Token::OpenParen => self.parse_list(),
            Token::True => Ok(Datum::Bool(true)),
            Token::False => Ok(Datum::Bool(false)),
            Token::Character(ref ch) => match parse_char(ch.as_slice()) {
                Some(c) => Ok(Datum::Char(c)),
                None => Err(invalid_token(&tok))
            },
            Token::Numeric(ref rep) => match parse_numeric(rep.as_slice()) {
                Some(n) => Ok(Datum::Num(n)),
                None => Err(invalid_token(&tok))
            },
            _ => Err(unexpected_token(&tok, "Datum or OpenParen".to_string()))
        }
    }

    fn consume_token(&mut self) -> Result<TokenWrapper, ParserError> {
        let mut tok = None;
        mem::swap(&mut self.token_buf, &mut tok);
        match tok {
            Some(t) => Ok(t),
            None => self.lexer.lex_token()
        }
    }

    fn lookahead_token<'t>(&'t mut self) -> Result<&'t TokenWrapper, ParserError> {
        if self.token_buf.is_none() {
            self.token_buf = Some(try!(self.lexer.lex_token()));
        }

        Ok(self.token_buf.as_ref().unwrap())
    }

    fn consume_if(&mut self, tok: &Token) -> Result<bool, ParserError> {
        let res = self.lookahead_token().map(|t| t.token == *tok);
        if res == Ok(true) {
            self.token_buf = None;
        }
        res
    }

    fn expect(&mut self, tok: &Token) -> Result<(), ParserError> {
        let t = try!(self.consume_token());
        if t.token == *tok {
            Ok(())
        } else {
            Err(unexpected_token(&t, format!("{:?}", tok)))
        }
    }

    fn parse_list<T>(&mut self) -> Result<Datum<T>, ParserError> {
        if try!(self.consume_if(&Token::CloseParen)) {
            return Ok(Datum::Nil);
        }

        let head = try!(self.parse_datum());

        if try!(self.consume_if(&Token::Dot)) {
            let tail = try!(self.parse_datum());
            try!(self.expect(&Token::CloseParen));
            Ok(cons(head, tail))
        } else {
            let tail = try!(self.parse_list());
            Ok(cons(head, tail))
        }
    }
}

#[cfg(test)]
mod test {
    use std::io::BufReader;
    use std::borrow::Cow;
    use super::Parser;
    use super::super::datum::{Datum, cons};

    fn test_parse(source: &str, result: Datum<()>) {
        let mut reader = BufReader::new(source.as_bytes());
        let mut parser = Parser::new(&mut reader);

        assert_eq!(parser.parse_datum(), Ok(result))
    }

    #[test]
    fn test_sym() {
        test_parse("lambda", sym!("lambda"));
        test_parse("list->vector", sym!("list->vector"));
        test_parse("->vector", sym!("->vector"));
        test_parse("+", sym!("+"));
    }

    #[test]
    fn test_list() {
        test_parse("()", list!());
        test_parse("(a)", list!(sym!("a")));
        test_parse("(a b)", list!(sym!("a"), sym!("b")));
        test_parse("(a . b)", cons(sym!("a"), sym!("b")));
        test_parse("(a; comment!\nb)", list!(sym!("a"), sym!("b")));
    }

    #[test]
    fn test_simple_datum() {
        test_parse("#t", Datum::Bool(true));
        test_parse("#f", Datum::Bool(false));
        test_parse(r##"#\f"##, Datum::Char('f'));
        test_parse(r##"#\x3f"##, Datum::Char('\x3f'));
        test_parse(r##"#\space"##, Datum::Char(' '));
        test_parse(r##"#\nul"##, Datum::Char('\0'));
    }

    #[test]
    fn test_numeric() {
        test_parse("2", Datum::Num(2));
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use std::str::Chars;
use std::iter::FromIterator;
use std::marker::PhantomData;

use combine::{Parser, ParseResult, Stream, parser};
use combine::char::{CrLf, Tab, tab, char, crlf};
use combine::combinator::{Many, FnParser, NoneOf, Skip, Or, Token, or, many, none_of};

pub type Name = String;
pub type SelectionSet = Vec<Selection>;

#[derive(Debug,PartialEq)]
pub struct Document {
  definitions: Vec<Definition>,
}

#[derive(Debug,PartialEq)]
pub enum Definition {
  OperationDefinition(Operation),
  SelectionSetDefinition(SelectionSet),
  FragmentDefinition(Fragment),
}

#[derive(Debug,PartialEq)]
pub struct Operation {
  op_type: OperationType,
  name: Option<Name>,
  variable_definitions: Vec<VariableDefinition>,
  directives: Vec<Directive>,
}

impl Operation {
  fn new(op_type: OperationType,
         name: Option<Name>,
         variable_definitions: Vec<VariableDefinition>,
         directives: Vec<Directive>)
         -> Operation {
    Operation {
      op_type: op_type,
      name: name,
      variable_definitions: variable_definitions,
      directives: directives,
    }
  }
}

#[derive(Debug,PartialEq)]
pub enum OperationType {
  Query,
  Mutation,
}

#[derive(Debug,PartialEq)]
pub struct VariableDefinition {
  variable: Variable,
  var_type: Type,
  default_value: Option<Value>,
}

type Variable = String;

#[derive(Debug,PartialEq)]
pub enum Type {
  NamedType(Name),
  ListType(Box<Type>),
  NonNullType(Box<Type>),
}

#[derive(Debug,PartialEq)]
pub enum Value {
  Var(Variable),
  IntValue(i32),
  FloatValue(f32),
  StringValue(String),
  BooleanValue(bool),
  NullValue,
  EnumValue(String),
  ListValue(Vec<Value>),
  ObjectValue(HashMap<String, Value>),
}

#[derive(Debug,PartialEq)]
pub struct Directive {
  name: Name,
  arguments: Vec<Argument>,
}

#[derive(Debug,PartialEq)]
pub struct Argument {
  name: Name,
  value: Value,
}

#[derive(Debug,PartialEq)]
pub enum Selection {
  FieldSelection(Field),
  FragmentSpread(Name, Vec<Directive>),
  InlineFragment(Option<Type>, Vec<Directive>, SelectionSet),
}

#[derive(Debug,PartialEq)]
pub struct Field {
  alias: Option<Name>,
  name: Name,
  arguments: Vec<Argument>,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

impl Field {
  fn new(alias: Option<Name>,
         name: Name,
         arguments: Vec<Argument>,
         directives: Vec<Directive>,
         selection_set: SelectionSet)
         -> Field {
    Field {
      alias: alias,
      name: name,
      arguments: arguments,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq)]
pub struct Fragment {
  name: Name,
  type_condition: Type,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

// ok wtf is going on here
type WhiteSpace<I> = Or<Token<I>, Tab<I>>;
pub fn white_space<I: Stream<Item = char>>() -> WhiteSpace<I> {
  char(' ').or(tab())
}

// https://doc.rust-lang.org/error-index.html#E0207
// struct LineTerminator<T> {
//   phantom: PhantomData<T>,
// }

// impl<T> LineTerminator<T> {
//   fn new() -> Self {
//     LineTerminator {
//       phantom: PhantomData
//     }
//   }
// }

macro_rules! make_parser_struct {
  ($name: ident) => {
    pub struct $name<T> {
      phantom: PhantomData<T>,
    }

    impl<T> $name<T> {
      fn new() -> Self {
        $name {
          phantom: PhantomData
        }
      }
    }
  }
}

macro_rules! make_parser {

    // base case
    () => {};

    ($name:ident ($input_var:ident : $input_item_type:ty) -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

      pub struct $name<T> {
        phantom: PhantomData<T>,
      }

      impl<T> $name<T> {
          pub fn new() -> Self {
              $name {
                phantom: PhantomData
              }
          }
      }

      impl<I> Parser for $name<I> where I: Stream<Item=$input_item_type> {
        type Input = I;
        type Output = $output_type;

        fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
          $($tmpl)*
        }
      }

      make_parser!($($rest)*);
    };

    ($name:ident ($input_var:ident : $input_item_type:ty , $($field:ident : &$typ:ty),*)
      -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

        pub struct $name<'a, T> {
          phantom: PhantomData<T>,
          $( $field: &'a $typ),*
        }

        impl<'a, T> $name<'a, T> {
          pub fn new($($field: &'a $typ),*) -> Self {
            $name {
              phantom: PhantomData,
              $( $field: $field),*
            }
          }
        }

        impl<'a, I> Parser for $name<'a, I> where I: Stream<Item=$input_item_type> {
          type Input = I;
          type Output = $output_type;

          fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
            let &mut $name { phantom, $($field),* } = self;

            $($tmpl)*
          }
        }

        make_parser!($($rest)*);
    };
}

// make_parser_struct!(LineTerminator);

// impl<I> Parser for LineTerminator<I> where I: Stream<Item=char> {
//   type Input = I;
//   type Output = char;

//   fn parse_stream(&mut self, input: I) -> ParseResult<Self::Output, Self::Input> {
//     crlf()
//       .or(char('\r'))
//       .or(char('\n'))
//       .parse_stream(input)
//   }
// }

// make_parser_struct!(Comment);

// impl<I> Parser for Comment<I> where I: Stream<Item=char> {
//   type Input = I;
//   type Output = char;

//   fn parse_stream(&mut self, input: I) -> ParseResult<Self::Output, Self::Input> {
//     char('#')
//       .skip(LineTerminator::new())
//       .parse_stream(input)
//   }
// }

make_parser!(
  LineTerminator(input: char, is_clr: &bool) -> char {

    if !is_clr {
      return char('\r')
        .or(char('\n'))
        .parse_stream(input);
    }

    crlf()
      .or(char('\r'))
      .or(char('\n'))
      .parse_stream(input)
  }
);

make_parser!(
  Comment(input: char) -> char {
    char('#')
      .skip(LineTerminator::new(&true))
      .parse_stream(input)
  }
);

// TODO: combine definitions
// make_parser!(
//   LineTerminator(input: char) -> char {
//     crlf()
//       .or(char('\r'))
//       .or(char('\n'))
//       .parse_stream(input)
//   }

//   Comment(input: char) -> char {
//     char('#')
//       .skip(LineTerminator::new())
//       .parse_stream(input)
//   }
// );

// ok wtf is going on here
// type LineTerminator<I> = Or<Or<CrLf<I>, Token<I>>, Token<I>>;
// pub fn line_terminator<I: Stream<Item = char>>() -> impl Parser<Input=I> {
//     crlf().or(char('\r')).or(char('\n'))
// }

// fn foo<I: Stream<Item = char>>(input: I) -> ParseResult<I::Item, I> {
//   crlf().or(char('\r')).or(char('\n')).parse_stream(input)
// }

// ok wtf is going on here
// type Comment<I> = Skip<Token<I>, LineTerminator<I>>;
// pub fn comment<I: Stream<Item = char>>() -> impl Parser<Input=I>
// {

//   // let lol = line_terminator();

//     char('#')
//         // .skip(many(none_of("".chars())))
//         .skip(LineTerminator::new())
//         // .skip()
// }

// pub fn comma<I: U8Input>(i: I) -> SimpleResult<I,u8>
// {
//   token(i, b',')
// }

// pub fn operation_definition<I: U8Input>(i: I) -> SimpleResult<I,Definition>
// {
//   parse!{i;
//     let op_type = operation_type();
//     white_space() <|> line_terminator();
//     let name = option(|i| name(i).map(Some), None);

//     ret {
//       let op = Operation::new(op_type, name, Vec::new(), Vec::new());
//       Definition::OperationDefinition(op)
//     }
//   }
// }

// pub fn operation_type<I: U8Input>(i: I) -> SimpleResult<I,OperationType>
// {
//   let op_type = |i,b,r| string(i,b).map(|_| r);
//   parse!{i;
//       op_type(b"query", OperationType::Query) <|>
//       op_type(b"mutation", OperationType::Mutation)
//   }
// }

// pub fn name<I: U8Input>(i: I) -> SimpleResult<I,Name>
// {
//   parse!{i;
//     let start = satisfy(|c| is_alpha(c) || c == b'_');
//     let rest = take_while(|c| is_alphanumeric(c) || c == b'_');

//     ret {
//       let mut start = String::from_utf8(vec![start]).unwrap();
//       let rest = String::from_utf8(rest.to_vec()).unwrap();
//       start.push_str(&rest);
//       start
//     }
//   }
// }

// pub fn alias<I: U8Input>(i: I) -> SimpleResult<I, Option<Name>>
// {
//   let parser = |i: I| {
//       parse!{i;
//         let name = name();

//         either(white_space, line_terminator);
//         token(b':');

//         ret Some(name)
//       }
//   };

//   option(i, parser, None)
// }

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

    #[test]
    fn test_parse_comment() {
      assert_eq!(Comment::new().parse("#\r\n").map(|x| x.0), Ok('#'));
    }

  #[test]
  fn test_operation_type() {}

  #[test]
  fn test_alias() {}
}
<commit_msg>format; cleanup<commit_after>use std::collections::HashMap;

use std::marker::PhantomData;

use combine::{Parser, ParseResult, Stream, value};
use combine::char::{tab, char, crlf};
use combine::combinator::{many, none_of};

pub type Name = String;
pub type SelectionSet = Vec<Selection>;

#[derive(Debug,PartialEq)]
pub struct Document {
  definitions: Vec<Definition>,
}

#[derive(Debug,PartialEq)]
pub enum Definition {
  Operation(Operation),
  SelectionSet(SelectionSet),
  Fragment(Fragment),
}

#[derive(Debug,PartialEq)]
pub struct Operation {
  op_type: OperationType,
  name: Option<Name>,
  variable_definitions: Vec<VariableDefinition>,
  directives: Vec<Directive>,
}

impl Operation {
  fn new(op_type: OperationType,
         name: Option<Name>,
         variable_definitions: Vec<VariableDefinition>,
         directives: Vec<Directive>)
         -> Operation {
    Operation {
      op_type: op_type,
      name: name,
      variable_definitions: variable_definitions,
      directives: directives,
    }
  }
}

#[derive(Debug,PartialEq)]
pub enum OperationType {
  Query,
  Mutation,
}

#[derive(Debug,PartialEq)]
pub struct VariableDefinition {
  variable: Variable,
  var_type: Type,
  default_value: Option<Value>,
}

type Variable = String;

#[derive(Debug,PartialEq)]
pub enum Type {
  Named(Name),
  List(Box<Type>),
  NonNull(Box<Type>),
}

#[derive(Debug,PartialEq)]
pub enum Value {
  Variable(Variable),
  Int(i32),
  Float(f32),
  String(String),
  Boolean(bool),
  Null,
  Enum(String),
  List(Vec<Value>),
  Object(HashMap<String, Value>),
}

#[derive(Debug,PartialEq)]
pub struct Directive {
  name: Name,
  arguments: Vec<Argument>,
}

#[derive(Debug,PartialEq)]
pub struct Argument {
  name: Name,
  value: Value,
}

#[derive(Debug,PartialEq)]
pub enum Selection {
  Field(Field),
  FragmentSpread(Name, Vec<Directive>),
  InlineFragment(Option<Type>, Vec<Directive>, SelectionSet),
}

#[derive(Debug,PartialEq)]
pub struct Field {
  alias: Option<Name>,
  name: Name,
  arguments: Vec<Argument>,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

impl Field {
  fn new(alias: Option<Name>,
         name: Name,
         arguments: Vec<Argument>,
         directives: Vec<Directive>,
         selection_set: SelectionSet)
         -> Field {
    Field {
      alias: alias,
      name: name,
      arguments: arguments,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq)]
pub struct Fragment {
  name: Name,
  type_condition: Type,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

macro_rules! make_parser {

    // base case
    () => {};

    ($name:ident ($input_var:ident : $input_item_type:ty) -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

      pub struct $name<T> {
        phantom: PhantomData<T>,
      }

      impl<T> $name<T> {
          pub fn new() -> Self {
              $name {
                phantom: PhantomData
              }
          }
      }

      impl<I> Parser for $name<I> where I: Stream<Item=$input_item_type> {
        type Input = I;
        type Output = $output_type;

        fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
          $($tmpl)*
        }
      }

      make_parser!($($rest)*);
    };

    ($name:ident ($input_var:ident : $input_item_type:ty , $($field:ident : &$typ:ty),*)
      -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

        pub struct $name<'a, T> {
          phantom: PhantomData<T>,
          $( $field: &'a $typ),*
        }

        impl<'a, T> $name<'a, T> {
          pub fn new($($field: &'a $typ),*) -> Self {
            $name {
              phantom: PhantomData,
              $( $field: $field),*
            }
          }
        }

        impl<'a, I> Parser for $name<'a, I> where I: Stream<Item=$input_item_type> {
          type Input = I;
          type Output = $output_type;

          fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
            let &mut $name { phantom, $($field),* } = self;

            $($tmpl)*
          }
        }

        make_parser!($($rest)*);
    };
}

make_parser!(
  WhiteSpace(input: char) -> char {
    char(' ').or(tab())
      .parse_stream(input)
  }
);

make_parser!(
  LineTerminator(input: char, is_clr: &bool) -> char {

    if !is_clr {
      char('\r')
        .or(char('\n'))
        .parse_stream(input)
    } else {
      crlf()
        .or(char('\r'))
        .or(char('\n'))
        .parse_stream(input)
    }
  }
);

make_parser!(
  LineComment(input: char) -> () {
    value(())
      .skip(char('#'))
      .skip(many::<Vec<_>,_>(none_of("\r\n".chars())))
      .skip(LineTerminator::new(&true))
      .parse_stream(input)
  }
);

// pub fn comma<I: U8Input>(i: I) -> SimpleResult<I,u8>
// {
//   token(i, b',')
// }

// pub fn operation_definition<I: U8Input>(i: I) -> SimpleResult<I,Definition>
// {
//   parse!{i;
//     let op_type = operation_type();
//     white_space() <|> line_terminator();
//     let name = option(|i| name(i).map(Some), None);

//     ret {
//       let op = Operation::new(op_type, name, Vec::new(), Vec::new());
//       Definition::OperationDefinition(op)
//     }
//   }
// }

// pub fn operation_type<I: U8Input>(i: I) -> SimpleResult<I,OperationType>
// {
//   let op_type = |i,b,r| string(i,b).map(|_| r);
//   parse!{i;
//       op_type(b"query", OperationType::Query) <|>
//       op_type(b"mutation", OperationType::Mutation)
//   }
// }

// pub fn name<I: U8Input>(i: I) -> SimpleResult<I,Name>
// {
//   parse!{i;
//     let start = satisfy(|c| is_alpha(c) || c == b'_');
//     let rest = take_while(|c| is_alphanumeric(c) || c == b'_');

//     ret {
//       let mut start = String::from_utf8(vec![start]).unwrap();
//       let rest = String::from_utf8(rest.to_vec()).unwrap();
//       start.push_str(&rest);
//       start
//     }
//   }
// }

// pub fn alias<I: U8Input>(i: I) -> SimpleResult<I, Option<Name>>
// {
//   let parser = |i: I| {
//       parse!{i;
//         let name = name();

//         either(white_space, line_terminator);
//         token(b':');

//         ret Some(name)
//       }
//   };

//   option(i, parser, None)
// }

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

  #[test]
  fn test_parse_comment() {
    assert_eq!(LineComment::new().parse("#hello world\r\n").map(|x| x.0), Ok(()));
  }
}
<|endoftext|>


<commit_before>
use regex::Regex;
use collections::treemap::TreeMap;
use serialize::json;
use serialize::json::{Json};
use serialize::json::ToJson;
use url::percent_encoding::lossy_utf8_percent_decode;

use merge::merge;
use helpers::{create_array, push_item_to_array};

static parent_regexp: Regex = regex!(r"^([^][]+)");
static child_regexp: Regex = regex!(r"(\[[^][]*\])");

#[deriving(Show)]
pub enum ParseErrorKind {
    DecodingError,
    Other
}

#[deriving(Show)]
pub struct ParseError {
    pub kind: ParseErrorKind,
    pub message: String
}

pub type ParseResult<T> = Result<T,ParseError>;

pub fn decode_component(source: &str) -> Result<String,String> {
    return Ok(lossy_utf8_percent_decode(source.as_bytes()));
}

fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {

    let mut pairs = vec![];

    for part in body.split_str("&") {
        let separator = part.find_str("]=")
                            .and_then(|pos| Some(pos+1))
                            .or_else(|| part.find_str("="));

        match separator {
            None => pairs.push((part, None)),
            Some(pos) => {
                let key = part.slice_to(pos);
                let val = part.slice_from(pos + 1);
                pairs.push((key, Some(val)));
            }
        }
    }

    return pairs
}

fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match parent_regexp.captures(key) {
        Some(captures) => {
            match decode_component(captures.at(1)) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: DecodingError, message: err_msg })
            }
        }
        None => ()
    };

    for captures in child_regexp.captures_iter(key) {
        match decode_component(captures.at(1)) {
            Ok(decoded_key) => keys.push(decoded_key),
            Err(err_msg) => return Err(ParseError{ kind: DecodingError, message: err_msg })
        }
    }

    Ok(keys)
}

fn cleanup_key(key: &str) -> &str {
    if key.starts_with("[") && key.ends_with("]") {
        key.slice_chars(1, key.len()-1)
    } else {
        key
    }
}

fn create_idx_merger(idx: uint, obj: Json) -> Json {
    let mut tree: TreeMap<String,Json> = TreeMap::new();
    tree.insert("__idx".to_string(), idx.to_json());
    tree.insert("__object".to_string(), obj);
    return json::Object(tree)
}

fn create_object_with_key(key: String, obj: Json) -> Json {
    let mut tree: TreeMap<String,Json> = TreeMap::new();
    tree.insert(key, obj);
    return json::Object(tree)
}

fn apply_object(keys: &[String], val: Json) -> Json {

    if keys.len() > 0 {
        let key = keys.get(0).unwrap();
        if key.as_slice() == "[]" {
            let mut new_array = create_array();
            let item = apply_object(keys.tail(), val);
            push_item_to_array(&mut new_array, item);
            return new_array;
        } else {
            let key = cleanup_key(key.as_slice());
            let array_index: Option<uint> = from_str(key);

            match array_index {
                Some(idx) => {
                    let result = apply_object(keys.tail(), val);
                    let item = create_idx_merger(idx, result);
                    return item;
                },
                None => {
                    return create_object_with_key(key.to_string(), apply_object(keys.tail(), val));
                }
            }
        }

    } else {
        return val;
    }
}

pub fn parse(params: &str) -> ParseResult<Json> {
    let tree: TreeMap<String,Json> = TreeMap::new();
    let mut obj = tree.to_json();
    let pairs = parse_pairs(params);
    for &(key, value) in pairs.iter() {
        let parse_key_res = try!(parse_key(key));
        let key_chain = parse_key_res.slice_from(0);
        let decoded_value = match decode_component(value.unwrap_or("")) {
            Ok(val) => val,
            Err(err) => return Err(ParseError{ kind: DecodingError, message: err })
        };
        let partial = apply_object(key_chain, decoded_value.to_json());
        merge(&mut obj, &partial);
    }

    Ok(obj)
}

#[test]
fn it_parses_simple_string() {
    assert_eq!(parse("0=foo").unwrap().to_string(), r#"{"0":"foo"}"#.to_string())
    assert_eq!(parse("a[<=>]==23").unwrap().to_string(), r#"{"a":{"<=>":"=23"}}"#.to_string())
    assert_eq!(parse(" foo = bar = baz ").unwrap().to_string(), r#"{" foo ":" bar = baz "}"#.to_string())
}

#[test]
fn it_parses_nested_string() {
    assert_eq!(parse("a[b][c][d][e][f][g][h]=i").unwrap().to_string(),
        r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#.to_string())
}

#[test]
fn it_parses_simple_array() {
    assert_eq!(parse("a=b&a=c").unwrap().to_string(),
        r#"{"a":["b","c"]}"#.to_string())
}

#[test]
fn it_parses_explicit_array() {
    assert_eq!(parse("a[]=b&a[]=c&a[]=d").unwrap().to_string(),
        r#"{"a":["b","c","d"]}"#.to_string())
}

#[test]
fn it_parses_nested_array() {
    assert_eq!(parse("a[b][]=c&a[b][]=d").unwrap().to_string(),
        r#"{"a":{"b":["c","d"]}}"#.to_string())
}

#[test]
fn it_allows_to_specify_array_indexes() {
    assert_eq!(parse("a[0][]=c&a[1][]=d").unwrap().to_string(),
        r#"{"a":[["c"],["d"]]}"#.to_string())
}

#[test]
fn it_transforms_arrays_to_object() {
    assert_eq!(parse("foo[0]=bar&foo[bad]=baz").unwrap().to_string(),
        r#"{"foo":{"0":"bar","bad":"baz"}}"#.to_string());

    assert_eq!(parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").unwrap().to_string(),
        r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#.to_string());
}

#[test]
fn it_doesnt_produce_empty_keys() {
    assert_eq!(parse("_r=1&").unwrap().to_string(),
        r#"{"_r":"1"}"#.to_string());
}

#[test]
fn it_supports_encoded_strings() {
    assert_eq!(parse("a[b%20c]=c%20d").unwrap().to_string(),
        r#"{"a":{"b c":"c d"}}"#.to_string());
}<commit_msg>refactor: fix naming to prevent warnings in modern Rust<commit_after>
use regex::Regex;
use collections::treemap::TreeMap;
use serialize::json;
use serialize::json::{Json};
use serialize::json::ToJson;
use url::percent_encoding::lossy_utf8_percent_decode;

use merge::merge;
use helpers::{create_array, push_item_to_array};

static PARENT_REGEX: Regex = regex!(r"^([^][]+)");
static CHILD_REGEX: Regex = regex!(r"(\[[^][]*\])");

#[deriving(Show)]
pub enum ParseErrorKind {
    DecodingError,
    Other
}

#[deriving(Show)]
pub struct ParseError {
    pub kind: ParseErrorKind,
    pub message: String
}

pub type ParseResult<T> = Result<T,ParseError>;

pub fn decode_component(source: &str) -> Result<String,String> {
    return Ok(lossy_utf8_percent_decode(source.as_bytes()));
}

fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {

    let mut pairs = vec![];

    for part in body.split_str("&") {
        let separator = part.find_str("]=")
                            .and_then(|pos| Some(pos+1))
                            .or_else(|| part.find_str("="));

        match separator {
            None => pairs.push((part, None)),
            Some(pos) => {
                let key = part.slice_to(pos);
                let val = part.slice_from(pos + 1);
                pairs.push((key, Some(val)));
            }
        }
    }

    return pairs
}

fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match PARENT_REGEX.captures(key) {
        Some(captures) => {
            match decode_component(captures.at(1)) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: DecodingError, message: err_msg })
            }
        }
        None => ()
    };

    for captures in CHILD_REGEX.captures_iter(key) {
        match decode_component(captures.at(1)) {
            Ok(decoded_key) => keys.push(decoded_key),
            Err(err_msg) => return Err(ParseError{ kind: DecodingError, message: err_msg })
        }
    }

    Ok(keys)
}

fn cleanup_key(key: &str) -> &str {
    if key.starts_with("[") && key.ends_with("]") {
        key.slice_chars(1, key.len()-1)
    } else {
        key
    }
}

fn create_idx_merger(idx: uint, obj: Json) -> Json {
    let mut tree: TreeMap<String,Json> = TreeMap::new();
    tree.insert("__idx".to_string(), idx.to_json());
    tree.insert("__object".to_string(), obj);
    return json::Object(tree)
}

fn create_object_with_key(key: String, obj: Json) -> Json {
    let mut tree: TreeMap<String,Json> = TreeMap::new();
    tree.insert(key, obj);
    return json::Object(tree)
}

fn apply_object(keys: &[String], val: Json) -> Json {

    if keys.len() > 0 {
        let key = keys.get(0).unwrap();
        if key.as_slice() == "[]" {
            let mut new_array = create_array();
            let item = apply_object(keys.tail(), val);
            push_item_to_array(&mut new_array, item);
            return new_array;
        } else {
            let key = cleanup_key(key.as_slice());
            let array_index: Option<uint> = from_str(key);

            match array_index {
                Some(idx) => {
                    let result = apply_object(keys.tail(), val);
                    let item = create_idx_merger(idx, result);
                    return item;
                },
                None => {
                    return create_object_with_key(key.to_string(), apply_object(keys.tail(), val));
                }
            }
        }

    } else {
        return val;
    }
}

pub fn parse(params: &str) -> ParseResult<Json> {
    let tree: TreeMap<String,Json> = TreeMap::new();
    let mut obj = tree.to_json();
    let pairs = parse_pairs(params);
    for &(key, value) in pairs.iter() {
        let parse_key_res = try!(parse_key(key));
        let key_chain = parse_key_res.slice_from(0);
        let decoded_value = match decode_component(value.unwrap_or("")) {
            Ok(val) => val,
            Err(err) => return Err(ParseError{ kind: DecodingError, message: err })
        };
        let partial = apply_object(key_chain, decoded_value.to_json());
        merge(&mut obj, &partial);
    }

    Ok(obj)
}

#[test]
fn it_parses_simple_string() {
    assert_eq!(parse("0=foo").unwrap().to_string(), r#"{"0":"foo"}"#.to_string())
    assert_eq!(parse("a[<=>]==23").unwrap().to_string(), r#"{"a":{"<=>":"=23"}}"#.to_string())
    assert_eq!(parse(" foo = bar = baz ").unwrap().to_string(), r#"{" foo ":" bar = baz "}"#.to_string())
}

#[test]
fn it_parses_nested_string() {
    assert_eq!(parse("a[b][c][d][e][f][g][h]=i").unwrap().to_string(),
        r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#.to_string())
}

#[test]
fn it_parses_simple_array() {
    assert_eq!(parse("a=b&a=c").unwrap().to_string(),
        r#"{"a":["b","c"]}"#.to_string())
}

#[test]
fn it_parses_explicit_array() {
    assert_eq!(parse("a[]=b&a[]=c&a[]=d").unwrap().to_string(),
        r#"{"a":["b","c","d"]}"#.to_string())
}

#[test]
fn it_parses_nested_array() {
    assert_eq!(parse("a[b][]=c&a[b][]=d").unwrap().to_string(),
        r#"{"a":{"b":["c","d"]}}"#.to_string())
}

#[test]
fn it_allows_to_specify_array_indexes() {
    assert_eq!(parse("a[0][]=c&a[1][]=d").unwrap().to_string(),
        r#"{"a":[["c"],["d"]]}"#.to_string())
}

#[test]
fn it_transforms_arrays_to_object() {
    assert_eq!(parse("foo[0]=bar&foo[bad]=baz").unwrap().to_string(),
        r#"{"foo":{"0":"bar","bad":"baz"}}"#.to_string());

    assert_eq!(parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").unwrap().to_string(),
        r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#.to_string());
}

#[test]
fn it_doesnt_produce_empty_keys() {
    assert_eq!(parse("_r=1&").unwrap().to_string(),
        r#"{"_r":"1"}"#.to_string());
}

#[test]
fn it_supports_encoded_strings() {
    assert_eq!(parse("a[b%20c]=c%20d").unwrap().to_string(),
        r#"{"a":{"b c":"c d"}}"#.to_string());
}<|endoftext|>


<commit_before>use nom::IResult;
use std::str;

pub use common::{FieldExpression, Operator};
use insert::*;
use select::*;

#[derive(Clone, Debug, Hash, PartialEq)]
pub enum SqlQuery {
    Insert(InsertStatement),
    Select(SelectStatement),
}

/// Parse sequence of SQL statements, divided by semicolons or newlines
// named!(pub query_list<&[u8], Vec<SqlQuery> >,
//    many1!(map_res!(selection, |s| { SqlQuery::Select(s) }))
// );

pub fn parse_query(input: &str) -> Result<SqlQuery, &str> {
    // we process all queries in lowercase to avoid having to deal with capitalization in the
    // parser.
    let q_bytes = String::from(input).into_bytes();

    // TODO(malte): appropriately pass through errors from nom
    match insertion(&q_bytes) {
        IResult::Done(_, o) => return Ok(SqlQuery::Insert(o)),
        _ => (),
    };

    match selection(&q_bytes) {
        IResult::Done(_, o) => return Ok(SqlQuery::Select(o)),
        _ => (),
    };

    Err("failed to parse query")
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::hash::{Hash, Hasher};
    use std::collections::hash_map::DefaultHasher;

    #[test]
    fn hash_query() {
        let qstring = "INSERT INTO users VALUES (42, test);";
        let res = parse_query(qstring);
        assert!(res.is_ok());

        let mut h = DefaultHasher::new();
        res.unwrap().hash(&mut h);
        assert_eq!(format!("{:x}", h.finish()), "18c5663ec2a3a77b");
    }
}
<commit_msg>Trim queries before parsing<commit_after>use nom::IResult;
use std::str;

pub use common::{FieldExpression, Operator};
use insert::*;
use select::*;

#[derive(Clone, Debug, Hash, PartialEq)]
pub enum SqlQuery {
    Insert(InsertStatement),
    Select(SelectStatement),
}

/// Parse sequence of SQL statements, divided by semicolons or newlines
// named!(pub query_list<&[u8], Vec<SqlQuery> >,
//    many1!(map_res!(selection, |s| { SqlQuery::Select(s) }))
// );

pub fn parse_query(input: &str) -> Result<SqlQuery, &str> {
    // we process all queries in lowercase to avoid having to deal with capitalization in the
    // parser.
    let q_bytes = String::from(input.trim()).into_bytes();

    // TODO(malte): appropriately pass through errors from nom
    match insertion(&q_bytes) {
        IResult::Done(_, o) => return Ok(SqlQuery::Insert(o)),
        _ => (),
    };

    match selection(&q_bytes) {
        IResult::Done(_, o) => return Ok(SqlQuery::Select(o)),
        _ => (),
    };

    Err("failed to parse query")
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::hash::{Hash, Hasher};
    use std::collections::hash_map::DefaultHasher;

    #[test]
    fn hash_query() {
        let qstring = "INSERT INTO users VALUES (42, test);";
        let res = parse_query(qstring);
        assert!(res.is_ok());

        let mut h = DefaultHasher::new();
        res.unwrap().hash(&mut h);
        assert_eq!(format!("{:x}", h.finish()), "18c5663ec2a3a77b");
    }

    #[test]
    fn trim_query() {
        let qstring = "   INSERT INTO users VALUES (42, test);     ";
        let res = parse_query(qstring);
        assert!(res.is_ok());
    }
}
<|endoftext|>


<commit_before>use nom::{IResult, alpha, alphanumeric};
use std::vec::Vec;

use template::Chunk;

fn rest(i: &[u8]) -> IResult<&[u8], &[u8]> {
    IResult::Done(&[], i)
}

named!(var_name<&[u8], Vec<u8>>,
    map!(
        recognize!(
            do_parse!(
                alpha >>
                many0!(alt!(alphanumeric | tag!("_"))) >>
                ()
            )
        ), Vec::from
    )
);

named!(var<&[u8], Chunk>,
    map!(
        ws!(
            delimited!(
                tag!("{%"),
                var_name,
                tag!("%}")
            )
        ),
        |v| Chunk::Var(Vec::from(v))
    )
);

named!(literal<&[u8], Chunk>,
    map!(
        alt_complete!(take_until!("{%") | rest),
        |s| Chunk::Str(Vec::from(s))
    )
);

named!(pub template<&[u8], Vec<Chunk>>,
    many0!(
        alt!(var | literal)
    )
);
<commit_msg>Use nom's built-in rest implementation<commit_after>use nom::{IResult, alpha, alphanumeric, rest};
use std::vec::Vec;

use template::Chunk;

named!(var_name<&[u8], Vec<u8>>,
    map!(
        recognize!(
            do_parse!(
                alpha >>
                many0!(alt!(alphanumeric | tag!("_"))) >>
                ()
            )
        ), Vec::from
    )
);

named!(var<&[u8], Chunk>,
    map!(
        ws!(
            delimited!(
                tag!("{%"),
                var_name,
                tag!("%}")
            )
        ),
        |v| Chunk::Var(Vec::from(v))
    )
);

named!(literal<&[u8], Chunk>,
    map!(
        alt_complete!(take_until!("{%") | rest),
        |s| Chunk::Str(Vec::from(s))
    )
);

named!(pub template<&[u8], Vec<Chunk>>,
    many0!(
        alt!(var | literal)
    )
);
<|endoftext|>