<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="mask" products="gecko" extra_prefixes="webkit"
                    sub_properties="mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position-x
                                    mask-position-y mask-size mask-image"
                    spec="https://drafts.fxtf.org/css-masking/#propdef-mask">
    use properties::longhands::{mask_mode, mask_repeat, mask_clip, mask_origin, mask_composite, mask_position_x,
                                mask_position_y};
    use properties::longhands::{mask_size, mask_image};
    use values::specified::position::Position;
    use parser::Parse;

    impl From<mask_origin::single_value::SpecifiedValue> for mask_clip::single_value::SpecifiedValue {
        fn from(origin: mask_origin::single_value::SpecifiedValue) -> mask_clip::single_value::SpecifiedValue {
            match origin {
                mask_origin::single_value::SpecifiedValue::content_box =>
                    mask_clip::single_value::SpecifiedValue::content_box,
                mask_origin::single_value::SpecifiedValue::padding_box =>
                    mask_clip::single_value::SpecifiedValue::padding_box,
                mask_origin::single_value::SpecifiedValue::border_box =>
                    mask_clip::single_value::SpecifiedValue::border_box,
                % if product == "gecko":
                mask_origin::single_value::SpecifiedValue::fill_box =>
                    mask_clip::single_value::SpecifiedValue::fill_box,
                mask_origin::single_value::SpecifiedValue::stroke_box =>
                    mask_clip::single_value::SpecifiedValue::stroke_box,
                mask_origin::single_value::SpecifiedValue::view_box =>
                    mask_clip::single_value::SpecifiedValue::view_box,
                % endif
            }
        }
    }

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "image mode position_x position_y size repeat origin clip composite".split():
            let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::new());
        % endfor

        try!(input.parse_comma_separated(|input| {
            % for name in "image mode position_x position_y size repeat origin clip composite".split():
                let mut ${name} = None;
            % endfor
            loop {
                if image.is_none() {
                    if let Ok(value) = input.try(|input| mask_image::single_value
                                                                   ::parse(context, input)) {
                        image = Some(value);
                        continue
                    }
                }
                if position_x.is_none() && position_y.is_none() {
                    if let Ok(value) = input.try(|input| Position::parse(context, input)) {
                        position_x = Some(value.horizontal);
                        position_y = Some(value.vertical);

                        // Parse mask size, if applicable.
                        size = input.try(|input| {
                            try!(input.expect_delim('/'));
                            mask_size::single_value::parse(context, input)
                        }).ok();

                        continue
                    }
                }
                % for name in "repeat origin clip composite mode".split():
                    if ${name}.is_none() {
                        if let Ok(value) = input.try(|input| mask_${name}::single_value
                                                                               ::parse(context, input)) {
                            ${name} = Some(value);
                            continue
                        }
                    }
                % endfor
                break
            }
            if clip.is_none() {
                if let Some(origin) = origin {
                    clip = Some(mask_clip::single_value::SpecifiedValue::from(origin));
                }
            }
            let mut any = false;
            % for name in "image mode position_x position_y size repeat origin clip composite".split():
                any = any || ${name}.is_some();
            % endfor
            if any {
                if position_x.is_some() || position_y.is_some() {
                    % for name in "position_x position_y".split():
                        if let Some(bg_${name}) = ${name} {
                            mask_${name}.0.push(bg_${name});
                        }
                    % endfor
                } else {
                    % for name in "position_x position_y".split():
                        mask_${name}.0.push(mask_${name}::single_value
                                            ::get_initial_position_value());
                    % endfor
                }
                % for name in "image mode size repeat origin clip composite".split():
                    if let Some(m_${name}) = ${name} {
                        mask_${name}.0.push(m_${name});
                    } else {
                        mask_${name}.0.push(mask_${name}::single_value
                                                        ::get_initial_specified_value());
                    }
                % endfor
                Ok(())
            } else {
                Err(())
            }
        }));

        Ok(Longhands {
            % for name in "image mode position_x position_y size repeat origin clip composite".split():
                mask_${name}: Some(mask_${name}),
            % endfor
         })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            // mako doesn't like ampersands following `<`
            fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                match *x {
                    DeclaredValue::Value(ref val) => Some(val),
                    _ => None,
                }
            }
            use std::cmp;
            let mut len = 0;
            % for name in "image mode position_x position_y size repeat origin clip composite".split():
                len = cmp::max(len, extract_value(self.mask_${name}).map(|i| i.0.len())
                                                                   .unwrap_or(0));
            % endfor

            // There should be at least one declared value
            if len == 0 {
                return dest.write_str("")
            }

            for i in 0..len {
                % for name in "image mode position_x position_y size repeat origin clip composite".split():
                    let ${name} = if let DeclaredValue::Value(ref arr) = *self.mask_${name} {
                        arr.0.get(i % arr.0.len())
                    } else {
                        None
                    };
                % endfor

                if let Some(image) = image {
                    try!(image.to_css(dest));
                } else {
                    try!(write!(dest, "none"));
                }

                try!(write!(dest, " "));

                if let Some(mode) = mode {
                    try!(mode.to_css(dest));
                } else {
                    try!(write!(dest, "match-source"));
                }

                try!(write!(dest, " "));

                try!(position_x.unwrap_or(&mask_position_x::single_value
                                                      ::get_initial_position_value())
                     .to_css(dest));

                try!(write!(dest, " "));

                try!(position_y.unwrap_or(&mask_position_y::single_value
                                                      ::get_initial_position_value())
                     .to_css(dest));

                if let Some(size) = size {
                    try!(write!(dest, " / "));
                    try!(size.to_css(dest));
                }

                try!(write!(dest, " "));

                if let Some(repeat) = repeat {
                    try!(repeat.to_css(dest));
                } else {
                    try!(write!(dest, "repeat"));
                }

                match (origin, clip) {
                    (Some(origin), Some(clip)) => {
                        use properties::longhands::mask_origin::single_value::computed_value::T as Origin;
                        use properties::longhands::mask_clip::single_value::computed_value::T as Clip;

                        try!(write!(dest, " "));

                        match (origin, clip) {
                            (&Origin::padding_box, &Clip::padding_box) => {
                                try!(origin.to_css(dest));
                            },
                            (&Origin::border_box, &Clip::border_box) => {
                                try!(origin.to_css(dest));
                            },
                            (&Origin::content_box, &Clip::content_box) => {
                                try!(origin.to_css(dest));
                            },
                            _ => {
                                try!(origin.to_css(dest));
                                try!(write!(dest, " "));
                                try!(clip.to_css(dest));
                            }
                        }
                    },
                    _ => {}
                };

                try!(write!(dest, " "));

                if let Some(composite) = composite {
                    try!(composite.to_css(dest));
                } else {
                    try!(write!(dest, "add"));
                }
            }

            Ok(())
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="mask-position" products="gecko" extra_prefixes="webkit"
                    sub_properties="mask-position-x mask-position-y"
                    spec="https://drafts.csswg.org/css-masks-4/#the-mask-position">
    use properties::longhands::{mask_position_x,mask_position_y};
    use values::specified::position::Position;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut position_x = mask_position_x::SpecifiedValue(Vec::new());
        let mut position_y = mask_position_y::SpecifiedValue(Vec::new());
        let mut any = false;

        try!(input.parse_comma_separated(|input| {
            loop {
                if let Ok(value) = input.try(|input| Position::parse(context, input)) {
                    position_x.0.push(value.horizontal);
                    position_y.0.push(value.vertical);
                    any = true;
                    continue
                }
                break
            }
            Ok(())
        }));
        if any == false {
            return Err(());
        }

        Ok(Longhands {
            mask_position_x: Some(position_x),
            mask_position_y: Some(position_y),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            // mako doesn't like ampersands following `<`
            fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                match *x {
                    DeclaredValue::Value(ref val) => Some(val),
                    _ => None,
                }
            }
            use std::cmp;
            let mut len = 0;
            % for name in "x y".split():
                len = cmp::max(len, extract_value(self.mask_position_${name})
                                                      .map(|i| i.0.len())
                                                      .unwrap_or(0));
            % endfor

            // There should be at least one declared value
            if len == 0 {
                return dest.write_str("")
            }

            for i in 0..len {
                % for name in "x y".split():
                    let position_${name} = if let DeclaredValue::Value(ref arr) =
                                           *self.mask_position_${name} {
                        arr.0.get(i % arr.0.len())
                    } else {
                        None
                    };
                % endfor

                try!(position_x.unwrap_or(&mask_position_x::single_value
                                                                ::get_initial_position_value())
                               .to_css(dest));

                try!(write!(dest, " "));

                try!(position_y.unwrap_or(&mask_position_y::single_value
                                                                ::get_initial_position_value())
                               .to_css(dest));
            }

            Ok(())
        }
    }
</%helpers:shorthand>
<commit_msg>Add comma between layers for mask shorthand<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="mask" products="gecko" extra_prefixes="webkit"
                    sub_properties="mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position-x
                                    mask-position-y mask-size mask-image"
                    spec="https://drafts.fxtf.org/css-masking/#propdef-mask">
    use properties::longhands::{mask_mode, mask_repeat, mask_clip, mask_origin, mask_composite, mask_position_x,
                                mask_position_y};
    use properties::longhands::{mask_size, mask_image};
    use values::specified::position::Position;
    use parser::Parse;

    impl From<mask_origin::single_value::SpecifiedValue> for mask_clip::single_value::SpecifiedValue {
        fn from(origin: mask_origin::single_value::SpecifiedValue) -> mask_clip::single_value::SpecifiedValue {
            match origin {
                mask_origin::single_value::SpecifiedValue::content_box =>
                    mask_clip::single_value::SpecifiedValue::content_box,
                mask_origin::single_value::SpecifiedValue::padding_box =>
                    mask_clip::single_value::SpecifiedValue::padding_box,
                mask_origin::single_value::SpecifiedValue::border_box =>
                    mask_clip::single_value::SpecifiedValue::border_box,
                % if product == "gecko":
                mask_origin::single_value::SpecifiedValue::fill_box =>
                    mask_clip::single_value::SpecifiedValue::fill_box,
                mask_origin::single_value::SpecifiedValue::stroke_box =>
                    mask_clip::single_value::SpecifiedValue::stroke_box,
                mask_origin::single_value::SpecifiedValue::view_box =>
                    mask_clip::single_value::SpecifiedValue::view_box,
                % endif
            }
        }
    }

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "image mode position_x position_y size repeat origin clip composite".split():
            let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::new());
        % endfor

        try!(input.parse_comma_separated(|input| {
            % for name in "image mode position_x position_y size repeat origin clip composite".split():
                let mut ${name} = None;
            % endfor
            loop {
                if image.is_none() {
                    if let Ok(value) = input.try(|input| mask_image::single_value
                                                                   ::parse(context, input)) {
                        image = Some(value);
                        continue
                    }
                }
                if position_x.is_none() && position_y.is_none() {
                    if let Ok(value) = input.try(|input| Position::parse(context, input)) {
                        position_x = Some(value.horizontal);
                        position_y = Some(value.vertical);

                        // Parse mask size, if applicable.
                        size = input.try(|input| {
                            try!(input.expect_delim('/'));
                            mask_size::single_value::parse(context, input)
                        }).ok();

                        continue
                    }
                }
                % for name in "repeat origin clip composite mode".split():
                    if ${name}.is_none() {
                        if let Ok(value) = input.try(|input| mask_${name}::single_value
                                                                               ::parse(context, input)) {
                            ${name} = Some(value);
                            continue
                        }
                    }
                % endfor
                break
            }
            if clip.is_none() {
                if let Some(origin) = origin {
                    clip = Some(mask_clip::single_value::SpecifiedValue::from(origin));
                }
            }
            let mut any = false;
            % for name in "image mode position_x position_y size repeat origin clip composite".split():
                any = any || ${name}.is_some();
            % endfor
            if any {
                if position_x.is_some() || position_y.is_some() {
                    % for name in "position_x position_y".split():
                        if let Some(bg_${name}) = ${name} {
                            mask_${name}.0.push(bg_${name});
                        }
                    % endfor
                } else {
                    % for name in "position_x position_y".split():
                        mask_${name}.0.push(mask_${name}::single_value
                                            ::get_initial_position_value());
                    % endfor
                }
                % for name in "image mode size repeat origin clip composite".split():
                    if let Some(m_${name}) = ${name} {
                        mask_${name}.0.push(m_${name});
                    } else {
                        mask_${name}.0.push(mask_${name}::single_value
                                                        ::get_initial_specified_value());
                    }
                % endfor
                Ok(())
            } else {
                Err(())
            }
        }));

        Ok(Longhands {
            % for name in "image mode position_x position_y size repeat origin clip composite".split():
                mask_${name}: Some(mask_${name}),
            % endfor
         })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            // mako doesn't like ampersands following `<`
            fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                match *x {
                    DeclaredValue::Value(ref val) => Some(val),
                    _ => None,
                }
            }
            use std::cmp;
            let mut len = 0;
            % for name in "image mode position_x position_y size repeat origin clip composite".split():
                len = cmp::max(len, extract_value(self.mask_${name}).map(|i| i.0.len())
                                                                   .unwrap_or(0));
            % endfor

            // There should be at least one declared value
            if len == 0 {
                return dest.write_str("")
            }

            for i in 0..len {
                if i > 0 {
                    try!(dest.write_str(", "));
                }

                % for name in "image mode position_x position_y size repeat origin clip composite".split():
                    let ${name} = if let DeclaredValue::Value(ref arr) = *self.mask_${name} {
                        arr.0.get(i % arr.0.len())
                    } else {
                        None
                    };
                % endfor

                if let Some(image) = image {
                    try!(image.to_css(dest));
                } else {
                    try!(write!(dest, "none"));
                }

                try!(write!(dest, " "));

                if let Some(mode) = mode {
                    try!(mode.to_css(dest));
                } else {
                    try!(write!(dest, "match-source"));
                }

                try!(write!(dest, " "));

                try!(position_x.unwrap_or(&mask_position_x::single_value
                                                      ::get_initial_position_value())
                     .to_css(dest));

                try!(write!(dest, " "));

                try!(position_y.unwrap_or(&mask_position_y::single_value
                                                      ::get_initial_position_value())
                     .to_css(dest));

                if let Some(size) = size {
                    try!(write!(dest, " / "));
                    try!(size.to_css(dest));
                }

                try!(write!(dest, " "));

                if let Some(repeat) = repeat {
                    try!(repeat.to_css(dest));
                } else {
                    try!(write!(dest, "repeat"));
                }

                match (origin, clip) {
                    (Some(origin), Some(clip)) => {
                        use properties::longhands::mask_origin::single_value::computed_value::T as Origin;
                        use properties::longhands::mask_clip::single_value::computed_value::T as Clip;

                        try!(write!(dest, " "));

                        match (origin, clip) {
                            (&Origin::padding_box, &Clip::padding_box) => {
                                try!(origin.to_css(dest));
                            },
                            (&Origin::border_box, &Clip::border_box) => {
                                try!(origin.to_css(dest));
                            },
                            (&Origin::content_box, &Clip::content_box) => {
                                try!(origin.to_css(dest));
                            },
                            _ => {
                                try!(origin.to_css(dest));
                                try!(write!(dest, " "));
                                try!(clip.to_css(dest));
                            }
                        }
                    },
                    _ => {}
                };

                try!(write!(dest, " "));

                if let Some(composite) = composite {
                    try!(composite.to_css(dest));
                } else {
                    try!(write!(dest, "add"));
                }
            }

            Ok(())
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="mask-position" products="gecko" extra_prefixes="webkit"
                    sub_properties="mask-position-x mask-position-y"
                    spec="https://drafts.csswg.org/css-masks-4/#the-mask-position">
    use properties::longhands::{mask_position_x,mask_position_y};
    use values::specified::position::Position;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut position_x = mask_position_x::SpecifiedValue(Vec::new());
        let mut position_y = mask_position_y::SpecifiedValue(Vec::new());
        let mut any = false;

        try!(input.parse_comma_separated(|input| {
            loop {
                if let Ok(value) = input.try(|input| Position::parse(context, input)) {
                    position_x.0.push(value.horizontal);
                    position_y.0.push(value.vertical);
                    any = true;
                    continue
                }
                break
            }
            Ok(())
        }));
        if any == false {
            return Err(());
        }

        Ok(Longhands {
            mask_position_x: Some(position_x),
            mask_position_y: Some(position_y),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            // mako doesn't like ampersands following `<`
            fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                match *x {
                    DeclaredValue::Value(ref val) => Some(val),
                    _ => None,
                }
            }
            use std::cmp;
            let mut len = 0;
            % for name in "x y".split():
                len = cmp::max(len, extract_value(self.mask_position_${name})
                                                      .map(|i| i.0.len())
                                                      .unwrap_or(0));
            % endfor

            // There should be at least one declared value
            if len == 0 {
                return dest.write_str("")
            }

            for i in 0..len {
                % for name in "x y".split():
                    let position_${name} = if let DeclaredValue::Value(ref arr) =
                                           *self.mask_position_${name} {
                        arr.0.get(i % arr.0.len())
                    } else {
                        None
                    };
                % endfor

                try!(position_x.unwrap_or(&mask_position_x::single_value
                                                                ::get_initial_position_value())
                               .to_css(dest));

                try!(write!(dest, " "));

                try!(position_y.unwrap_or(&mask_position_y::single_value
                                                                ::get_initial_position_value())
                               .to_css(dest));
            }

            Ok(())
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>use libc::{c_char, c_int, c_void};

use crate::pyport::Py_ssize_t;
use crate::object::PyObject;

#[repr(C)]
#[derive(Copy)]
pub struct Py_buffer {
    pub buf: *mut c_void,
    pub obj: *mut PyObject,
    pub len: Py_ssize_t,
    pub itemsize: Py_ssize_t,
    pub readonly: c_int,
    pub ndim: c_int,
    pub format: *mut c_char,
    pub shape: *mut Py_ssize_t,
    pub strides: *mut Py_ssize_t,
    pub suboffsets: *mut Py_ssize_t,
    pub internal: *mut c_void,
}
impl Clone for Py_buffer {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}
impl Default for Py_buffer {
    #[inline]
    fn default() -> Self {
        unsafe { core::mem::zeroed() }
    }
}

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
    #[cfg(Py_3_9)]
    pub fn PyObject_CheckBuffer(obj: *mut PyObject) -> c_int;
    pub fn PyObject_GetBuffer(obj: *mut PyObject, view: *mut Py_buffer, flags: c_int) -> c_int;
    pub fn PyBuffer_GetPointer(view: *mut Py_buffer, indices: *mut Py_ssize_t) -> *mut c_void;
    pub fn PyBuffer_SizeFromFormat(format: *const c_char) -> Py_ssize_t;
    pub fn PyBuffer_ToContiguous(
        buf: *mut c_void,
        view: *mut Py_buffer,
        len: Py_ssize_t,
        order: c_char,
    ) -> c_int;
    pub fn PyBuffer_FromContiguous(
        view: *mut Py_buffer,
        buf: *mut c_void,
        len: Py_ssize_t,
        order: c_char,
    ) -> c_int;
    pub fn PyObject_CopyData(dest: *mut PyObject, src: *mut PyObject) -> c_int;
    pub fn PyBuffer_IsContiguous(view: *const Py_buffer, fort: c_char) -> c_int;
    pub fn PyBuffer_FillContiguousStrides(
        ndims: c_int,
        shape: *mut Py_ssize_t,
        strides: *mut Py_ssize_t,
        itemsize: c_int,
        fort: c_char,
    ) -> ();
    pub fn PyBuffer_FillInfo(
        view: *mut Py_buffer,
        o: *mut PyObject,
        buf: *mut c_void,
        len: Py_ssize_t,
        readonly: c_int,
        flags: c_int,
    ) -> c_int;
    pub fn PyBuffer_Release(view: *mut Py_buffer) -> ();
}

 /// Maximum number of dimensions
 pub const PyBUF_MAX_NDIM: c_int = 64;

 /* Flags for getting buffers */
 pub const PyBUF_SIMPLE: c_int = 0;
 pub const PyBUF_WRITABLE: c_int = 0x0001;
 /*  we used to include an E, backwards compatible alias  */
#[cfg(not(Py_LIMITED_API))]
 pub const PyBUF_WRITEABLE: c_int = PyBUF_WRITABLE;
 pub const PyBUF_FORMAT: c_int = 0x0004;
 pub const PyBUF_ND: c_int = 0x0008;
 pub const PyBUF_STRIDES: c_int = (0x0010 | PyBUF_ND);
 pub const PyBUF_C_CONTIGUOUS: c_int = (0x0020 | PyBUF_STRIDES);
 pub const PyBUF_F_CONTIGUOUS: c_int = (0x0040 | PyBUF_STRIDES);
 pub const PyBUF_ANY_CONTIGUOUS: c_int = (0x0080 | PyBUF_STRIDES);
 pub const PyBUF_INDIRECT: c_int = (0x0100 | PyBUF_STRIDES);

 pub const PyBUF_CONTIG: c_int = (PyBUF_ND | PyBUF_WRITABLE);
 pub const PyBUF_CONTIG_RO: c_int = (PyBUF_ND);

 pub const PyBUF_STRIDED: c_int = (PyBUF_STRIDES | PyBUF_WRITABLE);
 pub const PyBUF_STRIDED_RO: c_int = (PyBUF_STRIDES);

 pub const PyBUF_RECORDS: c_int = (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT);
 pub const PyBUF_RECORDS_RO: c_int = (PyBUF_STRIDES | PyBUF_FORMAT);

 pub const PyBUF_FULL: c_int = (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT);
 pub const PyBUF_FULL_RO: c_int = (PyBUF_INDIRECT | PyBUF_FORMAT);

 pub const PyBUF_READ: c_int = 0x100;
 pub const PyBUF_WRITE: c_int = 0x200;<commit_msg>PyBuffer_SizeFromFormat was added to limited API in 3.11<commit_after>use libc::{c_char, c_int, c_void};

use crate::pyport::Py_ssize_t;
use crate::object::PyObject;

#[repr(C)]
#[derive(Copy)]
pub struct Py_buffer {
    pub buf: *mut c_void,
    pub obj: *mut PyObject,
    pub len: Py_ssize_t,
    pub itemsize: Py_ssize_t,
    pub readonly: c_int,
    pub ndim: c_int,
    pub format: *mut c_char,
    pub shape: *mut Py_ssize_t,
    pub strides: *mut Py_ssize_t,
    pub suboffsets: *mut Py_ssize_t,
    pub internal: *mut c_void,
}
impl Clone for Py_buffer {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}
impl Default for Py_buffer {
    #[inline]
    fn default() -> Self {
        unsafe { core::mem::zeroed() }
    }
}

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
    #[cfg(Py_3_9)]
    pub fn PyObject_CheckBuffer(obj: *mut PyObject) -> c_int;
    pub fn PyObject_GetBuffer(obj: *mut PyObject, view: *mut Py_buffer, flags: c_int) -> c_int;
    pub fn PyBuffer_GetPointer(view: *mut Py_buffer, indices: *mut Py_ssize_t) -> *mut c_void;
    #[cfg(any(Py_3_11, all(not(Py_LIMITED_API), Py_3_9)))]
    pub fn PyBuffer_SizeFromFormat(format: *const c_char) -> Py_ssize_t;
    pub fn PyBuffer_ToContiguous(
        buf: *mut c_void,
        view: *mut Py_buffer,
        len: Py_ssize_t,
        order: c_char,
    ) -> c_int;
    pub fn PyBuffer_FromContiguous(
        view: *mut Py_buffer,
        buf: *mut c_void,
        len: Py_ssize_t,
        order: c_char,
    ) -> c_int;
    pub fn PyObject_CopyData(dest: *mut PyObject, src: *mut PyObject) -> c_int;
    pub fn PyBuffer_IsContiguous(view: *const Py_buffer, fort: c_char) -> c_int;
    pub fn PyBuffer_FillContiguousStrides(
        ndims: c_int,
        shape: *mut Py_ssize_t,
        strides: *mut Py_ssize_t,
        itemsize: c_int,
        fort: c_char,
    ) -> ();
    pub fn PyBuffer_FillInfo(
        view: *mut Py_buffer,
        o: *mut PyObject,
        buf: *mut c_void,
        len: Py_ssize_t,
        readonly: c_int,
        flags: c_int,
    ) -> c_int;
    pub fn PyBuffer_Release(view: *mut Py_buffer) -> ();
}

 /// Maximum number of dimensions
 pub const PyBUF_MAX_NDIM: c_int = 64;

 /* Flags for getting buffers */
 pub const PyBUF_SIMPLE: c_int = 0;
 pub const PyBUF_WRITABLE: c_int = 0x0001;
 /*  we used to include an E, backwards compatible alias  */
#[cfg(not(Py_LIMITED_API))]
 pub const PyBUF_WRITEABLE: c_int = PyBUF_WRITABLE;
 pub const PyBUF_FORMAT: c_int = 0x0004;
 pub const PyBUF_ND: c_int = 0x0008;
 pub const PyBUF_STRIDES: c_int = (0x0010 | PyBUF_ND);
 pub const PyBUF_C_CONTIGUOUS: c_int = (0x0020 | PyBUF_STRIDES);
 pub const PyBUF_F_CONTIGUOUS: c_int = (0x0040 | PyBUF_STRIDES);
 pub const PyBUF_ANY_CONTIGUOUS: c_int = (0x0080 | PyBUF_STRIDES);
 pub const PyBUF_INDIRECT: c_int = (0x0100 | PyBUF_STRIDES);

 pub const PyBUF_CONTIG: c_int = (PyBUF_ND | PyBUF_WRITABLE);
 pub const PyBUF_CONTIG_RO: c_int = (PyBUF_ND);

 pub const PyBUF_STRIDED: c_int = (PyBUF_STRIDES | PyBUF_WRITABLE);
 pub const PyBUF_STRIDED_RO: c_int = (PyBUF_STRIDES);

 pub const PyBUF_RECORDS: c_int = (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT);
 pub const PyBUF_RECORDS_RO: c_int = (PyBUF_STRIDES | PyBUF_FORMAT);

 pub const PyBUF_FULL: c_int = (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT);
 pub const PyBUF_FULL_RO: c_int = (PyBUF_INDIRECT | PyBUF_FORMAT);

 pub const PyBUF_READ: c_int = 0x100;
 pub const PyBUF_WRITE: c_int = 0x200;<|endoftext|>


<commit_before>use std::sync::Arc;

use ra_db::SourceDatabaseExt;

use super::*;

fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) {
    let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
    let krate = db.test_crate();
    {
        let events = db.log_executed(|| {
            db.crate_def_map(krate);
        });
        assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
    }
    db.set_file_text(pos.file_id, Arc::new(ra_fixture_change.to_string()));

    {
        let events = db.log_executed(|| {
            db.crate_def_map(krate);
        });
        assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
    }
}

#[test]
fn typing_inside_a_function_should_not_invalidate_def_map() {
    check_def_map_is_not_recomputed(
        r"
        //- /lib.rs
        mod foo;<|>

        use crate::foo::bar::Baz;

        fn foo() -> i32 {
            1 + 1
        }
        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        pub struct Baz;
        ",
        r"
        mod foo;

        use crate::foo::bar::Baz;

        fn foo() -> i32 { 92 }
        ",
    );
}

#[test]
fn adding_inner_items_should_not_invalidate_def_map() {
    check_def_map_is_not_recomputed(
        r"
        //- /lib.rs
        struct S { a: i32}
        enum E { A }
        trait T {
            fn a() {}
        }
        mod foo;<|>
        impl S {
            fn a() {}
        }
        use crate::foo::bar::Baz;
        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        pub struct Baz;
        ",
        r"
        struct S { a: i32, b: () }
        enum E { A, B }
        trait T {
            fn a() {}
            fn b() {}
        }
        mod foo;<|>
        impl S {
            fn a() {}
            fn b() {}
        }
        use crate::foo::bar::Baz;
        ",
    );
}

#[test]
fn typing_inside_a_macro_should_not_invalidate_def_map() {
    let (mut db, pos) = TestDB::with_position(
        r"
        //- /lib.rs
        macro_rules! m {
            ($ident:ident) => {
                fn f() {
                    $ident + $ident;
                };
            }
        }
        mod foo;

        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        <|>
        m!(X);
        ",
    );
    let krate = db.test_crate();
    {
        let events = db.log_executed(|| {
            let crate_def_map = db.crate_def_map(krate);
            let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
            assert_eq!(module_data.scope.resolutions().count(), 1);
        });
        assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
    }
    db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string()));

    {
        let events = db.log_executed(|| {
            let crate_def_map = db.crate_def_map(krate);
            let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
            assert_eq!(module_data.scope.resolutions().count(), 1);
        });
        assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
    }
}
<commit_msg>Make incremental nameres test harder<commit_after>use std::sync::Arc;

use ra_db::SourceDatabaseExt;

use super::*;

fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) {
    let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
    let krate = db.test_crate();
    {
        let events = db.log_executed(|| {
            db.crate_def_map(krate);
        });
        assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
    }
    db.set_file_text(pos.file_id, Arc::new(ra_fixture_change.to_string()));

    {
        let events = db.log_executed(|| {
            db.crate_def_map(krate);
        });
        assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
    }
}

#[test]
fn typing_inside_a_function_should_not_invalidate_def_map() {
    check_def_map_is_not_recomputed(
        r"
        //- /lib.rs
        mod foo;<|>

        use crate::foo::bar::Baz;

        enum E { A, B }
        use E::*;

        fn foo() -> i32 {
            1 + 1
        }
        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        pub struct Baz;
        ",
        r"
        mod foo;

        use crate::foo::bar::Baz;

        enum E { A, B }
        use E::*;

        fn foo() -> i32 { 92 }
        ",
    );
}

#[test]
fn adding_inner_items_should_not_invalidate_def_map() {
    check_def_map_is_not_recomputed(
        r"
        //- /lib.rs
        struct S { a: i32}
        enum E { A }
        trait T {
            fn a() {}
        }
        mod foo;<|>
        impl S {
            fn a() {}
        }
        use crate::foo::bar::Baz;
        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        pub struct Baz;
        ",
        r"
        struct S { a: i32, b: () }
        enum E { A, B }
        trait T {
            fn a() {}
            fn b() {}
        }
        mod foo;<|>
        impl S {
            fn a() {}
            fn b() {}
        }
        use crate::foo::bar::Baz;
        ",
    );
}

#[test]
fn typing_inside_a_macro_should_not_invalidate_def_map() {
    let (mut db, pos) = TestDB::with_position(
        r"
        //- /lib.rs
        macro_rules! m {
            ($ident:ident) => {
                fn f() {
                    $ident + $ident;
                };
            }
        }
        mod foo;

        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        <|>
        m!(X);
        ",
    );
    let krate = db.test_crate();
    {
        let events = db.log_executed(|| {
            let crate_def_map = db.crate_def_map(krate);
            let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
            assert_eq!(module_data.scope.resolutions().count(), 1);
        });
        assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
    }
    db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string()));

    {
        let events = db.log_executed(|| {
            let crate_def_map = db.crate_def_map(krate);
            let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
            assert_eq!(module_data.scope.resolutions().count(), 1);
        });
        assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
    }
}
<|endoftext|>


<commit_before>//! See [`complete_fn_param`].

use rustc_hash::FxHashMap;
use syntax::{
    ast::{self, HasModuleItem},
    match_ast, AstNode, SyntaxKind,
};

use crate::{
    context::{ParamKind, PatternContext},
    CompletionContext, CompletionItem, CompletionItemKind, Completions,
};

/// Complete repeated parameters, both name and type. For example, if all
/// functions in a file have a `spam: &mut Spam` parameter, a completion with
/// `spam: &mut Spam` insert text/label and `spam` lookup string will be
/// suggested.
pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
    let param_of_fn =
        matches!(ctx.pattern_ctx, Some(PatternContext { is_param: Some(ParamKind::Function), .. }));

    if !param_of_fn {
        return None;
    }

    let mut file_params = FxHashMap::default();

    let mut extract_params = |f: ast::Fn| {
        f.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
            if let Some(pat) = param.pat() {
                // FIXME: We should be able to turn these into SmolStr without having to allocate a String
                let whole_param = param.syntax().text().to_string();
                let binding = pat.syntax().text().to_string();
                file_params.entry(whole_param).or_insert(binding);
            }
        });
    };

    for node in ctx.token.ancestors() {
        match_ast! {
            match node {
                ast::SourceFile(it) => it.items().filter_map(|item| match item {
                    ast::Item::Fn(it) => Some(it),
                    _ => None,
                }).for_each(&mut extract_params),
                ast::ItemList(it) => it.items().filter_map(|item| match item {
                    ast::Item::Fn(it) => Some(it),
                    _ => None,
                }).for_each(&mut extract_params),
                ast::AssocItemList(it) => it.assoc_items().filter_map(|item| match item {
                    ast::AssocItem::Fn(it) => Some(it),
                    _ => None,
                }).for_each(&mut extract_params),
                _ => continue,
            }
        };
    }

    let function = ctx.token.ancestors().find_map(ast::Fn::cast)?;
    let param_list = function.param_list()?;

    remove_duplicated(&mut file_params, param_list.params())?;

    let self_completion_items = ["self", "&self", "mut self", "&mut self"];
    if should_add_self_completions(ctx, param_list) {
        self_completion_items.into_iter().for_each(|self_item| {
            add_new_item_to_acc(ctx, acc, self_item.to_string(), self_item.to_string())
        });
    }

    file_params.into_iter().try_for_each(|(whole_param, binding)| {
        Some(add_new_item_to_acc(ctx, acc, surround_with_commas(ctx, whole_param)?, binding))
    })?;

    Some(())
}

fn remove_duplicated(
    file_params: &mut FxHashMap<String, String>,
    mut fn_params: ast::AstChildren<ast::Param>,
) -> Option<()> {
    fn_params.try_for_each(|param| {
        let whole_param = param.syntax().text().to_string();
        file_params.remove(&whole_param);

        let binding = param.pat()?.syntax().text().to_string();

        file_params.retain(|_, v| v != &binding);
        Some(())
    })
}

fn should_add_self_completions(ctx: &CompletionContext, param_list: ast::ParamList) -> bool {
    let inside_impl = ctx.impl_def.is_some();
    let no_params = param_list.params().next().is_none() && param_list.self_param().is_none();

    inside_impl && no_params
}

fn surround_with_commas(ctx: &CompletionContext, param: String) -> Option<String> {
    let next_token = {
        let t = ctx.token.next_token()?;
        if !matches!(t.kind(), SyntaxKind::WHITESPACE) {
            t
        } else {
            t.next_token()?
        }
    };

    let trailing_comma_missing = matches!(next_token.kind(), SyntaxKind::IDENT);
    let trailing = if trailing_comma_missing { "," } else { "" };

    let previous_token = if matches!(ctx.token.kind(), SyntaxKind::IDENT | SyntaxKind::WHITESPACE) {
        ctx.previous_token.as_ref()?
    } else {
        &ctx.token
    };

    let needs_leading = !matches!(previous_token.kind(), SyntaxKind::L_PAREN | SyntaxKind::COMMA);
    let leading = if needs_leading { ", " } else { "" };

    Some(format!("{}{}{}", leading, param, trailing))
}

fn add_new_item_to_acc(
    ctx: &CompletionContext,
    acc: &mut Completions,
    label: String,
    lookup: String,
) {
    let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label);
    item.lookup_by(lookup);
    item.add_to(acc)
}
<commit_msg>refactor: apply review suggestions<commit_after>//! See [`complete_fn_param`].

use rustc_hash::FxHashMap;
use syntax::{
    ast::{self, HasModuleItem},
    match_ast, AstNode, SyntaxKind,
};

use crate::{
    context::{ParamKind, PatternContext},
    CompletionContext, CompletionItem, CompletionItemKind, Completions,
};

/// Complete repeated parameters, both name and type. For example, if all
/// functions in a file have a `spam: &mut Spam` parameter, a completion with
/// `spam: &mut Spam` insert text/label and `spam` lookup string will be
/// suggested.
pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
    let param_of_fn =
        matches!(ctx.pattern_ctx, Some(PatternContext { is_param: Some(ParamKind::Function), .. }));

    if !param_of_fn {
        return None;
    }

    let mut file_params = FxHashMap::default();

    let mut extract_params = |f: ast::Fn| {
        f.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
            if let Some(pat) = param.pat() {
                // FIXME: We should be able to turn these into SmolStr without having to allocate a String
                let whole_param = param.syntax().text().to_string();
                let binding = pat.syntax().text().to_string();
                file_params.entry(whole_param).or_insert(binding);
            }
        });
    };

    for node in ctx.token.ancestors() {
        match_ast! {
            match node {
                ast::SourceFile(it) => it.items().filter_map(|item| match item {
                    ast::Item::Fn(it) => Some(it),
                    _ => None,
                }).for_each(&mut extract_params),
                ast::ItemList(it) => it.items().filter_map(|item| match item {
                    ast::Item::Fn(it) => Some(it),
                    _ => None,
                }).for_each(&mut extract_params),
                ast::AssocItemList(it) => it.assoc_items().filter_map(|item| match item {
                    ast::AssocItem::Fn(it) => Some(it),
                    _ => None,
                }).for_each(&mut extract_params),
                _ => continue,
            }
        };
    }

    let function = ctx.token.ancestors().find_map(ast::Fn::cast)?;
    let param_list = function.param_list()?;

    remove_duplicated(&mut file_params, param_list.params());

    let self_completion_items = ["self", "&self", "mut self", "&mut self"];
    if should_add_self_completions(ctx, param_list) {
        self_completion_items.into_iter().for_each(|self_item| {
            add_new_item_to_acc(ctx, acc, self_item.to_string(), self_item.to_string())
        });
    }

    file_params.into_iter().try_for_each(|(whole_param, binding)| {
        Some(add_new_item_to_acc(ctx, acc, surround_with_commas(ctx, whole_param), binding))
    })?;

    Some(())
}

fn remove_duplicated(
    file_params: &mut FxHashMap<String, String>,
    fn_params: ast::AstChildren<ast::Param>,
) {
    fn_params.for_each(|param| {
        let whole_param = param.syntax().text().to_string();
        file_params.remove(&whole_param);

        if let Some(pattern) = param.pat() {
            let binding = pattern.syntax().text().to_string();
            file_params.retain(|_, v| v != &binding);
        }
    })
}

fn should_add_self_completions(ctx: &CompletionContext, param_list: ast::ParamList) -> bool {
    let inside_impl = ctx.impl_def.is_some();
    let no_params = param_list.params().next().is_none() && param_list.self_param().is_none();

    inside_impl && no_params
}

fn surround_with_commas(ctx: &CompletionContext, param: String) -> String {
    match fallible_surround_with_commas(ctx, &param) {
        Some(surrounded) => surrounded,
        // fallback to the original parameter
        None => param,
    }
}

fn fallible_surround_with_commas(ctx: &CompletionContext, param: &str) -> Option<String> {
    let next_token = {
        let t = ctx.token.next_token()?;
        match t.kind() {
            SyntaxKind::WHITESPACE => t.next_token()?,
            _ => t,
        }
    };

    let trailing_comma_missing = matches!(next_token.kind(), SyntaxKind::IDENT);
    let trailing = if trailing_comma_missing { "," } else { "" };

    let previous_token = if matches!(ctx.token.kind(), SyntaxKind::IDENT | SyntaxKind::WHITESPACE) {
        ctx.previous_token.as_ref()?
    } else {
        &ctx.token
    };

    let needs_leading = !matches!(previous_token.kind(), SyntaxKind::L_PAREN | SyntaxKind::COMMA);
    let leading = if needs_leading { ", " } else { "" };

    Some(format!("{}{}{}", leading, param, trailing))
}

fn add_new_item_to_acc(
    ctx: &CompletionContext,
    acc: &mut Completions,
    label: String,
    lookup: String,
) {
    let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label);
    item.lookup_by(lookup);
    item.add_to(acc)
}
<|endoftext|>


<commit_before>use super::value;
use super::interpreter;
use super::parser;
use rustyline;
use std::iter;

pub struct Repl {

}

impl Repl {
    pub fn start() {
        let quit = "(quit)";
        let mut rl = rustyline::Editor::<ParensCloser>::new();
        rl.add_history_entry(quit);
        rl.set_completer(Some(ParensCloser{}));

        loop {
            let line = rl.readline(">> ");
            let line = if line.is_err() { return } else { line.unwrap() };
            if line == quit { return }
            let result = parse_and_compile(line.as_bytes());
            rl.add_history_entry(&line);
            match result {
                Ok(value) => println!("=> {}", value),
                Err(err)  => println!("{}", err),
            }
        }
    }
}

struct ParensCloser {}

impl rustyline::completion::Completer for ParensCloser {
    fn complete(&self, line: &str, _: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let unclosed_parens = line.chars()
        .fold(0, |n, c| if c == '(' { n + 1 } else if c == ')' { n - 1 } else { n });
        let missing_parens: String = iter::repeat(')').take(unclosed_parens).collect();
        Result::Ok((line.len(), vec![missing_parens]))
    }
}

pub fn parse_and_compile(input: &[u8]) -> Result<value::Value, String>
{
    let parsed = parser::parse(input)?;
    let mut interpreter = interpreter::Interpreter::new(parsed);
    Ok(interpreter.start())
}
<commit_msg>fix repl completion bug<commit_after>use super::value;
use super::interpreter;
use super::parser;
use rustyline::{self, line_buffer};
use std::iter;

pub struct Repl {

}

impl Repl {
    pub fn start() {
        let quit = "(quit)";
        let mut rl = rustyline::Editor::<ParensCloser>::new();
        rl.add_history_entry(quit);
        rl.set_completer(Some(ParensCloser{}));

        loop {
            let line = rl.readline(">> ");
            let line = if line.is_err() { return } else { line.unwrap() };
            if line == quit { return }
            let result = parse_and_compile(line.as_bytes());
            rl.add_history_entry(&line);
            match result {
                Ok(value) => println!("=> {}", value),
                Err(err)  => println!("{}", err),
            }
        }
    }
}

struct ParensCloser {}

impl rustyline::completion::Completer for ParensCloser {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let unclosed_parens = line.chars()
        .fold(0, |n, c| if c == '(' { n + 1 } else if c == ')' { n - 1 } else { n });
        let missing_parens: String = iter::repeat(')').take(unclosed_parens).collect();
        Result::Ok((line.len(), vec![missing_parens]))
    }

    fn update(&self, line: &mut line_buffer::LineBuffer, _: usize, elected: &str) {
        let len = line.len();
        line.replace(len, len, elected);
    }}

pub fn parse_and_compile(input: &[u8]) -> Result<value::Value, String>
{
    let parsed = parser::parse(input)?;
    let mut interpreter = interpreter::Interpreter::new(parsed);
    Ok(interpreter.start())
}
<|endoftext|>


<commit_before>use libc::{self, c_char, c_void, size_t};

use std::mem;
use std::ptr;
use num::{Integer, NumCast};
use num::traits::cast;
use std::ffi::{CStr, CString};

use error::Result;

/// Convert a zero-terminated string (`const char *`) into a `String`.
pub fn string_from_cstr(string: *const c_char) -> String {
    unsafe {
        String::from_utf8_unchecked(CStr::from_ptr(string).to_bytes().to_vec())
    }
}

/// Convert a `String` or an `&str` into a zero-terminated string (`const char *`).
pub fn string_to_cstr<S: Into<String>>(string: S) -> *const c_char {
    unsafe {
        CString::from_vec_unchecked(string.into().into_bytes()).as_ptr()
    }
}

#[test]
pub fn test_string_cstr() {
    let s1: String = "foo".to_string();
    assert_eq!(s1, string_from_cstr(string_to_cstr(s1.clone())));
    let s2: &str = "bar";
    assert_eq!(s2, string_from_cstr(string_to_cstr(s2)));
}

#[doc(hidden)]
pub fn get_h5_str<T, F>(func: F) -> Result<String>
                 where F: Fn(*mut c_char, size_t) -> T, T: Integer + NumCast {
    unsafe {
        let len: isize = 1 + cast::<T, isize>(func(ptr::null_mut(), 0)).unwrap();
        ensure!(len > 0, "negative string length in get_h5_str()");
        let buf = libc::malloc((len as size_t) * mem::size_of::<c_char>() as size_t) as *mut c_char;
        func(buf, len as size_t);
        let msg = string_from_cstr(buf);
        libc::free(buf as *mut c_void);
        Ok(msg)
    }
}

#[test]
pub fn test_get_h5_str() {
    use ffi::h5e::H5Eget_msg;
    use globals::H5E_CANTOPENOBJ;

    let s = unsafe {
        get_h5_str(|msg, size| {
            H5Eget_msg(*H5E_CANTOPENOBJ, ptr::null_mut(), msg, size)
        }).ok().unwrap()
    };
    assert_eq!(s, "Can't open object");
}
<commit_msg>Add a failing test for util::string_to_cstr()<commit_after>use libc::{self, c_char, c_void, size_t};

use std::mem;
use std::ptr;
use num::{Integer, NumCast};
use num::traits::cast;
use std::ffi::{CStr, CString};

use error::Result;

/// Convert a zero-terminated string (`const char *`) into a `String`.
pub fn string_from_cstr(string: *const c_char) -> String {
    unsafe {
        String::from_utf8_unchecked(CStr::from_ptr(string).to_bytes().to_vec())
    }
}

/// Convert a `String` or an `&str` into a zero-terminated string (`const char *`).
pub fn string_to_cstr<S: Into<String>>(string: S) -> *const c_char {
    unsafe {
        CString::from_vec_unchecked(string.into().into_bytes()).as_ptr()
    }
}

#[test]
pub fn test_string_cstr() {
    let s1: String = "foo".to_string();
    assert_eq!(s1, string_from_cstr(string_to_cstr(s1.clone())));
    let s2: &str = "bar";
    assert_eq!(s2, string_from_cstr(string_to_cstr(s2)));
    let s3 = string_to_cstr("33");
    let s4 = string_to_cstr("44");
    assert_eq!(string_from_cstr(s3), "33");
    assert_eq!(string_from_cstr(s4), "44");
}

#[doc(hidden)]
pub fn get_h5_str<T, F>(func: F) -> Result<String>
                 where F: Fn(*mut c_char, size_t) -> T, T: Integer + NumCast {
    unsafe {
        let len: isize = 1 + cast::<T, isize>(func(ptr::null_mut(), 0)).unwrap();
        ensure!(len > 0, "negative string length in get_h5_str()");
        let buf = libc::malloc((len as size_t) * mem::size_of::<c_char>() as size_t) as *mut c_char;
        func(buf, len as size_t);
        let msg = string_from_cstr(buf);
        libc::free(buf as *mut c_void);
        Ok(msg)
    }
}

#[test]
pub fn test_get_h5_str() {
    use ffi::h5e::H5Eget_msg;
    use globals::H5E_CANTOPENOBJ;

    let s = unsafe {
        get_h5_str(|msg, size| {
            H5Eget_msg(*H5E_CANTOPENOBJ, ptr::null_mut(), msg, size)
        }).ok().unwrap()
    };
    assert_eq!(s, "Can't open object");
}
<|endoftext|>


<commit_before>#![cfg(test)]
use crate::per_block_processing;
use super::block_processing_builder::BlockProcessingBuilder;
use types::*;

pub const VALIDATOR_COUNT: usize = 10;

#[test]
fn runs_without_error() {
    let spec = ChainSpec::foundation();
    let mut builder = BlockProcessingBuilder::new(VALIDATOR_COUNT, &spec);

    // Set the state and block to be in the last slot of the 4th epoch.
    let last_slot_of_epoch = (spec.genesis_epoch + 4).end_slot(spec.slots_per_epoch);
    builder.set_slot(last_slot_of_epoch, &spec);

    builder.build_caches(&spec);

    let (block, mut state) = builder.build(&spec);

    per_block_processing(&mut state, &block, &spec).unwrap();
}

//  process_block_header
//      Invalid::StateSlotMismatch
//      Invalid::ParentBlockRootMismatch

//  verify_block_signature
//      Invalid::BadSignature

//  process_randao
//      Invalid::BadRandaoSignature

//  process_proposer_slashings
//      Invalid::MaxProposerSlashingsExceeded
//      verify_proposer_slashing
//          Invalid::ProposerUnknown
//          Invalid::ProposalSlotMismatch
//          Invalid::ProposalsIdentical
//          Invalid::ProposerAlreadySlashed
//          Invalid::ProposerAlreadyWithdrawn
//          Invalid::BadProposal1Signature
//          Invalid::BadProposal2Signature

//  process_attester_slashings
//      Invalid::MaxAttesterSlashingsExceed
//      verify_attester_slashing
//          Invalid::AttestationDataIdentical
//          Invalid::NotSlashable
//          Invalid::SlashableAttestation1Invalid
//          Invalid::SlashableAttestation2Invalid

//  process_attestations
//      Invalid::MaxAttestationsExceeded
//      validate_attestation
//          Invalid::PreGenesis
//          Invalid::IncludedTooLate
//          Invalid::IncludedTooEarly
//          Invalid::BadPreviousCrosslink
//          Invalid::AggregationBitfieldIsEmpty
//          Invalid::CustodyBitfieldHasSetBits
//          Invalid::NoCommitteeForShard
//          Invalid::BadCustodyBitfieldLength
//          Invalid::BadAggregationBitfieldLength
//          Invalid::ShardBlockRootNotZero
//          verify_justified_epoch_and_root
//              Invalid::WrongJustifiedEpoch (current)
//              Invalid::WrongJustifiedRoot (current)
//              Invalid::WrongJustifiedEpoch (previous)
//              Invalid::WrongJustifiedRoot (previous)
//          verify_attestation_signature
//              Invalid::BadAggregationBitfieldLength
//              Invalid::BadCustodyBitfieldLength
//              BeaconStateError::UnknownValidator
//              Invalid::BadSignature

//  process_deposits
//      Invalid::MaxDepositsExceeded
//      verify_deposit
//          Invalid::BadProofOfPossession
//          Invalid::BadMerkleProof
//      verify_deposit_index
//          Invalid::BadIndex

//  process_exits
//      Invalid::MaxExitsExceeded
//      verify_exit
//          Invalid::ValidatorUnknown
//          Invalid::AlreadyExited
//          Invalid::AlreadyInitiatedExited
//          Invalid::FutureEpoch
//          Invalid::TooYoungToLeave
//          Invalid::BadSignature

<commit_msg>mapped out invalid states... 59<commit_after>#![cfg(test)]
use crate::per_block_processing;
use super::block_processing_builder::BlockProcessingBuilder;
use types::*;

pub const VALIDATOR_COUNT: usize = 10;

#[test]
fn runs_without_error() {
    let spec = ChainSpec::foundation();
    let mut builder = BlockProcessingBuilder::new(VALIDATOR_COUNT, &spec);

    // Set the state and block to be in the last slot of the 4th epoch.
    let last_slot_of_epoch = (spec.genesis_epoch + 4).end_slot(spec.slots_per_epoch);
    builder.set_slot(last_slot_of_epoch, &spec);

    builder.build_caches(&spec);

    let (block, mut state) = builder.build(&spec);

    per_block_processing(&mut state, &block, &spec).unwrap();
}

//  process_block_header
//      Invalid::StateSlotMismatch
//      Invalid::ParentBlockRootMismatch

//  verify_block_signature
//      Invalid::BadSignature

//  process_randao
//      Invalid::BadRandaoSignature

//  process_proposer_slashings
//      Invalid::MaxProposerSlashingsExceeded
//      verify_proposer_slashing
//          Invalid::ProposerUnknown
//          Invalid::ProposalSlotMismatch
//          Invalid::ProposalsIdentical
//          Invalid::ProposerAlreadySlashed
//          Invalid::ProposerAlreadyWithdrawn
//          Invalid::BadProposal1Signature
//          Invalid::BadProposal2Signature

//  process_attester_slashings
//      Invalid::MaxAttesterSlashingsExceed
//      verify_attester_slashing
//          Invalid::AttestationDataIdentical
//          Invalid::NotSlashable
//          Invalid::SlashableAttestation1Invalid
//          Invalid::SlashableAttestation2Invalid

//  process_attestations
//      Invalid::MaxAttestationsExceeded
//      validate_attestation
//          Invalid::PreGenesis
//          Invalid::IncludedTooLate
//          Invalid::IncludedTooEarly
//          Invalid::BadPreviousCrosslink
//          Invalid::AggregationBitfieldIsEmpty
//          Invalid::CustodyBitfieldHasSetBits
//          Invalid::NoCommitteeForShard
//          Invalid::BadCustodyBitfieldLength
//          Invalid::BadAggregationBitfieldLength
//          Invalid::ShardBlockRootNotZero
//          verify_justified_epoch_and_root
//              Invalid::WrongJustifiedEpoch (current)
//              Invalid::WrongJustifiedRoot (current)
//              Invalid::WrongJustifiedEpoch (previous)
//              Invalid::WrongJustifiedRoot (previous)
//          verify_attestation_signature
//              Invalid::BadAggregationBitfieldLength
//              Invalid::BadCustodyBitfieldLength
//              BeaconStateError::UnknownValidator
//              Invalid::BadSignature

//  process_deposits
//      Invalid::MaxDepositsExceeded
//      verify_deposit
//          Invalid::BadProofOfPossession
//          Invalid::BadMerkleProof
//      verify_deposit_index
//          Invalid::BadIndex

//  process_exits
//      Invalid::MaxExitsExceeded
//      verify_exit
//          Invalid::ValidatorUnknown
//          Invalid::AlreadyExited
//          Invalid::AlreadyInitiatedExited
//          Invalid::FutureEpoch
//          Invalid::TooYoungToLeave
//          Invalid::BadSignature

//  process_transfers
//      Invalid::MaxTransfersExceed
//      verify_transfer
//          Invalid::FromValidatorUnknown
//          Invalid::FeeOverflow
//          Invalid::FromBalanceInsufficient (amount)
//          Invalid::FromBalanceInsufficient (fee)
//          Invalid::InvalidResultingFromBalance
//          Invalid::TransferSlotInPast
//          Invalid::StateSlotMismatch
//          Invalid::FromValidatorUnknown (???)
//          Invalid::FromValidatorIneligableForTransfer
//          Invalid::WithdrawalCredentialsMismatch
//          Invalid::BadSignature

<|endoftext|>


<commit_before>//! Endpoints that expose metadata about crate versions
//!
//! These endpoints provide data that could be obtained direclty from the
//! index or cached metadata which was extracted (client side) from the
//! `Cargo.toml` file.

use crate::controllers::frontend_prelude::*;

use crate::models::VersionOwnerAction;
use crate::views::{EncodableDependency, EncodablePublicUser, EncodableVersion};

use super::{extract_crate_name_and_semver, version_and_crate};

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
///
/// This information can be obtained direclty from the index.
///
/// In addition to returning cached data from the index, this returns
/// fields for `id`, `version_id`, and `downloads` (which appears to always
/// be 0)
pub fn dependencies(req: &mut dyn RequestExt) -> EndpointResult {
    let (crate_name, semver) = extract_crate_name_and_semver(req)?;
    let conn = req.db_read_only()?;
    let (version, _) = version_and_crate(&conn, crate_name, semver)?;
    let deps = version.dependencies(&conn)?;
    let deps = deps
        .into_iter()
        .map(|(dep, crate_name)| EncodableDependency::from_dep(dep, &crate_name))
        .collect();

    #[derive(Serialize)]
    struct R {
        dependencies: Vec<EncodableDependency>,
    }
    Ok(req.json(&R { dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut dyn RequestExt) -> EndpointResult {
    // Currently we return the empty list.
    // Because the API is not used anymore after RFC https://github.com/rust-lang/rfcs/pull/3052.
    #[derive(Serialize)]
    struct R {
        users: Vec<EncodablePublicUser>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        names: Vec<String>,
    }
    Ok(req.json(&R {
        users: vec![],
        meta: Meta { names: vec![] },
    }))
}

/// Handles the `GET /crates/:crate/:version` route.
///
/// The frontend doesn't appear to hit this endpoint, but our tests do, and it seems to be a useful
/// API route to have.
pub fn show(req: &mut dyn RequestExt) -> EndpointResult {
    let (crate_name, semver) = extract_crate_name_and_semver(req)?;
    let conn = req.db_read_only()?;
    let (version, krate) = version_and_crate(&conn, crate_name, semver)?;
    let published_by = version.published_by(&conn);
    let actions = VersionOwnerAction::by_version(&conn, &version)?;

    #[derive(Serialize)]
    struct R {
        version: EncodableVersion,
    }
    Ok(req.json(&R {
        version: EncodableVersion::from(version, &krate.name, published_by, actions),
    }))
}
<commit_msg>controllers::version::metadata: Use `json!` macro to simplify JSON serialization code<commit_after>//! Endpoints that expose metadata about crate versions
//!
//! These endpoints provide data that could be obtained direclty from the
//! index or cached metadata which was extracted (client side) from the
//! `Cargo.toml` file.

use crate::controllers::frontend_prelude::*;

use crate::models::VersionOwnerAction;
use crate::views::{EncodableDependency, EncodableVersion};

use super::{extract_crate_name_and_semver, version_and_crate};

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
///
/// This information can be obtained direclty from the index.
///
/// In addition to returning cached data from the index, this returns
/// fields for `id`, `version_id`, and `downloads` (which appears to always
/// be 0)
pub fn dependencies(req: &mut dyn RequestExt) -> EndpointResult {
    let (crate_name, semver) = extract_crate_name_and_semver(req)?;
    let conn = req.db_read_only()?;
    let (version, _) = version_and_crate(&conn, crate_name, semver)?;
    let deps = version.dependencies(&conn)?;
    let deps = deps
        .into_iter()
        .map(|(dep, crate_name)| EncodableDependency::from_dep(dep, &crate_name))
        .collect::<Vec<_>>();

    Ok(req.json(&json!({ "dependencies": deps })))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut dyn RequestExt) -> EndpointResult {
    // Currently we return the empty list.
    // Because the API is not used anymore after RFC https://github.com/rust-lang/rfcs/pull/3052.

    Ok(req.json(&json!({
        "users": [],
        "meta": { "names": [] },
    })))
}

/// Handles the `GET /crates/:crate/:version` route.
///
/// The frontend doesn't appear to hit this endpoint, but our tests do, and it seems to be a useful
/// API route to have.
pub fn show(req: &mut dyn RequestExt) -> EndpointResult {
    let (crate_name, semver) = extract_crate_name_and_semver(req)?;
    let conn = req.db_read_only()?;
    let (version, krate) = version_and_crate(&conn, crate_name, semver)?;
    let published_by = version.published_by(&conn);
    let actions = VersionOwnerAction::by_version(&conn, &version)?;

    let version = EncodableVersion::from(version, &krate.name, published_by, actions);
    Ok(req.json(&json!({ "version": version })))
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module contains utilities that work with the `CodeMap` from `libsyntax` / `syntex_syntax`.
//! This includes extension traits and methods for looking up spans and line ranges for AST nodes.

use config::file_lines::LineRange;
use syntax::codemap::{BytePos, CodeMap, Span};

use comment::FindUncommented;

pub trait SpanUtils {
    fn span_after(&self, original: Span, needle: &str) -> BytePos;
    fn span_after_last(&self, original: Span, needle: &str) -> BytePos;
    fn span_before(&self, original: Span, needle: &str) -> BytePos;
    fn opt_span_after(&self, original: Span, needle: &str) -> Option<BytePos>;
}

pub trait LineRangeUtils {
    /// Returns the `LineRange` that corresponds to `span` in `self`.
    ///
    /// # Panics
    ///
    /// Panics if `span` crosses a file boundary, which shouldn't happen.
    fn lookup_line_range(&self, span: Span) -> LineRange;
}

impl SpanUtils for CodeMap {
    fn span_after(&self, original: Span, needle: &str) -> BytePos {
        let snippet = self.span_to_snippet(original).expect("Bad snippet");
        let offset = snippet.find_uncommented(needle).expect("Bad offset") + needle.len();

        original.lo() + BytePos(offset as u32)
    }

    fn span_after_last(&self, original: Span, needle: &str) -> BytePos {
        let snippet = self.span_to_snippet(original).unwrap();
        let mut offset = 0;

        while let Some(additional_offset) = snippet[offset..].find_uncommented(needle) {
            offset += additional_offset + needle.len();
        }

        original.lo() + BytePos(offset as u32)
    }

    fn span_before(&self, original: Span, needle: &str) -> BytePos {
        let snippet = self.span_to_snippet(original).unwrap();
        let offset = snippet.find_uncommented(needle).unwrap();

        original.lo() + BytePos(offset as u32)
    }

    fn opt_span_after(&self, original: Span, needle: &str) -> Option<BytePos> {
        let snippet = self.span_to_snippet(original).ok()?;
        let offset = snippet.find_uncommented(needle)? + needle.len();

        Some(original.lo() + BytePos(offset as u32))
    }
}

impl LineRangeUtils for CodeMap {
    fn lookup_line_range(&self, span: Span) -> LineRange {
        let lo = self.lookup_line(span.lo()).unwrap();
        let hi = self.lookup_line(span.hi()).unwrap();

        assert_eq!(
            lo.fm.name, hi.fm.name,
            "span crossed file boundary: lo: {:?}, hi: {:?}",
            lo, hi
        );

        // Line numbers start at 1
        LineRange {
            file: lo.fm.clone(),
            lo: lo.line + 1,
            hi: hi.line + 1,
        }
    }
}
<commit_msg>Use debug_assert_eq! to avoid comparing PathBuf on release<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module contains utilities that work with the `CodeMap` from `libsyntax` / `syntex_syntax`.
//! This includes extension traits and methods for looking up spans and line ranges for AST nodes.

use config::file_lines::LineRange;
use syntax::codemap::{BytePos, CodeMap, Span};

use comment::FindUncommented;

pub trait SpanUtils {
    fn span_after(&self, original: Span, needle: &str) -> BytePos;
    fn span_after_last(&self, original: Span, needle: &str) -> BytePos;
    fn span_before(&self, original: Span, needle: &str) -> BytePos;
    fn opt_span_after(&self, original: Span, needle: &str) -> Option<BytePos>;
}

pub trait LineRangeUtils {
    /// Returns the `LineRange` that corresponds to `span` in `self`.
    ///
    /// # Panics
    ///
    /// Panics if `span` crosses a file boundary, which shouldn't happen.
    fn lookup_line_range(&self, span: Span) -> LineRange;
}

impl SpanUtils for CodeMap {
    fn span_after(&self, original: Span, needle: &str) -> BytePos {
        let snippet = self.span_to_snippet(original).expect("Bad snippet");
        let offset = snippet.find_uncommented(needle).expect("Bad offset") + needle.len();

        original.lo() + BytePos(offset as u32)
    }

    fn span_after_last(&self, original: Span, needle: &str) -> BytePos {
        let snippet = self.span_to_snippet(original).unwrap();
        let mut offset = 0;

        while let Some(additional_offset) = snippet[offset..].find_uncommented(needle) {
            offset += additional_offset + needle.len();
        }

        original.lo() + BytePos(offset as u32)
    }

    fn span_before(&self, original: Span, needle: &str) -> BytePos {
        let snippet = self.span_to_snippet(original).unwrap();
        let offset = snippet.find_uncommented(needle).unwrap();

        original.lo() + BytePos(offset as u32)
    }

    fn opt_span_after(&self, original: Span, needle: &str) -> Option<BytePos> {
        let snippet = self.span_to_snippet(original).ok()?;
        let offset = snippet.find_uncommented(needle)? + needle.len();

        Some(original.lo() + BytePos(offset as u32))
    }
}

impl LineRangeUtils for CodeMap {
    fn lookup_line_range(&self, span: Span) -> LineRange {
        let lo = self.lookup_line(span.lo()).unwrap();
        let hi = self.lookup_line(span.hi()).unwrap();

        debug_assert_eq!(
            lo.fm.name, hi.fm.name,
            "span crossed file boundary: lo: {:?}, hi: {:?}",
            lo, hi
        );

        // Line numbers start at 1
        LineRange {
            file: lo.fm.clone(),
            lo: lo.line + 1,
            hi: hi.line + 1,
        }
    }
}
<|endoftext|>


<commit_before>///
/// Text Scanner
///

use alloc::heap;
use std::marker::PhantomData;
use std::mem;
use std::ptr::copy_nonoverlapping;
use std::result::Result;
use std::slice;

use common::constant::ROWBLOCK_SIZE;
use common::err::*;
use exec::Executor;
use io::stream::*;
use schema::Schema;
use rows::RowBlock;
use rows::vrows::BorrowedVRowBlock;
use types::*;
use util::str::{StrSlice,split_str_slice};

const BUF_SIZE: usize = 65536;

pub struct DelimTextScanner<'a> {
  data_schema : Schema,
  read_fields : Option<Schema>,
  line_delim  : u8,
  field_delim : u8,
  reader      : Box<StreamReader>,
  marker      : PhantomData<&'a ()>,

  // variable
  readbuf_ptr          : *mut u8,
  need_more_line_slices: bool, // parse lines from read buffer
  line_slices_idx      : usize,
  read_line_num        : usize,    // number of read lines for each next
  line_slices_ptr      : *mut StrSlice,
  line_slices          : &'a mut [StrSlice],
  fields_slices_ptr    : *mut StrSlice,
  fields_slices        : &'a mut [StrSlice],
  parsed_batch_len     : usize,
  read_len             : usize,
}

impl<'a> DelimTextScanner<'a> {
  pub fn new(
        data_schema: Schema,
        read_fields: Option<Schema>,
        stream: Box<StreamReader>,
        field_delim: u8) -> DelimTextScanner<'a> {

    let mut line_slices_ptr = unsafe {
      heap::allocate(mem::size_of::<StrSlice>() * 1024, mem::min_align_of::<StrSlice>())
    } as *mut StrSlice;

    let mut line_slices: &mut [StrSlice] = unsafe {
      slice::from_raw_parts_mut(line_slices_ptr as *mut StrSlice, 1024)
    };

    let mut fields_slices_ptr = unsafe {
      heap::allocate(
        mem::size_of::<StrSlice>() * data_schema.size(),
        mem::min_align_of::<StrSlice>()
      )
    } as *mut StrSlice;

    let mut fields_slices: &mut [StrSlice] = unsafe {
      slice::from_raw_parts_mut(fields_slices_ptr as *mut StrSlice, data_schema.size())
    };

    DelimTextScanner {
      data_schema: data_schema,
      read_fields: read_fields,

      line_delim: '\n' as u8,
      field_delim: field_delim,

      reader: stream,
      marker: PhantomData,

      readbuf_ptr: unsafe { heap::allocate(BUF_SIZE, 16) },
      need_more_line_slices: true,
      line_slices_idx: 0,
      read_line_num: 0,
      line_slices_ptr: line_slices_ptr,
      line_slices: line_slices,
      fields_slices_ptr: fields_slices_ptr,
      fields_slices: fields_slices,
      parsed_batch_len: 0,
      read_len: 0
    }
  }

  fn read_line_num(&self) -> usize {
    self.read_line_num
  }

  fn line_slices(&self) -> &[StrSlice] {
    self.line_slices
  }

  fn find_first_record_index(&self, bytes: &[u8]) -> Option<usize> {
    //let bytes : &[u8] = unsafe { mem::transmute(text) };

    let mut pos : usize = 0;
    let mut found : bool = false;

    for c in bytes {
      if self.line_delim == *c {
        found = true;
        break;
      }

      pos = pos + 1;
    }

    match found {
      true => Some(pos + 1),
      false => None
    }
  }

  /// Return the last index of fields, which will be used for the following call.
  /// It will return a tuple consisting of found line number and last delim index.
  fn fill_line_slices(&mut self) {

    self.read_line_num      = 0; // read line counter
    let mut last_pos: usize = 0; // keep the start offset
    let mut cur_pos : usize = 0; // the current offset

    while (cur_pos < self.read_len && self.read_line_num < ROWBLOCK_SIZE) {
      // for each character
      let c: u8  = unsafe { *self.readbuf_ptr.offset(cur_pos as isize) };

      // check if the character is line delimiter
      if c == self.line_delim {

        // if found, set each StrSlice with the start offset and the current position
        self.line_slices[self.read_line_num].set_ptr(unsafe {self.readbuf_ptr.offset(last_pos as isize)});
        self.line_slices[self.read_line_num].set_len((cur_pos - last_pos) as i32);

        last_pos = cur_pos + 1; // to skip the delimiter character
        self.read_line_num = self.read_line_num + 1; // increase the line number
      }

      cur_pos = cur_pos + 1;
    }

    self.parsed_batch_len = last_pos;
    self.need_more_line_slices = false;
    self.line_slices_idx = 0;
  }

  fn add_row(&mut self, row_idx: usize, split_num: usize) {
  }

  /// move the remain bytes into the header of buffer and fill the buffer.
  fn compact_and_refill_readbuf(&mut self) -> Void {
    //println!("compact enter!");
    if self.read_len < self.parsed_batch_len {
      println!("read_len: {}, parsed_batch_len: {}", self.read_len, self.parsed_batch_len);
    }
    let remain_len = self.read_len - self.parsed_batch_len;
    debug_assert!(remain_len >= 0, "remain length must be positive number.");

    // move the remain bytes into the head of the readbuf
    if remain_len > 0 {
      unsafe {
        copy_nonoverlapping(
          self.readbuf_ptr.offset(self.parsed_batch_len as isize),
          self.readbuf_ptr,
          remain_len);
      }
    }

    // refill the readbuf
    self.read_len = try!(
      self.reader.read(
        unsafe {
          slice::from_raw_parts_mut(
            self.readbuf_ptr.offset(remain_len as isize),
            BUF_SIZE - remain_len
          )
        },
      )
    );

    self.read_len = self.read_len + remain_len;
    self.need_more_line_slices = true;
    void_ok()
  }
}

impl<'a> Executor for DelimTextScanner<'a> {

  fn init(&mut self) -> Void {
    self.read_len = try!(self.reader.read(
      unsafe {slice::from_raw_parts_mut(self.readbuf_ptr, BUF_SIZE)}
    ));

    void_ok()
  }

  fn next(&mut self, rowblock: &mut RowBlock) -> TResult<bool> {

    if (try!(self.reader.pos()) >= try!(self.reader.len())) {
      rowblock.set_row_num(0);
      return Ok(false);
    }

    let mut row_num: usize = 0;
    let mut field_parse_res: (usize, usize);
    let mut need_more_rows = true;
    loop { // this loop continues until rowblock is filled or

      // parse lines in batch
      if self.need_more_line_slices {
        self.fill_line_slices();
      }

      unsafe {
        let mut line_idx = self.line_slices_idx;
        while line_idx < self.read_line_num && need_more_rows {

          // split each line slice into field slices
          field_parse_res = split_str_slice(
            &mut self.line_slices[line_idx],
            self.fields_slices,
            self.field_delim
          );

          line_idx = line_idx + 1;
          row_num = row_num + 1;
          need_more_rows = row_num < ROWBLOCK_SIZE;
        }

        // record parsed line index
        self.line_slices_idx = line_idx;
      }

      if need_more_rows {
        // compact and fill read buffer
        self.compact_and_refill_readbuf();

        if self.read_len < 1 {
          break;
        }
      } else {
        break;
      }

    } // outmost loop

    println!("pos: {}, file_len: {}", try!(self.reader.pos()), try!(self.reader.len()));
    rowblock.set_row_num(row_num);
    Ok(row_num > 0)
  }

  fn close(&mut self) -> Void {
    void_ok()
  }

  fn in_schema(&self) -> &Schema {
    &self.data_schema
  }

  fn out_schema(&self) -> &Schema {
    match self.read_fields {
      Some(ref s) => s,
      None => &self.data_schema
    }
  }
}

#[test]
fn test_find_first_record_index() {
  let mut s = Schema::new();
  s.add_column("c1", *TEXT_TY);
  s.add_column("c2", *TEXT_TY);

  let fin = Box::new(FileInputStream::new("/home/hyunsik/tpch/lineitem/lineitem.tbl".to_string()));
  let s = DelimTextScanner::new(s, None, fin, '\n' as u8);

  assert_eq!(4, s.find_first_record_index("abc\nbb".as_bytes()).unwrap());
  assert_eq!(1, s.find_first_record_index("\nabc\nbb".as_bytes()).unwrap());
  assert_eq!(2, s.find_first_record_index("\r\nabc\nbb".as_bytes()).unwrap());
  assert!(s.find_first_record_index("aaaaabcabbb".as_bytes()).is_none());

}

#[test]
fn test_str_array() {
  let a: [&str;1024];

  //let mut slices: Vec<&str> = Vec::with_capacity(12);
  //unsafe { slices.set_len(12) };
  //slices.get_unchecked_mut(x)
  //slices[1] = "abc";

  let mut ptr: *mut &str = unsafe {
    heap::allocate(
      mem::size_of::<&str>() * 1024,
      mem::min_align_of::<&str>()
    ) as *mut &str
  };

  let mut slices: &mut [&str] = unsafe {
    slice::from_raw_parts_mut(ptr as *mut &str, 1024)
  };

  slices[0] = "abc";

  //slices[0] = "abc";
}

#[test]
fn test_read_line_batch() {
  let mut schema = Schema::new();
  schema.add_column("c1", *TEXT_TY);
  schema.add_column("c2", *TEXT_TY);

  let mut rowblock = BorrowedVRowBlock::new(&schema);

  let mut fin = Box::new(FileInputStream::new("/Users/hyunsik/tpch/lineitem/lineitem.tbl".to_string()));
  assert!(fin.open().is_ok());
  let mut s = DelimTextScanner::new(schema, None, fin, '\n' as u8);
  assert!(s.init().is_ok());

  let mut sum = 0;
  while(s.next(&mut rowblock).unwrap()) {
    sum = sum + rowblock.row_num();
    println!("acc: {}, rows: {}", sum, rowblock.row_num());
  }

  println!("{}", sum);
}
  // let mut delim_indexes:Vec<usize> = Vec::new();
  // let r1 =
  //   s.next_line_indexes("abc\nbb\nabcdef\nabcd".as_ptr(), &mut delim_indexes);
  // assert_eq!(3, r1.0);
  // assert_eq!(13, r1.1);

//   delim_indexes.clear();

//   let r2 =
//     s.next_line_indexes("a\nb\nabcde\n".as_ptr(), &mut delim_indexes);
//   assert_eq!(3, r2.0);
//   assert_eq!(9, r2.1);
// }<commit_msg>Refine DelimTextScanner::next() iteration<commit_after>///
/// Text Scanner
///

use alloc::heap;
use std::marker::PhantomData;
use std::mem;
use std::ptr::copy_nonoverlapping;
use std::result::Result;
use std::slice;

use common::constant::ROWBLOCK_SIZE;
use common::err::*;
use exec::Executor;
use io::stream::*;
use schema::Schema;
use rows::RowBlock;
use rows::vrows::BorrowedVRowBlock;
use types::*;
use util::str::{StrSlice,split_str_slice};

const BUF_SIZE: usize = 65536;

pub struct DelimTextScanner<'a> {
  data_schema : Schema,
  read_fields : Option<Schema>,
  line_delim  : u8,
  field_delim : u8,
  reader      : Box<StreamReader>,
  marker      : PhantomData<&'a ()>,

  // variable
  readbuf_ptr          : *mut u8,
  line_slices_idx      : usize,
  read_line_num        : usize,    // number of read lines for each next
  line_slices_ptr      : *mut StrSlice,
  line_slices          : &'a mut [StrSlice],
  fields_slices_ptr    : *mut StrSlice,
  fields_slices        : &'a mut [StrSlice],
  parsed_batch_len     : usize,
  read_len             : usize,
}

impl<'a> DelimTextScanner<'a> {
  pub fn new(
        data_schema: Schema,
        read_fields: Option<Schema>,
        stream: Box<StreamReader>,
        field_delim: u8) -> DelimTextScanner<'a> {

    let mut line_slices_ptr = unsafe {
      heap::allocate(mem::size_of::<StrSlice>() * 1024, mem::min_align_of::<StrSlice>())
    } as *mut StrSlice;

    let mut line_slices: &mut [StrSlice] = unsafe {
      slice::from_raw_parts_mut(line_slices_ptr as *mut StrSlice, 1024)
    };

    let mut fields_slices_ptr = unsafe {
      heap::allocate(
        mem::size_of::<StrSlice>() * data_schema.size(),
        mem::min_align_of::<StrSlice>()
      )
    } as *mut StrSlice;

    let mut fields_slices: &mut [StrSlice] = unsafe {
      slice::from_raw_parts_mut(fields_slices_ptr as *mut StrSlice, data_schema.size())
    };

    DelimTextScanner {
      data_schema: data_schema,
      read_fields: read_fields,

      line_delim: '\n' as u8,
      field_delim: field_delim,

      reader: stream,
      marker: PhantomData,

      readbuf_ptr: unsafe { heap::allocate(BUF_SIZE, 16) },
      line_slices_idx: 0,
      read_line_num: 0,
      line_slices_ptr: line_slices_ptr,
      line_slices: line_slices,
      fields_slices_ptr: fields_slices_ptr,
      fields_slices: fields_slices,
      parsed_batch_len: 0,
      read_len: 0
    }
  }

  fn read_line_num(&self) -> usize {
    self.read_line_num
  }

  fn line_slices(&self) -> &[StrSlice] {
    self.line_slices
  }

  fn find_first_record_index(&self, bytes: &[u8]) -> Option<usize> {
    //let bytes : &[u8] = unsafe { mem::transmute(text) };

    let mut pos : usize = 0;
    let mut found : bool = false;

    for c in bytes {
      if self.line_delim == *c {
        found = true;
        break;
      }

      pos = pos + 1;
    }

    match found {
      true => Some(pos + 1),
      false => None
    }
  }

  /// Return the last index of fields, which will be used for the following call.
  /// It will return a tuple consisting of found line number and last delim index.
  fn fill_line_slices(&mut self) {

    self.read_line_num      = 0; // read line counter
    let mut last_pos: usize = 0; // keep the start offset
    let mut cur_pos : usize = 0; // the current offset

    while (cur_pos < self.read_len && self.read_line_num < ROWBLOCK_SIZE) {
      // for each character
      let c: u8  = unsafe { *self.readbuf_ptr.offset(cur_pos as isize) };

      // check if the character is line delimiter
      if c == self.line_delim {

        // if found, set each StrSlice with the start offset and the current position
        self.line_slices[self.read_line_num].set_ptr(unsafe {self.readbuf_ptr.offset(last_pos as isize)});
        self.line_slices[self.read_line_num].set_len((cur_pos - last_pos) as i32);

        last_pos = cur_pos + 1; // to skip the delimiter character
        self.read_line_num = self.read_line_num + 1; // increase the line number
      }

      cur_pos = cur_pos + 1;
    }

    self.parsed_batch_len = last_pos;
    self.line_slices_idx = 0;
  }

  fn add_row(&mut self, row_idx: usize, split_num: usize) {
  }

  /// move the remain bytes into the header of buffer and fill the buffer.
  fn fill_readbuf(&mut self) -> Void {
    let remain_len = self.read_len - self.parsed_batch_len;
    debug_assert!(remain_len >= 0, "remain length must be positive number.");

    // check if buffer should be compact.
    // If true, move the remain bytes into the head of the readbuf.
    if remain_len > 0 {
      unsafe {
        copy_nonoverlapping(
          self.readbuf_ptr.offset(self.parsed_batch_len as isize),
          self.readbuf_ptr,
          remain_len);
      }
    }

    // fill readbuf
    self.read_len = try!(
      self.reader.read(
        unsafe {
          slice::from_raw_parts_mut(
            self.readbuf_ptr.offset(remain_len as isize),
            BUF_SIZE - remain_len
          )
        },
      )
    );

    self.read_len = self.read_len + remain_len;

    void_ok()
  }
}

impl<'a> Executor for DelimTextScanner<'a> {

  fn init(&mut self) -> Void {
    void_ok()
  }

  fn next(&mut self, rowblock: &mut RowBlock) -> TResult<bool> {

    // check if all data are consumed
    if (try!(self.reader.pos()) >= try!(self.reader.len())) {
      rowblock.set_row_num(0);
      return Ok(false); // return false to stop iteration
    }

    let mut row_num: usize = 0;
    let mut field_parse_res: (usize, usize);
    let mut need_more_rows = true;
    loop { // this loop continues until rowblock is filled or

      if self.line_slices_idx >= self.read_line_num { // need more line slices
        // compact and fill read buffer
        self.fill_readbuf();
        if self.read_len < 1 { // there is no readable buffer
          break;
        }
        self.fill_line_slices();
      }

      unsafe {
        let mut cur_line_idx = self.line_slices_idx;
        while cur_line_idx < self.read_line_num && need_more_rows {

          // split each line slice into field slices
          field_parse_res = split_str_slice(
            &mut self.line_slices[cur_line_idx],
            self.fields_slices,
            self.field_delim
          );

          cur_line_idx = cur_line_idx + 1;
          row_num = row_num + 1;
          need_more_rows = row_num < ROWBLOCK_SIZE;
        }

        // record parsed line index
        self.line_slices_idx = cur_line_idx;
      }

      if !need_more_rows {
        break;
      }

    } // outmost loop

    println!("pos: {}, file_len: {}", try!(self.reader.pos()), try!(self.reader.len()));
    rowblock.set_row_num(row_num);
    Ok(row_num > 0)
  }

  fn close(&mut self) -> Void {
    void_ok()
  }

  fn in_schema(&self) -> &Schema {
    &self.data_schema
  }

  fn out_schema(&self) -> &Schema {
    match self.read_fields {
      Some(ref s) => s,
      None => &self.data_schema
    }
  }
}

#[test]
fn test_find_first_record_index() {
  let mut s = Schema::new();
  s.add_column("c1", *TEXT_TY);
  s.add_column("c2", *TEXT_TY);

  let fin = Box::new(FileInputStream::new("/home/hyunsik/tpch/lineitem/lineitem.tbl".to_string()));
  let s = DelimTextScanner::new(s, None, fin, '\n' as u8);

  assert_eq!(4, s.find_first_record_index("abc\nbb".as_bytes()).unwrap());
  assert_eq!(1, s.find_first_record_index("\nabc\nbb".as_bytes()).unwrap());
  assert_eq!(2, s.find_first_record_index("\r\nabc\nbb".as_bytes()).unwrap());
  assert!(s.find_first_record_index("aaaaabcabbb".as_bytes()).is_none());

}

#[test]
fn test_str_array() {
  let a: [&str;1024];

  //let mut slices: Vec<&str> = Vec::with_capacity(12);
  //unsafe { slices.set_len(12) };
  //slices.get_unchecked_mut(x)
  //slices[1] = "abc";

  let mut ptr: *mut &str = unsafe {
    heap::allocate(
      mem::size_of::<&str>() * 1024,
      mem::min_align_of::<&str>()
    ) as *mut &str
  };

  let mut slices: &mut [&str] = unsafe {
    slice::from_raw_parts_mut(ptr as *mut &str, 1024)
  };

  slices[0] = "abc";

  //slices[0] = "abc";
}

#[test]
fn test_read_line_batch() {
  let mut schema = Schema::new();
  schema.add_column("c1", *TEXT_TY);
  schema.add_column("c2", *TEXT_TY);

  let mut rowblock = BorrowedVRowBlock::new(&schema);

  let mut fin = Box::new(FileInputStream::new("/Users/hyunsik/tpch/lineitem/lineitem.tbl".to_string()));
  assert!(fin.open().is_ok());
  let mut s = DelimTextScanner::new(schema, None, fin, '\n' as u8);
  assert!(s.init().is_ok());

  let mut sum = 0;
  while(s.next(&mut rowblock).unwrap()) {
    sum = sum + rowblock.row_num();
    println!("acc: {}, rows: {}", sum, rowblock.row_num());
  }

  println!("{}", sum);
}
  // let mut delim_indexes:Vec<usize> = Vec::new();
  // let r1 =
  //   s.next_line_indexes("abc\nbb\nabcdef\nabcd".as_ptr(), &mut delim_indexes);
  // assert_eq!(3, r1.0);
  // assert_eq!(13, r1.1);

//   delim_indexes.clear();

//   let r2 =
//     s.next_line_indexes("a\nb\nabcde\n".as_ptr(), &mut delim_indexes);
//   assert_eq!(3, r2.0);
//   assert_eq!(9, r2.1);
// }<|endoftext|>