<commit_before>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// Reexport for `local_inner_macros`; see
/// <https://doc.rust-lang.org/edition-guide/rust-2018/macros/macro-changes.html#macros-using-local_inner_macros>.
#[doc(hidden)]
#[macro_export]
macro_rules! _memoffset__compile_error {
    ($($inner:tt)*) => {
        compile_error! { $($inner)* }
    }
}

/// Produces a range instance representing the sub-slice containing the specified member.
///
/// This macro provides 2 forms of differing functionalities.
///
/// The first form is identical to the appearance of the `offset_of!` macro.
///
/// ```ignore
/// span_of!(Struct, member)
/// ```
///
/// The second form of `span_of!` returns a sub-slice which starts at one field, and ends at another.
/// The general pattern of this form is:
///
/// ```ignore
/// // Exclusive
/// span_of!(Struct, member_a .. member_b)
/// // Inclusive
/// span_of!(Struct, member_a ..= member_b)
///
/// // Open-ended ranges
/// span_of!(Struct, .. end)
/// span_of!(Struct, start ..)
/// ```
///
/// *Note*:
/// This macro uses recursion in order to resolve the range expressions, so there is a limit to
/// the complexity of the expression.
/// In order to raise the limit, the compiler's recursion limit should be lifted.
///
/// ## Examples
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C)]
/// struct Florp {
///     a: u32
/// }
///
/// #[repr(C)]
/// struct Blarg {
///     x: [u32; 2],
///     y: [u8; 56],
///     z: Florp,
///     egg: [[u8; 4]; 4]
/// }
///
/// fn main() {
///     assert_eq!(0..84,  span_of!(Blarg, ..));
///     assert_eq!(0..8,   span_of!(Blarg, .. y));
///     assert_eq!(0..64,  span_of!(Blarg, ..= y));
///     assert_eq!(0..8,   span_of!(Blarg, x));
///     assert_eq!(8..84,  span_of!(Blarg, y ..));
///     assert_eq!(0..8,   span_of!(Blarg, x .. y));
///     assert_eq!(0..64,  span_of!(Blarg, x ..= y));
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! span_of {
    (@helper  $root:ident, [] ..=) => {
        _memoffset__compile_error!("Expected a range, found '..='")
    };
    (@helper $root:ident, [] ..) => {
        _memoffset__compile_error!("Expected a range, found '..'")
    };
    // Lots of UB due to taking references to uninitialized fields! But that can currently
    // not be avoided.
    // No explicit begin for range.
    (@helper $root:ident, $parent:path, [] ..) => {{
        ($root as usize,
         $root as usize + $crate::mem::size_of_val(&(*$root)))
    }};
    (@helper $root:ident, $parent:path, [] ..= $field:tt) => {{
        _memoffset__field_check!($parent, $field);
        ($root as usize,
         &(*$root).$field as *const _ as usize + $crate::mem::size_of_val(&(*$root).$field))
    }};
    (@helper $root:ident, $parent:path, [] .. $field:tt) => {{
        _memoffset__field_check!($parent, $field);
        ($root as usize, &(*$root).$field as *const _ as usize)
    }};
    // Explicit begin and end for range.
    (@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{
        _memoffset__field_check!($parent, $begin);
        _memoffset__field_check!($parent, $end);
        (&(*$root).$begin as *const _ as usize,
         &(*$root).$end as *const _ as usize + $crate::mem::size_of_val(&(*$root).$end))
    }};
    (@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{
        _memoffset__field_check!($parent, $begin);
        _memoffset__field_check!($parent, $end);
        (&(*$root).$begin as *const _ as usize,
         &(*$root).$end as *const _ as usize)
    }};
    // No explicit end for range.
    (@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{
        _memoffset__field_check!($parent, $begin);
        (&(*$root).$begin as *const _ as usize,
         $root as usize + $crate::mem::size_of_val(&*$root))
    }};
    (@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{
        _memoffset__compile_error!(
            "Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?")
    }};
    // Just one field.
    (@helper $root:ident, $parent:path, # $begin:tt []) => {{
        _memoffset__field_check!($parent, $begin);
        (&(*$root).$begin as *const _ as usize,
         &(*$root).$begin as *const _ as usize + $crate::mem::size_of_val(&(*$root).$begin))
    }};
    // Parsing.
    (@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{
        span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*)
    }};
    (@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{
        span_of!(@helper $root, $parent, #$tt [] $($rest)*)
    }};

    // Entry point.
    ($sty:path, $($exp:tt)+) => ({
        unsafe {
            // Get a base pointer.
            _memoffset__let_base_ptr!(root, $sty);
            let base = root as usize;
            let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*);
            begin-base..end-base
        }
    });
}

#[cfg(test)]
mod tests {
    use core::mem;

    #[test]
    fn span_simple() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(span_of!(Foo, a), 0..4);
        assert_eq!(span_of!(Foo, b), 4..6);
        assert_eq!(span_of!(Foo, c), 8..8 + 8);
    }

    #[test]
    #[cfg_attr(miri, ignore)] // this creates unaligned references
    fn span_simple_packed() {
        #[repr(C, packed)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(span_of!(Foo, a), 0..4);
        assert_eq!(span_of!(Foo, b), 4..6);
        assert_eq!(span_of!(Foo, c), 6..6 + 8);
    }

    #[test]
    fn span_forms() {
        #[repr(C)]
        struct Florp {
            a: u32,
        }

        #[repr(C)]
        struct Blarg {
            x: u64,
            y: [u8; 56],
            z: Florp,
            egg: [[u8; 4]; 5],
        }

        // Love me some brute force
        assert_eq!(0..8, span_of!(Blarg, x));
        assert_eq!(64..68, span_of!(Blarg, z));
        assert_eq!(68..mem::size_of::<Blarg>(), span_of!(Blarg, egg));

        assert_eq!(8..64, span_of!(Blarg, y..z));
        assert_eq!(0..64, span_of!(Blarg, x..=y));
    }

    #[test]
    fn ig_test() {
        #[repr(C)]
        struct Member {
            foo: u32,
        }

        #[repr(C)]
        struct Test {
            x: u64,
            y: [u8; 56],
            z: Member,
            egg: [[u8; 4]; 4],
        }

        assert_eq!(span_of!(Test, ..x), 0..0);
        assert_eq!(span_of!(Test, ..=x), 0..8);
        assert_eq!(span_of!(Test, ..y), 0..8);
        assert_eq!(span_of!(Test, ..=y), 0..64);
        assert_eq!(span_of!(Test, ..z), 0..64);
        assert_eq!(span_of!(Test, ..=z), 0..68);
        assert_eq!(span_of!(Test, ..egg), 0..68);
        assert_eq!(span_of!(Test, ..=egg), 0..84);
        assert_eq!(span_of!(Test, ..), 0..mem::size_of::<Test>());
        assert_eq!(
            span_of!(Test, x..),
            offset_of!(Test, x)..mem::size_of::<Test>()
        );
        assert_eq!(
            span_of!(Test, y..),
            offset_of!(Test, y)..mem::size_of::<Test>()
        );

        assert_eq!(
            span_of!(Test, z..),
            offset_of!(Test, z)..mem::size_of::<Test>()
        );
        assert_eq!(
            span_of!(Test, egg..),
            offset_of!(Test, egg)..mem::size_of::<Test>()
        );
        assert_eq!(
            span_of!(Test, x..y),
            offset_of!(Test, x)..offset_of!(Test, y)
        );
        assert_eq!(
            span_of!(Test, x..=y),
            offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 56]>()
        );
    }
}
<commit_msg>span_of: use raw_field macro for more safety<commit_after>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// Reexport for `local_inner_macros`; see
/// <https://doc.rust-lang.org/edition-guide/rust-2018/macros/macro-changes.html#macros-using-local_inner_macros>.
#[doc(hidden)]
#[macro_export]
macro_rules! _memoffset__compile_error {
    ($($inner:tt)*) => {
        compile_error! { $($inner)* }
    }
}

/// Produces a range instance representing the sub-slice containing the specified member.
///
/// This macro provides 2 forms of differing functionalities.
///
/// The first form is identical to the appearance of the `offset_of!` macro.
///
/// ```ignore
/// span_of!(Struct, member)
/// ```
///
/// The second form of `span_of!` returns a sub-slice which starts at one field, and ends at another.
/// The general pattern of this form is:
///
/// ```ignore
/// // Exclusive
/// span_of!(Struct, member_a .. member_b)
/// // Inclusive
/// span_of!(Struct, member_a ..= member_b)
///
/// // Open-ended ranges
/// span_of!(Struct, .. end)
/// span_of!(Struct, start ..)
/// ```
///
/// *Note*:
/// This macro uses recursion in order to resolve the range expressions, so there is a limit to
/// the complexity of the expression.
/// In order to raise the limit, the compiler's recursion limit should be lifted.
///
/// ## Examples
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C)]
/// struct Florp {
///     a: u32
/// }
///
/// #[repr(C)]
/// struct Blarg {
///     x: [u32; 2],
///     y: [u8; 56],
///     z: Florp,
///     egg: [[u8; 4]; 4]
/// }
///
/// fn main() {
///     assert_eq!(0..84,  span_of!(Blarg, ..));
///     assert_eq!(0..8,   span_of!(Blarg, .. y));
///     assert_eq!(0..64,  span_of!(Blarg, ..= y));
///     assert_eq!(0..8,   span_of!(Blarg, x));
///     assert_eq!(8..84,  span_of!(Blarg, y ..));
///     assert_eq!(0..8,   span_of!(Blarg, x .. y));
///     assert_eq!(0..64,  span_of!(Blarg, x ..= y));
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! span_of {
    (@helper  $root:ident, [] ..=) => {
        _memoffset__compile_error!("Expected a range, found '..='")
    };
    (@helper $root:ident, [] ..) => {
        _memoffset__compile_error!("Expected a range, found '..'")
    };
    // No explicit begin for range.
    (@helper $root:ident, $parent:path, [] ..) => {{
        // UB due to taking references to uninitialized fields for `size_of_val`.
        ($root as usize,
         $root as usize + $crate::mem::size_of_val(&(*$root)))
    }};
    (@helper $root:ident, $parent:path, [] ..= $field:tt) => {{
        // UB due to taking references to uninitialized fields for `size_of_val`.
        ($root as usize,
         raw_field!($root, $parent, $field) as usize + $crate::mem::size_of_val(&(*$root).$field))
    }};
    (@helper $root:ident, $parent:path, [] .. $field:tt) => {{
        ($root as usize, raw_field!($root, $parent, $field) as usize)
    }};
    // Explicit begin and end for range.
    (@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{
        // UB due to taking references to uninitialized fields for `size_of_val`.
        (raw_field!($root, $parent, $begin) as usize,
         raw_field!($root, $parent, $end) as usize + $crate::mem::size_of_val(&(*$root).$end))
    }};
    (@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{
        (raw_field!($root, $parent, $begin) as usize,
         raw_field!($root, $parent, $end) as usize)
    }};
    // No explicit end for range.
    (@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{
        // UB due to taking references to uninitialized fields for `size_of_val`.
        (raw_field!($root, $parent, $begin) as usize,
         $root as usize + $crate::mem::size_of_val(&*$root))
    }};
    (@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{
        _memoffset__compile_error!(
            "Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?")
    }};
    // Just one field.
    (@helper $root:ident, $parent:path, # $begin:tt []) => {{
        // UB due to taking references to uninitialized fields for `size_of_val`.
        (raw_field!($root, $parent, $begin) as usize,
         raw_field!($root, $parent, $begin) as usize + $crate::mem::size_of_val(&(*$root).$begin))
    }};
    // Parsing.
    (@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{
        span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*)
    }};
    (@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{
        span_of!(@helper $root, $parent, #$tt [] $($rest)*)
    }};

    // Entry point.
    ($sty:path, $($exp:tt)+) => ({
        unsafe {
            // Get a base pointer.
            _memoffset__let_base_ptr!(root, $sty);
            let base = root as usize;
            let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*);
            begin-base..end-base
        }
    });
}

#[cfg(test)]
mod tests {
    use core::mem;

    #[test]
    fn span_simple() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(span_of!(Foo, a), 0..4);
        assert_eq!(span_of!(Foo, b), 4..6);
        assert_eq!(span_of!(Foo, c), 8..8 + 8);
    }

    #[test]
    #[cfg_attr(miri, ignore)] // this creates unaligned references
    fn span_simple_packed() {
        #[repr(C, packed)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(span_of!(Foo, a), 0..4);
        assert_eq!(span_of!(Foo, b), 4..6);
        assert_eq!(span_of!(Foo, c), 6..6 + 8);
    }

    #[test]
    fn span_forms() {
        #[repr(C)]
        struct Florp {
            a: u32,
        }

        #[repr(C)]
        struct Blarg {
            x: u64,
            y: [u8; 56],
            z: Florp,
            egg: [[u8; 4]; 5],
        }

        // Love me some brute force
        assert_eq!(0..8, span_of!(Blarg, x));
        assert_eq!(64..68, span_of!(Blarg, z));
        assert_eq!(68..mem::size_of::<Blarg>(), span_of!(Blarg, egg));

        assert_eq!(8..64, span_of!(Blarg, y..z));
        assert_eq!(0..64, span_of!(Blarg, x..=y));
    }

    #[test]
    fn ig_test() {
        #[repr(C)]
        struct Member {
            foo: u32,
        }

        #[repr(C)]
        struct Test {
            x: u64,
            y: [u8; 56],
            z: Member,
            egg: [[u8; 4]; 4],
        }

        assert_eq!(span_of!(Test, ..x), 0..0);
        assert_eq!(span_of!(Test, ..=x), 0..8);
        assert_eq!(span_of!(Test, ..y), 0..8);
        assert_eq!(span_of!(Test, ..=y), 0..64);
        assert_eq!(span_of!(Test, ..z), 0..64);
        assert_eq!(span_of!(Test, ..=z), 0..68);
        assert_eq!(span_of!(Test, ..egg), 0..68);
        assert_eq!(span_of!(Test, ..=egg), 0..84);
        assert_eq!(span_of!(Test, ..), 0..mem::size_of::<Test>());
        assert_eq!(
            span_of!(Test, x..),
            offset_of!(Test, x)..mem::size_of::<Test>()
        );
        assert_eq!(
            span_of!(Test, y..),
            offset_of!(Test, y)..mem::size_of::<Test>()
        );

        assert_eq!(
            span_of!(Test, z..),
            offset_of!(Test, z)..mem::size_of::<Test>()
        );
        assert_eq!(
            span_of!(Test, egg..),
            offset_of!(Test, egg)..mem::size_of::<Test>()
        );
        assert_eq!(
            span_of!(Test, x..y),
            offset_of!(Test, x)..offset_of!(Test, y)
        );
        assert_eq!(
            span_of!(Test, x..=y),
            offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 56]>()
        );
    }
}
<|endoftext|>


<commit_before>use std::cmp;

use misc::Slice;

// Note: There are different ways to implement ZipSlices.
// This version performed the best in benchmarks.
//
// I also implemented a version with three pointes (tptr, tend, uptr),
// that mimiced slice::Iter and only checked bounds by using tptr == tend,
// but that was inferior to this solution.

/// An iterator which iterates two slices simultaneously.
///
/// `ZipSlices` acts like a double-ended `.zip()` iterator, but more efficiently.
///
/// Note that elements past the end shortest of the shortest of the two slices
/// are ignored.
///
/// Iterator element type for `ZipSlices<T, U>` is `(T::Item, U::Item)`. For example,
/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`.
pub struct ZipSlices<T, U> {
    t: T,
    u: U,
    len: usize,
    index: usize,
}

/// `ZipSlices` is only clonable if both slices are shared references (`&[_]`).
impl<T: Copy, U: Copy> Clone for ZipSlices<T, U> {
    fn clone(&self) -> Self {
        ZipSlices {
            t: self.t,
            u: self.u,
            len: self.len,
            index: self.index,
        }
    }
}

impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]>
{
    /// Create a new `ZipSlices` from slices `a` and `b`.
    ///
    /// Act like a double-ended `.zip()` iterator, but more efficiently.
    ///
    /// Note that elements past the end shortest of the shortest of the two slices
    /// are ignored.
    ///
    #[inline(always)]
    pub fn new(a: &'a [A], b: &'b [B]) -> Self {
        Self::from_slices(a, b)
    }
}

impl<T, U> ZipSlices<T, U>
    where T: Slice, U: Slice
{
    /// Create a new `ZipSlices` from slices `a` and `b`.
    ///
    /// Act like a double-ended `.zip()` iterator, but more efficiently.
    ///
    /// Note that elements past the shortest of `a` or `b` are ignored.
    #[inline(always)]
    pub fn from_slices(a: T, b: U) -> Self {
        let minl = cmp::min(a.len(), b.len());
        ZipSlices {
            t: a,
            u: b,
            len: minl,
            index: 0,
        }
    }
}

impl<T, U> Iterator for ZipSlices<T, U>
    where T: Slice, U: Slice
{
    type Item = (T::Item, U::Item);

    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            if self.index >= self.len {
                None
            } else {
                let i = self.index;
                self.index += 1;
                Some((
                    self.t.get_unchecked(i),
                    self.u.get_unchecked(i)))
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len - self.index;
        (len, Some(len))
    }
}

impl<T, U> DoubleEndedIterator for ZipSlices<T, U>
    where T: Slice, U: Slice
{
    #[inline(always)]
    fn next_back(&mut self) -> Option<Self::Item> {
        unsafe {
            if self.index >= self.len {
                None
            } else {
                self.len -= 1;
                let i = self.len;
                Some((
                    self.t.get_unchecked(i),
                    self.u.get_unchecked(i)))
            }
        }
    }
}

impl<T, U> ExactSizeIterator for ZipSlices<T, U> where T: Slice, U: Slice { }

<commit_msg>zipslices: Fix on Rust 1.1<commit_after>use std::cmp;

use misc::Slice;

// Note: There are different ways to implement ZipSlices.
// This version performed the best in benchmarks.
//
// I also implemented a version with three pointes (tptr, tend, uptr),
// that mimiced slice::Iter and only checked bounds by using tptr == tend,
// but that was inferior to this solution.

/// An iterator which iterates two slices simultaneously.
///
/// `ZipSlices` acts like a double-ended `.zip()` iterator, but more efficiently.
///
/// Note that elements past the end shortest of the shortest of the two slices
/// are ignored.
///
/// Iterator element type for `ZipSlices<T, U>` is `(T::Item, U::Item)`. For example,
/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`.
pub struct ZipSlices<T, U> {
    t: T,
    u: U,
    len: usize,
    index: usize,
}

/// `ZipSlices` is only clonable if both slices are shared references (`&[_]`).
impl<T: Copy, U: Copy> Clone for ZipSlices<T, U> {
    fn clone(&self) -> Self {
        ZipSlices {
            t: self.t,
            u: self.u,
            len: self.len,
            index: self.index,
        }
    }
}

impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]>
{
    /// Create a new `ZipSlices` from slices `a` and `b`.
    ///
    /// Act like a double-ended `.zip()` iterator, but more efficiently.
    ///
    /// Note that elements past the end shortest of the shortest of the two slices
    /// are ignored.
    ///
    #[inline(always)]
    pub fn new(a: &'a [A], b: &'b [B]) -> Self {
        let minl = cmp::min(a.len(), b.len());
        ZipSlices {
            t: a,
            u: b,
            len: minl,
            index: 0,
        }
    }
}

impl<T, U> ZipSlices<T, U>
    where T: Slice, U: Slice
{
    /// Create a new `ZipSlices` from slices `a` and `b`.
    ///
    /// Act like a double-ended `.zip()` iterator, but more efficiently.
    ///
    /// Note that elements past the shortest of `a` or `b` are ignored.
    #[inline(always)]
    pub fn from_slices(a: T, b: U) -> Self {
        let minl = cmp::min(a.len(), b.len());
        ZipSlices {
            t: a,
            u: b,
            len: minl,
            index: 0,
        }
    }
}

impl<T, U> Iterator for ZipSlices<T, U>
    where T: Slice, U: Slice
{
    type Item = (T::Item, U::Item);

    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            if self.index >= self.len {
                None
            } else {
                let i = self.index;
                self.index += 1;
                Some((
                    self.t.get_unchecked(i),
                    self.u.get_unchecked(i)))
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len - self.index;
        (len, Some(len))
    }
}

impl<T, U> DoubleEndedIterator for ZipSlices<T, U>
    where T: Slice, U: Slice
{
    #[inline(always)]
    fn next_back(&mut self) -> Option<Self::Item> {
        unsafe {
            if self.index >= self.len {
                None
            } else {
                self.len -= 1;
                let i = self.len;
                Some((
                    self.t.get_unchecked(i),
                    self.u.get_unchecked(i)))
            }
        }
    }
}

impl<T, U> ExactSizeIterator for ZipSlices<T, U> where T: Slice, U: Slice { }

<|endoftext|>


<commit_before>use boxcars::crc::calc_crc;
use boxcars::*;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};

fn bench_crc(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/rumble.replay");
    let mut group = c.benchmark_group("crc_throughput");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.bench_function("bench_crc", |b| {
        let data = include_bytes!("../assets/replays/good/rumble.replay");
        b.iter(|| {
            black_box(calc_crc(&data[..]));
        })
    });
    group.finish();
}

fn bench_json_serialization(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let mut bytes = Vec::new();
    let replay = ParserBuilder::new(data)
        .on_error_check_crc()
        .parse()
        .unwrap();
    serde_json::to_writer(&mut bytes, &replay).unwrap();

    let mut group = c.benchmark_group("json_throughput");
    group.throughput(Throughput::Bytes(bytes.len() as u64));
    unsafe { bytes.set_len(0); };

    group.bench_function("bench_json_serialization", |b| {
        b.iter(|| {
            black_box(serde_json::to_writer(&mut bytes, &replay).is_ok());
            unsafe { bytes.set_len(0); };
        })
    });
    group.finish();
}

fn bench_parse_crc_body(c: &mut Criterion) {
    c.bench_function("bench_parse_crc_body", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .always_check_crc()
                    .must_parse_network_data()
                    .parse()
                    .is_ok(),
            )
        });
    });
}

fn bench_parse_no_crc_body(c: &mut Criterion) {
    c.bench_function("bench_parse_no_crc_body", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .on_error_check_crc()
                    .must_parse_network_data()
                    .parse()
                    .is_ok(),
            )
        });
    });
}

fn bench_parse_no_crc_no_body(c: &mut Criterion) {
    c.bench_function("bench_parse_no_crc_no_body", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .on_error_check_crc()
                    .never_parse_network_data()
                    .parse()
                    .is_ok(),
            )
        });
    });
}

fn bench_parse_crc_json(c: &mut Criterion) {
    c.bench_function("bench_parse_crc_json", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");

        // allocate a buffer big enough to hold all of the serialized data
        let mut bytes = Vec::with_capacity(2_usize.pow(25));
        b.iter(|| {
            let data = ParserBuilder::new(data).always_check_crc().parse().unwrap();
            black_box(serde_json::to_writer(&mut bytes, &data).is_ok());
            unsafe { bytes.set_len(0); }
        });
    });
}

fn bench_parse_no_crc_json(c: &mut Criterion) {
    c.bench_function("bench_parse_no_crc_json", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");

        // allocate a buffer big enough to hold all of the serialized data
        let mut bytes = Vec::with_capacity(2_usize.pow(25));
        b.iter(|| {
            let replay = ParserBuilder::new(data)
                .on_error_check_crc()
                .parse()
                .unwrap();
            black_box(serde_json::to_writer(&mut bytes, &replay).is_ok());
            unsafe { bytes.set_len(0); }
        });
    });
}

criterion_group!(
    benches,
    bench_crc,
    bench_json_serialization,
    bench_parse_crc_body,
    bench_parse_no_crc_body,
    bench_parse_no_crc_no_body,
    bench_parse_crc_json,
    bench_parse_no_crc_json
);

criterion_main!(benches);
<commit_msg>benchmarks: lazy assert number of bytes generated<commit_after>use boxcars::crc::calc_crc;
use boxcars::*;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};

fn bench_crc(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/rumble.replay");
    let mut group = c.benchmark_group("crc_throughput");
    group.throughput(Throughput::Bytes(data.len() as u64));
    group.bench_function("bench_crc", |b| {
        let data = include_bytes!("../assets/replays/good/rumble.replay");
        b.iter(|| {
            black_box(calc_crc(&data[..]));
        })
    });
    group.finish();
}

fn bench_json_serialization(c: &mut Criterion) {
    let data = include_bytes!("../assets/replays/good/3381.replay");
    let json_data_bytes = 19525895_u64;

    let mut group = c.benchmark_group("json_throughput");
    group.throughput(Throughput::Bytes(json_data_bytes));
    group.bench_function("bench_json_serialization", |b| {
        let mut bytes = Vec::new();
        let replay = ParserBuilder::new(data)
            .on_error_check_crc()
            .parse()
            .unwrap();
        serde_json::to_writer(&mut bytes, &replay).unwrap();
        assert!(json_data_bytes == bytes.len() as u64);
        unsafe { bytes.set_len(0); };

        b.iter(|| {
            black_box(serde_json::to_writer(&mut bytes, &replay).is_ok());
            unsafe { bytes.set_len(0); };
        })
    });
    group.finish();
}

fn bench_parse_crc_body(c: &mut Criterion) {
    c.bench_function("bench_parse_crc_body", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .always_check_crc()
                    .must_parse_network_data()
                    .parse()
                    .is_ok(),
            )
        });
    });
}

fn bench_parse_no_crc_body(c: &mut Criterion) {
    c.bench_function("bench_parse_no_crc_body", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .on_error_check_crc()
                    .must_parse_network_data()
                    .parse()
                    .is_ok(),
            )
        });
    });
}

fn bench_parse_no_crc_no_body(c: &mut Criterion) {
    c.bench_function("bench_parse_no_crc_no_body", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");
        b.iter(|| {
            black_box(
                ParserBuilder::new(data)
                    .on_error_check_crc()
                    .never_parse_network_data()
                    .parse()
                    .is_ok(),
            )
        });
    });
}

fn bench_parse_crc_json(c: &mut Criterion) {
    c.bench_function("bench_parse_crc_json", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");

        // allocate a buffer big enough to hold all of the serialized data
        let mut bytes = Vec::with_capacity(2_usize.pow(25));
        b.iter(|| {
            let data = ParserBuilder::new(data).always_check_crc().parse().unwrap();
            black_box(serde_json::to_writer(&mut bytes, &data).is_ok());
            unsafe { bytes.set_len(0); }
        });
    });
}

fn bench_parse_no_crc_json(c: &mut Criterion) {
    c.bench_function("bench_parse_no_crc_json", |b| {
        let data = include_bytes!("../assets/replays/good/3381.replay");

        // allocate a buffer big enough to hold all of the serialized data
        let mut bytes = Vec::with_capacity(2_usize.pow(25));
        b.iter(|| {
            let replay = ParserBuilder::new(data)
                .on_error_check_crc()
                .parse()
                .unwrap();
            black_box(serde_json::to_writer(&mut bytes, &replay).is_ok());
            unsafe { bytes.set_len(0); }
        });
    });
}

criterion_group!(
    benches,
    bench_crc,
    bench_json_serialization,
    bench_parse_crc_body,
    bench_parse_no_crc_body,
    bench_parse_no_crc_no_body,
    bench_parse_crc_json,
    bench_parse_no_crc_json
);

criterion_main!(benches);
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use async_trait::async_trait;
use diem_crypto::hash::HashValue;
use diem_types::{
    account_state_blob::AccountStatesChunkWithProof,
    ledger_info::LedgerInfoWithSignatures,
    transaction::{
        default_protocol::{TransactionListWithProof, TransactionOutputListWithProof},
        Version,
    },
};
use serde::{Deserialize, Serialize};
use storage_service_types::{CompleteDataRange, Epoch};
use thiserror::Error;

/// An error returned by the Diem Data Client for failed API calls.
#[derive(Clone, Debug, Deserialize, Error, PartialEq, Serialize)]
pub enum Error {
    #[error("The requested data is unavailable and cannot be found! Error: {0}")]
    DataIsUnavailable(String),
    #[error("The requested data is too large: {0}")]
    DataIsTooLarge(String),
    #[error("Timed out waiting for a response: {0}")]
    TimeoutWaitingForResponse(String),
    #[error("Unexpected error encountered: {0}")]
    UnexpectedErrorEncountered(String),
}

/// A response error that users of the Diem Data Client can use to notify
/// the Data Client about invalid or malformed responses.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum ResponseError {
    InvalidPayloadDataType,
    MissingData,
    ProofVerificationError,
}

/// The API offered by the Diem Data Client.
#[async_trait]
pub trait DiemDataClient {
    /// Returns a single account states chunk with proof, containing the accounts
    /// from start to end index (inclusive) at the specified version. The proof
    /// version is the same as the specified version.
    async fn get_account_states_with_proof(
        &self,
        version: u64,
        start_index: HashValue,
        end_index: HashValue,
    ) -> Result<DataClientResponse, Error>;

    /// Returns all epoch ending ledger infos between start and end (inclusive).
    /// If the data cannot be fetched (e.g., the number of epochs is too large),
    /// an error is returned.
    async fn get_epoch_ending_ledger_infos(
        &self,
        start_epoch: u64,
        end_epoch: u64,
    ) -> Result<DataClientResponse, Error>;

    /// Returns a global summary of the data currently available in the network.
    fn get_global_data_summary(&self) -> Result<DataClientResponse, Error>;

    /// Returns the number of account states at the specified version.
    async fn get_number_of_account_states(&self, version: u64)
        -> Result<DataClientResponse, Error>;

    /// Returns a transaction output list with proof object, with transaction
    /// outputs from start to end versions (inclusive). The proof is relative to
    /// the specified `proof_version`. If the data cannot be fetched (e.g., the
    /// number of transaction outputs is too large), an error is returned.
    async fn get_transaction_outputs_with_proof(
        &self,
        proof_version: u64,
        start_version: u64,
        end_version: u64,
    ) -> Result<DataClientResponse, Error>;

    /// Returns a transaction list with proof object, with transactions from
    /// start to end versions (inclusive). The proof is relative to the specified
    /// `proof_version`. If `include_events` is true, events are included in the
    /// proof. If the data cannot be fetched (e.g., the number of transactions is
    /// too large), an error is returned.
    async fn get_transactions_with_proof(
        &self,
        proof_version: u64,
        start_version: u64,
        end_version: u64,
        include_events: bool,
    ) -> Result<DataClientResponse, Error>;

    /// Notifies the Diem Data Client about a previously received response that
    /// was bad (e.g., invalid or malformed).
    ///
    /// Note: this is required because the Diem Data Client can only fetch
    /// data from peers in the network, but it is not able to fully verify that
    /// the given data responses are valid (e.g., it is unable to verify proofs).
    /// This API call provides a simple feedback mechanism for users of the Diem
    /// Data Client to alert it to bad responses so that the peers responsible
    /// for providing this data can be penalized. The `response_id` is the handle
    /// used by clients to notify the Diem Data Client of invalid responses.
    async fn notify_bad_response(
        &self,
        response_id: u64,
        response_error: ResponseError,
    ) -> Result<(), Error>;
}

/// A response from the Data Client for a single API call.
///
/// Note: the `response_id` is a simple handle returned by the Diem Data Client
/// that allows API callers to notify the Diem Data Client that the given
/// response payload is bad (e.g., it contains invalid or malformed data, or
/// the proof failed verification). This can be done using the
/// `notify_bad_response()` API call above.
#[derive(Clone, Debug)]
pub struct DataClientResponse {
    pub response_id: u64,
    pub response_payload: DataClientPayload,
}

/// The payload returned in a Data Client response.
#[derive(Clone, Debug)]
pub enum DataClientPayload {
    AccountStatesWithProof(AccountStatesChunkWithProof),
    EpochEndingLedgerInfos(Vec<LedgerInfoWithSignatures>),
    GlobalDataSummary(GlobalDataSummary),
    NumberOfAccountStates(u64),
    TransactionOutputsWithProof(TransactionOutputListWithProof),
    TransactionsWithProof(TransactionListWithProof),
}

/// A snapshot of the global state of data available in the Diem network.
#[derive(Clone, Debug)]
pub struct GlobalDataSummary {
    pub advertised_data: AdvertisedData,
    pub optimal_chunk_sizes: OptimalChunkSizes,
}

impl GlobalDataSummary {
    /// Returns an empty global data summary. This can be used on startup
    /// before the global state is known, or for testing.
    pub fn empty() -> Self {
        GlobalDataSummary {
            advertised_data: AdvertisedData {
                account_states: vec![],
                epoch_ending_ledger_infos: vec![],
                synced_ledger_infos: vec![],
                transactions: vec![],
                transaction_outputs: vec![],
            },
            optimal_chunk_sizes: OptimalChunkSizes {
                account_states_chunk_size: 0,
                epoch_chunk_size: 0,
                transaction_chunk_size: 0,
                transaction_output_chunk_size: 0,
            },
        }
    }
}

/// Holds the optimal chunk sizes that clients should use when
/// requesting data. This makes the request *more likely* to succeed.
#[derive(Clone, Debug)]
pub struct OptimalChunkSizes {
    pub account_states_chunk_size: u64,
    pub epoch_chunk_size: u64,
    pub transaction_chunk_size: u64,
    pub transaction_output_chunk_size: u64,
}

/// A summary of all data that is currently advertised in the network.
#[derive(Clone, Debug)]
pub struct AdvertisedData {
    /// The ranges of account states advertised, e.g., if a range is
    /// (X,Y), it means all account states are held for every version X->Y
    /// (inclusive).
    pub account_states: Vec<CompleteDataRange<Version>>,

    /// The ranges of epoch ending ledger infos advertised, e.g., if a range
    /// is (X,Y), it means all epoch ending ledger infos for epochs X->Y
    /// (inclusive) are available.
    pub epoch_ending_ledger_infos: Vec<CompleteDataRange<Epoch>>,

    /// The ledger infos corresponding to the highest synced versions
    /// currently advertised.
    pub synced_ledger_infos: Vec<LedgerInfoWithSignatures>,

    /// The ranges of transactions advertised, e.g., if a range is
    /// (X,Y), it means all transactions for versions X->Y (inclusive)
    /// are available.
    pub transactions: Vec<CompleteDataRange<Version>>,

    /// The ranges of transaction outputs advertised, e.g., if a range
    /// is (X,Y), it means all transaction outputs for versions X->Y
    /// (inclusive) are available.
    pub transaction_outputs: Vec<CompleteDataRange<Version>>,
}
<commit_msg>[State Sync] Add useful helper functions to diem data client.<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use async_trait::async_trait;
use diem_crypto::hash::HashValue;
use diem_types::{
    account_state_blob::AccountStatesChunkWithProof,
    ledger_info::LedgerInfoWithSignatures,
    transaction::{
        default_protocol::{TransactionListWithProof, TransactionOutputListWithProof},
        Version,
    },
};
use serde::{Deserialize, Serialize};
use storage_service_types::{CompleteDataRange, Epoch};
use thiserror::Error;

/// An error returned by the Diem Data Client for failed API calls.
#[derive(Clone, Debug, Deserialize, Error, PartialEq, Serialize)]
pub enum Error {
    #[error("The requested data is unavailable and cannot be found! Error: {0}")]
    DataIsUnavailable(String),
    #[error("The requested data is too large: {0}")]
    DataIsTooLarge(String),
    #[error("Timed out waiting for a response: {0}")]
    TimeoutWaitingForResponse(String),
    #[error("Unexpected error encountered: {0}")]
    UnexpectedErrorEncountered(String),
}

/// A response error that users of the Diem Data Client can use to notify
/// the Data Client about invalid or malformed responses.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum ResponseError {
    InvalidPayloadDataType,
    MissingData,
    ProofVerificationError,
}

/// The API offered by the Diem Data Client.
#[async_trait]
pub trait DiemDataClient {
    /// Returns a single account states chunk with proof, containing the accounts
    /// from start to end index (inclusive) at the specified version. The proof
    /// version is the same as the specified version.
    async fn get_account_states_with_proof(
        &self,
        version: u64,
        start_index: HashValue,
        end_index: HashValue,
    ) -> Result<DataClientResponse, Error>;

    /// Returns all epoch ending ledger infos between start and end (inclusive).
    /// If the data cannot be fetched (e.g., the number of epochs is too large),
    /// an error is returned.
    async fn get_epoch_ending_ledger_infos(
        &self,
        start_epoch: u64,
        end_epoch: u64,
    ) -> Result<DataClientResponse, Error>;

    /// Returns a global summary of the data currently available in the network.
    fn get_global_data_summary(&self) -> Result<DataClientResponse, Error>;

    /// Returns the number of account states at the specified version.
    async fn get_number_of_account_states(&self, version: u64)
        -> Result<DataClientResponse, Error>;

    /// Returns a transaction output list with proof object, with transaction
    /// outputs from start to end versions (inclusive). The proof is relative to
    /// the specified `proof_version`. If the data cannot be fetched (e.g., the
    /// number of transaction outputs is too large), an error is returned.
    async fn get_transaction_outputs_with_proof(
        &self,
        proof_version: u64,
        start_version: u64,
        end_version: u64,
    ) -> Result<DataClientResponse, Error>;

    /// Returns a transaction list with proof object, with transactions from
    /// start to end versions (inclusive). The proof is relative to the specified
    /// `proof_version`. If `include_events` is true, events are included in the
    /// proof. If the data cannot be fetched (e.g., the number of transactions is
    /// too large), an error is returned.
    async fn get_transactions_with_proof(
        &self,
        proof_version: u64,
        start_version: u64,
        end_version: u64,
        include_events: bool,
    ) -> Result<DataClientResponse, Error>;

    /// Notifies the Diem Data Client about a previously received response that
    /// was bad (e.g., invalid or malformed).
    ///
    /// Note: this is required because the Diem Data Client can only fetch
    /// data from peers in the network, but it is not able to fully verify that
    /// the given data responses are valid (e.g., it is unable to verify proofs).
    /// This API call provides a simple feedback mechanism for users of the Diem
    /// Data Client to alert it to bad responses so that the peers responsible
    /// for providing this data can be penalized. The `response_id` is the handle
    /// used by clients to notify the Diem Data Client of invalid responses.
    async fn notify_bad_response(
        &self,
        response_id: u64,
        response_error: ResponseError,
    ) -> Result<(), Error>;
}

/// A response from the Data Client for a single API call.
///
/// Note: the `response_id` is a simple handle returned by the Diem Data Client
/// that allows API callers to notify the Diem Data Client that the given
/// response payload is bad (e.g., it contains invalid or malformed data, or
/// the proof failed verification). This can be done using the
/// `notify_bad_response()` API call above.
#[derive(Clone, Debug)]
pub struct DataClientResponse {
    pub response_id: u64,
    pub response_payload: DataClientPayload,
}

/// The payload returned in a Data Client response.
#[derive(Clone, Debug)]
pub enum DataClientPayload {
    AccountStatesWithProof(AccountStatesChunkWithProof),
    EpochEndingLedgerInfos(Vec<LedgerInfoWithSignatures>),
    GlobalDataSummary(GlobalDataSummary),
    NumberOfAccountStates(u64),
    TransactionOutputsWithProof(TransactionOutputListWithProof),
    TransactionsWithProof(TransactionListWithProof),
}

/// A snapshot of the global state of data available in the Diem network.
#[derive(Clone, Debug)]
pub struct GlobalDataSummary {
    pub advertised_data: AdvertisedData,
    pub optimal_chunk_sizes: OptimalChunkSizes,
}

impl GlobalDataSummary {
    /// Returns an empty global data summary. This can be used on startup
    /// before the global state is known, or for testing.
    pub fn empty() -> Self {
        GlobalDataSummary {
            advertised_data: AdvertisedData::empty(),
            optimal_chunk_sizes: OptimalChunkSizes::empty(),
        }
    }
}

/// Holds the optimal chunk sizes that clients should use when
/// requesting data. This makes the request *more likely* to succeed.
#[derive(Clone, Debug)]
pub struct OptimalChunkSizes {
    pub account_states_chunk_size: u64,
    pub epoch_chunk_size: u64,
    pub transaction_chunk_size: u64,
    pub transaction_output_chunk_size: u64,
}

impl OptimalChunkSizes {
    pub fn empty() -> Self {
        OptimalChunkSizes {
            account_states_chunk_size: 0,
            epoch_chunk_size: 0,
            transaction_chunk_size: 0,
            transaction_output_chunk_size: 0,
        }
    }
}

/// A summary of all data that is currently advertised in the network.
#[derive(Clone, Debug)]
pub struct AdvertisedData {
    /// The ranges of account states advertised, e.g., if a range is
    /// (X,Y), it means all account states are held for every version X->Y
    /// (inclusive).
    pub account_states: Vec<CompleteDataRange<Version>>,

    /// The ranges of epoch ending ledger infos advertised, e.g., if a range
    /// is (X,Y), it means all epoch ending ledger infos for epochs X->Y
    /// (inclusive) are available.
    pub epoch_ending_ledger_infos: Vec<CompleteDataRange<Epoch>>,

    /// The ledger infos corresponding to the highest synced versions
    /// currently advertised.
    pub synced_ledger_infos: Vec<LedgerInfoWithSignatures>,

    /// The ranges of transactions advertised, e.g., if a range is
    /// (X,Y), it means all transactions for versions X->Y (inclusive)
    /// are available.
    pub transactions: Vec<CompleteDataRange<Version>>,

    /// The ranges of transaction outputs advertised, e.g., if a range
    /// is (X,Y), it means all transaction outputs for versions X->Y
    /// (inclusive) are available.
    pub transaction_outputs: Vec<CompleteDataRange<Version>>,
}

impl AdvertisedData {
    pub fn empty() -> Self {
        AdvertisedData {
            account_states: vec![],
            epoch_ending_ledger_infos: vec![],
            synced_ledger_infos: vec![],
            transactions: vec![],
            transaction_outputs: vec![],
        }
    }

    /// Returns true iff all data items (`lowest` to `highest`, inclusive) can
    /// be found in the given `advertised_ranges`.
    pub fn contains_range(
        lowest: u64,
        highest: u64,
        advertised_ranges: &[CompleteDataRange<u64>],
    ) -> bool {
        for item in lowest..=highest {
            let mut item_exists = false;

            for advertised_range in advertised_ranges {
                if advertised_range.contains(item) {
                    item_exists = true;
                    break;
                }
            }

            if !item_exists {
                return false;
            }
        }
        true
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! The I/O Prelude
//!
//! The purpose of this module is to alleviate imports of many common I/O traits
//! by adding a glob import to the top of I/O heavy modules:
//!
//! ```
//! # #![allow(unused_imports)]
//! use std::io::prelude::*;
//! ```
//!
//! This module contains reexports of many core I/O traits such as `Read`,
//! `Write` and `BufRead`. Structures and functions are not
//! contained in this module.

#![stable(feature = "rust1", since = "1.0.0")]

pub use super::{Read, Write, BufRead, Seek};
pub use fs::PathExt;
<commit_msg>Rollup merge of #26979 - tshepang:trim, r=Gankro<commit_after>// Copyright 2015 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.

//! The I/O Prelude
//!
//! The purpose of this module is to alleviate imports of many common I/O traits
//! by adding a glob import to the top of I/O heavy modules:
//!
//! ```
//! # #![allow(unused_imports)]
//! use std::io::prelude::*;
//! ```

#![stable(feature = "rust1", since = "1.0.0")]

pub use super::{Read, Write, BufRead, Seek};
pub use fs::PathExt;
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! The I/O Prelude
//!
//! The purpose of this module is to alleviate imports of many common I/O traits
//! by adding a glob import to the top of I/O heavy modules:
//!
//! ```
//! # #![allow(unused_imports)]
//! use std::io::prelude::*;
//! ```
//!
//! This module contains reexports of many core I/O traits such as `Read`,
//! `Write` and `BufRead`. Structures and functions are not
//! contained in this module.

#![stable(feature = "rust1", since = "1.0.0")]

pub use super::{Read, Write, BufRead, Seek};
pub use fs::PathExt;
<commit_msg>doc: remove redundant info<commit_after>// Copyright 2015 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.

//! The I/O Prelude
//!
//! The purpose of this module is to alleviate imports of many common I/O traits
//! by adding a glob import to the top of I/O heavy modules:
//!
//! ```
//! # #![allow(unused_imports)]
//! use std::io::prelude::*;
//! ```

#![stable(feature = "rust1", since = "1.0.0")]

pub use super::{Read, Write, BufRead, Seek};
pub use fs::PathExt;
<|endoftext|>


<commit_before>extern crate ctest;
extern crate cc;

use std::env;
use std::str;

fn main() {
    let mut cfg = ctest::TestGenerator::new();

    let mut build = cc::Build::new();
    build.file("version_detect.c");
    if let Ok(out) = env::var("DEP_CURL_INCLUDE") {
        cfg.include(&out);
        build.include(&out);
    }
    let version = build.expand();
    let version = str::from_utf8(&version).unwrap();
    let version = version.lines()
        .filter(|l| !l.is_empty() && !l.starts_with("#"))
        .next()
        .and_then(|s| s.parse::<u32>().ok())
        .unwrap_or(10000);

    if env::var("TARGET").unwrap().contains("msvc") {
        cfg.flag("/wd4574"); // did you mean to use '#if INCL_WINSOCK_API_TYPEDEFS'
    }

    cfg.header("curl/curl.h");
    cfg.define("CURL_STATICLIB", None);
    cfg.field_name(|s, field| {
        if s == "curl_fileinfo" {
            field.replace("strings_", "strings.")
        } else if s == "CURLMsg" && field == "data" {
            "data.whatever".to_string()
        } else {
            field.to_string()
        }
    });
    cfg.type_name(|s, is_struct, _is_union| {
        match s {
            "CURL" |
            "CURLM" |
            "CURLSH" |
            "curl_version_info_data" => s.to_string(),
            "curl_khtype" |
            "curl_khstat" |
            "curl_khmatch" => format!("enum {}", s),
            s if is_struct => format!("struct {}", s),
            "sockaddr" => format!("struct sockaddr"),
            s => s.to_string(),
        }
    });
    // cfg.fn_cname(|s, l| l.unwrap_or(s).to_string());
    cfg.skip_type(|n| n == "__enum_ty");
    cfg.skip_signededness(|s| {
        s.ends_with("callback") || s.ends_with("function")
    });

    cfg.skip_struct(move |s| {
        if version < 60 {
            match s {
                "curl_version_info_data" => return true,
                _ => {}
            }
        }

        false
    });

    cfg.skip_const(move |s| {
        if version < 60 {
            match s {
                "CURLVERSION_FIFTH" |
                "CURLVERSION_NOW" => return true,
                _ => {}
            }
        }

        if version < 49 {
            if s.starts_with("CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE") {
                return true
            }
        }

        if version < 47 {
            if s.starts_with("CURL_HTTP_VERSION_2") {
                return true
            }
        }

        if version < 43 {
            if s.starts_with("CURLPIPE_") {
                return true
            }
        }

        // OSX doesn't have this yet
        s == "CURLSSLOPT_NO_REVOKE" ||

        // A lot of curl versions doesn't support unix sockets
        s == "CURLOPT_UNIX_SOCKET_PATH" || s == "CURL_VERSION_UNIX_SOCKETS"
    });

    if cfg!(target_env = "msvc") {
        cfg.skip_fn_ptrcheck(|s| s.starts_with("curl_"));
    }

    cfg.generate("../curl-sys/lib.rs", "all.rs");
}
<commit_msg>Skip verifying CURLOPT_PIPEWAIT on older versions<commit_after>extern crate ctest;
extern crate cc;

use std::env;
use std::str;

fn main() {
    let mut cfg = ctest::TestGenerator::new();

    let mut build = cc::Build::new();
    build.file("version_detect.c");
    if let Ok(out) = env::var("DEP_CURL_INCLUDE") {
        cfg.include(&out);
        build.include(&out);
    }
    let version = build.expand();
    let version = str::from_utf8(&version).unwrap();
    let version = version.lines()
        .filter(|l| !l.is_empty() && !l.starts_with("#"))
        .next()
        .and_then(|s| s.parse::<u32>().ok())
        .unwrap_or(10000);

    if env::var("TARGET").unwrap().contains("msvc") {
        cfg.flag("/wd4574"); // did you mean to use '#if INCL_WINSOCK_API_TYPEDEFS'
    }

    cfg.header("curl/curl.h");
    cfg.define("CURL_STATICLIB", None);
    cfg.field_name(|s, field| {
        if s == "curl_fileinfo" {
            field.replace("strings_", "strings.")
        } else if s == "CURLMsg" && field == "data" {
            "data.whatever".to_string()
        } else {
            field.to_string()
        }
    });
    cfg.type_name(|s, is_struct, _is_union| {
        match s {
            "CURL" |
            "CURLM" |
            "CURLSH" |
            "curl_version_info_data" => s.to_string(),
            "curl_khtype" |
            "curl_khstat" |
            "curl_khmatch" => format!("enum {}", s),
            s if is_struct => format!("struct {}", s),
            "sockaddr" => format!("struct sockaddr"),
            s => s.to_string(),
        }
    });
    // cfg.fn_cname(|s, l| l.unwrap_or(s).to_string());
    cfg.skip_type(|n| n == "__enum_ty");
    cfg.skip_signededness(|s| {
        s.ends_with("callback") || s.ends_with("function")
    });

    cfg.skip_struct(move |s| {
        if version < 60 {
            match s {
                "curl_version_info_data" => return true,
                _ => {}
            }
        }

        false
    });

    cfg.skip_const(move |s| {
        if version < 61 {
            match s {
                "CURLOPT_PIPEWAIT" => return true,
                _ => {}
            }
        }
        if version < 60 {
            match s {
                "CURLVERSION_FIFTH" |
                "CURLVERSION_NOW" => return true,
                _ => {}
            }
        }

        if version < 49 {
            if s.starts_with("CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE") {
                return true
            }
        }

        if version < 47 {
            if s.starts_with("CURL_HTTP_VERSION_2") {
                return true
            }
        }

        if version < 43 {
            if s.starts_with("CURLPIPE_") {
                return true
            }
        }

        // OSX doesn't have this yet
        s == "CURLSSLOPT_NO_REVOKE" ||

        // A lot of curl versions doesn't support unix sockets
        s == "CURLOPT_UNIX_SOCKET_PATH" || s == "CURL_VERSION_UNIX_SOCKETS"
    });

    if cfg!(target_env = "msvc") {
        cfg.skip_fn_ptrcheck(|s| s.starts_with("curl_"));
    }

    cfg.generate("../curl-sys/lib.rs", "all.rs");
}
<|endoftext|>


<commit_before>//! # asn1-cereal
//! A collection of encoders and decoders for BER, DER and ASN.1.
//!
//! The grains of this library are a collection of traits and macros, that
//! allow serialization and deserialization of rust types to and from ASN.1.
//!
//! The `Asn1Info`, `BerSerialize` and `BerDeserialize` traits are what
//! most users will want to use.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

pub mod tag;
pub mod err;
pub mod byte;
#[macro_use]
pub mod info;
pub mod ber;

pub use info::Asn1Info;
pub use ber::serial::traits::{BerSerialize, BerDeserialize};
pub use ber::enc::{BER, DER, BERAlt, BerEncRules};
<commit_msg>Add example to root lib.rs<commit_after>//! # asn1-cereal
//! A collection of encoders and decoders for BER, DER and ASN.1.
//!
//! The grains of this library are a collection of traits and macros, that
//! allow serialization and deserialization of rust types to and from ASN.1.
//!
//! The `Asn1Info`, `BerSerialize` and `BerDeserialize` traits are what
//! most users will want to use.
//!
//! ```
//! #[macro_use] extern crate asn1_cereal; fn main() {
//!   struct ShortSequence {
//!     z: u64,
//!     y: u32,
//!   }
//!
//!   ber_sequence!(
//!     ShortSequence,
//!     "SHORT_SEQUENCE",
//!     z,
//!     y
//!   );
//!
//!   use asn1_cereal::BerSerialize;
//!
//!   let data = ShortSequence{ z: 1, y: 2 };
//!   let mut bytes: Vec<u8> = Vec::new();
//!   BerSerialize::serialize(&data, &mut bytes).unwrap();
//! }
//! ```

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

pub mod tag;
pub mod err;
pub mod byte;
#[macro_use]
pub mod info;
pub mod ber;

pub use info::Asn1Info;
pub use ber::serial::traits::{BerSerialize, BerDeserialize};
pub use ber::enc::{BER, DER, BERAlt, BerEncRules};
<|endoftext|>


<commit_before>#[derive(Eq,PartialEq,Hash,Debug,Clone,Copy)]
pub struct BS {
    pub length: i64,
    pub value: i64,
}

pub trait BitString {
    fn pow(i64, i64) -> i64;
    fn flip(i64, i64) -> i64;
    fn is_set(i64, i64) -> bool;
    fn prepend(i64, BS) -> BS;
    fn length(BS) -> i64;

    const max_len: u32;
}

impl BitString for BS {
    fn pow(b: i64, n: i64) -> i64 {
        match n {
            0 => 1,
            1 => b,
            n => {
                let x = Self::pow(b, n / 2);
                x * x * (if n % 2 == 0 { 1 } else { b })
            }
        }
    }
    fn flip(i: i64, b: i64) -> i64 {
        let n = Self::pow(2, i);
        if n & b == n {
            return b - Self::pow(2, i);
        } else {
            return b + Self::pow(2, i);
        }
    }
    fn is_set(i: i64, b: i64) -> bool {
        let n = Self::flip(i, 0);
        (n & b) == n
    }
    fn prepend(b: i64, bs: BS) -> BS {
        match b {
            0 => {
                if !(Self::is_set(bs.length, bs.value)) {
                    BS {
                        length: bs.length + 1,
                        value: bs.value,
                    }
                } else {
                    BS {
                        length: bs.length + 1,
                        value: Self::flip(bs.length, bs.value),
                    }
                }
            }
            1 => {
                if Self::is_set(bs.length, bs.value) {
                    BS {
                        length: bs.length + 1,
                        value: bs.value,
                    }
                } else {
                    BS {
                        length: bs.length + 1,
                        value: Self::flip(bs.length, bs.value),
                    }
                }
            }
            _ => panic!("b has to be a bit (0 or 1)"),
        }
    }
    fn length(bs: BS) -> i64 {
        bs.length
    }

    const max_len: u32  = 30;
}

#[test]
fn test_pow() {
    assert_eq!(BS::pow(0, 0), 1);
    assert_eq!(BS::pow(42, 0), 1);
    assert_eq!(BS::pow(-2, 0), 1);
    assert_eq!(BS::pow(2, 4), 16);
    assert_eq!(BS::pow(-2, 3), -8);
}

#[test]
fn test_flip() {
    assert_eq!(BS::flip(0, 0), 1);
    assert_eq!(BS::flip(2, 0), 4);
    assert_eq!(BS::flip(1, 7), 5);
    assert_eq!(BS::flip(3, 7), 15);
}

#[test]
fn test_is_set() {
    assert_eq!(BS::is_set(4, 0), false);
    assert_eq!(BS::is_set(0, 0), false);
    assert_eq!(BS::is_set(0, 1), true);
    assert_eq!(BS::is_set(1, 2), true);
    assert_eq!(BS::is_set(0, 2), false);
}

#[test]
fn test_prepend() {
    assert_eq!(BS::prepend(0, BS { length: 0, value: 0}), BS { length: 1, value: 0 });
    assert_eq!(BS::prepend(1, BS { length: 0, value: 0}), BS { length: 1, value: 1});
    assert_eq!(BS::prepend(1, BS { length: 1, value: 1}), BS { length: 2, value: 3});
    assert_eq!(BS::prepend(0, BS { length: 1, value: 1}), BS { length: 2, value: 1});
    assert_eq!(BS::prepend(1, BS { length: 2, value: 1}), BS { length: 3, value: 5});
}
<commit_msg>Uppercase associated constant<commit_after>#[derive(Eq,PartialEq,Hash,Debug,Clone,Copy)]
pub struct BS {
    pub length: i64,
    pub value: i64,
}

pub trait BitString {
    fn pow(i64, i64) -> i64;
    fn flip(i64, i64) -> i64;
    fn is_set(i64, i64) -> bool;
    fn prepend(i64, BS) -> BS;
    fn length(BS) -> i64;

    const MAX_LEN: u32;
}

impl BitString for BS {
    fn pow(b: i64, n: i64) -> i64 {
        match n {
            0 => 1,
            1 => b,
            n => {
                let x = Self::pow(b, n / 2);
                x * x * (if n % 2 == 0 { 1 } else { b })
            }
        }
    }
    fn flip(i: i64, b: i64) -> i64 {
        let n = Self::pow(2, i);
        if n & b == n {
            return b - Self::pow(2, i);
        } else {
            return b + Self::pow(2, i);
        }
    }
    fn is_set(i: i64, b: i64) -> bool {
        let n = Self::flip(i, 0);
        (n & b) == n
    }
    fn prepend(b: i64, bs: BS) -> BS {
        match b {
            0 => {
                if !(Self::is_set(bs.length, bs.value)) {
                    BS {
                        length: bs.length + 1,
                        value: bs.value,
                    }
                } else {
                    BS {
                        length: bs.length + 1,
                        value: Self::flip(bs.length, bs.value),
                    }
                }
            }
            1 => {
                if Self::is_set(bs.length, bs.value) {
                    BS {
                        length: bs.length + 1,
                        value: bs.value,
                    }
                } else {
                    BS {
                        length: bs.length + 1,
                        value: Self::flip(bs.length, bs.value),
                    }
                }
            }
            _ => panic!("b has to be a bit (0 or 1)"),
        }
    }
    fn length(bs: BS) -> i64 {
        bs.length
    }

    const MAX_LEN: u32 = 30;
}

#[test]
fn test_pow() {
    assert_eq!(BS::pow(0, 0), 1);
    assert_eq!(BS::pow(42, 0), 1);
    assert_eq!(BS::pow(-2, 0), 1);
    assert_eq!(BS::pow(2, 4), 16);
    assert_eq!(BS::pow(-2, 3), -8);
}

#[test]
fn test_flip() {
    assert_eq!(BS::flip(0, 0), 1);
    assert_eq!(BS::flip(2, 0), 4);
    assert_eq!(BS::flip(1, 7), 5);
    assert_eq!(BS::flip(3, 7), 15);
}

#[test]
fn test_is_set() {
    assert_eq!(BS::is_set(4, 0), false);
    assert_eq!(BS::is_set(0, 0), false);
    assert_eq!(BS::is_set(0, 1), true);
    assert_eq!(BS::is_set(1, 2), true);
    assert_eq!(BS::is_set(0, 2), false);
}

#[test]
fn test_prepend() {
    assert_eq!(BS::prepend(0,
                           BS {
                               length: 0,
                               value: 0,
                           }),
               BS {
                   length: 1,
                   value: 0,
               });
    assert_eq!(BS::prepend(1,
                           BS {
                               length: 0,
                               value: 0,
                           }),
               BS {
                   length: 1,
                   value: 1,
               });
    assert_eq!(BS::prepend(1,
                           BS {
                               length: 1,
                               value: 1,
                           }),
               BS {
                   length: 2,
                   value: 3,
               });
    assert_eq!(BS::prepend(0,
                           BS {
                               length: 1,
                               value: 1,
                           }),
               BS {
                   length: 2,
                   value: 1,
               });
    assert_eq!(BS::prepend(1,
                           BS {
                               length: 2,
                               value: 1,
                           }),
               BS {
                   length: 3,
                   value: 5,
               });
}
<|endoftext|>


<commit_before>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn_bytes
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn_bytes (needle: str, haystack: str, nn: uint) -> [uint] {
   let results = [];
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   log(error, ct);
   log(error, pt);

   let ii = 0u;
   let jj = 0u;

   while ii < str::len_bytes(haystack) {

      jj = str::len_bytes(needle) - 1u;

      // reverse through needle
      while 0u <= jj {

         // if still matching
         if needle[jj] == haystack[ii] {
            // if full match
            if jj == 0u {
               vec::push(results, jj);
               if vec::len(results) >= nn { ret results; }
            }

         // if partial match
         } else {
            let sufn = str::len_bytes(needle) - jj;

            let ctx;
            let ptx;

            alt ct.find(needle[sufn] as uint) {
               option::none { ctx = str::len_bytes(needle);}
               option::some(x) { ctx = x;}
            }

            alt pt.find(sufn) {
               option::none { fail "something is out of range" }
               option::some(x) { ptx = x;}
            }

            ii += greaterOf(ctx, ptx) - jj;
            jj = 0u;
         }

         jj -= 1u;
      }

      ii += 1u;
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len_bytes(needle);

   let jj = len - 1u; // drop the last byte

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint);
   assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   let prefs = vec::reversed(prefixes(needle)); // largest first
   let sufs  = vec::reversed(suffixes(needle)); // smallest first
   let jj    = 0u;
   let kk    = 0u;
   let lim   = str::len(needle);

   while jj < lim {    // sufixes
      std::io::println("\n<newsuff: " + sufs[jj] + ">");

      kk = 0u;

      while kk < lim { // prefixes
         std::io::print("<prefixes: " + prefs[kk] + "> ");

         let suf = sufs[jj];
         let pref = prefs[kk];

         if str::len_bytes(pref) > str::len_bytes(suf) {
            //std::io::println("[" + pref + ", " + suf + "]");
            std::io::print("(pref > suf)");
            if str::ends_with(pref, suf) {
               std::io::print("(ew)");
               if !str::ends_with(pref, sufs[jj+1u]) {
                  std::io::print("(ew+1)");

                  if ! mm.contains_key(jj)
                  {
                     std::io::print(#fmt("(+%u)", kk));
                     mm.insert(jj, kk);
                  }
               }
            }
         }

         if str::len_bytes(pref) <= str::len_bytes(suf) {
            std::io::print("(pref <= suf)");

            if str::ends_with(suf, pref) // partial
            {
               std::io::print("(^ew)");

               if ! mm.contains_key(jj)
               {
                  std::io::print(#fmt("(*%u)", kk));
                  mm.insert(jj, kk);
               }
            }
         }

         std::io::println("");

         kk += 1u;
      }

      // for this suffix jj, if no matching prefix, where did we fall out?
      // i.e., what is the last prefix that was still partially matching,
      // e.g., for suffix "man", the prefix "an" works, and is +6...
      //       but will not be added above...
      //
      // TODO: add that to table
      if ! mm.contains_key(jj)
      {
         std::io::print(#fmt("(=%u)", kk));
         mm.insert(jj, kk);
      }

      jj += 1u;
   }

   ret mm
}

#[test]
fn test_prefix_table() {
   let pt = prefix_table("ANPANMAN");
                        //     ... 8
   std::io::print("+");
   log(error, pt);
   assert 1u == pt.get(0u); //        (n)
   assert 8u == pt.get(1u); //       (a)n
   assert 3u == pt.get(2u); //      (m)an
   assert 6u == pt.get(3u); //     (n)man
   assert 6u == pt.get(4u); //    (a)nman
   assert 6u == pt.get(5u); //   (p)anman
   assert 6u == pt.get(6u); //  (n)panman
   assert 6u == pt.get(7u); // (a)npanman
   //assert 0u == pt.get(8u); // fail
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];
   let sz = 0u;
   vec::push(vv, "");
   str::bytes_iter(ss) {|_bb|
      sz += 1u;
      vec::push(vv, str::unsafe::slice_bytes(ss, 0u, sz));
   }
   ret vv;
}

#[test]
fn test_prefs() {
   assert ["", "a", "ab", "abc", "abcd"] == prefixes("abcd");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let sz = 0u;
   let lim = str::len_bytes(ss);
   str::bytes_iter(ss) {|_bb|
      vec::push(vv, str::unsafe::slice_bytes(ss, sz, lim));
      sz += 1u;
   }
   vec::push(vv, "");
   ret vv;
}

#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d", ""] == suffixes("abcd");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_bytes_(needle: str, haystack: str) -> option<uint> {
   ret option::some(findn_bytes(needle, haystack, 1u)[0u]);
}

#[test]
fn test_find_bytes() {
  // byte positions
  assert (find_bytes_("banana", "apple pie") == option::none);
  assert (find_bytes_("", "") == option::some(0u));

  let data = "ประเทศไทย中华Việt Nam";
  assert (find_bytes_(data, "")     == option::some(0u));
  assert (find_bytes_(data, "ประเ") == option::some( 0u));
  assert (find_bytes_(data, "ะเ")   == option::some( 6u));
  assert (find_bytes_(data, "中华") == option::some(27u));
  assert (find_bytes_(data, "ไท华") == option::none);
}

<commit_msg>(boyer-moore) finding still broken...<commit_after>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn_bytes
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn_bytes (needle: str, haystack: str, nn: uint) -> [uint] {
   let results = [];
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   log(error, ct);
   log(error, pt);

   let ii = 0u;
   let jj = 0u;

   while ii < str::len_bytes(haystack) {

      jj = str::len_bytes(needle);

      // reverse through needle
      while 0u <= jj {
         jj -= 1u;

         // if still matching
         if needle[jj] == haystack[ii] {
            // if full match
            if jj == 0u {
               vec::push(results, jj);
               if vec::len(results) >= nn { ret results; }
            }

         // if partial match
         } else {
            let sufn = str::len_bytes(needle) - jj;

            let ctx;
            let ptx;

            alt ct.find(needle[sufn] as uint) {
               option::none { ctx = str::len_bytes(needle);}
               option::some(x) { ctx = x;}
            }

            alt pt.find(sufn) {
               option::none { fail "something is out of range" }
               option::some(x) { ptx = x;}
            }

            ii += greaterOf(ctx, ptx) - jj;
            jj = 0u;
         }
      }

      ii += 1u;
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len_bytes(needle);

   let jj = len - 1u; // drop the last byte

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint);
   assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   let prefs = vec::reversed(prefixes(needle)); // largest first
   let sufs  = vec::reversed(suffixes(needle)); // smallest first
   let jj    = 0u;
   let kk    = 0u;
   let lim   = str::len(needle);

   while jj < lim {    // sufixes
      std::io::println("\n<newsuff: " + sufs[jj] + ">");

      kk = 0u;

      while kk < lim { // prefixes
         std::io::print("<prefixes: " + prefs[kk] + "> ");

         let suf = sufs[jj];
         let pref = prefs[kk];

         // combine this logic

         if str::len_bytes(pref) > str::len_bytes(suf) {
            //std::io::println("[" + pref + ", " + suf + "]");
            std::io::print("(pref > suf)");
            if str::ends_with(pref, suf) {
               std::io::print("(ew)");
               if !str::ends_with(pref, sufs[jj+1u]) {
                  std::io::print("(ew+1)");

                  if ! mm.contains_key(jj)
                  {
                     std::io::print(#fmt("(+%u)", kk));
                     mm.insert(jj, kk);
                  }
               }
            }
         }

         if str::len_bytes(pref) <= str::len_bytes(suf) {
            std::io::print("(pref <= suf)");

            if str::ends_with(suf, pref) // partial
            {
               std::io::print("(^ew)");

               if ! mm.contains_key(jj)
               {
                  std::io::print(#fmt("(*%u)", kk));
                  mm.insert(jj, kk);
               }
            }
         }

         std::io::println("");

         kk += 1u;
      }

      // for this suffix jj, if no matching prefix, where did we fall out?
      // i.e., what is the last prefix that was still partially matching,
      // e.g., for suffix "man", the prefix "an" works, and is +6...

      if ! mm.contains_key(jj)
      {
         std::io::print(#fmt("(=%u)", kk));
         mm.insert(jj, kk);
      }

      jj += 1u;
   }

   ret mm
}

#[test]
fn test_prefix_table() {
   let pt = prefix_table("ANPANMAN");
                        //     ... 8
   std::io::print("+");
   log(error, pt);
   assert 1u == pt.get(0u); //        (n)
   assert 8u == pt.get(1u); //       (a)n
   assert 3u == pt.get(2u); //      (m)an
   assert 6u == pt.get(3u); //     (n)man
   assert 6u == pt.get(4u); //    (a)nman
   assert 6u == pt.get(5u); //   (p)anman
   assert 6u == pt.get(6u); //  (n)panman
   assert 6u == pt.get(7u); // (a)npanman
   //assert 0u == pt.get(8u); // fail
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];
   let sz = 0u;
   vec::push(vv, "");
   str::bytes_iter(ss) {|_bb|
      sz += 1u;
      vec::push(vv, str::unsafe::slice_bytes(ss, 0u, sz));
   }
   ret vv;
}

#[test]
fn test_prefs() {
   assert ["", "a", "ab", "abc", "abcd"] == prefixes("abcd");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let sz = 0u;
   let lim = str::len_bytes(ss);
   str::bytes_iter(ss) {|_bb|
      vec::push(vv, str::unsafe::slice_bytes(ss, sz, lim));
      sz += 1u;
   }
   vec::push(vv, "");
   ret vv;
}

#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d", ""] == suffixes("abcd");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_bytes_(needle: str, haystack: str) -> option<uint> {
   ret option::some(findn_bytes(needle, haystack, 1u)[0u]);
}

#[test]
fn test_find_bytes() {
  // byte positions
  assert (find_bytes_("banana", "apple pie") == option::none);
  assert (find_bytes_("", "") == option::some(0u));

  let data = "ประเทศไทย中华Việt Nam";
  assert (find_bytes_(data, "")     == option::some(0u));
  assert (find_bytes_(data, "ประเ") == option::some( 0u));
  assert (find_bytes_(data, "ะเ")   == option::some( 6u));
  assert (find_bytes_(data, "中华") == option::some(27u));
  assert (find_bytes_(data, "ไท华") == option::none);
}

<|endoftext|>


<commit_before>use csv;
use regex::Regex;
use std::result::Result;
use std::str;
use std::process;
use curl::http;
use rustc_serialize::json;

fn get_page(url: String, token: &str) -> http::Response {
    println!("Fetching {:?}", url);
    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    if res.get_code() != 200 {
        match str::from_utf8(res.get_body()) {
            Ok(b) => {
                println!("\n*******************************************************************************");
                println!("{:?}", json::decode::<GithubError>(b).ok());
                println!("*******************************************************************************\n");
                process::exit(1)
            }
            Err(..) => {
                println!("Unable to parse the response from Github");
                process::exit(1)
            }
        }
    }

    res
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

fn to_issues(raw: &[u8]) -> Result<Issues, json::DecoderError> {
    match str::from_utf8(raw) {
        Ok(b) => json::decode(b),
        Err(..) => {
            println!("Unable to parse the response from Github");
            process::exit(1)
        }
    }
}

pub fn run(owner: &str,
           repo: &str,
           oauth_token: String,
           labels: Vec<String>,
           output_file: String) {

    let page = 1;
    let url = format!("https://api.github.com/repos/{}/{}/issues?state=all&page={}&labels={}",
                      owner, repo, page, labels.join(","));

    let res = get_page(url, &oauth_token);
    let mut issues = to_issues(res.get_body()).unwrap();

    // A Link header is not present if the requested collection has less than
    // _pagesize_.
    match res.get_headers().get("link") {
        Some(links) => {
            let mut nurl = next_url(links.first().unwrap().clone());

            while let Some(nu) = nurl {
                let r = get_page(nu.to_string(), &oauth_token);
                issues.extend(to_issues(r.get_body()).unwrap());

                let link = r.get_headers().get("link").unwrap()
                                          .first().unwrap()
                                          .clone();
                nurl = next_url(link);
            }
        }
        _ => {}
    }

    // let mut wtr = csv::Writer::from_memory();
    let mut wtr = csv::Writer::from_file(output_file).unwrap();
    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "assignee",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    println!("Total issues collected: {:?}", issues.len());

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");
        let user = issue.user;
        let assignee = issue.assignee;

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   assignee,
                   user,
                   labels,
                   issue.body);

        // println!("{:?}", row);
        // let result = wtr.encode(row);
        // println!("{:?}", result.is_ok());
        wtr.encode(row);
    }

    // println!("{:?}", wtr.as_string());
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Issue {
    assignee: Option<User>,
    body: Option<String>,
    created_at: Option<String>,
    closed_at: Option<String>,
    labels: Labels,
    number: u32,
    state: Option<String>,
    title: Option<String>,
    user: Option<User>,
}

type Issues = Vec<Issue>;

type Labels = Vec<Label>;

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Label {
    color: String,
    name: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct User {
    login: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct GithubError {
    message: String,
    documentation_url: String,
}
<commit_msg>Remove labels querystring when none are passed in<commit_after>use csv;
use regex::Regex;
use std::result::Result;
use std::str;
use std::process;
use curl::http;
use rustc_serialize::json;

fn get_page(url: String, token: &str) -> http::Response {
    println!("Fetching {:?}", url);
    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    if res.get_code() != 200 {
        match str::from_utf8(res.get_body()) {
            Ok(b) => {
                println!("\n*******************************************************************************");
                println!("{:?}", json::decode::<GithubError>(b).ok());
                println!("*******************************************************************************\n");
                process::exit(1)
            }
            Err(..) => {
                println!("Unable to parse the response from Github");
                process::exit(1)
            }
        }
    }

    res
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

fn to_issues(raw: &[u8]) -> Result<Issues, json::DecoderError> {
    match str::from_utf8(raw) {
        Ok(b) => json::decode(b),
        Err(..) => {
            println!("Unable to parse the response from Github");
            process::exit(1)
        }
    }
}

pub fn run(owner: &str,
           repo: &str,
           oauth_token: String,
           labels: Vec<String>,
           output_file: String) {

    let page = 1;
    let labels_pair = if labels.is_empty() { "".to_string() }
                      else { format!("&labels={}", labels.join(",")) };
    let url = format!("https://api.github.com/repos/{}/{}/issues?state=all&page={}{}",
                      owner, repo, page, labels_pair);

    let res = get_page(url, &oauth_token);
    let mut issues = to_issues(res.get_body()).unwrap();

    // A Link header is not present if the requested collection has less than
    // _pagesize_.
    match res.get_headers().get("link") {
        Some(links) => {
            let mut nurl = next_url(links.first().unwrap().clone());

            while let Some(nu) = nurl {
                let r = get_page(nu.to_string(), &oauth_token);
                issues.extend(to_issues(r.get_body()).unwrap());

                let link = r.get_headers().get("link").unwrap()
                                          .first().unwrap()
                                          .clone();
                nurl = next_url(link);
            }
        }
        _ => {}
    }

    // let mut wtr = csv::Writer::from_memory();
    let mut wtr = csv::Writer::from_file(output_file).unwrap();
    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "assignee",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    println!("Total issues collected: {:?}", issues.len());

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");
        let user = issue.user;
        let assignee = issue.assignee;

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   assignee,
                   user,
                   labels,
                   issue.body);

        // println!("{:?}", row);
        // let result = wtr.encode(row);
        // println!("{:?}", result.is_ok());
        wtr.encode(row);
    }

    // println!("{:?}", wtr.as_string());
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Issue {
    assignee: Option<User>,
    body: Option<String>,
    created_at: Option<String>,
    closed_at: Option<String>,
    labels: Labels,
    number: u32,
    state: Option<String>,
    title: Option<String>,
    user: Option<User>,
}

type Issues = Vec<Issue>;

type Labels = Vec<Label>;

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Label {
    color: String,
    name: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct User {
    login: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct GithubError {
    message: String,
    documentation_url: String,
}
<|endoftext|>


<commit_before><commit_msg>simplify problem 4 rust<commit_after><|endoftext|>