<commit_before>//! A generator for structs that can easily be converted to/from arrays and
//! slices.

/// The `struct_array!` macro generates a `struct` that can be easily converted
/// to/from arrays and slices.
///
/// The format of the macro is similar to a normal struct definition, as shown
/// in the example below. The only differences are an annotation after the
/// struct name for the member type and number of members, and the lack of type
/// annotations on individual members.
///
/// The members of the struct must all be the same type, and the **number of
/// members must be specified correctly**. As long as the number of members is
/// specified correctly, I think everything is safe.
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate struct_array;
///
/// struct_array! {
///     /// Example struct array.
///     #[derive(Clone,Debug,PartialEq)]
///     struct Example[u32; 2] {
///         /// x member
///         pub x,
///         /// y member
///         pub y,
///     }
/// }
///
/// fn main() {
///     // Deref as an array.
///     {
///         let example = Example { x: 42, y: 56 };
///         let array: &[u32; 2] = &example;
///         assert_eq!(array, &[42, 56]);
///     }
///
///     // Deref as a slice (via derefing as an array).
///     {
///         let example = Example { x: 42, y: 56 };
///         let slice: &[u32] = &*example;
///         assert_eq!(slice, &[42, 56]);
///     }
///
///     // Index (via derefing as an array).
///     {
///         let mut example = Example { x: 42, y: 56 };
///         example[1] = 23;
///         assert_eq!(example, Example { x: 42, y: 23 });
///     }
///
///     // Convert into an array.
///     {
///         let example = Example { x: 42, y: 56 };
///         let array: [u32; 2] = example.into();
///         assert_eq!(array, [42, 56]);
///     }
///
///     // Convert from an array to a struct.
///     {
///         let array = [42, 56];
///         let example: Example = array.into();
///         assert_eq!(example, Example { x: 42, y: 56 });
///     }
///
///     // Convert from a slice to a struct reference.
///     {
///         let slice = &[42, 56][..];
///         let example: &Example = slice.into();
///         assert_eq!(example, &Example { x: 42, y: 56 });
///     }
/// }
///
/// ```
///
/// # Attributes
///
/// The generated struct is `repr(C)`. Additional attributes can be attached to
/// the generated `struct` as shown in the example.
///
/// # Visibility
///
/// Members of the generated struct are always `pub`, but the struct itself is
/// not `pub` by default. The struct definition can be made `pub` by adding
/// `pub` before `struct`:
///
/// ```ignore
/// #[macro_use]
/// extern crate struct_array;
///
/// mod example {
///     struct_array! {
///         pub struct Example1[u32; 2] {
///             pub x,
///             pub y,
///         }
///     }
///
///     struct_array! {
///         struct Example2[u32; 2] {
///             pub x,
///             pub y,
///         }
///     }
/// }
///
/// fn main() {
///     let example1 = example::Example1 { x: 42, y: 56 };
///     let example2 = example::Example2 { x: 42, y: 56 }; // error: struct `Example2` is private.
/// }
/// ```
///
/// # Trait implementations
///
/// The struct generated by `struct_array! { struct Foo[T; len] { .. } }`
/// implements:
///
/// * `Deref<Target=[T; len]> for Foo`
/// * `DerefMut<Target=[T; len]> for Foo`
/// * `Into<[T; len] for Foo`
/// * `From<[T; len]> for Foo`
/// * `Into<&[T; len] for &Foo`
/// * `From<&[T; len] for &Foo`
/// * `Into<&mut [T; len] for &mut Foo`
/// * `From<&mut [T; len] for &mut Foo`
/// * `Into<&[T]> for &Foo`
/// * `From<&[T]> for &Foo`
/// * `Into<&mut [T]> for &mut Foo`
/// * `From<&mut [T]> for &mut Foo`
///
/// Note that converting from a slice will panic if the `len()` of the slice
/// does not must match the `len` specified for the struct. You can derive or
/// implement additional traits as for normal structs.
#[macro_export]
macro_rules! struct_array {
    (
        $( #[$attr:meta] )*
        pub struct $name:ident[$member_type:ident; $member_count:expr] {
            $(
                $( #[$member_attr:meta] )*
                pub $member:ident
            ),+
        }
    ) => {
        $( #[$attr] )*
        #[repr(C)]
        pub struct $name {
            $(
                $( #[$member_attr] )*
                pub $member: $member_type,
            )+
        }

        struct_array! {
            @_impl struct
                $name[$member_type; $member_count] {
                    $( $member ),+
                }
        }
    };
    (
        $( #[$attr:meta] )*
        struct $name:ident[$member_type:ident; $member_count:expr] {
            $(
                $( #[$member_attr:meta] )*
                pub $member:ident
            ),+
        }
    ) => {
        $( #[$attr] )*
        #[repr(C)]
        struct $name {
            $(
                $( #[$member_attr] )*
                pub $member: $member_type,
            )+
        }

        struct_array! {
            @_impl struct
                $name[$member_type; $member_count] {
                    $( $member ),+
                }
        }
    };
    (
        $( #[$attr:meta] )*
        pub struct $name:ident[$member_type:ident; $member_count:expr] {
            $(
                $( #[$member_attr:meta] )*
                pub $member:ident
            ),+,
        }
    ) => {
        $( #[$attr] )*
        #[repr(C)]
        pub struct $name {
            $(
                $( #[$member_attr] )*
                pub $member: $member_type,
            )+
        }

        struct_array! {
            @_impl struct
                $name[$member_type; $member_count] {
                    $( $member ),+
                }
        }
    };
    (
        $( #[$attr:meta] )*
        struct $name:ident[$member_type:ident; $member_count:expr] {
            $(
                $( #[$member_attr:meta] )*
                pub $member:ident
            ),+,
        }
    ) => {
        $( #[$attr] )*
        #[repr(C)]
        struct $name {
            $(
                $( #[$member_attr] )*
                pub $member: $member_type,
            )+
        }

        struct_array! {
            @_impl struct
                $name[$member_type; $member_count] {
                    $( $member ),+
                }
        }
    };
    (
        @_impl struct $name:ident[$member_type:ident; $member_count:expr] {
            $( $member:ident ),+
        }
    ) => {
        impl ::std::ops::Deref for $name {
            type Target = [$member_type; $member_count];

            fn deref(&self) -> &[$member_type; $member_count] {
                unsafe {
                    &*(self as *const $name as *const [$member_type; $member_count])
                }
            }
        }

        impl ::std::ops::DerefMut for $name {
            fn deref_mut(&mut self) -> &mut [$member_type; $member_count] {
                unsafe {
                    &mut *(self as *mut $name as *mut [$member_type; $member_count])
                }
            }
        }

        impl Into<[$member_type; $member_count]> for $name {
            fn into(self) -> [$member_type; $member_count] {
                unsafe {
                    ::std::mem::transmute(self)
                }
            }
        }

        impl From<[$member_type; $member_count]> for $name {
            fn from(array: [$member_type; $member_count]) -> $name {
                unsafe {
                    ::std::mem::transmute(array)
                }
            }
        }

        impl<'a> Into<&'a [$member_type; $member_count]> for &'a $name {
            fn into(self) -> &'a [$member_type; $member_count] {
                unsafe {
                    &*(self as *const $name as *const [$member_type; $member_count])
                }
            }
        }

        impl<'a> From<&'a [$member_type; $member_count]> for &'a $name {
            fn from(array: &[$member_type; $member_count]) -> &$name {
                unsafe {
                    &*(array as *const [$member_type; $member_count] as *const $name)
                }
            }
        }

        impl<'a> Into<&'a mut [$member_type; $member_count]> for &'a mut $name {
            fn into(self) -> &'a mut [$member_type; $member_count] {
                unsafe {
                    &mut *(self as *mut $name as *mut [$member_type; $member_count])
                }
            }
        }

        impl<'a> From<&'a mut [$member_type; $member_count]> for &'a mut $name {
            fn from(array: &mut [$member_type; $member_count]) -> &mut $name {
                unsafe {
                    &mut *(array as *mut [$member_type; $member_count] as *mut $name)
                }
            }
        }

        impl<'a> Into<&'a [$member_type]> for &'a $name {
            fn into(self) -> &'a [$member_type] {
                unsafe {
                    ::std::slice::from_raw_parts(self as *const $name as *const $member_type, $member_count)
                }
            }
        }

        impl<'a> From<&'a [$member_type]> for &'a $name {
            fn from(slice: &'a [$member_type]) -> &'a $name {
                assert!(slice.len() == $member_count);
                unsafe {
                    &*(slice.as_ptr() as *const $name)
                }
            }
        }

        impl<'a> Into<&'a mut [$member_type]> for &'a mut $name {
            fn into(self) -> &'a mut [$member_type] {
                unsafe {
                    ::std::slice::from_raw_parts_mut(self as *mut $name as *mut $member_type, $member_count)
                }
            }
        }

        impl<'a> From<&'a mut [$member_type]> for &'a mut $name {
            fn from(slice: &'a mut [$member_type]) -> &'a mut $name {
                assert!(slice.len() == $member_count);
                unsafe {
                    &mut *(slice.as_mut_ptr() as *mut $name)
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    struct_array! {
        /// Example struct array.
        #[derive(Clone,Debug,PartialEq)]
        struct Example[u32; 2] {
            /// x member
            pub x,
            /// y member
            pub y,
        }
    }

    #[test]
    fn test_deref() {
        let foo = Example {
            x: 0,
            y: 1,
        };
        let bar: &[u32; 2] = &foo;
        assert_eq!(bar, &[0, 1]);
    }

    #[test]
    fn test_deref_mut() {
        let mut foo = Example {
            x: 0,
            y: 1,
        };
        {
            let bar: &mut [u32; 2] = &mut foo;
            bar[1] = 2;
            assert_eq!(bar, &[0, 2]);
        }
        assert_eq!(foo, Example { x: 0, y: 2 });
    }

    #[test]
    fn test_into_array() {
        let foo = Example { x: 0, y: 1 };
        let bar: [u32; 2] = foo.into();
        assert_eq!(bar, [0, 1]);
    }

    #[test]
    fn test_from_array() {
        let foo = [0, 1];
        let mut bar: Example = foo.into();
        bar.y = 2;
        assert_eq!(bar, Example { x: 0, y: 2 });
    }

    #[test]
    fn test_into_array_ref() {
        let foo = &Example { x: 0, y: 1 };
        let bar: &[u32; 2] = foo.into();
        assert_eq!(bar, &[0, 1]);
    }

    #[test]
    fn test_from_array_ref() {
        let foo = &[0, 1];
        let bar: &Example = foo.into();
        assert_eq!(bar, &Example { x: 0, y: 1 });
    }

    #[test]
    fn test_into_array_ref_mut() {
        let mut foo = &mut Example { x: 0, y: 1 };
        {
            let mut bar: &mut [u32; 2] = foo.into();
            bar[1] = 2;
            assert_eq!(bar, &mut [0, 2]);
        }
        assert_eq!(foo, &mut Example { x: 0, y: 2 });
    }

    #[test]
    fn test_from_array_ref_mut() {
        let foo = &mut [0, 1];
        {
            let mut bar: &mut Example = foo.into();
            bar.y = 2;
            assert_eq!(bar, &mut Example { x: 0, y: 2 });
        }
        assert_eq!(foo, &mut [0, 2]);
    }

    #[test]
    fn test_into_slice() {
        let foo = Example { x: 0, y: 1 };
        let bar: &[u32] = (&foo).into();
        assert_eq!(bar, [0, 1]);
    }

    #[test]
    fn test_from_slice() {
        let foo = [0, 1];
        let bar: &[u32] = &foo;
        let baz: &Example = bar.into();
        assert_eq!(baz, &Example { x: 0, y: 1 });
    }

    #[test]
    fn test_into_mut_slice() {
        let mut foo = Example { x: 0, y: 1 };
        {
            let bar: &mut [u32] = (&mut foo).into();
            bar[1] = 2;
            assert_eq!(bar, &mut [0, 2]);
        }
        assert_eq!(foo, Example { x: 0, y: 2 });
    }

    #[test]
    fn test_from_mut_slice() {
        let mut foo = [0, 1];
        {
            let mut bar: &mut [u32] = &mut foo;
            let mut baz: &mut Example = bar.into();
            baz.y = 2;
            assert_eq!(baz, &Example { x: 0, y: 2 });
        }
        assert_eq!(foo, [0, 2]);
    }
}
<commit_msg>Don't take & in deref as an array example<commit_after>//! A generator for structs that can easily be converted to/from arrays and
//! slices.

/// The `struct_array!` macro generates a `struct` that can be easily converted
/// to/from arrays and slices.
///
/// The format of the macro is similar to a normal struct definition, as shown
/// in the example below. The only differences are an annotation after the
/// struct name for the member type and number of members, and the lack of type
/// annotations on individual members.
///
/// The members of the struct must all be the same type, and the **number of
/// members must be specified correctly**. As long as the number of members is
/// specified correctly, I think everything is safe.
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate struct_array;
///
/// struct_array! {
///     /// Example struct array.
///     #[derive(Clone,Debug,PartialEq)]
///     struct Example[u32; 2] {
///         /// x member
///         pub x,
///         /// y member
///         pub y,
///     }
/// }
///
/// fn main() {
///     // Deref as an array.
///     {
///         let example = Example { x: 42, y: 56 };
///         let array: [u32; 2] = *example;
///         assert_eq!(array, [42, 56]);
///     }
///
///     // Deref as a slice (via derefing as an array).
///     {
///         let example = Example { x: 42, y: 56 };
///         let slice: &[u32] = &*example;
///         assert_eq!(slice, &[42, 56]);
///     }
///
///     // Index (via derefing as an array).
///     {
///         let mut example = Example { x: 42, y: 56 };
///         example[1] = 23;
///         assert_eq!(example, Example { x: 42, y: 23 });
///     }
///
///     // Convert into an array.
///     {
///         let example = Example { x: 42, y: 56 };
///         let array: [u32; 2] = example.into();
///         assert_eq!(array, [42, 56]);
///     }
///
///     // Convert from an array to a struct.
///     {
///         let array = [42, 56];
///         let example: Example = array.into();
///         assert_eq!(example, Example { x: 42, y: 56 });
///     }
///
///     // Convert from a slice to a struct reference.
///     {
///         let slice = &[42, 56][..];
///         let example: &Example = slice.into();
///         assert_eq!(example, &Example { x: 42, y: 56 });
///     }
/// }
///
/// ```
///
/// # Attributes
///
/// The generated struct is `repr(C)`. Additional attributes can be attached to
/// the generated `struct` as shown in the example.
///
/// # Visibility
///
/// Members of the generated struct are always `pub`, but the struct itself is
/// not `pub` by default. The struct definition can be made `pub` by adding
/// `pub` before `struct`:
///
/// ```ignore
/// #[macro_use]
/// extern crate struct_array;
///
/// mod example {
///     struct_array! {
///         pub struct Example1[u32; 2] {
///             pub x,
///             pub y,
///         }
///     }
///
///     struct_array! {
///         struct Example2[u32; 2] {
///             pub x,
///             pub y,
///         }
///     }
/// }
///
/// fn main() {
///     let example1 = example::Example1 { x: 42, y: 56 };
///     let example2 = example::Example2 { x: 42, y: 56 }; // error: struct `Example2` is private.
/// }
/// ```
///
/// # Trait implementations
///
/// The struct generated by `struct_array! { struct Foo[T; len] { .. } }`
/// implements:
///
/// * `Deref<Target=[T; len]> for Foo`
/// * `DerefMut<Target=[T; len]> for Foo`
/// * `Into<[T; len] for Foo`
/// * `From<[T; len]> for Foo`
/// * `Into<&[T; len] for &Foo`
/// * `From<&[T; len] for &Foo`
/// * `Into<&mut [T; len] for &mut Foo`
/// * `From<&mut [T; len] for &mut Foo`
/// * `Into<&[T]> for &Foo`
/// * `From<&[T]> for &Foo`
/// * `Into<&mut [T]> for &mut Foo`
/// * `From<&mut [T]> for &mut Foo`
///
/// Note that converting from a slice will panic if the `len()` of the slice
/// does not must match the `len` specified for the struct. You can derive or
/// implement additional traits as for normal structs.
#[macro_export]
macro_rules! struct_array {
    (
        $( #[$attr:meta] )*
        pub struct $name:ident[$member_type:ident; $member_count:expr] {
            $(
                $( #[$member_attr:meta] )*
                pub $member:ident
            ),+
        }
    ) => {
        $( #[$attr] )*
        #[repr(C)]
        pub struct $name {
            $(
                $( #[$member_attr] )*
                pub $member: $member_type,
            )+
        }

        struct_array! {
            @_impl struct
                $name[$member_type; $member_count] {
                    $( $member ),+
                }
        }
    };
    (
        $( #[$attr:meta] )*
        struct $name:ident[$member_type:ident; $member_count:expr] {
            $(
                $( #[$member_attr:meta] )*
                pub $member:ident
            ),+
        }
    ) => {
        $( #[$attr] )*
        #[repr(C)]
        struct $name {
            $(
                $( #[$member_attr] )*
                pub $member: $member_type,
            )+
        }

        struct_array! {
            @_impl struct
                $name[$member_type; $member_count] {
                    $( $member ),+
                }
        }
    };
    (
        $( #[$attr:meta] )*
        pub struct $name:ident[$member_type:ident; $member_count:expr] {
            $(
                $( #[$member_attr:meta] )*
                pub $member:ident
            ),+,
        }
    ) => {
        $( #[$attr] )*
        #[repr(C)]
        pub struct $name {
            $(
                $( #[$member_attr] )*
                pub $member: $member_type,
            )+
        }

        struct_array! {
            @_impl struct
                $name[$member_type; $member_count] {
                    $( $member ),+
                }
        }
    };
    (
        $( #[$attr:meta] )*
        struct $name:ident[$member_type:ident; $member_count:expr] {
            $(
                $( #[$member_attr:meta] )*
                pub $member:ident
            ),+,
        }
    ) => {
        $( #[$attr] )*
        #[repr(C)]
        struct $name {
            $(
                $( #[$member_attr] )*
                pub $member: $member_type,
            )+
        }

        struct_array! {
            @_impl struct
                $name[$member_type; $member_count] {
                    $( $member ),+
                }
        }
    };
    (
        @_impl struct $name:ident[$member_type:ident; $member_count:expr] {
            $( $member:ident ),+
        }
    ) => {
        impl ::std::ops::Deref for $name {
            type Target = [$member_type; $member_count];

            fn deref(&self) -> &[$member_type; $member_count] {
                unsafe {
                    &*(self as *const $name as *const [$member_type; $member_count])
                }
            }
        }

        impl ::std::ops::DerefMut for $name {
            fn deref_mut(&mut self) -> &mut [$member_type; $member_count] {
                unsafe {
                    &mut *(self as *mut $name as *mut [$member_type; $member_count])
                }
            }
        }

        impl Into<[$member_type; $member_count]> for $name {
            fn into(self) -> [$member_type; $member_count] {
                unsafe {
                    ::std::mem::transmute(self)
                }
            }
        }

        impl From<[$member_type; $member_count]> for $name {
            fn from(array: [$member_type; $member_count]) -> $name {
                unsafe {
                    ::std::mem::transmute(array)
                }
            }
        }

        impl<'a> Into<&'a [$member_type; $member_count]> for &'a $name {
            fn into(self) -> &'a [$member_type; $member_count] {
                unsafe {
                    &*(self as *const $name as *const [$member_type; $member_count])
                }
            }
        }

        impl<'a> From<&'a [$member_type; $member_count]> for &'a $name {
            fn from(array: &[$member_type; $member_count]) -> &$name {
                unsafe {
                    &*(array as *const [$member_type; $member_count] as *const $name)
                }
            }
        }

        impl<'a> Into<&'a mut [$member_type; $member_count]> for &'a mut $name {
            fn into(self) -> &'a mut [$member_type; $member_count] {
                unsafe {
                    &mut *(self as *mut $name as *mut [$member_type; $member_count])
                }
            }
        }

        impl<'a> From<&'a mut [$member_type; $member_count]> for &'a mut $name {
            fn from(array: &mut [$member_type; $member_count]) -> &mut $name {
                unsafe {
                    &mut *(array as *mut [$member_type; $member_count] as *mut $name)
                }
            }
        }

        impl<'a> Into<&'a [$member_type]> for &'a $name {
            fn into(self) -> &'a [$member_type] {
                unsafe {
                    ::std::slice::from_raw_parts(self as *const $name as *const $member_type, $member_count)
                }
            }
        }

        impl<'a> From<&'a [$member_type]> for &'a $name {
            fn from(slice: &'a [$member_type]) -> &'a $name {
                assert!(slice.len() == $member_count);
                unsafe {
                    &*(slice.as_ptr() as *const $name)
                }
            }
        }

        impl<'a> Into<&'a mut [$member_type]> for &'a mut $name {
            fn into(self) -> &'a mut [$member_type] {
                unsafe {
                    ::std::slice::from_raw_parts_mut(self as *mut $name as *mut $member_type, $member_count)
                }
            }
        }

        impl<'a> From<&'a mut [$member_type]> for &'a mut $name {
            fn from(slice: &'a mut [$member_type]) -> &'a mut $name {
                assert!(slice.len() == $member_count);
                unsafe {
                    &mut *(slice.as_mut_ptr() as *mut $name)
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    struct_array! {
        /// Example struct array.
        #[derive(Clone,Debug,PartialEq)]
        struct Example[u32; 2] {
            /// x member
            pub x,
            /// y member
            pub y,
        }
    }

    #[test]
    fn test_deref() {
        let foo = Example {
            x: 0,
            y: 1,
        };
        let bar: &[u32; 2] = &foo;
        assert_eq!(bar, &[0, 1]);
    }

    #[test]
    fn test_deref_mut() {
        let mut foo = Example {
            x: 0,
            y: 1,
        };
        {
            let bar: &mut [u32; 2] = &mut foo;
            bar[1] = 2;
            assert_eq!(bar, &[0, 2]);
        }
        assert_eq!(foo, Example { x: 0, y: 2 });
    }

    #[test]
    fn test_into_array() {
        let foo = Example { x: 0, y: 1 };
        let bar: [u32; 2] = foo.into();
        assert_eq!(bar, [0, 1]);
    }

    #[test]
    fn test_from_array() {
        let foo = [0, 1];
        let mut bar: Example = foo.into();
        bar.y = 2;
        assert_eq!(bar, Example { x: 0, y: 2 });
    }

    #[test]
    fn test_into_array_ref() {
        let foo = &Example { x: 0, y: 1 };
        let bar: &[u32; 2] = foo.into();
        assert_eq!(bar, &[0, 1]);
    }

    #[test]
    fn test_from_array_ref() {
        let foo = &[0, 1];
        let bar: &Example = foo.into();
        assert_eq!(bar, &Example { x: 0, y: 1 });
    }

    #[test]
    fn test_into_array_ref_mut() {
        let mut foo = &mut Example { x: 0, y: 1 };
        {
            let mut bar: &mut [u32; 2] = foo.into();
            bar[1] = 2;
            assert_eq!(bar, &mut [0, 2]);
        }
        assert_eq!(foo, &mut Example { x: 0, y: 2 });
    }

    #[test]
    fn test_from_array_ref_mut() {
        let foo = &mut [0, 1];
        {
            let mut bar: &mut Example = foo.into();
            bar.y = 2;
            assert_eq!(bar, &mut Example { x: 0, y: 2 });
        }
        assert_eq!(foo, &mut [0, 2]);
    }

    #[test]
    fn test_into_slice() {
        let foo = Example { x: 0, y: 1 };
        let bar: &[u32] = (&foo).into();
        assert_eq!(bar, [0, 1]);
    }

    #[test]
    fn test_from_slice() {
        let foo = [0, 1];
        let bar: &[u32] = &foo;
        let baz: &Example = bar.into();
        assert_eq!(baz, &Example { x: 0, y: 1 });
    }

    #[test]
    fn test_into_mut_slice() {
        let mut foo = Example { x: 0, y: 1 };
        {
            let bar: &mut [u32] = (&mut foo).into();
            bar[1] = 2;
            assert_eq!(bar, &mut [0, 2]);
        }
        assert_eq!(foo, Example { x: 0, y: 2 });
    }

    #[test]
    fn test_from_mut_slice() {
        let mut foo = [0, 1];
        {
            let mut bar: &mut [u32] = &mut foo;
            let mut baz: &mut Example = bar.into();
            baz.y = 2;
            assert_eq!(baz, &Example { x: 0, y: 2 });
        }
        assert_eq!(foo, [0, 2]);
    }
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/twitter-stream/0.10.0-alpha.5")]

/*!
# Twitter Stream

A library for listening on Twitter Streaming API.

## Usage

Add `twitter-stream` to your dependencies in your project's `Cargo.toml`:

```toml
[dependencies]
futures = "0.3"
tokio = { version = "0.2", features = ["macros"] }
twitter-stream = "=0.10.0-alpha.5"
```

## Overview

Here is a basic example that prints public mentions to @Twitter in JSON format:

```rust,no_run
use futures::prelude::*;
use twitter_stream::Token;

# #[tokio::main]
# async fn main() {
let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");

twitter_stream::Builder::filter(token)
    .track(Some("@Twitter"))
    .listen()
    .try_flatten_stream()
    .try_for_each(|json| {
        println!("{}", json);
        future::ok(())
    })
    .await
    .unwrap();
# }
```
*/

#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(intra_doc_link_resolution_failure)]

#[cfg(feature = "hyper")]
#[cfg_attr(docsrs, doc(cfg(feature = "hyper")))]
extern crate hyper_pkg;

#[macro_use]
mod util;

pub mod error;
#[cfg(feature = "hyper")]
#[cfg_attr(docsrs, doc(cfg(feature = "hyper")))]
pub mod hyper;
pub mod service;
pub mod types;

mod gzip;
mod token;

pub use oauth::Credentials;

pub use crate::error::Error;
pub use crate::token::Token;

use std::borrow::Borrow;
use std::future::Future;
use std::pin::Pin;
use std::str;
use std::task::{Context, Poll};

use bytes::Bytes;
use futures_core::Stream;
use futures_util::ready;
use http::header::{
    HeaderValue, ACCEPT_ENCODING, AUTHORIZATION, CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TYPE,
};
use http::response::Parts;
use http::{Request, Response};
use http_body::Body;
use pin_project_lite::pin_project;

use crate::gzip::MaybeGzip;
use crate::service::HttpService;
use crate::types::{FilterLevel, RequestMethod, StatusCode, Uri};
use crate::util::*;

/// A builder for `TwitterStream`.
///
/// ## Example
///
/// ```rust,no_run
/// use futures::prelude::*;
/// use twitter_stream::Token;
///
/// # #[tokio::main]
/// # async fn main() {
/// let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");
///
/// twitter_stream::Builder::sample(token)
///     .listen()
///     .try_flatten_stream()
///     .try_for_each(|json| {
///         println!("{}", json);
///         future::ok(())
///     })
///     .await
///     .unwrap();
/// # }
/// ```
#[derive(Clone, Debug)]
pub struct Builder<'a, T = Token> {
    method: RequestMethod,
    endpoint: Uri,
    token: T,
    inner: BuilderInner<'a>,
}

pin_project! {
    /// A future returned by constructor methods
    /// which resolves to a `TwitterStream`.
    pub struct FutureTwitterStream<F> {
        #[pin]
        response: F,
    }
}

pin_project! {
    /// A listener for Twitter Streaming API.
    /// It yields JSON strings returned from the API.
    pub struct TwitterStream<B: Body> {
        #[pin]
        inner: Lines<MaybeGzip<HttpBodyAsStream<B>>>,
    }
}

#[derive(Clone, Debug, oauth::Authorize)]
struct BuilderInner<'a> {
    #[oauth1(skip_if = "not")]
    stall_warnings: bool,
    filter_level: Option<FilterLevel>,
    language: Option<&'a str>,
    #[oauth1(encoded, fmt = "fmt_follow")]
    follow: Option<&'a [u64]>,
    track: Option<&'a str>,
    #[oauth1(encoded, fmt = "fmt_locations")]
    #[allow(clippy::type_complexity)]
    locations: Option<&'a [((f64, f64), (f64, f64))]>,
    #[oauth1(encoded)]
    count: Option<i32>,
}

impl<'a, C, A> Builder<'a, Token<C, A>>
where
    C: Borrow<str>,
    A: Borrow<str>,
{
    /// Create a builder for `POST statuses/filter` endpoint.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://dev.twitter.com/streaming/reference/post/statuses/filter
    pub fn filter(token: Token<C, A>) -> Self {
        const URI: &str = "https://stream.twitter.com/1.1/statuses/filter.json";
        Self::custom(RequestMethod::POST, Uri::from_static(URI), token)
    }

    /// Create a builder for `GET statuses/sample` endpoint.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://dev.twitter.com/streaming/reference/get/statuses/sample
    pub fn sample(token: Token<C, A>) -> Self {
        const URI: &str = "https://stream.twitter.com/1.1/statuses/sample.json";
        Self::custom(RequestMethod::GET, Uri::from_static(URI), token)
    }

    /// Constructs a builder for a Stream at a custom endpoint.
    pub fn custom(method: RequestMethod, endpoint: Uri, token: Token<C, A>) -> Self {
        Self {
            method,
            endpoint,
            token,
            inner: BuilderInner {
                stall_warnings: false,
                filter_level: None,
                language: None,
                follow: None,
                track: None,
                locations: None,
                count: None,
            },
        }
    }

    /// Start listening on the Streaming API endpoint, returning a `Future` which resolves
    /// to a `Stream` yielding JSON messages from the API.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    #[cfg(feature = "hyper")]
    #[cfg_attr(docsrs, doc(cfg(feature = "hyper")))]
    pub fn listen(&self) -> crate::hyper::FutureTwitterStream {
        let conn = hyper_tls::HttpsConnector::new();
        self.listen_with_client(hyper_pkg::Client::builder().build::<_, hyper_pkg::Body>(conn))
    }

    /// Same as `listen` except that it uses `client` to make HTTP request to the endpoint.
    ///
    /// # Panics
    ///
    /// This will call `<S as Service>::call` without checking for `<S as Service>::poll_ready`
    /// and may cause a panic if `client` is not ready to send an HTTP request yet.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use tower::ServiceExt;
    ///
    /// # async fn doc() {
    /// # let mut client = hyper_pkg::Client::new();
    /// # let token = twitter_stream::Token::new("", "", "", "");
    /// client.ready().await; // Ensure that the client is ready to send a request.
    /// let stream = twitter_stream::Builder::sample(token)
    ///     .listen_with_client(&mut client)
    ///     .await
    ///     .unwrap();
    /// # }
    /// ```
    pub fn listen_with_client<S, B>(&self, mut client: S) -> FutureTwitterStream<S::Future>
    where
        S: HttpService<B>,
        B: Default + From<Vec<u8>>,
    {
        let req = Request::builder()
            .method(self.method.clone())
            .header(ACCEPT_ENCODING, HeaderValue::from_static("gzip"));

        let mut oauth = oauth::Builder::new(self.token.client.as_ref(), oauth::HmacSha1);
        oauth.token(self.token.token.as_ref());
        let req = if RequestMethod::POST == self.method {
            let oauth::Request {
                authorization,
                data,
            } = oauth.post_form(&self.endpoint, &self.inner);

            req.uri(self.endpoint.clone())
                .header(AUTHORIZATION, authorization)
                .header(
                    CONTENT_TYPE,
                    HeaderValue::from_static("application/x-www-form-urlencoded"),
                )
                .header(CONTENT_LENGTH, data.len())
                .body(data.into_bytes().into())
                .unwrap()
        } else {
            let oauth::Request {
                authorization,
                data: uri,
            } = oauth.build(self.method.as_ref(), &self.endpoint, &self.inner);

            req.uri(uri)
                .header(AUTHORIZATION, authorization)
                .body(B::default())
                .unwrap()
        };

        let response = client.call(req);
        FutureTwitterStream { response }
    }
}

impl<'a, C, A> Builder<'a, Token<C, A>> {
    /// Reset the HTTP request method to be used when connecting
    /// to the server.
    pub fn method(&mut self, method: RequestMethod) -> &mut Self {
        self.method = method;
        self
    }

    /// Reset the API endpoint URI to be connected.
    pub fn endpoint(&mut self, endpoint: Uri) -> &mut Self {
        self.endpoint = endpoint;
        self
    }

    /// Reset the token to be used to log into Twitter.
    pub fn token(&mut self, token: Token<C, A>) -> &mut Self {
        self.token = token;
        self
    }

    /// Set whether to receive messages when in danger of
    /// being disconnected.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#stall-warnings
    pub fn stall_warnings(&mut self, stall_warnings: bool) -> &mut Self {
        self.inner.stall_warnings = stall_warnings;
        self
    }

    /// Set the minimum `filter_level` Tweet attribute to receive.
    /// The default is `FilterLevel::None`.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#filter-level
    pub fn filter_level(&mut self, filter_level: impl Into<Option<FilterLevel>>) -> &mut Self {
        self.inner.filter_level = filter_level.into();
        self
    }

    /// Set a comma-separated language identifiers to receive Tweets
    /// written in the specified languages only.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#language
    pub fn language(&mut self, language: impl Into<Option<&'a str>>) -> &mut Self {
        self.inner.language = language.into();
        self
    }

    /// Set a list of user IDs to receive Tweets from the specified users.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#follow
    pub fn follow(&mut self, follow: impl Into<Option<&'a [u64]>>) -> &mut Self {
        self.inner.follow = follow.into();
        self
    }

    /// A comma separated list of phrases to filter Tweets by.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#track
    pub fn track(&mut self, track: impl Into<Option<&'a str>>) -> &mut Self {
        self.inner.track = track.into();
        self
    }

    /// Set a list of bounding boxes to filter Tweets by,
    /// specified by a pair of coordinates in the form of
    /// `((longitude, latitude), (longitude, latitude))` tuple.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#locations
    pub fn locations(
        &mut self,
        locations: impl Into<Option<&'a [((f64, f64), (f64, f64))]>>,
    ) -> &mut Self {
        self.inner.locations = locations.into();
        self
    }

    /// The `count` parameter.
    /// This parameter requires elevated access to use.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#count
    pub fn count(&mut self, count: impl Into<Option<i32>>) -> &mut Self {
        self.inner.count = count.into();
        self
    }
}

#[cfg(feature = "hyper")]
impl<B: Body> TwitterStream<B> {
    /// A shorthand for `Builder::filter().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn filter<C, A>(token: Token<C, A>) -> crate::hyper::FutureTwitterStream
    where
        C: Borrow<str>,
        A: Borrow<str>,
    {
        Builder::filter(token).listen()
    }

    /// A shorthand for `Builder::sample().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn sample<C, A>(token: Token<C, A>) -> crate::hyper::FutureTwitterStream
    where
        C: Borrow<str>,
        A: Borrow<str>,
    {
        Builder::sample(token).listen()
    }
}

impl<F, B, E> Future for FutureTwitterStream<F>
where
    F: Future<Output = Result<Response<B>, E>>,
    B: Body,
{
    type Output = Result<TwitterStream<B>, Error<E>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let res = match ready!(self.project().response.poll(cx)) {
            Ok(res) => res,
            Err(e) => return Poll::Ready(Err(Error::Service(e))),
        };
        let (parts, body) = res.into_parts();
        let Parts {
            status, headers, ..
        } = parts;

        if StatusCode::OK != status {
            return Poll::Ready(Err(Error::Http(status)));
        }

        let use_gzip = headers
            .get_all(CONTENT_ENCODING)
            .iter()
            .any(|e| e == "gzip");
        let inner = if use_gzip {
            Lines::new(gzip::gzip(HttpBodyAsStream::new(body)))
        } else {
            Lines::new(gzip::identity(HttpBodyAsStream::new(body)))
        };

        Poll::Ready(Ok(TwitterStream { inner }))
    }
}

impl<B> Stream for TwitterStream<B>
where
    B: Body,
{
    type Item = Result<string::String<Bytes>, Error<B::Error>>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut this = self.project();

        loop {
            let line = ready_some!(this.inner.as_mut().poll_next(cx))?;
            if line.iter().all(|&c| is_json_whitespace(c)) {
                continue;
            }

            str::from_utf8(&line).map_err(Error::Utf8)?;
            let line = unsafe {
                // Safety:
                // - We have checked above that `line` is valid as UTF-8.
                // - `Bytes` satisfies the requirements of `string::StableAsRef` trait
                // (https://github.com/carllerche/string/pull/17)
                string::String::<Bytes>::from_utf8_unchecked(line)
            };
            return Poll::Ready(Some(Ok(line)));
        }
    }
}

fn is_json_whitespace(c: u8) -> bool {
    // RFC7159 §2
    b" \t\n\r".contains(&c)
}
<commit_msg>Remove a dead code<commit_after>#![doc(html_root_url = "https://docs.rs/twitter-stream/0.10.0-alpha.5")]

/*!
# Twitter Stream

A library for listening on Twitter Streaming API.

## Usage

Add `twitter-stream` to your dependencies in your project's `Cargo.toml`:

```toml
[dependencies]
futures = "0.3"
tokio = { version = "0.2", features = ["macros"] }
twitter-stream = "=0.10.0-alpha.5"
```

## Overview

Here is a basic example that prints public mentions to @Twitter in JSON format:

```rust,no_run
use futures::prelude::*;
use twitter_stream::Token;

# #[tokio::main]
# async fn main() {
let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");

twitter_stream::Builder::filter(token)
    .track(Some("@Twitter"))
    .listen()
    .try_flatten_stream()
    .try_for_each(|json| {
        println!("{}", json);
        future::ok(())
    })
    .await
    .unwrap();
# }
```
*/

#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(intra_doc_link_resolution_failure)]

#[macro_use]
mod util;

pub mod error;
#[cfg(feature = "hyper")]
#[cfg_attr(docsrs, doc(cfg(feature = "hyper")))]
pub mod hyper;
pub mod service;
pub mod types;

mod gzip;
mod token;

pub use oauth::Credentials;

pub use crate::error::Error;
pub use crate::token::Token;

use std::borrow::Borrow;
use std::future::Future;
use std::pin::Pin;
use std::str;
use std::task::{Context, Poll};

use bytes::Bytes;
use futures_core::Stream;
use futures_util::ready;
use http::header::{
    HeaderValue, ACCEPT_ENCODING, AUTHORIZATION, CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TYPE,
};
use http::response::Parts;
use http::{Request, Response};
use http_body::Body;
use pin_project_lite::pin_project;

use crate::gzip::MaybeGzip;
use crate::service::HttpService;
use crate::types::{FilterLevel, RequestMethod, StatusCode, Uri};
use crate::util::*;

/// A builder for `TwitterStream`.
///
/// ## Example
///
/// ```rust,no_run
/// use futures::prelude::*;
/// use twitter_stream::Token;
///
/// # #[tokio::main]
/// # async fn main() {
/// let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");
///
/// twitter_stream::Builder::sample(token)
///     .listen()
///     .try_flatten_stream()
///     .try_for_each(|json| {
///         println!("{}", json);
///         future::ok(())
///     })
///     .await
///     .unwrap();
/// # }
/// ```
#[derive(Clone, Debug)]
pub struct Builder<'a, T = Token> {
    method: RequestMethod,
    endpoint: Uri,
    token: T,
    inner: BuilderInner<'a>,
}

pin_project! {
    /// A future returned by constructor methods
    /// which resolves to a `TwitterStream`.
    pub struct FutureTwitterStream<F> {
        #[pin]
        response: F,
    }
}

pin_project! {
    /// A listener for Twitter Streaming API.
    /// It yields JSON strings returned from the API.
    pub struct TwitterStream<B: Body> {
        #[pin]
        inner: Lines<MaybeGzip<HttpBodyAsStream<B>>>,
    }
}

#[derive(Clone, Debug, oauth::Authorize)]
struct BuilderInner<'a> {
    #[oauth1(skip_if = "not")]
    stall_warnings: bool,
    filter_level: Option<FilterLevel>,
    language: Option<&'a str>,
    #[oauth1(encoded, fmt = "fmt_follow")]
    follow: Option<&'a [u64]>,
    track: Option<&'a str>,
    #[oauth1(encoded, fmt = "fmt_locations")]
    #[allow(clippy::type_complexity)]
    locations: Option<&'a [((f64, f64), (f64, f64))]>,
    #[oauth1(encoded)]
    count: Option<i32>,
}

impl<'a, C, A> Builder<'a, Token<C, A>>
where
    C: Borrow<str>,
    A: Borrow<str>,
{
    /// Create a builder for `POST statuses/filter` endpoint.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://dev.twitter.com/streaming/reference/post/statuses/filter
    pub fn filter(token: Token<C, A>) -> Self {
        const URI: &str = "https://stream.twitter.com/1.1/statuses/filter.json";
        Self::custom(RequestMethod::POST, Uri::from_static(URI), token)
    }

    /// Create a builder for `GET statuses/sample` endpoint.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://dev.twitter.com/streaming/reference/get/statuses/sample
    pub fn sample(token: Token<C, A>) -> Self {
        const URI: &str = "https://stream.twitter.com/1.1/statuses/sample.json";
        Self::custom(RequestMethod::GET, Uri::from_static(URI), token)
    }

    /// Constructs a builder for a Stream at a custom endpoint.
    pub fn custom(method: RequestMethod, endpoint: Uri, token: Token<C, A>) -> Self {
        Self {
            method,
            endpoint,
            token,
            inner: BuilderInner {
                stall_warnings: false,
                filter_level: None,
                language: None,
                follow: None,
                track: None,
                locations: None,
                count: None,
            },
        }
    }

    /// Start listening on the Streaming API endpoint, returning a `Future` which resolves
    /// to a `Stream` yielding JSON messages from the API.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    #[cfg(feature = "hyper")]
    #[cfg_attr(docsrs, doc(cfg(feature = "hyper")))]
    pub fn listen(&self) -> crate::hyper::FutureTwitterStream {
        let conn = hyper_tls::HttpsConnector::new();
        self.listen_with_client(hyper_pkg::Client::builder().build::<_, hyper_pkg::Body>(conn))
    }

    /// Same as `listen` except that it uses `client` to make HTTP request to the endpoint.
    ///
    /// # Panics
    ///
    /// This will call `<S as Service>::call` without checking for `<S as Service>::poll_ready`
    /// and may cause a panic if `client` is not ready to send an HTTP request yet.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// use tower::ServiceExt;
    ///
    /// # async fn doc() {
    /// # let mut client = hyper_pkg::Client::new();
    /// # let token = twitter_stream::Token::new("", "", "", "");
    /// client.ready().await; // Ensure that the client is ready to send a request.
    /// let stream = twitter_stream::Builder::sample(token)
    ///     .listen_with_client(&mut client)
    ///     .await
    ///     .unwrap();
    /// # }
    /// ```
    pub fn listen_with_client<S, B>(&self, mut client: S) -> FutureTwitterStream<S::Future>
    where
        S: HttpService<B>,
        B: Default + From<Vec<u8>>,
    {
        let req = Request::builder()
            .method(self.method.clone())
            .header(ACCEPT_ENCODING, HeaderValue::from_static("gzip"));

        let mut oauth = oauth::Builder::new(self.token.client.as_ref(), oauth::HmacSha1);
        oauth.token(self.token.token.as_ref());
        let req = if RequestMethod::POST == self.method {
            let oauth::Request {
                authorization,
                data,
            } = oauth.post_form(&self.endpoint, &self.inner);

            req.uri(self.endpoint.clone())
                .header(AUTHORIZATION, authorization)
                .header(
                    CONTENT_TYPE,
                    HeaderValue::from_static("application/x-www-form-urlencoded"),
                )
                .header(CONTENT_LENGTH, data.len())
                .body(data.into_bytes().into())
                .unwrap()
        } else {
            let oauth::Request {
                authorization,
                data: uri,
            } = oauth.build(self.method.as_ref(), &self.endpoint, &self.inner);

            req.uri(uri)
                .header(AUTHORIZATION, authorization)
                .body(B::default())
                .unwrap()
        };

        let response = client.call(req);
        FutureTwitterStream { response }
    }
}

impl<'a, C, A> Builder<'a, Token<C, A>> {
    /// Reset the HTTP request method to be used when connecting
    /// to the server.
    pub fn method(&mut self, method: RequestMethod) -> &mut Self {
        self.method = method;
        self
    }

    /// Reset the API endpoint URI to be connected.
    pub fn endpoint(&mut self, endpoint: Uri) -> &mut Self {
        self.endpoint = endpoint;
        self
    }

    /// Reset the token to be used to log into Twitter.
    pub fn token(&mut self, token: Token<C, A>) -> &mut Self {
        self.token = token;
        self
    }

    /// Set whether to receive messages when in danger of
    /// being disconnected.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#stall-warnings
    pub fn stall_warnings(&mut self, stall_warnings: bool) -> &mut Self {
        self.inner.stall_warnings = stall_warnings;
        self
    }

    /// Set the minimum `filter_level` Tweet attribute to receive.
    /// The default is `FilterLevel::None`.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#filter-level
    pub fn filter_level(&mut self, filter_level: impl Into<Option<FilterLevel>>) -> &mut Self {
        self.inner.filter_level = filter_level.into();
        self
    }

    /// Set a comma-separated language identifiers to receive Tweets
    /// written in the specified languages only.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#language
    pub fn language(&mut self, language: impl Into<Option<&'a str>>) -> &mut Self {
        self.inner.language = language.into();
        self
    }

    /// Set a list of user IDs to receive Tweets from the specified users.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#follow
    pub fn follow(&mut self, follow: impl Into<Option<&'a [u64]>>) -> &mut Self {
        self.inner.follow = follow.into();
        self
    }

    /// A comma separated list of phrases to filter Tweets by.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#track
    pub fn track(&mut self, track: impl Into<Option<&'a str>>) -> &mut Self {
        self.inner.track = track.into();
        self
    }

    /// Set a list of bounding boxes to filter Tweets by,
    /// specified by a pair of coordinates in the form of
    /// `((longitude, latitude), (longitude, latitude))` tuple.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#locations
    pub fn locations(
        &mut self,
        locations: impl Into<Option<&'a [((f64, f64), (f64, f64))]>>,
    ) -> &mut Self {
        self.inner.locations = locations.into();
        self
    }

    /// The `count` parameter.
    /// This parameter requires elevated access to use.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#count
    pub fn count(&mut self, count: impl Into<Option<i32>>) -> &mut Self {
        self.inner.count = count.into();
        self
    }
}

#[cfg(feature = "hyper")]
impl<B: Body> TwitterStream<B> {
    /// A shorthand for `Builder::filter().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn filter<C, A>(token: Token<C, A>) -> crate::hyper::FutureTwitterStream
    where
        C: Borrow<str>,
        A: Borrow<str>,
    {
        Builder::filter(token).listen()
    }

    /// A shorthand for `Builder::sample().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn sample<C, A>(token: Token<C, A>) -> crate::hyper::FutureTwitterStream
    where
        C: Borrow<str>,
        A: Borrow<str>,
    {
        Builder::sample(token).listen()
    }
}

impl<F, B, E> Future for FutureTwitterStream<F>
where
    F: Future<Output = Result<Response<B>, E>>,
    B: Body,
{
    type Output = Result<TwitterStream<B>, Error<E>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let res = match ready!(self.project().response.poll(cx)) {
            Ok(res) => res,
            Err(e) => return Poll::Ready(Err(Error::Service(e))),
        };
        let (parts, body) = res.into_parts();
        let Parts {
            status, headers, ..
        } = parts;

        if StatusCode::OK != status {
            return Poll::Ready(Err(Error::Http(status)));
        }

        let use_gzip = headers
            .get_all(CONTENT_ENCODING)
            .iter()
            .any(|e| e == "gzip");
        let inner = if use_gzip {
            Lines::new(gzip::gzip(HttpBodyAsStream::new(body)))
        } else {
            Lines::new(gzip::identity(HttpBodyAsStream::new(body)))
        };

        Poll::Ready(Ok(TwitterStream { inner }))
    }
}

impl<B> Stream for TwitterStream<B>
where
    B: Body,
{
    type Item = Result<string::String<Bytes>, Error<B::Error>>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut this = self.project();

        loop {
            let line = ready_some!(this.inner.as_mut().poll_next(cx))?;
            if line.iter().all(|&c| is_json_whitespace(c)) {
                continue;
            }

            str::from_utf8(&line).map_err(Error::Utf8)?;
            let line = unsafe {
                // Safety:
                // - We have checked above that `line` is valid as UTF-8.
                // - `Bytes` satisfies the requirements of `string::StableAsRef` trait
                // (https://github.com/carllerche/string/pull/17)
                string::String::<Bytes>::from_utf8_unchecked(line)
            };
            return Poll::Ready(Some(Ok(line)));
        }
    }
}

fn is_json_whitespace(c: u8) -> bool {
    // RFC7159 §2
    b" \t\n\r".contains(&c)
}
<|endoftext|>


<commit_before>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

/// Item
///
/// [RSS 2.0 Specification § Item]
/// http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt
#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    pub categories: Vec<Category>,
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Support <author> within <item><commit_after>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

/// Item
///
/// [RSS 2.0 Specification § Item]
/// http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt
#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    pub author: Option<String>,
    pub categories: Vec<Category>,
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);
        item.tag_with_text_opt("author", &self.author);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);
        let author = element.get_child("author", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
            author: author,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>


<commit_before>//! A simple cross-platform library loader.
//!
//! ([crates.io](https://crates.io/crates/sharedlib)) ([github](https://github.com/Tyleo/sharedlib))
//!
//! Based on [libloading](https://crates.io/crates/libloading) by Simonas Kazlauskas.
//!
//! # Loading a library
//! To load a library you can use any of the [Lib](struct.Lib.html), [LibTracked](struct.LibTracked.html), or [LibUnsafe](struct.LibUnsafe.html) `structs`. Each of these `struct`s provides different guarantees. For more information about the guarantees they provide, see the [chosing your guarantees](index.html#choosing-your-guarantees) section, below. We use [Lib](struct.Lib.html) for the examples below.
//!
//! ### Calling a function in another library
//! ``` no_run
//! # use sharedlib::error::*;
//! # use sharedlib::Func;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let path_to_lib = "examplelib.dll";
//!     let lib = try!(Lib::new(path_to_lib));
//!     let hello_world_symbol: Func<extern "C" fn()> = try!(lib.find_func("hello_world"));
//!     let hello_world = hello_world_symbol.get();
//!     hello_world();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ### Accessing data in another library
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::error::*;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let path_to_lib = "examplelib.dll";
//!     let lib = try!(Lib::new(path_to_lib));
//!     let my_usize_symbol: Data<usize> = try!(lib.find_data("my_usize"));
//!     let my_usize = my_usize_symbol.get();
//!     assert_eq!(*my_usize, 0);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ### Choosing your guarantees
//! A common problem when loading a shared library at runtime is that a symbol may be accessed after its library has been unloaded. [sharedlib](index.html) attempts to prevent this by allowing the lifetime of the library to be tracked. Each of the different libraries, [LibUnsafe](struct.LibUnsafe.html), [Lib](struct.Lib.html), [LibTracked](struct.LibTracked.html), [LibArc](type.LibArc.html), or [LibRc](type.LibRc.html), provides a different tracking mechanism. Below is a small overview. For more information, see the struct level documentation.
//!
//! * [LibUnsafe](struct.LibUnsafe.html) does not provide any tracking at all. This requires no overhead but responsibility falls on the client to be sure that the library is still alive when its symbols are used.
//!
//! * [Lib](struct.Lib.html) attaches its own lifetime to each symbol it returns. This requires no overhead but it can be difficult to store the returned symbol in a `struct` because the `struct` must have a trackable lifetime which outlives the [Lib](struct.Lib.html). In other words, a struct containing a symbol must parameterize around some lifetime `a`, where `a` is less than or equal to the lifetime of the library.
//!
//! * [LibTracked](struct.LibTracked.html) returns symbols with ref-counts to the library. This requires overhead but it allows the returned symbol to be stored easily. Additionally, this `struct` is generic and can be used with `Rc`, `Arc`, or a user provided ref-count type.
//!
//! * [LibArc](type.LibArc.html) is a [LibTracked](struct.LibTracked.html) which uses atomic ref-counting. This type is provided for convienience.
//!
//! * [LibRc](type.LibRc.html) is a [LibTracked](struct.LibTracked.html) which uses non-atomic ref-counting. This type is provided for convienience.
//!
//! # Pitfalls
//! While [sharedlib](index.html) attempts to prevent undefined behavior, loading shared libraries is inherently unsafe. Below are some tips which you may find helpful so that your code is not exposed to undefined behavior.
//!
//! ### Avoid copying or moving data returned from `get()`
//! The [get](trait.Symbol.html#method.get) method on [Symbol](trait.Symbol.html) returns a transmuted pointer to something in a loaded library. While [sharedlib](index.html) tries to make sure that this pointer cannot outlive the library it is from, full protection is impossible. In particular: if a loaded `struct` contains pointers to things in the loaded library, and the loaded `struct` implements `Clone`, clients can clone the `struct` and make it to live longer than the library it is from. If this happens the pointers in the `struct` dangle. The example below demonstrate:
//!
//! ``` no_run
//! # use sharedlib::error::*;
//! # use sharedlib::Func;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let some_func = {
//!         let lib = try!(Lib::new("examplelib.dll"));
//!         let some_func_symbol: Func<extern "C" fn()> = try!(lib.find_func("some_func"));
//!         // All func pointers implement `Copy` so we can duplicate one.
//!         some_func_symbol.get()
//!         // lib goes out of scope here.
//!     };
//!     // Undefined behavior
//!     some_func();
//! }
//! # Ok(())
//! # }
//! ```
//! ### Use the correct method when getting functions or data
//! Each library provides two different ways to get symbols from shared libraries. One way is `find_func`, and the other is `find_data`. Two functions are provded because `find_data` needs to return a reference to a `T` rather than a `T` itself, while `find_func` just needs to return a `T` itself. Returning the wrong thing can cause some complications. For instance: suppose we only have the `find_data` method, and we want to get a function pointer with the signature `fn()`. We are inclined to call `lib.find_data::<fn()>(b"some_func")`. This searches the memory of the loaded binary and finds the address of the first line of the function `some_func`. Next, the *contents* of the first line of `some_func` are treated as a function pointer rather than the *address* of the first line of `some_func`. When the first line of `some_func` is returned it is incorrectly cast into a function pointer. Calling it produces undefined behavior. The example below demonstrates:
//!
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::error::*;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let lib = try!(Lib::new("examplelib.dll"));
//!     let some_func_symbol: Data<extern "C" fn()> = try!(lib.find_data("some_func"));
//!     // some_func actually points to a function but rust thinks it points to a function pointer.
//!     let some_func = some_func_symbol.get();
//!     // Undefined behavior
//!     some_func();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! The correct way to do this with `find_data` is as follows:
//!
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::error::*;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let lib = try!(Lib::new("examplelib.dll"));
//!     // Get a pointer to the block of memory at "some_func", this is the function itself.
//!     let some_func_symbol: Data<u8> = try!(lib.find_data("some_func"));
//!     // The type of some_func is &u8, a reference to the first byte of `some_func`. We can convert this into a function pointer.
//!     let some_func = some_func_symbol.get();
//!     let some_func_ptr: extern "C" fn() = std::mem::transmute(some_func);
//!     // This works now.
//!     some_func_ptr();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! For convienience, the second example is provided as the `find_func` method, which does this error-prone conversion behind the scenes.
//!
//! # Comparison with other crates for loabing shared libraries
//! sharedlib was created out of frusteration with the existing crates for loading shared libraries. Below is a list of some of these crates with some information abuot how sharedlib improves upon them.
//!
//! * [dylib](https://crates.io/crates/dylib) provides an extremely simple interface for loading shared libraries. For awhile, this was the standard for loading shared libraries at runtime. Unfortunately, development on dylib has been mostly abandoned and it is no longer supported on the latest versions of the rust compiler.
//!
//! * [libloading](https://crates.io/crates/libloading) provides some additional safety guarantees on top of [dylib](https://crates.io/crates/dylib). [sharedlib](index.html) even started as a fork of [libloading](https://crates.io/crates/libloading). Unfortunately the interface [libloading](https://crates.io/crates/libloading) provides is extremely inflexible, requiring clients to transmute symbols so they can be used in `struct`s. Additionally, loading data does not work with this library which is a non-starter for many projects.
//!
//! # Frequently asked questions
//!
//! ### What is a shared library?
//! A shared library is a set of functions and variables which can be loaded after a program has been compiled. By loading a library after compilation, the library can be recompiled or changed without recompiling the main program. Shared libraries can even be loaded at runtime. Common shared library filetypes are *.dll* for windows, *.so* for unix, and *.dylib* for osx. For more information about what a shared library is, see [wikipedia](https://en.wikipedia.org/wiki/Library_(computing)#Shared_libraries).
//!
//! ### Doesn't rust already provide linking against shared libraries?
//! While rust provides linking against shared libraries, it does not provide the ability to load them at runtime. If you only want to use shared libraries that you know about before runtime, you may find not find this crate very useful. On the other hand, if you wish to load something at runtime, like a plugin, you are in the right place.

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

#[cfg(windows)]
extern crate kernel32;

#[cfg(windows)]
extern crate winapi;

pub mod error;

mod os;

mod lib_impl;

mod string;

mod symbol;

#[cfg(test)]
mod test;

mod util;

pub use lib_impl::Lib;

pub use lib_impl::LibArc;

pub use lib_impl::LibRc;

pub use lib_impl::LibTracked;

pub use lib_impl::LibUnsafe;

pub use symbol::Data;

pub use symbol::DataArc;

pub use symbol::DataRc;

pub use symbol::DataTracked;

pub use symbol::DataUnsafe;

pub use symbol::Func;

pub use symbol::FuncArc;

pub use symbol::FuncRc;

pub use symbol::FuncTracked;

pub use symbol::FuncUnsafe;

pub use symbol::Symbol;
<commit_msg>Cleaned up the docs.<commit_after>//! A simple cross-platform library loader.
//!
//! ([crates.io](https://crates.io/crates/sharedlib)) ([github](https://github.com/Tyleo/sharedlib))
//!
//! Based on [libloading](https://crates.io/crates/libloading) by Simonas Kazlauskas.
//!
//! # Loading a library
//! To load a library you can use any of the [Lib](struct.Lib.html), [LibTracked](struct.LibTracked.html), or [LibUnsafe](struct.LibUnsafe.html) `structs`. Each of these `struct`s provides different guarantees. For more information about the guarantees they provide, see the [chosing your guarantees](index.html#choosing-your-guarantees) section, below. We use [Lib](struct.Lib.html) for the examples below.
//!
//! ### Calling a function in another library
//! ``` no_run
//! # use sharedlib::error::*;
//! # use sharedlib::Func;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let path_to_lib = "examplelib.dll";
//!     let lib = try!(Lib::new(path_to_lib));
//!     let hello_world_symbol: Func<extern "C" fn()> = try!(lib.find_func("hello_world"));
//!     let hello_world = hello_world_symbol.get();
//!     hello_world();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ### Accessing data in another library
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::error::*;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let path_to_lib = "examplelib.dll";
//!     let lib = try!(Lib::new(path_to_lib));
//!     let my_usize_symbol: Data<usize> = try!(lib.find_data("my_usize"));
//!     let my_usize = my_usize_symbol.get();
//!     assert_eq!(*my_usize, 0);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ### Choosing your guarantees
//! A common problem when loading a shared library at runtime is that a symbol may be accessed after its library has been unloaded. [sharedlib](index.html) attempts to prevent this by allowing the lifetime of the library to be tracked. Each of the different libraries, [LibUnsafe](struct.LibUnsafe.html), [Lib](struct.Lib.html), [LibTracked](struct.LibTracked.html), [LibArc](type.LibArc.html), or [LibRc](type.LibRc.html), provides a different tracking mechanism. Below is a small overview. For more information, see the struct level documentation.
//!
//! * [LibUnsafe](struct.LibUnsafe.html) does not provide any tracking at all. This requires no overhead but responsibility falls on the client to be sure that the library is still alive when its symbols are used.
//!
//! * [Lib](struct.Lib.html) attaches its own lifetime to each symbol it returns. This requires no overhead but it can be difficult to store the returned symbol in a `struct` because the `struct` must have a trackable lifetime which outlives the [Lib](struct.Lib.html). In other words, a struct containing a symbol must parameterize around some lifetime `a`, where `a` is less than or equal to the lifetime of the library.
//!
//! * [LibTracked](struct.LibTracked.html) returns symbols with ref-counts to the library. This requires overhead but it allows the returned symbol to be stored easily. Additionally, this `struct` is generic and can be used with `Rc`, `Arc`, or a user provided ref-count type.
//!
//! * [LibArc](type.LibArc.html) is a [LibTracked](struct.LibTracked.html) which uses atomic ref-counting. This type is provided for convienience.
//!
//! * [LibRc](type.LibRc.html) is a [LibTracked](struct.LibTracked.html) which uses non-atomic ref-counting. This type is provided for convienience.
//!
//! # Pitfalls
//! While [sharedlib](index.html) attempts to prevent undefined behavior, loading shared libraries is inherently unsafe. Below are some tips which you may find helpful so that your code is not exposed to undefined behavior.
//!
//! ### Avoid copying or moving data returned from `get()`
//! The [get](trait.Symbol.html#method.get) method on [Symbol](trait.Symbol.html) returns a transmuted pointer to something in a loaded library. While [sharedlib](index.html) tries to make sure that this pointer cannot outlive the library it is from, full protection is impossible. In particular: if a loaded `struct` contains pointers to things in the loaded library, and the loaded `struct` implements `Clone`, clients can clone the `struct` and make it to live longer than the library it is from. If this happens the pointers in the `struct` dangle. The example below demonstrate:
//!
//! ``` no_run
//! # use sharedlib::error::*;
//! # use sharedlib::Func;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let some_func = {
//!         let lib = try!(Lib::new("examplelib.dll"));
//!         let some_func_symbol: Func<extern "C" fn()> = try!(lib.find_func("some_func"));
//!         // All func pointers implement `Copy` so we can duplicate one.
//!         some_func_symbol.get()
//!         // lib goes out of scope here.
//!     };
//!     // Undefined behavior
//!     some_func();
//! }
//! # Ok(())
//! # }
//! ```
//! ### Use the correct method when getting functions or data
//! Each library provides two different ways to get symbols from shared libraries. One way is `find_func`, and the other is `find_data`. Two functions are provded because `find_data` needs to return a reference to a `T` rather than a `T` itself, while `find_func` just needs to return a `T` itself. Returning the wrong thing can cause some complications. For instance: suppose we only have the `find_data` method, and we want to get a function pointer with the signature `fn()`. We are inclined to call `lib.find_data::<fn()>(b"some_func")`. This searches the memory of the loaded binary and finds the address of the first line of the function `some_func`. Next, the *contents* of the first line of `some_func` are treated as a function pointer rather than the *address* of the first line of `some_func`. When the first line of `some_func` is returned it is incorrectly cast into a function pointer. Calling it produces undefined behavior. The example below demonstrates:
//!
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::error::*;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let lib = try!(Lib::new("examplelib.dll"));
//!     let some_func_symbol: Data<extern "C" fn()> = try!(lib.find_data("some_func"));
//!     // some_func actually points to a function but rust thinks it points to a function pointer.
//!     let some_func = some_func_symbol.get();
//!     // Undefined behavior
//!     some_func();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! The correct way to do this with `find_data` is as follows:
//!
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::error::*;
//! # use sharedlib::Lib;
//! # use sharedlib::Symbol;
//! # fn test() -> Result<()> {
//! unsafe {
//!     let lib = try!(Lib::new("examplelib.dll"));
//!     // Get a pointer to the block of memory at "some_func", this is the function itself.
//!     let some_func_symbol: Data<u8> = try!(lib.find_data("some_func"));
//!     // The type of some_func is &u8, a reference to the first byte of `some_func`. We can convert this into a function pointer.
//!     let some_func = some_func_symbol.get();
//!     let some_func_ptr: extern "C" fn() = std::mem::transmute(some_func);
//!     // This works now.
//!     some_func_ptr();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! For convienience, the second example is provided as the `find_func` method, which does this error-prone conversion behind the scenes.
//!
//! # Comparison with other crates for loabing shared libraries
//! sharedlib was created out of frusteration with the existing crates for loading shared libraries. Below is a list of some of these crates with some information abuot how sharedlib improves upon them.
//!
//! * [dylib](https://crates.io/crates/dylib) provides an extremely simple interface for loading shared libraries. For awhile, this was the standard for loading shared libraries at runtime. Unfortunately, development on dylib has been mostly abandoned and it is no longer supported on the latest versions of the rust compiler.
//!
//! * [libloading](https://crates.io/crates/libloading) provides additional safety guarantees on top of [dylib](https://crates.io/crates/dylib) and is more concise than [sharedlib](index.html). [sharedlib](index.html) started as a fork of [libloading](https://crates.io/crates/libloading). [sharedlib](index.html) provides a few more library types built-in than [libloading](https://crates.io/crates/libloading).
//!
//! # Frequently asked questions
//!
//! ### What is a shared library?
//! A shared library is a set of functions and variables which can be loaded after a program has been compiled. By loading a library after compilation, the library can be recompiled or changed without recompiling the main program. Shared libraries can even be loaded at runtime. Common shared library filetypes are *.dll* for windows, *.so* for unix, and *.dylib* for osx. For more information about what a shared library is, see [wikipedia](https://en.wikipedia.org/wiki/Library_(computing)#Shared_libraries).
//!
//! ### Doesn't rust already provide linking against shared libraries?
//! While rust provides linking against shared libraries, it does not provide the ability to load them at runtime. If you only want to use shared libraries that you know about before runtime, you may find not find this crate very useful. On the other hand, if you wish to load something at runtime, like a plugin, you are in the right place.

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

#[cfg(windows)]
extern crate kernel32;

#[cfg(windows)]
extern crate winapi;

pub mod error;

mod os;

mod lib_impl;

mod string;

mod symbol;

#[cfg(test)]
mod test;

mod util;

pub use lib_impl::Lib;

pub use lib_impl::LibArc;

pub use lib_impl::LibRc;

pub use lib_impl::LibTracked;

pub use lib_impl::LibUnsafe;

pub use symbol::Data;

pub use symbol::DataArc;

pub use symbol::DataRc;

pub use symbol::DataTracked;

pub use symbol::DataUnsafe;

pub use symbol::Func;

pub use symbol::FuncArc;

pub use symbol::FuncRc;

pub use symbol::FuncTracked;

pub use symbol::FuncUnsafe;

pub use symbol::Symbol;
<|endoftext|>