<commit_before>#![allow(non_camel_case_types)]
// FIXME ^ should be removed

use pyffi::*;
use libc::FILE;

pub type npy_intp = Py_intptr_t;
pub type npy_hash_t = Py_hash_t;

#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_CLIPMODE {
    NPY_CLIP = 0,
    NPY_WRAP = 1,
    NPY_RAISE = 2,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct _object {
    pub ob_refcnt: Py_ssize_t,
    pub ob_type: *mut PyTypeObject,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyMethodDef {
    pub ml_name: *const ::std::os::raw::c_char,
    pub ml_meth: PyCFunction,
    pub ml_flags: ::std::os::raw::c_int,
    pub ml_doc: *const ::std::os::raw::c_char,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyArray_Descr {
    pub ob_base: PyObject,
    pub typeobj: *mut PyTypeObject,
    pub kind: ::std::os::raw::c_char,
    pub type_: ::std::os::raw::c_char,
    pub byteorder: ::std::os::raw::c_char,
    pub flags: ::std::os::raw::c_char,
    pub type_num: ::std::os::raw::c_int,
    pub elsize: ::std::os::raw::c_int,
    pub alignment: ::std::os::raw::c_int,
    pub subarray: *mut _PyArray_Descr__arr_descr,
    pub fields: *mut PyObject,
    pub names: *mut PyObject,
    pub f: *mut PyArray_ArrFuncs,
    pub metadata: *mut PyObject,
    pub c_metadata: *mut NpyAuxData,
    pub hash: npy_hash_t,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyMemberDef([u8; 0]);

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyTypeObject {
    pub ob_base: PyVarObject,
    pub tp_name: *const ::std::os::raw::c_char,
    pub tp_basicsize: Py_ssize_t,
    pub tp_itemsize: Py_ssize_t,
    pub tp_dealloc: destructor,
    pub tp_print: printfunc,
    pub tp_getattr: getattrfunc,
    pub tp_setattr: setattrfunc,
    pub tp_as_async: *mut PyAsyncMethods,
    pub tp_repr: reprfunc,
    pub tp_as_number: *mut PyNumberMethods,
    pub tp_as_sequence: *mut PySequenceMethods,
    pub tp_as_mapping: *mut PyMappingMethods,
    pub tp_hash: hashfunc,
    pub tp_call: ternaryfunc,
    pub tp_str: reprfunc,
    pub tp_getattro: getattrofunc,
    pub tp_setattro: setattrofunc,
    pub tp_as_buffer: *mut PyBufferProcs,
    pub tp_flags: ::std::os::raw::c_ulong,
    pub tp_doc: *const ::std::os::raw::c_char,
    pub tp_traverse: traverseproc,
    pub tp_clear: inquiry,
    pub tp_richcompare: richcmpfunc,
    pub tp_weaklistoffset: Py_ssize_t,
    pub tp_iter: getiterfunc,
    pub tp_iternext: iternextfunc,
    pub tp_methods: *mut PyMethodDef,
    pub tp_members: *mut PyMemberDef,
    pub tp_getset: *mut PyGetSetDef,
    pub tp_base: *mut PyTypeObject,
    pub tp_dict: *mut PyObject,
    pub tp_descr_get: descrgetfunc,
    pub tp_descr_set: descrsetfunc,
    pub tp_dictoffset: Py_ssize_t,
    pub tp_init: initproc,
    pub tp_alloc: allocfunc,
    pub tp_new: newfunc,
    pub tp_free: freefunc,
    pub tp_is_gc: inquiry,
    pub tp_bases: *mut PyObject,
    pub tp_mro: *mut PyObject,
    pub tp_cache: *mut PyObject,
    pub tp_subclasses: *mut PyObject,
    pub tp_weaklist: *mut PyObject,
    pub tp_del: destructor,
    pub tp_version_tag: ::std::os::raw::c_uint,
    pub tp_finalize: destructor,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyArrayObject {
    pub ob_base: PyObject,
    pub data: *mut ::std::os::raw::c_char,
    pub nd: ::std::os::raw::c_int,
    pub dimensions: *mut npy_intp,
    pub strides: *mut npy_intp,
    pub base: *mut PyObject,
    pub descr: *mut PyArray_Descr,
    pub flags: ::std::os::raw::c_int,
    pub weakreflist: *mut PyObject,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct _PyArray_Descr__arr_descr {
    pub base: *mut PyArray_Descr,
    pub shape: *mut PyObject,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyArray_ArrFuncs {
    pub cast: [PyArray_VectorUnaryFunc; 21usize],
    pub getitem: PyArray_GetItemFunc,
    pub setitem: PyArray_SetItemFunc,
    pub copyswapn: PyArray_CopySwapNFunc,
    pub copyswap: PyArray_CopySwapFunc,
    pub compare: PyArray_CompareFunc,
    pub argmax: PyArray_ArgFunc,
    pub dotfunc: PyArray_DotFunc,
    pub scanfunc: PyArray_ScanFunc,
    pub fromstr: PyArray_FromStrFunc,
    pub nonzero: PyArray_NonzeroFunc,
    pub fill: PyArray_FillFunc,
    pub fillwithscalar: PyArray_FillWithScalarFunc,
    pub sort: [PyArray_SortFunc; 3usize],
    pub argsort: [PyArray_ArgSortFunc; 3usize],
    pub castdict: *mut PyObject,
    pub scalarkind: PyArray_ScalarKindFunc,
    pub cancastscalarkindto: *mut *mut ::std::os::raw::c_int,
    pub cancastto: *mut ::std::os::raw::c_int,
    pub fastclip: PyArray_FastClipFunc,
    pub fastputmask: PyArray_FastPutmaskFunc,
    pub fasttake: PyArray_FastTakeFunc,
    pub argmin: PyArray_ArgFunc,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct NpyAuxData {
    pub free: NpyAuxData_FreeFunc,
    pub clone: NpyAuxData_CloneFunc,
    pub reserved: [*mut ::std::os::raw::c_void; 2usize],
}

pub type PyArray_GetItemFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut ::std::os::raw::c_void)
                                                 -> *mut _object>;
pub type PyArray_SetItemFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut PyObject,
                                                 arg2: *mut ::std::os::raw::c_void,
                                                 arg3: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_CopySwapNFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void,
                                                 arg4: npy_intp,
                                                 arg5: npy_intp,
                                                 arg6: ::std::os::raw::c_int,
                                                 arg7: *mut ::std::os::raw::c_void)>;
pub type PyArray_CopySwapFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut ::std::os::raw::c_void,
                                                 arg3: ::std::os::raw::c_int,
                                                 arg4: *mut ::std::os::raw::c_void)>;
pub type PyArray_NonzeroFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_uchar>;
pub type PyArray_CompareFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *const ::std::os::raw::c_void,
                                                 arg2: *const ::std::os::raw::c_void,
                                                 arg3: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_ArgFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut npy_intp,
                                                 arg4: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_DotFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void,
                                                 arg4: npy_intp,
                                                 arg5: *mut ::std::os::raw::c_void,
                                                 arg6: npy_intp,
                                                 arg7: *mut ::std::os::raw::c_void)>;
pub type PyArray_VectorUnaryFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut ::std::os::raw::c_void,
                                                 arg3: npy_intp,
                                                 arg4: *mut ::std::os::raw::c_void,
                                                 arg5: *mut ::std::os::raw::c_void)>;
pub type PyArray_ScanFunc =
    ::std::option::Option<unsafe extern "C" fn(fp: *mut FILE,
                                                 dptr: *mut ::std::os::raw::c_void,
                                                 ignore: *mut ::std::os::raw::c_char,
                                                 arg1: *mut PyArray_Descr)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_FromStrFunc =
    ::std::option::Option<unsafe extern "C" fn(s: *mut ::std::os::raw::c_char,
                                                 dptr: *mut ::std::os::raw::c_void,
                                                 endptr: *mut *mut ::std::os::raw::c_char,
                                                 arg1: *mut PyArray_Descr)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_FillFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_SortFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_ArgSortFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut npy_intp,
                                                 arg3: npy_intp,
                                                 arg4: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_PartitionFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: npy_intp,
                                                 arg4: *mut npy_intp,
                                                 arg5: *mut npy_intp,
                                                 arg6: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_ArgPartitionFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut npy_intp,
                                                 arg3: npy_intp,
                                                 arg4: npy_intp,
                                                 arg5: *mut npy_intp,
                                                 arg6: *mut npy_intp,
                                                 arg7: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_FillWithScalarFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void,
                                                 arg4: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_ScalarKindFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_FastClipFunc =
    ::std::option::Option<unsafe extern "C" fn(in_: *mut ::std::os::raw::c_void,
                                                 n_in: npy_intp,
                                                 min: *mut ::std::os::raw::c_void,
                                                 max: *mut ::std::os::raw::c_void,
                                                 out: *mut ::std::os::raw::c_void)>;
pub type PyArray_FastPutmaskFunc =
    ::std::option::Option<unsafe extern "C" fn(in_: *mut ::std::os::raw::c_void,
                                                 mask: *mut ::std::os::raw::c_void,
                                                 n_in: npy_intp,
                                                 values: *mut ::std::os::raw::c_void,
                                                 nv: npy_intp)>;
pub type PyArray_FastTakeFunc =
    ::std::option::Option<unsafe extern "C" fn(dest: *mut ::std::os::raw::c_void,
                                                 src: *mut ::std::os::raw::c_void,
                                                 indarray: *mut npy_intp,
                                                 nindarray: npy_intp,
                                                 n_outer: npy_intp,
                                                 m_middle: npy_intp,
                                                 nelem: npy_intp,
                                                 clipmode: NPY_CLIPMODE)
                                                 -> ::std::os::raw::c_int>;
pub type NpyAuxData_FreeFunc = ::std::option::Option<unsafe extern "C" fn(arg1: *mut NpyAuxData)>;
pub type NpyAuxData_CloneFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut NpyAuxData) -> *mut NpyAuxData>;
<commit_msg>PyArray_{Dims,Chunk}, PyArrayFlagsObject<commit_after>#![allow(non_camel_case_types)]
// FIXME ^ should be removed

use pyffi::*;
use libc::FILE;

pub type npy_intp = Py_intptr_t;
pub type npy_hash_t = Py_hash_t;

#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum NPY_CLIPMODE {
    NPY_CLIP = 0,
    NPY_WRAP = 1,
    NPY_RAISE = 2,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct _object {
    pub ob_refcnt: Py_ssize_t,
    pub ob_type: *mut PyTypeObject,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyMethodDef {
    pub ml_name: *const ::std::os::raw::c_char,
    pub ml_meth: PyCFunction,
    pub ml_flags: ::std::os::raw::c_int,
    pub ml_doc: *const ::std::os::raw::c_char,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct PyArrayFlagsObject {
    pub ob_base: PyObject,
    pub arr: *mut PyObject,
    pub flags: ::std::os::raw::c_int,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct PyArray_Dims {
    pub ptr: *mut npy_intp,
    pub len: ::std::os::raw::c_int,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct PyArray_Chunk {
    pub ob_base: PyObject,
    pub base: *mut PyObject,
    pub ptr: *mut ::std::os::raw::c_void,
    pub len: npy_intp,
    pub flags: ::std::os::raw::c_int,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyArray_Descr {
    pub ob_base: PyObject,
    pub typeobj: *mut PyTypeObject,
    pub kind: ::std::os::raw::c_char,
    pub type_: ::std::os::raw::c_char,
    pub byteorder: ::std::os::raw::c_char,
    pub flags: ::std::os::raw::c_char,
    pub type_num: ::std::os::raw::c_int,
    pub elsize: ::std::os::raw::c_int,
    pub alignment: ::std::os::raw::c_int,
    pub subarray: *mut _PyArray_Descr__arr_descr,
    pub fields: *mut PyObject,
    pub names: *mut PyObject,
    pub f: *mut PyArray_ArrFuncs,
    pub metadata: *mut PyObject,
    pub c_metadata: *mut NpyAuxData,
    pub hash: npy_hash_t,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyMemberDef([u8; 0]);

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyTypeObject {
    pub ob_base: PyVarObject,
    pub tp_name: *const ::std::os::raw::c_char,
    pub tp_basicsize: Py_ssize_t,
    pub tp_itemsize: Py_ssize_t,
    pub tp_dealloc: destructor,
    pub tp_print: printfunc,
    pub tp_getattr: getattrfunc,
    pub tp_setattr: setattrfunc,
    pub tp_as_async: *mut PyAsyncMethods,
    pub tp_repr: reprfunc,
    pub tp_as_number: *mut PyNumberMethods,
    pub tp_as_sequence: *mut PySequenceMethods,
    pub tp_as_mapping: *mut PyMappingMethods,
    pub tp_hash: hashfunc,
    pub tp_call: ternaryfunc,
    pub tp_str: reprfunc,
    pub tp_getattro: getattrofunc,
    pub tp_setattro: setattrofunc,
    pub tp_as_buffer: *mut PyBufferProcs,
    pub tp_flags: ::std::os::raw::c_ulong,
    pub tp_doc: *const ::std::os::raw::c_char,
    pub tp_traverse: traverseproc,
    pub tp_clear: inquiry,
    pub tp_richcompare: richcmpfunc,
    pub tp_weaklistoffset: Py_ssize_t,
    pub tp_iter: getiterfunc,
    pub tp_iternext: iternextfunc,
    pub tp_methods: *mut PyMethodDef,
    pub tp_members: *mut PyMemberDef,
    pub tp_getset: *mut PyGetSetDef,
    pub tp_base: *mut PyTypeObject,
    pub tp_dict: *mut PyObject,
    pub tp_descr_get: descrgetfunc,
    pub tp_descr_set: descrsetfunc,
    pub tp_dictoffset: Py_ssize_t,
    pub tp_init: initproc,
    pub tp_alloc: allocfunc,
    pub tp_new: newfunc,
    pub tp_free: freefunc,
    pub tp_is_gc: inquiry,
    pub tp_bases: *mut PyObject,
    pub tp_mro: *mut PyObject,
    pub tp_cache: *mut PyObject,
    pub tp_subclasses: *mut PyObject,
    pub tp_weaklist: *mut PyObject,
    pub tp_del: destructor,
    pub tp_version_tag: ::std::os::raw::c_uint,
    pub tp_finalize: destructor,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyArrayObject {
    pub ob_base: PyObject,
    pub data: *mut ::std::os::raw::c_char,
    pub nd: ::std::os::raw::c_int,
    pub dimensions: *mut npy_intp,
    pub strides: *mut npy_intp,
    pub base: *mut PyObject,
    pub descr: *mut PyArray_Descr,
    pub flags: ::std::os::raw::c_int,
    pub weakreflist: *mut PyObject,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct _PyArray_Descr__arr_descr {
    pub base: *mut PyArray_Descr,
    pub shape: *mut PyObject,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyArray_ArrFuncs {
    pub cast: [PyArray_VectorUnaryFunc; 21usize],
    pub getitem: PyArray_GetItemFunc,
    pub setitem: PyArray_SetItemFunc,
    pub copyswapn: PyArray_CopySwapNFunc,
    pub copyswap: PyArray_CopySwapFunc,
    pub compare: PyArray_CompareFunc,
    pub argmax: PyArray_ArgFunc,
    pub dotfunc: PyArray_DotFunc,
    pub scanfunc: PyArray_ScanFunc,
    pub fromstr: PyArray_FromStrFunc,
    pub nonzero: PyArray_NonzeroFunc,
    pub fill: PyArray_FillFunc,
    pub fillwithscalar: PyArray_FillWithScalarFunc,
    pub sort: [PyArray_SortFunc; 3usize],
    pub argsort: [PyArray_ArgSortFunc; 3usize],
    pub castdict: *mut PyObject,
    pub scalarkind: PyArray_ScalarKindFunc,
    pub cancastscalarkindto: *mut *mut ::std::os::raw::c_int,
    pub cancastto: *mut ::std::os::raw::c_int,
    pub fastclip: PyArray_FastClipFunc,
    pub fastputmask: PyArray_FastPutmaskFunc,
    pub fasttake: PyArray_FastTakeFunc,
    pub argmin: PyArray_ArgFunc,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct NpyAuxData {
    pub free: NpyAuxData_FreeFunc,
    pub clone: NpyAuxData_CloneFunc,
    pub reserved: [*mut ::std::os::raw::c_void; 2usize],
}

pub type PyArray_GetItemFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut ::std::os::raw::c_void)
                                                 -> *mut _object>;
pub type PyArray_SetItemFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut PyObject,
                                                 arg2: *mut ::std::os::raw::c_void,
                                                 arg3: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_CopySwapNFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void,
                                                 arg4: npy_intp,
                                                 arg5: npy_intp,
                                                 arg6: ::std::os::raw::c_int,
                                                 arg7: *mut ::std::os::raw::c_void)>;
pub type PyArray_CopySwapFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut ::std::os::raw::c_void,
                                                 arg3: ::std::os::raw::c_int,
                                                 arg4: *mut ::std::os::raw::c_void)>;
pub type PyArray_NonzeroFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_uchar>;
pub type PyArray_CompareFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *const ::std::os::raw::c_void,
                                                 arg2: *const ::std::os::raw::c_void,
                                                 arg3: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_ArgFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut npy_intp,
                                                 arg4: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_DotFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void,
                                                 arg4: npy_intp,
                                                 arg5: *mut ::std::os::raw::c_void,
                                                 arg6: npy_intp,
                                                 arg7: *mut ::std::os::raw::c_void)>;
pub type PyArray_VectorUnaryFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut ::std::os::raw::c_void,
                                                 arg3: npy_intp,
                                                 arg4: *mut ::std::os::raw::c_void,
                                                 arg5: *mut ::std::os::raw::c_void)>;
pub type PyArray_ScanFunc =
    ::std::option::Option<unsafe extern "C" fn(fp: *mut FILE,
                                                 dptr: *mut ::std::os::raw::c_void,
                                                 ignore: *mut ::std::os::raw::c_char,
                                                 arg1: *mut PyArray_Descr)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_FromStrFunc =
    ::std::option::Option<unsafe extern "C" fn(s: *mut ::std::os::raw::c_char,
                                                 dptr: *mut ::std::os::raw::c_void,
                                                 endptr: *mut *mut ::std::os::raw::c_char,
                                                 arg1: *mut PyArray_Descr)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_FillFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_SortFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_ArgSortFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut npy_intp,
                                                 arg3: npy_intp,
                                                 arg4: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_PartitionFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: npy_intp,
                                                 arg4: *mut npy_intp,
                                                 arg5: *mut npy_intp,
                                                 arg6: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_ArgPartitionFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: *mut npy_intp,
                                                 arg3: npy_intp,
                                                 arg4: npy_intp,
                                                 arg5: *mut npy_intp,
                                                 arg6: *mut npy_intp,
                                                 arg7: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_FillWithScalarFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void,
                                                 arg2: npy_intp,
                                                 arg3: *mut ::std::os::raw::c_void,
                                                 arg4: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_ScalarKindFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)
                                                 -> ::std::os::raw::c_int>;
pub type PyArray_FastClipFunc =
    ::std::option::Option<unsafe extern "C" fn(in_: *mut ::std::os::raw::c_void,
                                                 n_in: npy_intp,
                                                 min: *mut ::std::os::raw::c_void,
                                                 max: *mut ::std::os::raw::c_void,
                                                 out: *mut ::std::os::raw::c_void)>;
pub type PyArray_FastPutmaskFunc =
    ::std::option::Option<unsafe extern "C" fn(in_: *mut ::std::os::raw::c_void,
                                                 mask: *mut ::std::os::raw::c_void,
                                                 n_in: npy_intp,
                                                 values: *mut ::std::os::raw::c_void,
                                                 nv: npy_intp)>;
pub type PyArray_FastTakeFunc =
    ::std::option::Option<unsafe extern "C" fn(dest: *mut ::std::os::raw::c_void,
                                                 src: *mut ::std::os::raw::c_void,
                                                 indarray: *mut npy_intp,
                                                 nindarray: npy_intp,
                                                 n_outer: npy_intp,
                                                 m_middle: npy_intp,
                                                 nelem: npy_intp,
                                                 clipmode: NPY_CLIPMODE)
                                                 -> ::std::os::raw::c_int>;
pub type NpyAuxData_FreeFunc = ::std::option::Option<unsafe extern "C" fn(arg1: *mut NpyAuxData)>;
pub type NpyAuxData_CloneFunc =
    ::std::option::Option<unsafe extern "C" fn(arg1: *mut NpyAuxData) -> *mut NpyAuxData>;
<|endoftext|>


<commit_before>//!  structural search replace

use crate::source_change::SourceFileEdit;
use ra_ide_db::RootDatabase;
use ra_syntax::ast::make::expr_from_text;
use ra_syntax::{AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken};
use ra_text_edit::{TextEdit, TextEditBuilder};
use rustc_hash::FxHashMap;
use std::collections::HashMap;
use std::str::FromStr;

pub use ra_db::{SourceDatabase, SourceDatabaseExt};
use ra_ide_db::symbol_index::SymbolsDatabase;

#[derive(Debug, PartialEq)]
pub struct SsrError(String);

impl std::fmt::Display for SsrError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "Parse error: {}", self.0)
    }
}

impl std::error::Error for SsrError {}

pub fn parse_search_replace(
    query: &str,
    db: &RootDatabase,
) -> Result<Vec<SourceFileEdit>, SsrError> {
    let mut edits = vec![];
    let query: SsrQuery = query.parse()?;
    for &root in db.local_roots().iter() {
        let sr = db.source_root(root);
        for file_id in sr.walk() {
            dbg!(db.file_relative_path(file_id));
            let matches = find(&query.pattern, db.parse(file_id).tree().syntax());
            if !matches.matches.is_empty() {
                edits.push(SourceFileEdit { file_id, edit: replace(&matches, &query.template) });
            }
        }
    }
    Ok(edits)
}

#[derive(Debug)]
struct SsrQuery {
    pattern: SsrPattern,
    template: SsrTemplate,
}

#[derive(Debug)]
struct SsrPattern {
    pattern: SyntaxNode,
    vars: Vec<Var>,
}

/// represents an `$var` in an SSR query
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Var(String);

#[derive(Debug)]
struct SsrTemplate {
    template: SyntaxNode,
    placeholders: FxHashMap<SyntaxNode, Var>,
}

type Binding = HashMap<Var, SyntaxNode>;

#[derive(Debug)]
struct Match {
    place: SyntaxNode,
    binding: Binding,
    ignored_comments: Vec<SyntaxToken>,
}

#[derive(Debug)]
struct SsrMatches {
    matches: Vec<Match>,
}

impl FromStr for SsrQuery {
    type Err = SsrError;

    fn from_str(query: &str) -> Result<SsrQuery, SsrError> {
        let mut it = query.split("==>>");
        let pattern = it.next().expect("at least empty string").trim();
        let mut template = it
            .next()
            .ok_or_else(|| SsrError("Cannot find delemiter `==>>`".into()))?
            .trim()
            .to_string();
        if it.next().is_some() {
            return Err(SsrError("More than one delimiter found".into()));
        }
        let mut vars = vec![];
        let mut it = pattern.split('$');
        let mut pattern = it.next().expect("something").to_string();

        for part in it.map(split_by_var) {
            let (var, var_type, remainder) = part?;
            is_expr(var_type)?;
            let new_var = create_name(var, &mut vars)?;
            pattern.push_str(new_var);
            pattern.push_str(remainder);
            template = replace_in_template(template, var, new_var);
        }

        let template = expr_from_text(&template).syntax().clone();
        let mut placeholders = FxHashMap::default();

        traverse(&template, &mut |n| {
            if let Some(v) = vars.iter().find(|v| v.0.as_str() == n.text()) {
                placeholders.insert(n.clone(), v.clone());
                false
            } else {
                true
            }
        });

        let pattern = SsrPattern { pattern: expr_from_text(&pattern).syntax().clone(), vars };
        let template = SsrTemplate { template, placeholders };
        Ok(SsrQuery { pattern, template })
    }
}

fn traverse(node: &SyntaxNode, go: &mut impl FnMut(&SyntaxNode) -> bool) {
    if !go(node) {
        return;
    }
    for ref child in node.children() {
        traverse(child, go);
    }
}

fn split_by_var(s: &str) -> Result<(&str, &str, &str), SsrError> {
    let end_of_name = s.find(':').ok_or_else(|| SsrError("Use $<name>:expr".into()))?;
    let name = &s[0..end_of_name];
    is_name(name)?;
    let type_begin = end_of_name + 1;
    let type_length =
        s[type_begin..].find(|c| !char::is_ascii_alphanumeric(&c)).unwrap_or_else(|| s.len());
    let type_name = &s[type_begin..type_begin + type_length];
    Ok((name, type_name, &s[type_begin + type_length..]))
}

fn is_name(s: &str) -> Result<(), SsrError> {
    if s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
        Ok(())
    } else {
        Err(SsrError("Name can contain only alphanumerics and _".into()))
    }
}

fn is_expr(s: &str) -> Result<(), SsrError> {
    if s == "expr" {
        Ok(())
    } else {
        Err(SsrError("Only $<name>:expr is supported".into()))
    }
}

fn replace_in_template(template: String, var: &str, new_var: &str) -> String {
    let name = format!("${}", var);
    template.replace(&name, new_var)
}

fn create_name<'a>(name: &str, vars: &'a mut Vec<Var>) -> Result<&'a str, SsrError> {
    let sanitized_name = format!("__search_pattern_{}", name);
    if vars.iter().any(|a| a.0 == sanitized_name) {
        return Err(SsrError(format!("Name `{}` repeats more than once", name)));
    }
    vars.push(Var(sanitized_name));
    Ok(&vars.last().unwrap().0)
}

fn find(pattern: &SsrPattern, code: &SyntaxNode) -> SsrMatches {
    fn check(
        pattern: &SyntaxElement,
        code: &SyntaxElement,
        placeholders: &[Var],
        mut match_: Match,
    ) -> Option<Match> {
        match (pattern, code) {
            (SyntaxElement::Token(ref pattern), SyntaxElement::Token(ref code)) => {
                if pattern.text() == code.text() {
                    Some(match_)
                } else {
                    None
                }
            }
            (SyntaxElement::Node(ref pattern), SyntaxElement::Node(ref code)) => {
                if placeholders.iter().any(|n| n.0.as_str() == pattern.text()) {
                    match_.binding.insert(Var(pattern.text().to_string()), code.clone());
                    Some(match_)
                } else {
                    let mut pattern_children = pattern
                        .children_with_tokens()
                        .filter(|element| !element.kind().is_trivia());
                    let mut code_children =
                        code.children_with_tokens().filter(|element| !element.kind().is_trivia());
                    let new_ignored_comments = code.children_with_tokens().filter_map(|element| {
                        if let SyntaxElement::Token(token) = element {
                            if token.kind() == SyntaxKind::COMMENT {
                                return Some(token.clone());
                            }
                        }
                        None
                    });
                    match_.ignored_comments.extend(new_ignored_comments);
                    let match_from_children = pattern_children
                        .by_ref()
                        .zip(code_children.by_ref())
                        .fold(Some(match_), |accum, (a, b)| {
                            accum.and_then(|match_| check(&a, &b, placeholders, match_))
                        });
                    match_from_children.and_then(|match_| {
                        if pattern_children.count() == 0 && code_children.count() == 0 {
                            Some(match_)
                        } else {
                            None
                        }
                    })
                }
            }
            _ => None,
        }
    }
    let kind = pattern.pattern.kind();
    let matches = code
        .descendants_with_tokens()
        .filter(|n| n.kind() == kind)
        .filter_map(|code| {
            let match_ = Match {
                place: code.as_node().unwrap().clone(),
                binding: HashMap::new(),
                ignored_comments: vec![],
            };
            check(&SyntaxElement::from(pattern.pattern.clone()), &code, &pattern.vars, match_)
        })
        .collect();
    SsrMatches { matches }
}

fn replace(matches: &SsrMatches, template: &SsrTemplate) -> TextEdit {
    let mut builder = TextEditBuilder::default();
    for match_ in &matches.matches {
        builder.replace(
            match_.place.text_range(),
            render_replace(&match_.binding, &match_.ignored_comments, template),
        );
    }
    builder.finish()
}

fn render_replace(
    binding: &Binding,
    ignored_comments: &Vec<SyntaxToken>,
    template: &SsrTemplate,
) -> String {
    let mut builder = TextEditBuilder::default();
    for element in template.template.descendants() {
        if let Some(var) = template.placeholders.get(&element) {
            builder.replace(element.text_range(), binding[var].to_string())
        }
    }
    for comment in ignored_comments {
        builder.insert(template.template.text_range().end(), comment.to_string())
    }
    builder.finish().apply(&template.template.text().to_string())
}

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

    fn parse_error_text(query: &str) -> String {
        format!("{}", query.parse::<SsrQuery>().unwrap_err())
    }

    #[test]
    fn parser_happy_case() {
        let result: SsrQuery = "foo($a:expr, $b:expr) ==>> bar($b, $a)".parse().unwrap();
        assert_eq!(&result.pattern.pattern.text(), "foo(__search_pattern_a, __search_pattern_b)");
        assert_eq!(result.pattern.vars.len(), 2);
        assert_eq!(result.pattern.vars[0].0, "__search_pattern_a");
        assert_eq!(result.pattern.vars[1].0, "__search_pattern_b");
        assert_eq!(&result.template.template.text(), "bar(__search_pattern_b, __search_pattern_a)");
        dbg!(result.template.placeholders);
    }

    #[test]
    fn parser_empty_query() {
        assert_eq!(parse_error_text(""), "Parse error: Cannot find delemiter `==>>`");
    }

    #[test]
    fn parser_no_delimiter() {
        assert_eq!(parse_error_text("foo()"), "Parse error: Cannot find delemiter `==>>`");
    }

    #[test]
    fn parser_two_delimiters() {
        assert_eq!(
            parse_error_text("foo() ==>> a ==>> b "),
            "Parse error: More than one delimiter found"
        );
    }

    #[test]
    fn parser_no_pattern_type() {
        assert_eq!(parse_error_text("foo($a) ==>>"), "Parse error: Use $<name>:expr");
    }

    #[test]
    fn parser_invalid_name() {
        assert_eq!(
            parse_error_text("foo($a+:expr) ==>>"),
            "Parse error: Name can contain only alphanumerics and _"
        );
    }

    #[test]
    fn parser_invalid_type() {
        assert_eq!(
            parse_error_text("foo($a:ident) ==>>"),
            "Parse error: Only $<name>:expr is supported"
        );
    }

    #[test]
    fn parser_repeated_name() {
        assert_eq!(
            parse_error_text("foo($a:expr, $a:expr) ==>>"),
            "Parse error: Name `a` repeats more than once"
        );
    }

    #[test]
    fn parse_match_replace() {
        let query: SsrQuery = "foo($x:expr) ==>> bar($x)".parse().unwrap();
        let input = "fn main() { foo(1+2); }";

        let code = SourceFile::parse(input).tree();
        let matches = find(&query.pattern, code.syntax());
        assert_eq!(matches.matches.len(), 1);
        assert_eq!(matches.matches[0].place.text(), "foo(1+2)");
        assert_eq!(matches.matches[0].binding.len(), 1);
        assert_eq!(
            matches.matches[0].binding[&Var("__search_pattern_x".to_string())].text(),
            "1+2"
        );

        let edit = replace(&matches, &query.template);
        assert_eq!(edit.apply(input), "fn main() { bar(1+2); }");
    }

    fn assert_ssr_transform(query: &str, input: &str, result: &str) {
        let query: SsrQuery = query.parse().unwrap();
        let code = SourceFile::parse(input).tree();
        let matches = find(&query.pattern, code.syntax());
        let edit = replace(&matches, &query.template);
        assert_eq!(edit.apply(input), result);
    }

    #[test]
    fn ssr_function_to_method() {
        assert_ssr_transform(
            "my_function($a:expr, $b:expr) ==>> ($a).my_method($b)",
            "loop { my_function( other_func(x, y), z + w) }",
            "loop { (other_func(x, y)).my_method(z + w) }",
        )
    }

    #[test]
    fn ssr_nested_function() {
        assert_ssr_transform(
            "foo($a:expr, $b:expr, $c:expr) ==>> bar($c, baz($a, $b))",
            "fn main { foo  (x + value.method(b), x+y-z, true && false) }",
            "fn main { bar(true && false, baz(x + value.method(b), x+y-z)) }",
        )
    }

    #[test]
    fn ssr_expected_spacing() {
        assert_ssr_transform(
            "foo($x:expr) + bar() ==>> bar($x)",
            "fn main() { foo(5) + bar() }",
            "fn main() { bar(5) }",
        );
    }

    #[test]
    fn ssr_with_extra_space() {
        assert_ssr_transform(
            "foo($x:expr  ) +    bar() ==>> bar($x)",
            "fn main() { foo(  5 )  +bar(   ) }",
            "fn main() { bar(5) }",
        );
    }

    #[test]
    fn ssr_keeps_nested_comment() {
        assert_ssr_transform(
            "foo($x:expr) ==>> bar($x)",
            "fn main() { foo(other(5 /* using 5 */)) }",
            "fn main() { bar(other(5 /* using 5 */)) }",
        )
    }

    #[test]
    fn ssr_keeps_comment() {
        assert_ssr_transform(
            "foo($x:expr) ==>> bar($x)",
            "fn main() { foo(5 /* using 5 */) }",
            "fn main() { bar(5)/* using 5 */ }",
        )
    }
}
<commit_msg>save comments as ra_syntax::ast::Comment<commit_after>//!  structural search replace

use crate::source_change::SourceFileEdit;
use ra_ide_db::RootDatabase;
use ra_syntax::ast::make::expr_from_text;
use ra_syntax::ast::{AstToken, Comment};
use ra_syntax::{AstNode, SyntaxElement, SyntaxNode};
use ra_text_edit::{TextEdit, TextEditBuilder};
use rustc_hash::FxHashMap;
use std::collections::HashMap;
use std::str::FromStr;

pub use ra_db::{SourceDatabase, SourceDatabaseExt};
use ra_ide_db::symbol_index::SymbolsDatabase;

#[derive(Debug, PartialEq)]
pub struct SsrError(String);

impl std::fmt::Display for SsrError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "Parse error: {}", self.0)
    }
}

impl std::error::Error for SsrError {}

pub fn parse_search_replace(
    query: &str,
    db: &RootDatabase,
) -> Result<Vec<SourceFileEdit>, SsrError> {
    let mut edits = vec![];
    let query: SsrQuery = query.parse()?;
    for &root in db.local_roots().iter() {
        let sr = db.source_root(root);
        for file_id in sr.walk() {
            dbg!(db.file_relative_path(file_id));
            let matches = find(&query.pattern, db.parse(file_id).tree().syntax());
            if !matches.matches.is_empty() {
                edits.push(SourceFileEdit { file_id, edit: replace(&matches, &query.template) });
            }
        }
    }
    Ok(edits)
}

#[derive(Debug)]
struct SsrQuery {
    pattern: SsrPattern,
    template: SsrTemplate,
}

#[derive(Debug)]
struct SsrPattern {
    pattern: SyntaxNode,
    vars: Vec<Var>,
}

/// represents an `$var` in an SSR query
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Var(String);

#[derive(Debug)]
struct SsrTemplate {
    template: SyntaxNode,
    placeholders: FxHashMap<SyntaxNode, Var>,
}

type Binding = HashMap<Var, SyntaxNode>;

#[derive(Debug)]
struct Match {
    place: SyntaxNode,
    binding: Binding,
    ignored_comments: Vec<Comment>,
}

#[derive(Debug)]
struct SsrMatches {
    matches: Vec<Match>,
}

impl FromStr for SsrQuery {
    type Err = SsrError;

    fn from_str(query: &str) -> Result<SsrQuery, SsrError> {
        let mut it = query.split("==>>");
        let pattern = it.next().expect("at least empty string").trim();
        let mut template = it
            .next()
            .ok_or_else(|| SsrError("Cannot find delemiter `==>>`".into()))?
            .trim()
            .to_string();
        if it.next().is_some() {
            return Err(SsrError("More than one delimiter found".into()));
        }
        let mut vars = vec![];
        let mut it = pattern.split('$');
        let mut pattern = it.next().expect("something").to_string();

        for part in it.map(split_by_var) {
            let (var, var_type, remainder) = part?;
            is_expr(var_type)?;
            let new_var = create_name(var, &mut vars)?;
            pattern.push_str(new_var);
            pattern.push_str(remainder);
            template = replace_in_template(template, var, new_var);
        }

        let template = expr_from_text(&template).syntax().clone();
        let mut placeholders = FxHashMap::default();

        traverse(&template, &mut |n| {
            if let Some(v) = vars.iter().find(|v| v.0.as_str() == n.text()) {
                placeholders.insert(n.clone(), v.clone());
                false
            } else {
                true
            }
        });

        let pattern = SsrPattern { pattern: expr_from_text(&pattern).syntax().clone(), vars };
        let template = SsrTemplate { template, placeholders };
        Ok(SsrQuery { pattern, template })
    }
}

fn traverse(node: &SyntaxNode, go: &mut impl FnMut(&SyntaxNode) -> bool) {
    if !go(node) {
        return;
    }
    for ref child in node.children() {
        traverse(child, go);
    }
}

fn split_by_var(s: &str) -> Result<(&str, &str, &str), SsrError> {
    let end_of_name = s.find(':').ok_or_else(|| SsrError("Use $<name>:expr".into()))?;
    let name = &s[0..end_of_name];
    is_name(name)?;
    let type_begin = end_of_name + 1;
    let type_length =
        s[type_begin..].find(|c| !char::is_ascii_alphanumeric(&c)).unwrap_or_else(|| s.len());
    let type_name = &s[type_begin..type_begin + type_length];
    Ok((name, type_name, &s[type_begin + type_length..]))
}

fn is_name(s: &str) -> Result<(), SsrError> {
    if s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
        Ok(())
    } else {
        Err(SsrError("Name can contain only alphanumerics and _".into()))
    }
}

fn is_expr(s: &str) -> Result<(), SsrError> {
    if s == "expr" {
        Ok(())
    } else {
        Err(SsrError("Only $<name>:expr is supported".into()))
    }
}

fn replace_in_template(template: String, var: &str, new_var: &str) -> String {
    let name = format!("${}", var);
    template.replace(&name, new_var)
}

fn create_name<'a>(name: &str, vars: &'a mut Vec<Var>) -> Result<&'a str, SsrError> {
    let sanitized_name = format!("__search_pattern_{}", name);
    if vars.iter().any(|a| a.0 == sanitized_name) {
        return Err(SsrError(format!("Name `{}` repeats more than once", name)));
    }
    vars.push(Var(sanitized_name));
    Ok(&vars.last().unwrap().0)
}

fn find(pattern: &SsrPattern, code: &SyntaxNode) -> SsrMatches {
    fn check(
        pattern: &SyntaxElement,
        code: &SyntaxElement,
        placeholders: &[Var],
        mut match_: Match,
    ) -> Option<Match> {
        match (pattern, code) {
            (SyntaxElement::Token(ref pattern), SyntaxElement::Token(ref code)) => {
                if pattern.text() == code.text() {
                    Some(match_)
                } else {
                    None
                }
            }
            (SyntaxElement::Node(ref pattern), SyntaxElement::Node(ref code)) => {
                if placeholders.iter().any(|n| n.0.as_str() == pattern.text()) {
                    match_.binding.insert(Var(pattern.text().to_string()), code.clone());
                    Some(match_)
                } else {
                    let mut pattern_children = pattern
                        .children_with_tokens()
                        .filter(|element| !element.kind().is_trivia());
                    let mut code_children =
                        code.children_with_tokens().filter(|element| !element.kind().is_trivia());
                    let new_ignored_comments = code.children_with_tokens().filter_map(|element| {
                        element.as_token().and_then(|token| Comment::cast(token.clone()))
                    });
                    match_.ignored_comments.extend(new_ignored_comments);
                    let match_from_children = pattern_children
                        .by_ref()
                        .zip(code_children.by_ref())
                        .fold(Some(match_), |accum, (a, b)| {
                            accum.and_then(|match_| check(&a, &b, placeholders, match_))
                        });
                    match_from_children.and_then(|match_| {
                        if pattern_children.count() == 0 && code_children.count() == 0 {
                            Some(match_)
                        } else {
                            None
                        }
                    })
                }
            }
            _ => None,
        }
    }
    let kind = pattern.pattern.kind();
    let matches = code
        .descendants_with_tokens()
        .filter(|n| n.kind() == kind)
        .filter_map(|code| {
            let match_ = Match {
                place: code.as_node().unwrap().clone(),
                binding: HashMap::new(),
                ignored_comments: vec![],
            };
            check(&SyntaxElement::from(pattern.pattern.clone()), &code, &pattern.vars, match_)
        })
        .collect();
    SsrMatches { matches }
}

fn replace(matches: &SsrMatches, template: &SsrTemplate) -> TextEdit {
    let mut builder = TextEditBuilder::default();
    for match_ in &matches.matches {
        builder.replace(
            match_.place.text_range(),
            render_replace(&match_.binding, &match_.ignored_comments, template),
        );
    }
    builder.finish()
}

fn render_replace(
    binding: &Binding,
    ignored_comments: &Vec<Comment>,
    template: &SsrTemplate,
) -> String {
    let mut builder = TextEditBuilder::default();
    for element in template.template.descendants() {
        if let Some(var) = template.placeholders.get(&element) {
            builder.replace(element.text_range(), binding[var].to_string())
        }
    }
    for comment in ignored_comments {
        builder.insert(template.template.text_range().end(), comment.syntax().to_string())
    }
    builder.finish().apply(&template.template.text().to_string())
}

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

    fn parse_error_text(query: &str) -> String {
        format!("{}", query.parse::<SsrQuery>().unwrap_err())
    }

    #[test]
    fn parser_happy_case() {
        let result: SsrQuery = "foo($a:expr, $b:expr) ==>> bar($b, $a)".parse().unwrap();
        assert_eq!(&result.pattern.pattern.text(), "foo(__search_pattern_a, __search_pattern_b)");
        assert_eq!(result.pattern.vars.len(), 2);
        assert_eq!(result.pattern.vars[0].0, "__search_pattern_a");
        assert_eq!(result.pattern.vars[1].0, "__search_pattern_b");
        assert_eq!(&result.template.template.text(), "bar(__search_pattern_b, __search_pattern_a)");
        dbg!(result.template.placeholders);
    }

    #[test]
    fn parser_empty_query() {
        assert_eq!(parse_error_text(""), "Parse error: Cannot find delemiter `==>>`");
    }

    #[test]
    fn parser_no_delimiter() {
        assert_eq!(parse_error_text("foo()"), "Parse error: Cannot find delemiter `==>>`");
    }

    #[test]
    fn parser_two_delimiters() {
        assert_eq!(
            parse_error_text("foo() ==>> a ==>> b "),
            "Parse error: More than one delimiter found"
        );
    }

    #[test]
    fn parser_no_pattern_type() {
        assert_eq!(parse_error_text("foo($a) ==>>"), "Parse error: Use $<name>:expr");
    }

    #[test]
    fn parser_invalid_name() {
        assert_eq!(
            parse_error_text("foo($a+:expr) ==>>"),
            "Parse error: Name can contain only alphanumerics and _"
        );
    }

    #[test]
    fn parser_invalid_type() {
        assert_eq!(
            parse_error_text("foo($a:ident) ==>>"),
            "Parse error: Only $<name>:expr is supported"
        );
    }

    #[test]
    fn parser_repeated_name() {
        assert_eq!(
            parse_error_text("foo($a:expr, $a:expr) ==>>"),
            "Parse error: Name `a` repeats more than once"
        );
    }

    #[test]
    fn parse_match_replace() {
        let query: SsrQuery = "foo($x:expr) ==>> bar($x)".parse().unwrap();
        let input = "fn main() { foo(1+2); }";

        let code = SourceFile::parse(input).tree();
        let matches = find(&query.pattern, code.syntax());
        assert_eq!(matches.matches.len(), 1);
        assert_eq!(matches.matches[0].place.text(), "foo(1+2)");
        assert_eq!(matches.matches[0].binding.len(), 1);
        assert_eq!(
            matches.matches[0].binding[&Var("__search_pattern_x".to_string())].text(),
            "1+2"
        );

        let edit = replace(&matches, &query.template);
        assert_eq!(edit.apply(input), "fn main() { bar(1+2); }");
    }

    fn assert_ssr_transform(query: &str, input: &str, result: &str) {
        let query: SsrQuery = query.parse().unwrap();
        let code = SourceFile::parse(input).tree();
        let matches = find(&query.pattern, code.syntax());
        let edit = replace(&matches, &query.template);
        assert_eq!(edit.apply(input), result);
    }

    #[test]
    fn ssr_function_to_method() {
        assert_ssr_transform(
            "my_function($a:expr, $b:expr) ==>> ($a).my_method($b)",
            "loop { my_function( other_func(x, y), z + w) }",
            "loop { (other_func(x, y)).my_method(z + w) }",
        )
    }

    #[test]
    fn ssr_nested_function() {
        assert_ssr_transform(
            "foo($a:expr, $b:expr, $c:expr) ==>> bar($c, baz($a, $b))",
            "fn main { foo  (x + value.method(b), x+y-z, true && false) }",
            "fn main { bar(true && false, baz(x + value.method(b), x+y-z)) }",
        )
    }

    #[test]
    fn ssr_expected_spacing() {
        assert_ssr_transform(
            "foo($x:expr) + bar() ==>> bar($x)",
            "fn main() { foo(5) + bar() }",
            "fn main() { bar(5) }",
        );
    }

    #[test]
    fn ssr_with_extra_space() {
        assert_ssr_transform(
            "foo($x:expr  ) +    bar() ==>> bar($x)",
            "fn main() { foo(  5 )  +bar(   ) }",
            "fn main() { bar(5) }",
        );
    }

    #[test]
    fn ssr_keeps_nested_comment() {
        assert_ssr_transform(
            "foo($x:expr) ==>> bar($x)",
            "fn main() { foo(other(5 /* using 5 */)) }",
            "fn main() { bar(other(5 /* using 5 */)) }",
        )
    }

    #[test]
    fn ssr_keeps_comment() {
        assert_ssr_transform(
            "foo($x:expr) ==>> bar($x)",
            "fn main() { foo(5 /* using 5 */) }",
            "fn main() { bar(5)/* using 5 */ }",
        )
    }
}
<|endoftext|>


<commit_before>use hlt::entity::Position;
use hlt::parse::Decodable;
use hlt::entity::Entity;

/// A planet on the game map.
#[derive(PartialEq, Debug)]
pub struct Planet {
    pub id: i32,
    pub position: Position,
    pub hp: i32,
    pub radius: f64,
    pub num_docking_spots: usize,
    pub current_production: i32,
    pub remaining_resources: i32,
    pub owner: Option<i32>,
    pub docked_ships: Vec<i32>,
}

impl Planet {
    /// Determines if the planet has an owner.
    pub fn is_owned(&self) -> bool {
        self.owner.is_some()
    }
}

impl Decodable for Planet {
    fn parse<'a, I>(tokens: &mut I) -> Self
    where
        I: Iterator<Item = &'a str>,
    {

        let id = i32::parse(tokens);
        let position = Position::parse(tokens);
        let hp = i32::parse(tokens);
        let radius = f64::parse(tokens);
        let num_docking_spots = i32::parse(tokens) as usize;
        let current_production = i32::parse(tokens);
        let remaining_resources = i32::parse(tokens);
        let owner = Option::parse(tokens);
        let docked_ships = Vec::parse(tokens);

        Self {
            id,
            position,
            hp,
            radius,
            num_docking_spots,
            current_production,
            remaining_resources,
            owner,
            docked_ships,
        }
    }
}

impl Entity for Planet {
    fn position(&self) -> Position {
        self.position
    }

    fn radius(&self) -> f64 {
        self.radius
    }
}
<commit_msg>feat: Add a method to know if a planet is full<commit_after>use hlt::entity::Position;
use hlt::parse::Decodable;
use hlt::entity::Entity;

/// A planet on the game map.
#[derive(PartialEq, Debug)]
pub struct Planet {
    pub id: i32,
    pub position: Position,
    pub hp: i32,
    pub radius: f64,
    pub num_docking_spots: usize,
    pub current_production: i32,
    pub remaining_resources: i32,
    pub owner: Option<i32>,
    pub docked_ships: Vec<i32>,
}

impl Planet {
    /// Determines if the planet has an owner.
    pub fn is_owned(&self) -> bool {
        self.owner.is_some()
    }

    /// Determines if the planet has been fully occupied (all possible ships are docked).
    pub fn is_full(&self) -> bool {
        self.docked_ships.len() >= self.num_docking_spots
    }
}

impl Decodable for Planet {
    fn parse<'a, I>(tokens: &mut I) -> Self
    where
        I: Iterator<Item = &'a str>,
    {

        let id = i32::parse(tokens);
        let position = Position::parse(tokens);
        let hp = i32::parse(tokens);
        let radius = f64::parse(tokens);
        let num_docking_spots = i32::parse(tokens) as usize;
        let current_production = i32::parse(tokens);
        let remaining_resources = i32::parse(tokens);
        let owner = Option::parse(tokens);
        let docked_ships = Vec::parse(tokens);

        Self {
            id,
            position,
            hp,
            radius,
            num_docking_spots,
            current_production,
            remaining_resources,
            owner,
            docked_ships,
        }
    }
}

impl Entity for Planet {
    fn position(&self) -> Position {
        self.position
    }

    fn radius(&self) -> f64 {
        self.radius
    }
}
<|endoftext|>


<commit_before>// These are taken from http://en.wikipedia.org/wiki/List_of_HTTP_Status_Codes.
// Last updated on 2013-07-04
// Entries from third-party vendors not standardised upon are not included.
// If not specified otherwise, they are defined in RFC 2616.

// Yes, this is ugly code.
// No, I don't mind.
// That was easy. :-)

use std::collections::hashmap::HashSet;
use std::ascii::StrAsciiExt;
use std::io::IoResult;
use super::get_writer;

enum HeadingOrStatus {
    Heading(&'static str),
    Status(Status),
}

struct Status {
    code: uint,
    reason: &'static str,
    comment: Option<&'static str>,
}

/// Status with comment
fn status_c(code: uint, reason: &'static str, comment: &'static str) -> HeadingOrStatus {
    Status(Status { code: code, reason: reason, comment: Some(comment) })
}

/// Status without comment
fn status_n(code: uint, reason: &'static str) -> HeadingOrStatus {
    Status(Status { code: code, reason: reason, comment: None })
}

impl Status {
    fn ident(&self) -> String {
        camel_case(self.reason)
    }

    fn padded_ident(&self) -> String {
        self.ident().append(self.reason_padding_spaces().as_slice())
    }

    fn reason_padding_spaces(&self) -> String {
        " ".repeat(unsafe { longest_reason } - self.reason.len())
    }
}

/// >>> camel_case("I'm a Tea-pot")
/// "ImATeaPot"
fn camel_case(msg: &str) -> String {
    let msg = msg.replace("-", " ").replace("'", "");
    let mut result = String::with_capacity(msg.len());
    let mut capitalise = true;
    for c in msg.as_slice().chars() {
        let c = match capitalise {
            true => c.to_ascii().to_uppercase().to_char(),
            false => c.to_ascii().to_lowercase().to_char(),
        };
        // For a space, capitalise the next char
        capitalise = c == ' ';
        if !capitalise {  // And also, for a space, don't keep it
            result.push_char(c);
        }
    }
    result
}

static mut longest_ident: uint = 0;
static mut longest_reason: uint = 0;

pub fn generate(output_dir: &Path) -> IoResult<()> {
    let mut out = get_writer(output_dir, "status.rs");
    let entries = [
        Heading("1xx Informational"),
        status_n(100, "Continue"),
        status_n(101, "Switching Protocols"),
        status_c(102, "Processing", "WebDAV; RFC 2518"),

        Heading("2xx Success"),
        status_n(200, "OK"),
        status_n(201, "Created"),
        status_n(202, "Accepted"),
        status_c(203, "Non-Authoritative Information", "since HTTP/1.1"),
        status_n(204, "No Content"),
        status_n(205, "Reset Content"),
        status_n(206, "Partial Content"),
        status_c(207, "Multi-Status", "WebDAV; RFC 4918"),
        status_c(208, "Already Reported", "WebDAV; RFC 5842"),
        status_c(226, "IM Used", "RFC 3229"),

        Heading("3xx Redirection"),
        status_n(300, "Multiple Choices"),
        status_n(301, "Moved Permanently"),
        status_n(302, "Found"),
        status_c(303, "See Other", "since HTTP/1.1"),
        status_n(304, "Not Modified"),
        status_c(305, "Use Proxy", "since HTTP/1.1"),
        status_n(306, "Switch Proxy"),
        status_c(307, "Temporary Redirect", "since HTTP/1.1"),
        status_c(308, "Permanent Redirect", "approved as experimental RFC: http://tools.ietf.org/html/draft-reschke-http-status-308"),

        Heading("4xx Client Error"),
        status_n(400, "Bad Request"),
        status_n(401, "Unauthorized"),
        status_n(402, "Payment Required"),
        status_n(403, "Forbidden"),
        status_n(404, "Not Found"),
        status_n(405, "Method Not Allowed"),
        status_n(406, "Not Acceptable"),
        status_n(407, "Proxy Authentication Required"),
        status_n(408, "Request Timeout"),
        status_n(409, "Conflict"),
        status_n(410, "Gone"),
        status_n(411, "Length Required"),
        status_n(412, "Precondition Failed"),
        status_n(413, "Request Entity Too Large"),
        status_n(414, "Request-URI Too Long"),
        status_n(415, "Unsupported Media Type"),
        status_n(416, "Requested Range Not Satisfiable"),
        status_n(417, "Expectation Failed"),
        status_c(418, "I'm a teapot", "RFC 2324"),
        status_n(419, "Authentication Timeout"),
        status_c(422, "Unprocessable Entity", "WebDAV; RFC 4918"),
        status_c(423, "Locked", "WebDAV; RFC 4918"),
        status_c(424, "Failed Dependency", "WebDAV; RFC 4918"),
        status_c(424, "Method Failure", "WebDAV"),
        status_c(425, "Unordered Collection", "Internet draft"),
        status_c(426, "Upgrade Required", "RFC 2817"),
        status_c(428, "Precondition Required", "RFC 6585"),
        status_c(429, "Too Many Requests", "RFC 6585"),
        status_c(431, "Request Header Fields Too Large", "RFC 6585"),
        status_c(451, "Unavailable For Legal Reasons", "Internet draft"),

        Heading("5xx Server Error"),
        status_n(500, "Internal Server Error"),
        status_n(501, "Not Implemented"),
        status_n(502, "Bad Gateway"),
        status_n(503, "Service Unavailable"),
        status_n(504, "Gateway Timeout"),
        status_n(505, "HTTP Version Not Supported"),
        status_c(506, "Variant Also Negotiates", "RFC 2295"),
        status_c(507, "Insufficient Storage", "WebDAV; RFC 4918"),
        status_c(508, "Loop Detected", "WebDAV; RFC 5842"),
        status_c(510, "Not Extended", "RFC 2774"),
        status_c(511, "Network Authentication Required", "RFC 6585"),
        ];
    unsafe {
        longest_ident = entries.iter().map(|&e| match e {
            Heading(_heading) => 0,
            Status(status) => status.ident().len(),
        }).max_by(|&i| i).unwrap();
        longest_reason = entries.iter().map(|&e| match e {
            Heading(_heading) => 0,
            Status(status) => status.reason.len(),
        }).max_by(|&i| i).unwrap();
    }
    try!(out.write("// This file is automatically generated file is used as http::status.

use std::fmt;
use std::ascii::StrAsciiExt;

/// HTTP status code
#[deriving(Eq, PartialEq, Clone)]
pub enum Status {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n    // {}\n", heading)),
            Status(status) => match status.comment {
                None => try!(write!(out, "    {},\n", status.ident())),
                Some(comment) => try!(write!(out, "    {},  // {}\n", status.ident(), comment)),
            },
        }
    }

    try!(out.write("
    UnregisteredStatus(u16, String),
}

impl Status {

    /// Get the status code
    pub fn code(&self) -> u16 {
        match *self {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            {} => {},\n",
                                                status.padded_ident(), status.code)),
        }
    }
    try!(out.write("
            UnregisteredStatus(code, _)   => code,
        }
    }

    /// Get the reason phrase
    pub fn reason(&self) -> String {
        match *self {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            {} => String::from_str(\"{}\"),\n",
                                                status.padded_ident(), status.reason))
        }
    }
    try!(out.write("
            UnregisteredStatus(_, ref reason) => (*reason).clone(),
        }
    }

    /// Get a status from the code and reason
    pub fn from_code_and_reason(status: u16, reason: String) -> Status {
        let reason_lower = reason.as_slice().to_ascii_lower();
        match (status, reason_lower.as_slice()) {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            ({}, \"{}\"){} => {},\n",
                                                status.code,
                                                status.reason.to_ascii_lower(),
                                                status.reason_padding_spaces(),
                                                status.ident())),
        }
    }
    try!(out.write("
            (_, _) => UnregisteredStatus(status, reason),
        }
    }
}

impl fmt::Show for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, \"{} {}\", self.code(), self.reason())
    }
}

impl fmt::Unsigned for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Unsigned;
        self.code().fmt(f)
    }
}

impl ToPrimitive for Status {

    /// Equivalent to `Some(self.code() as i64)`
    fn to_i64(&self) -> Option<i64> {
        Some(self.code() as i64)
    }

    /// Equivalent to `Some(self.code() as u64)`
    fn to_u64(&self) -> Option<u64> {
        Some(self.code() as u64)
    }
}

impl FromPrimitive for Status {
    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will return None if an unknown (or negative, which are invalid) code is passed.
    ///
    /// For example, `from_i64(200)` will return `OK`.
    fn from_i64(n: i64) -> Option<Status> {
        if n < 0 {
            None
        } else {
            FromPrimitive::from_u64(n as u64)
        }
    }

    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will return None if an unknown code is passed.
    ///
    /// For example, `from_u64(200)` will return `OK`.
    fn from_u64(n: u64) -> Option<Status> {
        Some(match n {
".as_bytes()));
    let mut matched_numbers = HashSet::new();
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => {
                if !matched_numbers.contains(&status.code) {
                    // Purpose: FailedDependency and MethodFailure both use 424,
                    // but clearly they mustn't both go in here
                    try!(write!(out, "            {:u} => {},\n", status.code, status.ident()));
                    matched_numbers.insert(status.code);
                }
            },
        }
    }
    out.write("
            _   => { return None }
        })
    }
}".as_bytes())
}
<commit_msg>fixes #144 codegen duplicate definition of Status<commit_after>// These are taken from http://en.wikipedia.org/wiki/List_of_HTTP_Status_Codes.
// Last updated on 2013-07-04
// Entries from third-party vendors not standardised upon are not included.
// If not specified otherwise, they are defined in RFC 2616.

// Yes, this is ugly code.
// No, I don't mind.
// That was easy. :-)

use std::collections::hashmap::HashSet;
use std::ascii::StrAsciiExt;
use std::io::IoResult;
use super::get_writer;

enum HeadingOrStatus {
    Heading(&'static str),
    Status(HttpStatus),
}

struct HttpStatus {
    code: uint,
    reason: &'static str,
    comment: Option<&'static str>,
}

/// Status with comment
fn status_c(code: uint, reason: &'static str, comment: &'static str) -> HeadingOrStatus {
    Status(HttpStatus { code: code, reason: reason, comment: Some(comment) })
}

/// Status without comment
fn status_n(code: uint, reason: &'static str) -> HeadingOrStatus {
    Status(HttpStatus { code: code, reason: reason, comment: None })
}

impl HttpStatus {
    fn ident(&self) -> String {
        camel_case(self.reason)
    }

    fn padded_ident(&self) -> String {
        self.ident().append(self.reason_padding_spaces().as_slice())
    }

    fn reason_padding_spaces(&self) -> String {
        " ".repeat(unsafe { longest_reason } - self.reason.len())
    }
}

/// >>> camel_case("I'm a Tea-pot")
/// "ImATeaPot"
fn camel_case(msg: &str) -> String {
    let msg = msg.replace("-", " ").replace("'", "");
    let mut result = String::with_capacity(msg.len());
    let mut capitalise = true;
    for c in msg.as_slice().chars() {
        let c = match capitalise {
            true => c.to_ascii().to_uppercase().to_char(),
            false => c.to_ascii().to_lowercase().to_char(),
        };
        // For a space, capitalise the next char
        capitalise = c == ' ';
        if !capitalise {  // And also, for a space, don't keep it
            result.push_char(c);
        }
    }
    result
}

static mut longest_ident: uint = 0;
static mut longest_reason: uint = 0;

pub fn generate(output_dir: &Path) -> IoResult<()> {
    let mut out = get_writer(output_dir, "status.rs");
    let entries = [
        Heading("1xx Informational"),
        status_n(100, "Continue"),
        status_n(101, "Switching Protocols"),
        status_c(102, "Processing", "WebDAV; RFC 2518"),

        Heading("2xx Success"),
        status_n(200, "OK"),
        status_n(201, "Created"),
        status_n(202, "Accepted"),
        status_c(203, "Non-Authoritative Information", "since HTTP/1.1"),
        status_n(204, "No Content"),
        status_n(205, "Reset Content"),
        status_n(206, "Partial Content"),
        status_c(207, "Multi-Status", "WebDAV; RFC 4918"),
        status_c(208, "Already Reported", "WebDAV; RFC 5842"),
        status_c(226, "IM Used", "RFC 3229"),

        Heading("3xx Redirection"),
        status_n(300, "Multiple Choices"),
        status_n(301, "Moved Permanently"),
        status_n(302, "Found"),
        status_c(303, "See Other", "since HTTP/1.1"),
        status_n(304, "Not Modified"),
        status_c(305, "Use Proxy", "since HTTP/1.1"),
        status_n(306, "Switch Proxy"),
        status_c(307, "Temporary Redirect", "since HTTP/1.1"),
        status_c(308, "Permanent Redirect", "approved as experimental RFC: http://tools.ietf.org/html/draft-reschke-http-status-308"),

        Heading("4xx Client Error"),
        status_n(400, "Bad Request"),
        status_n(401, "Unauthorized"),
        status_n(402, "Payment Required"),
        status_n(403, "Forbidden"),
        status_n(404, "Not Found"),
        status_n(405, "Method Not Allowed"),
        status_n(406, "Not Acceptable"),
        status_n(407, "Proxy Authentication Required"),
        status_n(408, "Request Timeout"),
        status_n(409, "Conflict"),
        status_n(410, "Gone"),
        status_n(411, "Length Required"),
        status_n(412, "Precondition Failed"),
        status_n(413, "Request Entity Too Large"),
        status_n(414, "Request-URI Too Long"),
        status_n(415, "Unsupported Media Type"),
        status_n(416, "Requested Range Not Satisfiable"),
        status_n(417, "Expectation Failed"),
        status_c(418, "I'm a teapot", "RFC 2324"),
        status_n(419, "Authentication Timeout"),
        status_c(422, "Unprocessable Entity", "WebDAV; RFC 4918"),
        status_c(423, "Locked", "WebDAV; RFC 4918"),
        status_c(424, "Failed Dependency", "WebDAV; RFC 4918"),
        status_c(424, "Method Failure", "WebDAV"),
        status_c(425, "Unordered Collection", "Internet draft"),
        status_c(426, "Upgrade Required", "RFC 2817"),
        status_c(428, "Precondition Required", "RFC 6585"),
        status_c(429, "Too Many Requests", "RFC 6585"),
        status_c(431, "Request Header Fields Too Large", "RFC 6585"),
        status_c(451, "Unavailable For Legal Reasons", "Internet draft"),

        Heading("5xx Server Error"),
        status_n(500, "Internal Server Error"),
        status_n(501, "Not Implemented"),
        status_n(502, "Bad Gateway"),
        status_n(503, "Service Unavailable"),
        status_n(504, "Gateway Timeout"),
        status_n(505, "HTTP Version Not Supported"),
        status_c(506, "Variant Also Negotiates", "RFC 2295"),
        status_c(507, "Insufficient Storage", "WebDAV; RFC 4918"),
        status_c(508, "Loop Detected", "WebDAV; RFC 5842"),
        status_c(510, "Not Extended", "RFC 2774"),
        status_c(511, "Network Authentication Required", "RFC 6585"),
        ];
    unsafe {
        longest_ident = entries.iter().map(|&e| match e {
            Heading(_heading) => 0,
            Status(status) => status.ident().len(),
        }).max_by(|&i| i).unwrap();
        longest_reason = entries.iter().map(|&e| match e {
            Heading(_heading) => 0,
            Status(status) => status.reason.len(),
        }).max_by(|&i| i).unwrap();
    }
    try!(out.write("// This file is automatically generated file is used as http::status.

use std::fmt;
use std::ascii::StrAsciiExt;

/// HTTP status code
#[deriving(Eq, PartialEq, Clone)]
pub enum Status {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n    // {}\n", heading)),
            Status(status) => match status.comment {
                None => try!(write!(out, "    {},\n", status.ident())),
                Some(comment) => try!(write!(out, "    {},  // {}\n", status.ident(), comment)),
            },
        }
    }

    try!(out.write("
    UnregisteredStatus(u16, String),
}

impl Status {

    /// Get the status code
    pub fn code(&self) -> u16 {
        match *self {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            {} => {},\n",
                                                status.padded_ident(), status.code)),
        }
    }
    try!(out.write("
            UnregisteredStatus(code, _)   => code,
        }
    }

    /// Get the reason phrase
    pub fn reason(&self) -> String {
        match *self {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            {} => String::from_str(\"{}\"),\n",
                                                status.padded_ident(), status.reason))
        }
    }
    try!(out.write("
            UnregisteredStatus(_, ref reason) => (*reason).clone(),
        }
    }

    /// Get a status from the code and reason
    pub fn from_code_and_reason(status: u16, reason: String) -> Status {
        let reason_lower = reason.as_slice().to_ascii_lower();
        match (status, reason_lower.as_slice()) {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            ({}, \"{}\"){} => {},\n",
                                                status.code,
                                                status.reason.to_ascii_lower(),
                                                status.reason_padding_spaces(),
                                                status.ident())),
        }
    }
    try!(out.write("
            (_, _) => UnregisteredStatus(status, reason),
        }
    }
}

impl fmt::Show for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, \"{} {}\", self.code(), self.reason())
    }
}

impl fmt::Unsigned for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Unsigned;
        self.code().fmt(f)
    }
}

impl ToPrimitive for Status {

    /// Equivalent to `Some(self.code() as i64)`
    fn to_i64(&self) -> Option<i64> {
        Some(self.code() as i64)
    }

    /// Equivalent to `Some(self.code() as u64)`
    fn to_u64(&self) -> Option<u64> {
        Some(self.code() as u64)
    }
}

impl FromPrimitive for Status {
    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will return None if an unknown (or negative, which are invalid) code is passed.
    ///
    /// For example, `from_i64(200)` will return `OK`.
    fn from_i64(n: i64) -> Option<Status> {
        if n < 0 {
            None
        } else {
            FromPrimitive::from_u64(n as u64)
        }
    }

    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will return None if an unknown code is passed.
    ///
    /// For example, `from_u64(200)` will return `OK`.
    fn from_u64(n: u64) -> Option<Status> {
        Some(match n {
".as_bytes()));
    let mut matched_numbers = HashSet::new();
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => {
                if !matched_numbers.contains(&status.code) {
                    // Purpose: FailedDependency and MethodFailure both use 424,
                    // but clearly they mustn't both go in here
                    try!(write!(out, "            {:u} => {},\n", status.code, status.ident()));
                    matched_numbers.insert(status.code);
                }
            },
        }
    }
    out.write("
            _   => { return None }
        })
    }
}".as_bytes())
}
<|endoftext|>


<commit_before>#![feature(no_std, allocator)]
#![no_std]
#![allocator]

extern "C" {
  fn memmove(dest: *mut u8, src: *mut u8, count: u32);
}

static mut allocator: BumpPointer = BumpPointer {
  start: 0 as *mut u8,
  stop:  0 as *mut u8,
};

pub fn set_allocator(start: *mut u8, stop: *mut u8) {
  unsafe {
    allocator = BumpPointer::new(start, stop);
  }
}

pub trait Allocator
{
  fn allocate(&mut self, size: usize, align: usize) -> Option<*mut u8>;

  fn deallocate(&mut self, ptr: *mut u8, old_size: usize, align: usize);

  fn reallocate(&mut self, ptr: *mut u8, old_size: usize, size: usize,
                align: usize) -> Option<*mut u8>
  {
    let attempt = self.allocate(size, align);
    if let Some(new) = attempt {
      unsafe { memmove(new, ptr, old_size as u32) };
      self.deallocate(ptr, old_size, align);
    }
    attempt
  }

  fn reallocate_inplace(&mut self, _ptr: *mut u8, old_size: usize, _size: usize,
                        _align: usize) -> usize
  {
    old_size
  }

  fn usable_size(&mut self, size: usize, _align: usize) -> usize
  {
    size
  }
  //fn stats_print(&mut self);

  fn debug(&mut self) -> (*mut u8, usize);
}

pub struct BumpPointer {
  start: *mut u8,
  stop:  *mut u8,
}

impl BumpPointer
{
  pub fn new(start: *mut u8, stop: *mut u8) -> BumpPointer {
    return BumpPointer { start: start, stop: stop };
  }
}

impl Allocator for BumpPointer
{
  #[inline]
  fn allocate(&mut self, size: usize, align: usize) -> Option<*mut u8>
  {
    let aligned: usize = {
      let a = self.start as usize + align - 1;
      a - (a % align)
    };
    let new_start = aligned + size;

    if new_start > self.stop as usize {
      None
    } else {
      self.start = new_start as *mut u8;
      Some(aligned as *mut u8)
    }
  }

  #[inline]
  fn deallocate(&mut self, _ptr: *mut u8, _old_size: usize, _align: usize) { }

  #[inline]
  fn debug(&mut self) -> (*mut u8, usize) {
    (self.start, self.stop as usize - self.start as usize)
  }
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
  unsafe {
    match allocator.allocate(size, align) {
    Some(ptr) => ptr,
    None      => 0 as *mut u8
    }
  }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize,
                                    align: usize) {
  unsafe {
    allocator.deallocate(ptr, old_size, align)
  }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
                              align: usize) -> *mut u8 {
  unsafe {
    match allocator.reallocate(ptr, old_size, size, align) {
      Some(ptr) => ptr,
      None      => 0 as *mut u8
    }
  }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize,
                                            size: usize, align: usize) -> usize {
  unsafe {
    allocator.reallocate_inplace(ptr, old_size, size, align)
  }
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
  unsafe {
    allocator.usable_size(size, align)
  }
}
<commit_msg>Don't need no_std feature in bump-pointer<commit_after>#![feature(allocator)]
#![no_std]
#![allocator]

extern "C" {
  fn memmove(dest: *mut u8, src: *mut u8, count: u32);
}

static mut allocator: BumpPointer = BumpPointer {
  start: 0 as *mut u8,
  stop:  0 as *mut u8,
};

pub fn set_allocator(start: *mut u8, stop: *mut u8) {
  unsafe {
    allocator = BumpPointer::new(start, stop);
  }
}

pub trait Allocator
{
  fn allocate(&mut self, size: usize, align: usize) -> Option<*mut u8>;

  fn deallocate(&mut self, ptr: *mut u8, old_size: usize, align: usize);

  fn reallocate(&mut self, ptr: *mut u8, old_size: usize, size: usize,
                align: usize) -> Option<*mut u8>
  {
    let attempt = self.allocate(size, align);
    if let Some(new) = attempt {
      unsafe { memmove(new, ptr, old_size as u32) };
      self.deallocate(ptr, old_size, align);
    }
    attempt
  }

  fn reallocate_inplace(&mut self, _ptr: *mut u8, old_size: usize, _size: usize,
                        _align: usize) -> usize
  {
    old_size
  }

  fn usable_size(&mut self, size: usize, _align: usize) -> usize
  {
    size
  }
  //fn stats_print(&mut self);

  fn debug(&mut self) -> (*mut u8, usize);
}

pub struct BumpPointer {
  start: *mut u8,
  stop:  *mut u8,
}

impl BumpPointer
{
  pub fn new(start: *mut u8, stop: *mut u8) -> BumpPointer {
    return BumpPointer { start: start, stop: stop };
  }
}

impl Allocator for BumpPointer
{
  #[inline]
  fn allocate(&mut self, size: usize, align: usize) -> Option<*mut u8>
  {
    let aligned: usize = {
      let a = self.start as usize + align - 1;
      a - (a % align)
    };
    let new_start = aligned + size;

    if new_start > self.stop as usize {
      None
    } else {
      self.start = new_start as *mut u8;
      Some(aligned as *mut u8)
    }
  }

  #[inline]
  fn deallocate(&mut self, _ptr: *mut u8, _old_size: usize, _align: usize) { }

  #[inline]
  fn debug(&mut self) -> (*mut u8, usize) {
    (self.start, self.stop as usize - self.start as usize)
  }
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
  unsafe {
    match allocator.allocate(size, align) {
    Some(ptr) => ptr,
    None      => 0 as *mut u8
    }
  }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize,
                                    align: usize) {
  unsafe {
    allocator.deallocate(ptr, old_size, align)
  }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
                              align: usize) -> *mut u8 {
  unsafe {
    match allocator.reallocate(ptr, old_size, size, align) {
      Some(ptr) => ptr,
      None      => 0 as *mut u8
    }
  }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize,
                                            size: usize, align: usize) -> usize {
  unsafe {
    allocator.reallocate_inplace(ptr, old_size, size, align)
  }
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
  unsafe {
    allocator.usable_size(size, align)
  }
}
<|endoftext|>