<commit_before>use multi_objective::MultiObjective;
use non_dominated_sort::NonDominatedSort;
use crowding_distance::{assign_crowding_distance, AssignedCrowdingDistance};
use std::cmp::PartialOrd;

/// Select `n` solutions using the approach taken by NSGA. We first sort
/// the solutions into their corresponding pareto fronts. Then, we put
/// as many "whole" fronts into the result as possible, until we cannot
/// fit a whole front into the result (otherwise we would have more than
/// `n` solutions). For this last front, sort it's solutions according
/// to their crowding distance (higher crowding distance is better!),
/// and chose those solutions with the higher crowding distance.

pub fn selection_nsga<'a, S>(
    solutions: &'a [S],
    n: usize,
    multi_objective: &MultiObjective<S, f64>,
) -> Vec<AssignedCrowdingDistance<'a, S>>
where
    S: 'a,
{
    // Cannot select more solutions than we actually have
    let n = solutions.len().min(n);
    debug_assert!(n <= solutions.len());

    let mut result = Vec::with_capacity(n);
    let mut missing_solutions = n;

    for front in NonDominatedSort::new(solutions, multi_objective) {
        let (mut assigned_crowding, _) = assign_crowding_distance(&front, multi_objective);

        if assigned_crowding.len() <= missing_solutions {
            // the whole front fits into the result
            missing_solutions -= assigned_crowding.len();
            result.extend(assigned_crowding);

            if missing_solutions == 0 {
                break;
            }
        } else {
            // the front does not fit in total. sort it's solutions
            // according to the crowding distance and take the best
            // until we have "n" solutions in the result.

            assigned_crowding.sort_by(|a, b| {
                debug_assert_eq!(a.rank, b.rank);
                a.crowding_distance
                    .partial_cmp(&b.crowding_distance)
                    .unwrap()
                    .reverse()
            });

            result.extend(assigned_crowding.into_iter().take(missing_solutions));

            break;
        }
    }

    debug_assert_eq!(n, result.len());

    return result;
}
<commit_msg>Simplify logic<commit_after>use multi_objective::MultiObjective;
use non_dominated_sort::NonDominatedSort;
use crowding_distance::{assign_crowding_distance, AssignedCrowdingDistance};
use std::cmp::PartialOrd;

/// Select `n` solutions using the approach taken by NSGA. We first sort
/// the solutions into their corresponding pareto fronts. Then, we put
/// as many "whole" fronts into the result as possible, until we cannot
/// fit a whole front into the result (otherwise we would have more than
/// `n` solutions). For this last front, sort it's solutions according
/// to their crowding distance (higher crowding distance is better!),
/// and chose those solutions with the higher crowding distance.

pub fn selection_nsga<'a, S>(
    solutions: &'a [S],
    n: usize,
    multi_objective: &MultiObjective<S, f64>,
) -> Vec<AssignedCrowdingDistance<'a, S>>
where
    S: 'a,
{
    // Cannot select more solutions than we actually have
    let n = solutions.len().min(n);
    debug_assert!(n <= solutions.len());

    let mut result = Vec::with_capacity(n);
    let mut missing_solutions = n;

    for front in NonDominatedSort::new(solutions, multi_objective) {
        let (mut assigned_crowding, _) = assign_crowding_distance(&front, multi_objective);

        if assigned_crowding.len() > missing_solutions {
            // the front does not fit in total. sort it's solutions
            // according to the crowding distance and take the best
            // solutions until we have "n" solutions in the result.

            assigned_crowding.sort_by(|a, b| {
                debug_assert_eq!(a.rank, b.rank);
                a.crowding_distance
                    .partial_cmp(&b.crowding_distance)
                    .unwrap()
                    .reverse()
            });
        }

        // Take no more than `missing_solutions`
        let take = assigned_crowding.len().min(missing_solutions);

        result.extend(assigned_crowding.into_iter().take(take));

        missing_solutions -= take;
        if missing_solutions == 0 {
            break;
        }
    }

    debug_assert_eq!(n, result.len());

    return result;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::sync::Arc;

use buffer::Buffer;
use buffer::BufferView;
use buffer::TypedBuffer;
use descriptor::descriptor::DescriptorDescTy;
use descriptor::descriptor::DescriptorBufferDesc;
use descriptor::descriptor::DescriptorImageDesc;
use descriptor::descriptor::DescriptorImageDescDimensions;
use descriptor::descriptor::DescriptorImageDescArray;
use descriptor::descriptor_set::DescriptorWrite;
use image::ImageView;
use sampler::Sampler;

/// Call this macro with the layout of a pipeline to generate some helper structs that wrap around
/// vulkano's unsafe APIs.
// TODO: more docs
#[macro_export]
macro_rules! pipeline_layout {
    (push_constants: { $($pc_f:ident: $pc_t:ty),* } $(, $name:ident: { $($field:ident: $ty:ty),* })*) => {
        use std::mem;
        use std::sync::Arc;
        use std::vec::IntoIter as VecIntoIter;
        use $crate::device::Device;
        use $crate::descriptor::descriptor::DescriptorDesc;
        use $crate::descriptor::descriptor::ShaderStages;
        use $crate::descriptor::pipeline_layout::PipelineLayout;
        use $crate::descriptor::pipeline_layout::PipelineLayoutDesc;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayout;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayoutCreationError;

        #[derive(Debug, Copy, Clone)]
        pub struct PushConstants {
            $(pub $pc_f: $pc_t,)*
        }

        pub struct CustomPipeline {
            inner: UnsafePipelineLayout
        }

        impl CustomPipeline {
            #[allow(unsafe_code)]
            pub fn new(device: &Arc<Device>)
                       -> Result<Arc<CustomPipeline>, UnsafePipelineLayoutCreationError>
            {
                let layouts = vec![
                    $(
                        Arc::new(try!($name::build_set_layout_raw(device)))
                    ),*
                ];

                let push_constants = if mem::size_of::<PushConstants>() >= 1 {
                    Some((0, mem::size_of::<PushConstants>(), ShaderStages::all()))
                } else {
                    None
                };

                let inner = {
                    try!(UnsafePipelineLayout::new(device, layouts.iter(), push_constants))
                };

                Ok(Arc::new(CustomPipeline {
                    inner: inner
                }))
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayout for CustomPipeline {
            #[inline]
            fn inner(&self) -> &UnsafePipelineLayout {
                &self.inner
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayoutDesc for CustomPipeline {
            type SetsIter = VecIntoIter<Self::DescIter>;
            type DescIter = VecIntoIter<DescriptorDesc>;

            fn descriptors_desc(&self) -> Self::SetsIter {
                // FIXME:
                vec![].into_iter()
            }
        }

        /* TODO: uncomment when specialization lands
        #[allow(unsafe_code)]
        unsafe impl<'a> PipelineLayoutSetsCompatible<($(&'a Arc<$name::Set>),*)> for CustomPipeline {
            #[inline]
            default fn is_compatible(&self, _: &($(&'a Arc<$name::Set>),*)) -> bool {
                true
            }
        }*/

        pipeline_layout!{__inner__ (0) $($name: {$($field: $ty),*})*}
    };

    ($($name:ident: { $($field:ident: $ty:ty),* }),*) => {
        pipeline_layout!{ push_constants: {} $(, $name: {$($field: $ty),*})* }
    };

    (__inner__ ($num:expr) $name:ident: { $($field:ident: $ty:ty),* } $($rest:tt)*) => {
        pub mod $name {
            #![allow(unused_imports)]

            use std::sync::Arc;
            use std::vec::IntoIter as VecIntoIter;
            use super::CustomPipeline;
            use $crate::OomError;
            use $crate::device::Device;
            use $crate::descriptor::descriptor::DescriptorDesc;
            use $crate::descriptor::descriptor::ShaderStages;
            use $crate::descriptor::descriptor_set::DescriptorPool;
            use $crate::descriptor::descriptor_set::DescriptorSet;
            use $crate::descriptor::descriptor_set::DescriptorSetDesc;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSet;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
            use $crate::descriptor::descriptor_set::DescriptorWrite;
            use $crate::descriptor::pipeline_layout::PipelineLayout;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformTexelBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::StorageTexelBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::CombinedImageSampler;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::SampledImage;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::DescriptorMarker;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::StorageBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::StorageImage;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::InputAttachment;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::ValidParameter;

            // This constant is part of the API, but Rust sees it as dead code.
            #[allow(dead_code)]
            pub const SET_NUM: u32 = $num;

            #[allow(non_camel_case_types)]
            pub struct Descriptors<$($field),*> {
                $(
                    pub $field: $field
                ),*
            }

            #[allow(non_camel_case_types)]
            #[allow(unused_assignments)]
            impl<$($field: ValidParameter<$ty>),*> Descriptors<$($field),*> {
                pub fn writes(&self) -> Vec<DescriptorWrite> {
                    let mut writes = Vec::new();
                    let mut binding = 0;
                    $(
                        writes.push(self.$field.write(binding));
                        binding += 1;
                    )*
                    writes
                }
            }

            pub struct Set {
                inner: UnsafeDescriptorSet
            }

            impl Set {
                #[inline]
                #[allow(non_camel_case_types)]
                pub fn raw<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field),*>)
                           -> Result<Set, OomError>
                {
                    #![allow(unsafe_code)]
                    unsafe {
                        let layout = layout.inner().descriptor_set_layout($num).unwrap();
                        let mut set = try!(UnsafeDescriptorSet::uninitialized_raw(pool, layout));
                        set.write(descriptors.writes());
                        Ok(Set { inner: set })
                    }
                }

                #[inline]
                #[allow(non_camel_case_types)]
                pub fn new<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field),*>)
                           -> Arc<Set>
                {
                    Arc::new(Set::raw(pool, layout, descriptors).unwrap())
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSet for Set {
                #[inline]
                fn inner(&self) -> &UnsafeDescriptorSet {
                    &self.inner
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSetDesc for Set {
                type Iter = VecIntoIter<DescriptorDesc>;

                #[inline]
                fn desc(&self) -> Self::Iter {
                    // FIXME:
                    vec![].into_iter()
                }
            }

            #[allow(unused_assignments)]
            #[allow(dead_code)]
            pub fn build_set_layout_raw(device: &Arc<Device>)
                                        -> Result<UnsafeDescriptorSetLayout, OomError>
            {
                let mut descriptors = Vec::new();
                let mut binding = 0;

                $(
                    descriptors.push(DescriptorDesc {
                        binding: binding,
                        ty: <$ty as DescriptorMarker>::descriptor_type(),
                        array_count: 1,                     // TODO:
                        stages: ShaderStages::all(),        // TODO:
                        readonly: false,                    // TODO:
                    });

                    binding += 1;
                )*

                UnsafeDescriptorSetLayout::raw(device.clone(), descriptors.into_iter())
            }

            #[inline]
            #[allow(dead_code)]
            pub fn build_set_layout(device: &Arc<Device>)
                                    -> Arc<UnsafeDescriptorSetLayout>
            {
                Arc::new(build_set_layout_raw(device).unwrap())
            }
        }

        pipeline_layout!{__inner__ ($num+1) $($rest)*}
    };

    (__inner__ ($num:expr)) => {};
}

pub unsafe trait ValidParameter<Target> {
    fn write(&self, binding: u32) -> DescriptorWrite;
}

pub unsafe trait DescriptorMarker {
    fn descriptor_type() -> DescriptorDescTy;
}

pub struct UniformBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for UniformBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::Buffer(DescriptorBufferDesc {
            dynamic: Some(false),
            storage: false,
        })
    }
}

unsafe impl<'a, B, T: ?Sized + 'static> ValidParameter<UniformBuffer<T>> for &'a Arc<B>
    where B: TypedBuffer<Content = T>
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::uniform_buffer(binding, *self)
    }
}

pub struct StorageBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for StorageBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::Buffer(DescriptorBufferDesc {
            dynamic: Some(false),
            storage: true,
        })
    }
}

unsafe impl<'a, B, T: ?Sized + 'static> ValidParameter<StorageBuffer<T>> for &'a Arc<B>
    where B: TypedBuffer<Content = T>
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::storage_buffer(binding, *self)
    }
}

pub struct UniformTexelBuffer;
unsafe impl DescriptorMarker for UniformTexelBuffer {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::TexelBuffer {
            storage: false,
            format: None,       // TODO:
        }
    }
}

unsafe impl<'a, B, F> ValidParameter<UniformTexelBuffer> for &'a Arc<BufferView<F, B>>   // TODO: format not checked
    where B: Buffer, F: 'static + Send + Sync
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::uniform_texel_buffer(binding, *self)
    }
}

pub struct StorageTexelBuffer;
unsafe impl DescriptorMarker for StorageTexelBuffer {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::TexelBuffer {
            storage: true,
            format: None,       // TODO:
        }
    }
}

unsafe impl<'a, B, F> ValidParameter<StorageTexelBuffer> for &'a Arc<BufferView<F, B>>   // TODO: format not checked
    where B: Buffer, F: 'static + Send + Sync
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::storage_texel_buffer(binding, *self)
    }
}

pub struct CombinedImageSampler;
unsafe impl DescriptorMarker for CombinedImageSampler {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::CombinedImageSampler(DescriptorImageDesc {
            sampled: true,
            // FIXME: correct values
            dimensions: DescriptorImageDescDimensions::TwoDimensional,
            multisampled: false,
            array_layers: DescriptorImageDescArray::NonArrayed,
            format: None,
        })
    }
}

unsafe impl<'a, I> ValidParameter<CombinedImageSampler> for (&'a Arc<Sampler>, &'a Arc<I>)
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::combined_image_sampler(binding, self.0, self.1)
    }
}

pub struct SampledImage;
unsafe impl DescriptorMarker for SampledImage {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::Image(DescriptorImageDesc {
            sampled: true,
            // FIXME: correct values
            dimensions: DescriptorImageDescDimensions::TwoDimensional,
            multisampled: false,
            array_layers: DescriptorImageDescArray::NonArrayed,
            format: None,
        })
    }
}

unsafe impl<'a, I> ValidParameter<SampledImage> for &'a Arc<I>
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::sampled_image(binding, self)
    }
}

pub struct StorageImage;
unsafe impl DescriptorMarker for StorageImage {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::Image(DescriptorImageDesc {
            sampled: false,
            // FIXME: correct values
            dimensions: DescriptorImageDescDimensions::TwoDimensional,
            multisampled: false,
            array_layers: DescriptorImageDescArray::NonArrayed,
            format: None,
        })
    }
}

unsafe impl<'a, I> ValidParameter<StorageImage> for &'a Arc<I>
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::storage_image(binding, self)
    }
}

pub struct InputAttachment;
unsafe impl DescriptorMarker for InputAttachment {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        // FIXME: correct values
        DescriptorDescTy::InputAttachment { multisampled: false, array_layers: DescriptorImageDescArray::NonArrayed }
    }
}

unsafe impl<'a, I> ValidParameter<InputAttachment> for &'a Arc<I>
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::input_attachment(binding, self)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn no_warning() {
        #![deny(warnings)]
        mod layout {
            pipeline_layout! {
                set0: {
                    field1: UniformBuffer<[u8]>,
                    field2: UniformBuffer<[u8]>
                },
                set1: {
                    field1: UniformBuffer<[u8]>,
                    field2: UniformBuffer<[u8]>
                }
            }
        }
    }
}
<commit_msg>Fix compilation<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::sync::Arc;

use buffer::Buffer;
use buffer::BufferView;
use buffer::TypedBuffer;
use descriptor::descriptor::DescriptorDescTy;
use descriptor::descriptor::DescriptorBufferDesc;
use descriptor::descriptor::DescriptorImageDesc;
use descriptor::descriptor::DescriptorImageDescDimensions;
use descriptor::descriptor::DescriptorImageDescArray;
use descriptor::descriptor_set::DescriptorWrite;
use descriptor::descriptor_set::resources_collection::Buf;
use descriptor::descriptor_set::resources_collection::ResourcesCollection;
use image::ImageView;
use sampler::Sampler;
use sync::AccessFlagBits;
use sync::PipelineStages;

/// Call this macro with the layout of a pipeline to generate some helper structs that wrap around
/// vulkano's unsafe APIs.
// TODO: more docs
#[macro_export]
macro_rules! pipeline_layout {
    (push_constants: { $($pc_f:ident: $pc_t:ty),* } $(, $name:ident: { $($field:ident: $ty:ty),* })*) => {
        use std::mem;
        use std::sync::Arc;
        use std::vec::IntoIter as VecIntoIter;
        use $crate::device::Device;
        use $crate::descriptor::descriptor::DescriptorDesc;
        use $crate::descriptor::descriptor::ShaderStages;
        use $crate::descriptor::pipeline_layout::PipelineLayout;
        use $crate::descriptor::pipeline_layout::PipelineLayoutDesc;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayout;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayoutCreationError;

        #[derive(Debug, Copy, Clone)]
        pub struct PushConstants {
            $(pub $pc_f: $pc_t,)*
        }

        pub struct CustomPipeline {
            inner: UnsafePipelineLayout
        }

        impl CustomPipeline {
            #[allow(unsafe_code)]
            pub fn new(device: &Arc<Device>)
                       -> Result<Arc<CustomPipeline>, UnsafePipelineLayoutCreationError>
            {
                let layouts = vec![
                    $(
                        Arc::new(try!($name::build_set_layout_raw(device)))
                    ),*
                ];

                let push_constants = if mem::size_of::<PushConstants>() >= 1 {
                    Some((0, mem::size_of::<PushConstants>(), ShaderStages::all()))
                } else {
                    None
                };

                let inner = {
                    try!(UnsafePipelineLayout::new(device, layouts.iter(), push_constants))
                };

                Ok(Arc::new(CustomPipeline {
                    inner: inner
                }))
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayout for CustomPipeline {
            #[inline]
            fn inner(&self) -> &UnsafePipelineLayout {
                &self.inner
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayoutDesc for CustomPipeline {
            type SetsIter = VecIntoIter<Self::DescIter>;
            type DescIter = VecIntoIter<DescriptorDesc>;

            fn descriptors_desc(&self) -> Self::SetsIter {
                // FIXME:
                vec![].into_iter()
            }
        }

        /* TODO: uncomment when specialization lands
        #[allow(unsafe_code)]
        unsafe impl<'a> PipelineLayoutSetsCompatible<($(&'a Arc<$name::Set>),*)> for CustomPipeline {
            #[inline]
            default fn is_compatible(&self, _: &($(&'a Arc<$name::Set>),*)) -> bool {
                true
            }
        }*/

        pipeline_layout!{__inner__ (0) $($name: {$($field: $ty),*})*}
    };

    ($($name:ident: { $($field:ident: $ty:ty),* }),*) => {
        pipeline_layout!{ push_constants: {} $(, $name: {$($field: $ty),*})* }
    };

    (__inner__ ($num:expr) $name:ident: { $($field:ident: $ty:ty),* } $($rest:tt)*) => {
        pub mod $name {
            #![allow(unused_imports)]

            use std::sync::Arc;
            use std::vec::IntoIter as VecIntoIter;
            use super::CustomPipeline;
            use $crate::OomError;
            use $crate::device::Device;
            use $crate::descriptor::descriptor::DescriptorDesc;
            use $crate::descriptor::descriptor::ShaderStages;
            use $crate::descriptor::descriptor_set::DescriptorPool;
            use $crate::descriptor::descriptor_set::DescriptorSet;
            use $crate::descriptor::descriptor_set::DescriptorSetDesc;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSet;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
            use $crate::descriptor::descriptor_set::DescriptorWrite;
            use $crate::descriptor::pipeline_layout::PipelineLayout;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformTexelBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::StorageTexelBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::CombinedImageSampler;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::SampledImage;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::DescriptorMarker;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::StorageBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::StorageImage;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::InputAttachment;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::ValidParameter;

            // This constant is part of the API, but Rust sees it as dead code.
            #[allow(dead_code)]
            pub const SET_NUM: u32 = $num;

            #[allow(non_camel_case_types)]
            pub struct Descriptors<$($field),*> {
                $(
                    pub $field: $field
                ),*
            }

            #[allow(non_camel_case_types)]
            #[allow(unused_assignments)]
            #[inline]
            impl<$($field: ValidParameter<$ty>),*> Descriptors<$($field),*> {
                pub fn res(&self) -> ($(<$field as ValidParameter<$ty>>::Resource),*) {
                    (
                        ValidParameter<$ty>::build(&self.$field)
                    )
                }
            }

            pub struct Set {
                inner: UnsafeDescriptorSet
            }

            impl Set {
                #[inline]
                #[allow(non_camel_case_types)]
                pub fn raw<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field),*>)
                           -> Result<Set, OomError>
                {
                    #![allow(unsafe_code)]
                    unsafe {
                        let layout = layout.inner().descriptor_set_layout($num).unwrap();
                        let mut set = try!(UnsafeDescriptorSet::uninitialized_raw(pool, layout));
                        set.write(descriptors.writes());
                        Ok(Set { inner: set })
                    }
                }

                #[inline]
                #[allow(non_camel_case_types)]
                pub fn new<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field),*>)
                           -> Arc<Set>
                {
                    Arc::new(Set::raw(pool, layout, descriptors).unwrap())
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSet for Set {
                #[inline]
                fn inner(&self) -> &UnsafeDescriptorSet {
                    &self.inner
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSetDesc for Set {
                type Iter = VecIntoIter<DescriptorDesc>;

                #[inline]
                fn desc(&self) -> Self::Iter {
                    // FIXME:
                    vec![].into_iter()
                }
            }

            #[allow(unused_assignments)]
            #[allow(dead_code)]
            pub fn build_set_layout_raw(device: &Arc<Device>)
                                        -> Result<UnsafeDescriptorSetLayout, OomError>
            {
                let mut descriptors = Vec::new();
                let mut binding = 0;

                $(
                    descriptors.push(DescriptorDesc {
                        binding: binding,
                        ty: <$ty as DescriptorMarker>::descriptor_type(),
                        array_count: 1,                     // TODO:
                        stages: ShaderStages::all(),        // TODO:
                        readonly: false,                    // TODO:
                    });

                    binding += 1;
                )*

                UnsafeDescriptorSetLayout::raw(device.clone(), descriptors.into_iter())
            }

            #[inline]
            #[allow(dead_code)]
            pub fn build_set_layout(device: &Arc<Device>)
                                    -> Arc<UnsafeDescriptorSetLayout>
            {
                Arc::new(build_set_layout_raw(device).unwrap())
            }
        }

        pipeline_layout!{__inner__ ($num+1) $($rest)*}
    };

    (__inner__ ($num:expr)) => {};
}

pub unsafe trait ValidParameter<Target> {
    type Resource;
    fn build(self) -> Self::Resource;
}

pub unsafe trait DescriptorMarker {
    fn descriptor_type() -> DescriptorDescTy;
}

pub struct UniformBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for UniformBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::Buffer(DescriptorBufferDesc {
            dynamic: Some(false),
            storage: false,
        })
    }
}

unsafe impl<'a, B, T: ?Sized + 'static> ValidParameter<UniformBuffer<T>> for B
    where B: TypedBuffer<Content = T>
{
    type Resource = Buf<B>;

    #[inline]
    fn build(self) -> Self::Resource {
        let size = self.size();

        Buf {
            buffer: self,
            offset: 0,
            size: size,
            write: false,
            stage: PipelineStages {       // FIXME:
                all_graphics: true,
                all_commands: true,
                .. PipelineStages::none()
            },
            access: AccessFlagBits::all(),      // FIXME:
        }
    }
}

pub struct StorageBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for StorageBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::Buffer(DescriptorBufferDesc {
            dynamic: Some(false),
            storage: true,
        })
    }
}

unsafe impl<'a, B, T: ?Sized + 'static> ValidParameter<StorageBuffer<T>> for B
    where B: TypedBuffer<Content = T>
{
    type Resource = Buf<B>;

    #[inline]
    fn build(self) -> Self::Resource {
        let size = self.size();

        Buf {
            buffer: self,
            offset: 0,
            size: size,
            write: false,
            stage: PipelineStages {       // FIXME:
                all_graphics: true,
                all_commands: true,
                .. PipelineStages::none()
            },
            access: AccessFlagBits::all(),      // FIXME:
        }
    }
}
/*
pub struct UniformTexelBuffer;
unsafe impl DescriptorMarker for UniformTexelBuffer {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::TexelBuffer {
            storage: false,
            format: None,       // TODO:
        }
    }
}

unsafe impl<'a, B, F> ValidParameter<UniformTexelBuffer> for &'a Arc<BufferView<F, B>>   // TODO: format not checked
    where B: Buffer, F: 'static + Send + Sync
{
    type Resource = Buf<B>;

    #[inline]
    fn build(self) -> Self::Resource {
        let buffer = self.buffer();
        let size = self.size();

        Buf {
            buffer: self,
            offset: 0,
            size: size,
            write: false,
            stage: PipelineStages::all(),       // FIXME:
            access: AccessFlagBits::all(),      // FIXME:
        }
    }
}

pub struct StorageTexelBuffer;
unsafe impl DescriptorMarker for StorageTexelBuffer {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::TexelBuffer {
            storage: true,
            format: None,       // TODO:
        }
    }
}

unsafe impl<'a, B, F> ValidParameter<StorageTexelBuffer> for &'a Arc<BufferView<F, B>>   // TODO: format not checked
    where B: Buffer, F: 'static + Send + Sync
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::storage_texel_buffer(binding, *self)
    }
}

pub struct CombinedImageSampler;
unsafe impl DescriptorMarker for CombinedImageSampler {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::CombinedImageSampler(DescriptorImageDesc {
            sampled: true,
            // FIXME: correct values
            dimensions: DescriptorImageDescDimensions::TwoDimensional,
            multisampled: false,
            array_layers: DescriptorImageDescArray::NonArrayed,
            format: None,
        })
    }
}

unsafe impl<'a, I> ValidParameter<CombinedImageSampler> for (&'a Arc<Sampler>, &'a Arc<I>)
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::combined_image_sampler(binding, self.0, self.1)
    }
}

pub struct SampledImage;
unsafe impl DescriptorMarker for SampledImage {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::Image(DescriptorImageDesc {
            sampled: true,
            // FIXME: correct values
            dimensions: DescriptorImageDescDimensions::TwoDimensional,
            multisampled: false,
            array_layers: DescriptorImageDescArray::NonArrayed,
            format: None,
        })
    }
}

unsafe impl<'a, I> ValidParameter<SampledImage> for &'a Arc<I>
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::sampled_image(binding, self)
    }
}

pub struct StorageImage;
unsafe impl DescriptorMarker for StorageImage {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        DescriptorDescTy::Image(DescriptorImageDesc {
            sampled: false,
            // FIXME: correct values
            dimensions: DescriptorImageDescDimensions::TwoDimensional,
            multisampled: false,
            array_layers: DescriptorImageDescArray::NonArrayed,
            format: None,
        })
    }
}

unsafe impl<'a, I> ValidParameter<StorageImage> for &'a Arc<I>
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::storage_image(binding, self)
    }
}

pub struct InputAttachment;
unsafe impl DescriptorMarker for InputAttachment {
    #[inline]
    fn descriptor_type() -> DescriptorDescTy {
        // FIXME: correct values
        DescriptorDescTy::InputAttachment { multisampled: false, array_layers: DescriptorImageDescArray::NonArrayed }
    }
}

unsafe impl<'a, I> ValidParameter<InputAttachment> for &'a Arc<I>
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::input_attachment(binding, self)
    }
}*/

#[cfg(test)]
mod tests {
    #[test]
    fn no_warning() {
        #![deny(warnings)]
        mod layout {
            pipeline_layout! {
                set0: {
                    field1: UniformBuffer<[u8]>,
                    field2: UniformBuffer<[u8]>
                },
                set1: {
                    field1: UniformBuffer<[u8]>,
                    field2: UniformBuffer<[u8]>
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use {Errno, Result};
use libc::{self, c_int};
use std::os::unix::io::RawFd;
use std::ptr;
use std::mem;

bitflags!(
    #[repr(C)]
    flags EpollFlags: u32 {
        const EPOLLIN = 0x001,
        const EPOLLPRI = 0x002,
        const EPOLLOUT = 0x004,
        const EPOLLRDNORM = 0x040,
        const EPOLLRDBAND = 0x080,
        const EPOLLWRNORM = 0x100,
        const EPOLLWRBAND = 0x200,
        const EPOLLMSG = 0x400,
        const EPOLLERR = 0x008,
        const EPOLLHUP = 0x010,
        const EPOLLRDHUP = 0x2000,
        const EPOLLEXCLUSIVE = 1 << 28,
        const EPOLLWAKEUP = 1 << 29,
        const EPOLLONESHOT = 1 << 30,
        const EPOLLET = 1 << 31
    }
);

#[derive(Clone, Copy)]
#[repr(C)]
pub enum EpollOp {
    EpollCtlAdd = 1,
    EpollCtlDel = 2,
    EpollCtlMod = 3
}

libc_bitflags!{
    flags EpollCreateFlags: c_int {
        EPOLL_CLOEXEC,
    }
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct EpollEvent {
    event: libc::epoll_event,
}

impl EpollEvent {
    pub fn new(events: EpollFlags, data: u64) -> Self {
        EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } }
    }

    pub fn empty() -> Self {
        unsafe { mem::uninitialized::<EpollEvent>() }
    }

    pub fn events(&self) -> EpollFlags {
        EpollFlags::from_bits(self.event.events).unwrap()
    }

    pub fn data(&self) -> u64 {
        self.event.u64
    }
}

impl<'a> Into<&'a mut EpollEvent> for Option<&'a mut EpollEvent> {
    #[inline]
    fn into(self) -> &'a mut EpollEvent {
        match self {
            Some(epoll_event) => epoll_event,
            None => unsafe { &mut *ptr::null_mut::<EpollEvent>() }
        }
    }
}

#[inline]
pub fn epoll_create() -> Result<RawFd> {
    let res = unsafe { libc::epoll_create(1024) };

    Errno::result(res)
}

#[inline]
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
    let res = unsafe { libc::epoll_create1(flags.bits()) };

    Errno::result(res)
}

#[inline]
pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
    where T: Into<&'a mut EpollEvent>
{
    let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.into().event) };
    Errno::result(res).map(drop)
}

#[inline]
pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
    let res = unsafe {
        libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
    };

    Errno::result(res).map(|r| r as usize)
}
<commit_msg>EpollEvent::empty(): using mem::zeroed instead of mem::uninitialized.<commit_after>use {Errno, Result};
use libc::{self, c_int};
use std::os::unix::io::RawFd;
use std::ptr;
use std::mem;

bitflags!(
    #[repr(C)]
    flags EpollFlags: u32 {
        const EPOLLIN = 0x001,
        const EPOLLPRI = 0x002,
        const EPOLLOUT = 0x004,
        const EPOLLRDNORM = 0x040,
        const EPOLLRDBAND = 0x080,
        const EPOLLWRNORM = 0x100,
        const EPOLLWRBAND = 0x200,
        const EPOLLMSG = 0x400,
        const EPOLLERR = 0x008,
        const EPOLLHUP = 0x010,
        const EPOLLRDHUP = 0x2000,
        const EPOLLEXCLUSIVE = 1 << 28,
        const EPOLLWAKEUP = 1 << 29,
        const EPOLLONESHOT = 1 << 30,
        const EPOLLET = 1 << 31
    }
);

#[derive(Clone, Copy)]
#[repr(C)]
pub enum EpollOp {
    EpollCtlAdd = 1,
    EpollCtlDel = 2,
    EpollCtlMod = 3
}

libc_bitflags!{
    flags EpollCreateFlags: c_int {
        EPOLL_CLOEXEC,
    }
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct EpollEvent {
    event: libc::epoll_event,
}

impl EpollEvent {
    pub fn new(events: EpollFlags, data: u64) -> Self {
        EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } }
    }

    pub fn empty() -> Self {
        unsafe { mem::zeroed::<EpollEvent>() }
    }

    pub fn events(&self) -> EpollFlags {
        EpollFlags::from_bits(self.event.events).unwrap()
    }

    pub fn data(&self) -> u64 {
        self.event.u64
    }
}

impl<'a> Into<&'a mut EpollEvent> for Option<&'a mut EpollEvent> {
    #[inline]
    fn into(self) -> &'a mut EpollEvent {
        match self {
            Some(epoll_event) => epoll_event,
            None => unsafe { &mut *ptr::null_mut::<EpollEvent>() }
        }
    }
}

#[inline]
pub fn epoll_create() -> Result<RawFd> {
    let res = unsafe { libc::epoll_create(1024) };

    Errno::result(res)
}

#[inline]
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
    let res = unsafe { libc::epoll_create1(flags.bits()) };

    Errno::result(res)
}

#[inline]
pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
    where T: Into<&'a mut EpollEvent>
{
    let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.into().event) };
    Errno::result(res).map(drop)
}

#[inline]
pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
    let res = unsafe {
        libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
    };

    Errno::result(res).map(|r| r as usize)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use handlebars::{Handlebars, Template};
use std::collections::BTreeMap;
use std::sync::Arc;

use message::Message;
use state::State;
use timer::TimerEvent;
use context::base::BaseContext;
use dispatcher::request::Request;
use dispatcher::response::ResponseSender;

const CONTEXT_ID: &'static str = ".context.id";

pub struct MapContext {
    base: BaseContext,
    map: BTreeMap<String, State>,
    context_id: Handlebars,
}

impl MapContext {
    pub fn new(base: BaseContext, context_id: Template) -> MapContext {
        let mut handlebars = Handlebars::new();
        handlebars.register_template(CONTEXT_ID, context_id);
        MapContext {
            base: base,
            map: BTreeMap::new(),
            context_id: handlebars,
        }
    }

    pub fn on_event(&mut self, event: Request, responder: &mut ResponseSender) {
        trace!("MapContext: received event");
        match event {
            Request::Timer(event) => self.on_timer(&event, responder),
            Request::Message(message) => self.on_message(message, responder),
            _ => {}
        }
    }

    #[allow(for_kv_map)]
    pub fn on_timer(&mut self, event: &TimerEvent, responder: &mut ResponseSender) {
        for (_, mut state) in &mut self.map {
            self.base.on_timer(event, &mut state, responder);
        }
        self.remove_closed_states();
    }

    fn get_closed_state_ids(&self) -> Vec<String> {
        self.map
            .iter()
            .filter_map(|(id, state)| {
                if !state.is_open() {
                    Some(id.clone())
                } else {
                    None
                }
            })
            .collect::<Vec<String>>()
    }

    fn remove_closed_states(&mut self) {
        for id in self.get_closed_state_ids() {
            let _ = self.map.remove(&id);
        }
    }

    pub fn on_message(&mut self, event: Arc<Message>, responder: &mut ResponseSender) {
        self.update_state(event, responder);
        self.remove_closed_states();
    }

    fn update_state(&mut self, event: Arc<Message>, responder: &mut ResponseSender) {
        if let Ok(id) = self.context_id.render(CONTEXT_ID, event.values()) {
            let mut state = self.map.entry(id).or_insert_with(State::new);
            self.base.on_message(event, &mut state, responder);
        } else {
            error!("Failed to render the context-id: {:?}",
                   self.context_id.get_template(&CONTEXT_ID.to_owned()));
        }
    }

    #[allow(dead_code)]
    pub fn is_open(&self) -> bool {
        !self.map.is_empty()
    }

    pub fn patterns(&self) -> &[String] {
        &self.base.patterns
    }
}
<commit_msg>MapContext: fix clippy warning<commit_after>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use handlebars::{Handlebars, Template};
use std::collections::BTreeMap;
use std::sync::Arc;

use message::Message;
use state::State;
use timer::TimerEvent;
use context::base::BaseContext;
use dispatcher::request::Request;
use dispatcher::response::ResponseSender;

const CONTEXT_ID: &'static str = ".context.id";

pub struct MapContext {
    base: BaseContext,
    map: BTreeMap<String, State>,
    context_id: Handlebars,
}

impl MapContext {
    pub fn new(base: BaseContext, context_id: Template) -> MapContext {
        let mut handlebars = Handlebars::new();
        handlebars.register_template(CONTEXT_ID, context_id);
        MapContext {
            base: base,
            map: BTreeMap::new(),
            context_id: handlebars,
        }
    }

    pub fn on_event(&mut self, event: Request, responder: &mut ResponseSender) {
        trace!("MapContext: received event");
        match event {
            Request::Timer(event) => self.on_timer(&event, responder),
            Request::Message(message) => self.on_message(message, responder),
            _ => {}
        }
    }

    #[allow(for_kv_map)]
    pub fn on_timer(&mut self, event: &TimerEvent, responder: &mut ResponseSender) {
        for (_, mut state) in &mut self.map {
            self.base.on_timer(event, &mut state, responder);
        }
        self.remove_closed_states();
    }

    fn get_closed_state_ids(&self) -> Vec<String> {
        self.map
            .iter()
            .filter_map(|(id, state)| {
                if state.is_open() {
                    None
                } else {
                    Some(id.clone())
                }
            })
            .collect::<Vec<String>>()
    }

    fn remove_closed_states(&mut self) {
        for id in self.get_closed_state_ids() {
            let _ = self.map.remove(&id);
        }
    }

    pub fn on_message(&mut self, event: Arc<Message>, responder: &mut ResponseSender) {
        self.update_state(event, responder);
        self.remove_closed_states();
    }

    fn update_state(&mut self, event: Arc<Message>, responder: &mut ResponseSender) {
        if let Ok(id) = self.context_id.render(CONTEXT_ID, event.values()) {
            let mut state = self.map.entry(id).or_insert_with(State::new);
            self.base.on_message(event, &mut state, responder);
        } else {
            error!("Failed to render the context-id: {:?}",
                   self.context_id.get_template(&CONTEXT_ID.to_owned()));
        }
    }

    #[allow(dead_code)]
    pub fn is_open(&self) -> bool {
        !self.map.is_empty()
    }

    pub fn patterns(&self) -> &[String] {
        &self.base.patterns
    }
}
<|endoftext|>


<commit_before>/// The tokenizer for the query interpreter

use error::*;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Identifier {
        ident: String,
        next: Option<Box<Token>>
    },

    Index {
        idx: usize,
        next: Option<Box<Token>>
    }
}

impl Token {

    pub fn next(&self) -> Option<&Box<Token>> {
        match self {
            &Token::Identifier { ref next, .. } => next.as_ref(),
            &Token::Index { ref next, .. }      => next.as_ref(),
        }
    }

    /// Convenience function for `token.next().is_some()`
    pub fn has_next(&self) -> bool {
        self.next().is_some()
    }

    pub fn set_next(&mut self, token: Token) {
        match self {
            &mut Token::Identifier { ref mut next, .. } => *next = Some(Box::new(token)),
            &mut Token::Index { ref mut next, .. }      => *next = Some(Box::new(token)),
        }
    }

    /// Pop the last token from the chain of tokens
    ///
    /// Returns None if the current Token has no next token
    pub fn pop_last(&mut self) -> Option<Box<Token>> {
        if !self.has_next() {
            None
        } else {
            match self {
                &mut Token::Identifier { next: ref mut next, .. } => {
                    if next.is_some() {
                        let mut next = next.take().unwrap();
                        if next.has_next() {
                            next.pop_last()
                        } else {
                            Some(next)
                        }
                    } else {
                        None
                    }
                },

                &mut Token::Index { next: ref mut next, .. } => {
                    next.take()
                },
            }
        }
    }

    #[cfg(test)]
    pub fn identifier(&self) -> &String {
        match self {
            &Token::Identifier { ref ident, .. } => &ident,
            _ => unreachable!(),
        }
    }

    #[cfg(test)]
    pub fn idx(&self) -> usize {
        match self {
            &Token::Index { idx: i, .. } => i,
            _ => unreachable!(),
        }
    }

}

pub fn tokenize_with_seperator(query: &String, seperator: char) -> Result<Token> {
    use std::str::Split;

    /// Creates a Token object from a string
    ///
    /// # Panics
    ///
    /// * If the internal regex does not compile (should never happen)
    /// * If the token is non-valid (that is, a array index with a non-i64)
    /// * If the regex does not find anything
    /// * If the integer in the brackets (`[]`) cannot be parsed to a valid i64
    ///
    /// # Incorrect behaviour
    ///
    /// * If the regex finds multiple captures
    ///
    /// # Returns
    ///
    /// The `Token` object with the correct identifier/index for this token and no next token.
    ///
    fn mk_token_object(s: &str) -> Result<Token> {
        use regex::Regex;
        use std::str::FromStr;

        lazy_static! {
            static ref RE: Regex = Regex::new(r"^\[\d+\]$").unwrap();
        }

        if !has_array_brackets(s) {
            return Ok(Token::Identifier { ident: String::from(s), next: None });
        }

        match RE.captures(s) {
            None => return Err(Error::from(ErrorKind::ArrayAccessWithoutIndex)),
            Some(captures) => {
                match captures.get(0) {
                    None => Ok(Token::Identifier { ident: String::from(s), next: None }),
                    Some(mtch) => {
                        let mtch = without_array_brackets(mtch.as_str());
                        let i : usize = FromStr::from_str(&mtch).unwrap(); // save because regex
                        Ok(Token::Index {
                            idx: i,
                            next: None,
                        })
                    }
                }
            }
        }
    }

    /// Check whether a str begins with '[' and ends with ']'
    fn has_array_brackets(s: &str) -> bool {
        s.as_bytes()[0] == b'[' && s.as_bytes()[s.len() - 1] == b']'
    }

    /// Remove '[' and ']' from a str
    fn without_array_brackets(s: &str) -> String {
        s.replace("[","").replace("]","")
    }

    fn build_token_tree(split: &mut Split<char>, last: &mut Token) -> Result<()> {
        match split.next() {
            None        => { /* No more tokens */ }
            Some(token) => {
                if token.len() == 0 {
                    return Err(Error::from(ErrorKind::EmptyIdentifier));
                }
                let mut token = try!(mk_token_object(token));
                try!(build_token_tree(split, &mut token));
                last.set_next(token);
            }
        }
        Ok(())
    }

    if query.is_empty() {
        return Err(Error::from(ErrorKind::EmptyQueryError));
    }

    let mut tokens = query.split(seperator);

    match tokens.next() {
        None        => Err(Error::from(ErrorKind::EmptyQueryError)),
        Some(token) => {
            if token.len() == 0 {
                return Err(Error::from(ErrorKind::EmptyIdentifier));
            }
            let mut tok = try!(mk_token_object(token));
            let _       = try!(build_token_tree(&mut tokens, &mut tok));
            Ok(tok)
        }
    }
}

#[cfg(test)]
mod test {
    use error::ErrorKind;
    use super::*;

    use std::ops::Deref;

    #[test]
    fn test_tokenize_empty_query_to_error() {
        let tokens = tokenize_with_seperator(&String::from(""), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyQueryError { .. }));
    }

    #[test]
    fn test_tokenize_seperator_only() {
        let tokens = tokenize_with_seperator(&String::from("."), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    #[test]
    fn test_tokenize_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_with_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_in_array_brackets() {
        let tokens = tokenize_with_seperator(&String::from("[a]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_single_token_query() {
        let tokens = tokenize_with_seperator(&String::from("example"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { ref ident, next: None } => {
                assert_eq!("example", ident);
                true
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_double_token_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!("b", next.deref().identifier());
                match next.deref() {
                    &Token::Identifier { next: None, .. } => true,
                    _ => false
                }
            },
            _ => false,
        });
        assert_eq!("a", tokens.identifier());
    }

    #[test]
    fn test_tokenize_ident_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.[0]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());
        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                match next.deref() {
                    &Token::Index { idx: 0, next: None } => true,
                    _ => false
                }
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_many_idents_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[1000]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());

        let expected =
            Token::Identifier {
                ident: String::from("a"),
                next: Some(Box::new(Token::Identifier {
                    ident: String::from("b"),
                    next: Some(Box::new(Token::Identifier {
                        ident: String::from("c"),
                        next: Some(Box::new(Token::Index {
                            idx: 1000,
                            next: None,
                        })),
                    })),
                })),
            };

        assert_eq!(expected, tokens);
    }

    #[test]
    fn test_tokenize_empty_token_after_good_token() {
        let tokens = tokenize_with_seperator(&String::from("a..b"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    quickcheck! {
        fn test_array_index(i: usize) -> bool {
            match tokenize_with_seperator(&format!("[{}]", i), '.') {
                Ok(Token::Index { next: None, ..  }) => true,
                _                                    => false,
            }
        }
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_none() {
        let mut token = Token::Identifier {
            ident: String::from("something"),
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_none() {
        let mut token = Token::Index {
            idx: 0,
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_one() {
        let mut token = Token::Identifier {
            ident: String::from("some"),
            next: Some(Box::new(Token::Identifier {
                ident: String::from("thing"),
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Identifier { .. }));
        match *last {
            Token::Identifier { ident: ident, .. } => {
                assert_eq!("thing", ident);
            }
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_one() {
        let mut token = Token::Index {
            idx: 0,
            next: Some(Box::new(Token::Index {
                idx: 1,
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Index { idx: 1, .. }));
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_one_token() {
        let tokens = tokenize_with_seperator(&String::from("a"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_none());
    }

}
<commit_msg>Impl Token::pop_last to fix test_pop_last_token_from_mixed_chain_is_array<commit_after>/// The tokenizer for the query interpreter

use error::*;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Identifier {
        ident: String,
        next: Option<Box<Token>>
    },

    Index {
        idx: usize,
        next: Option<Box<Token>>
    }
}

impl Token {

    pub fn next(&self) -> Option<&Box<Token>> {
        match self {
            &Token::Identifier { ref next, .. } => next.as_ref(),
            &Token::Index { ref next, .. }      => next.as_ref(),
        }
    }

    /// Convenience function for `token.next().is_some()`
    pub fn has_next(&self) -> bool {
        self.next().is_some()
    }

    pub fn set_next(&mut self, token: Token) {
        match self {
            &mut Token::Identifier { ref mut next, .. } => *next = Some(Box::new(token)),
            &mut Token::Index { ref mut next, .. }      => *next = Some(Box::new(token)),
        }
    }

    /// Pop the last token from the chain of tokens
    ///
    /// Returns None if the current Token has no next token
    pub fn pop_last(&mut self) -> Option<Box<Token>> {
        if !self.has_next() {
            None
        } else {
            match self {
                &mut Token::Identifier { next: ref mut next, .. } => {
                    if next.is_some() {
                        let mut next = next.take().unwrap();
                        if next.has_next() {
                            next.pop_last()
                        } else {
                            Some(next)
                        }
                    } else {
                        None
                    }
                },

                &mut Token::Index { next: ref mut next, .. } => {
                    if next.is_some() {
                        let mut next = next.take().unwrap();
                        if next.has_next() {
                            next.pop_last()
                        } else {
                            Some(next)
                        }
                    } else {
                        None
                    }
                },
            }
        }
    }

    #[cfg(test)]
    pub fn identifier(&self) -> &String {
        match self {
            &Token::Identifier { ref ident, .. } => &ident,
            _ => unreachable!(),
        }
    }

    #[cfg(test)]
    pub fn idx(&self) -> usize {
        match self {
            &Token::Index { idx: i, .. } => i,
            _ => unreachable!(),
        }
    }

}

pub fn tokenize_with_seperator(query: &String, seperator: char) -> Result<Token> {
    use std::str::Split;

    /// Creates a Token object from a string
    ///
    /// # Panics
    ///
    /// * If the internal regex does not compile (should never happen)
    /// * If the token is non-valid (that is, a array index with a non-i64)
    /// * If the regex does not find anything
    /// * If the integer in the brackets (`[]`) cannot be parsed to a valid i64
    ///
    /// # Incorrect behaviour
    ///
    /// * If the regex finds multiple captures
    ///
    /// # Returns
    ///
    /// The `Token` object with the correct identifier/index for this token and no next token.
    ///
    fn mk_token_object(s: &str) -> Result<Token> {
        use regex::Regex;
        use std::str::FromStr;

        lazy_static! {
            static ref RE: Regex = Regex::new(r"^\[\d+\]$").unwrap();
        }

        if !has_array_brackets(s) {
            return Ok(Token::Identifier { ident: String::from(s), next: None });
        }

        match RE.captures(s) {
            None => return Err(Error::from(ErrorKind::ArrayAccessWithoutIndex)),
            Some(captures) => {
                match captures.get(0) {
                    None => Ok(Token::Identifier { ident: String::from(s), next: None }),
                    Some(mtch) => {
                        let mtch = without_array_brackets(mtch.as_str());
                        let i : usize = FromStr::from_str(&mtch).unwrap(); // save because regex
                        Ok(Token::Index {
                            idx: i,
                            next: None,
                        })
                    }
                }
            }
        }
    }

    /// Check whether a str begins with '[' and ends with ']'
    fn has_array_brackets(s: &str) -> bool {
        s.as_bytes()[0] == b'[' && s.as_bytes()[s.len() - 1] == b']'
    }

    /// Remove '[' and ']' from a str
    fn without_array_brackets(s: &str) -> String {
        s.replace("[","").replace("]","")
    }

    fn build_token_tree(split: &mut Split<char>, last: &mut Token) -> Result<()> {
        match split.next() {
            None        => { /* No more tokens */ }
            Some(token) => {
                if token.len() == 0 {
                    return Err(Error::from(ErrorKind::EmptyIdentifier));
                }
                let mut token = try!(mk_token_object(token));
                try!(build_token_tree(split, &mut token));
                last.set_next(token);
            }
        }
        Ok(())
    }

    if query.is_empty() {
        return Err(Error::from(ErrorKind::EmptyQueryError));
    }

    let mut tokens = query.split(seperator);

    match tokens.next() {
        None        => Err(Error::from(ErrorKind::EmptyQueryError)),
        Some(token) => {
            if token.len() == 0 {
                return Err(Error::from(ErrorKind::EmptyIdentifier));
            }
            let mut tok = try!(mk_token_object(token));
            let _       = try!(build_token_tree(&mut tokens, &mut tok));
            Ok(tok)
        }
    }
}

#[cfg(test)]
mod test {
    use error::ErrorKind;
    use super::*;

    use std::ops::Deref;

    #[test]
    fn test_tokenize_empty_query_to_error() {
        let tokens = tokenize_with_seperator(&String::from(""), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyQueryError { .. }));
    }

    #[test]
    fn test_tokenize_seperator_only() {
        let tokens = tokenize_with_seperator(&String::from("."), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    #[test]
    fn test_tokenize_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_with_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_in_array_brackets() {
        let tokens = tokenize_with_seperator(&String::from("[a]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_single_token_query() {
        let tokens = tokenize_with_seperator(&String::from("example"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { ref ident, next: None } => {
                assert_eq!("example", ident);
                true
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_double_token_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!("b", next.deref().identifier());
                match next.deref() {
                    &Token::Identifier { next: None, .. } => true,
                    _ => false
                }
            },
            _ => false,
        });
        assert_eq!("a", tokens.identifier());
    }

    #[test]
    fn test_tokenize_ident_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.[0]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());
        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                match next.deref() {
                    &Token::Index { idx: 0, next: None } => true,
                    _ => false
                }
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_many_idents_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[1000]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());

        let expected =
            Token::Identifier {
                ident: String::from("a"),
                next: Some(Box::new(Token::Identifier {
                    ident: String::from("b"),
                    next: Some(Box::new(Token::Identifier {
                        ident: String::from("c"),
                        next: Some(Box::new(Token::Index {
                            idx: 1000,
                            next: None,
                        })),
                    })),
                })),
            };

        assert_eq!(expected, tokens);
    }

    #[test]
    fn test_tokenize_empty_token_after_good_token() {
        let tokens = tokenize_with_seperator(&String::from("a..b"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    quickcheck! {
        fn test_array_index(i: usize) -> bool {
            match tokenize_with_seperator(&format!("[{}]", i), '.') {
                Ok(Token::Index { next: None, ..  }) => true,
                _                                    => false,
            }
        }
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_none() {
        let mut token = Token::Identifier {
            ident: String::from("something"),
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_none() {
        let mut token = Token::Index {
            idx: 0,
            next: None,
        };

        let last = token.pop_last();
        assert!(last.is_none());
    }

    #[test]
    fn test_pop_last_token_from_single_identifier_token_is_one() {
        let mut token = Token::Identifier {
            ident: String::from("some"),
            next: Some(Box::new(Token::Identifier {
                ident: String::from("thing"),
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Identifier { .. }));
        match *last {
            Token::Identifier { ident: ident, .. } => {
                assert_eq!("thing", ident);
            }
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_pop_last_token_from_single_index_token_is_one() {
        let mut token = Token::Index {
            idx: 0,
            next: Some(Box::new(Token::Index {
                idx: 1,
                next: None,
            })),
        };

        let last = token.pop_last();

        assert!(last.is_some());
        let last = last.unwrap();

        assert!(is_match!(*last, Token::Index { idx: 1, .. }));
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!("f", last.unwrap().identifier());
    }

    #[test]
    fn test_pop_last_token_from_identifier_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.d.e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_mixed_chain_is_array() {
        let tokens = tokenize_with_seperator(&String::from("a.[100].c.[3].e.f.[1000]"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_some());
        assert_eq!(1000, last.unwrap().idx());
    }

    #[test]
    fn test_pop_last_token_from_one_token() {
        let tokens = tokenize_with_seperator(&String::from("a"), '.');
        assert!(tokens.is_ok());
        let mut tokens = tokens.unwrap();

        let last = tokens.pop_last();
        assert!(last.is_none());
    }

}
<|endoftext|>


<commit_before>use Request;

use std::io::Read;
use std::error::Error;

/// Request and response transport abstraction.
///
/// The `Transport` trait provides a way to send a `Request` to a server and to receive the
/// corresponding response. A `Transport` implementor is passed to [`Request::call`] in order to use
/// it to perform that request.
///
/// The most commonly used transport is simple HTTP: If the `reqwest` feature is enabled (it is by
/// default), the reqwest `RequestBuilder` will implement this trait and send the XML-RPC
/// [`Request`] via HTTP.
///
/// You can implement this trait for your own types if you want to customize how requests are sent.
/// You can modify HTTP headers or wrap requests in a completely different protocol.
///
/// [`Request::call`]: struct.Request.html#method.call
/// [`Request`]: struct.Request.html
pub trait Transport {
    // FIXME replace with `impl Trait` when stable
    /// The response stream returned by `transmit`.
    type Stream: Read;

    /// Transmits an XML-RPC request and returns the server's response.
    ///
    /// The response is returned as a `Self::Stream` - some type implementing the `Read` trait. The
    /// library will read all of the data and parse it as a response. It must be UTF-8 encoded XML,
    /// otherwise the call will fail.
    ///
    /// # Errors
    ///
    /// If a transport error occurs, it should be returned as a boxed error - the library will then
    /// return an appropriate [`Error`] to the caller.
    ///
    /// [`Error`]: struct.Error.html
    fn transmit(self, request: &Request) -> Result<Self::Stream, Box<Error + Send + Sync>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
// everything and abs. links don't work locally.
/// Provides helpers for implementing custom `Transport`s using reqwest.
///
/// This module will be disabled if the `reqwest` feature is not enabled.
///
/// The default [`Transport`] implementation for `RequestBuilder` looks roughly like
/// this:
///
/// ```notrust
/// // serialize request into `body` (a `Vec<u8>`)
///
/// build_headers(builder, body.len());
///
/// // send `body` using `builder` and get response
///
/// check_response(&response)?;
/// ```
///
/// From this, you can build your own custom transports.
///
/// [`Transport`]: ../trait.Transport.html
#[cfg(feature = "reqwest")]
pub mod http {
    extern crate reqwest;

    use {Request, Transport};
    use self::reqwest::{RequestBuilder, mime};
    use self::reqwest::header::{ContentType, ContentLength, UserAgent};

    use std::error::Error;

    /// Appends all HTTP headers required by the XML-RPC specification to the `RequestBuilder`.
    ///
    /// More specifically, the following headers are set:
    ///
    /// ```notrust
    /// User-Agent: Rust xmlrpc
    /// Content-Type: text/xml; charset=utf-8
    /// Content-Length: $body_len
    /// ```
    pub fn build_headers(builder: &mut RequestBuilder, body_len: u64) {
        // Set all required request headers
        // NB: The `Host` header is also required, but reqwest adds it automatically, since
        // HTTP/1.1 requires it.
        builder
            .header(UserAgent::new("Rust xmlrpc"))
            .header(ContentType("text/xml; charset=utf-8".parse().unwrap()))
            .header(ContentLength(body_len));
    }

    /// Checks that a reqwest `Response` has a status code indicating success and verifies certain
    /// headers.
    pub fn check_response(response: &reqwest::Response) -> Result<(), Box<Error + Send + Sync>> {
        // This is essentially an open-coded version of `Response::error_for_status` that does not
        // consume the response.
        if response.status().is_client_error() || response.status().is_server_error() {
            return Err(format!("server response indicates error: {}", response.status()).into());
        }

        // Check response headers
        // "The Content-Type is text/xml. Content-Length must be present and correct."
        if let Some(content) = response.headers().get::<ContentType>() {
            // (we ignore this if the header is missing completely)
            match (content.type_(), content.subtype()) {
                (mime::TEXT, mime::XML) => {},
                (ty, sub) => return Err(
                    format!("expected Content-Type 'text/xml', got '{}/{}'", ty, sub).into()
                ),
            }
        }

        Ok(())
    }

    /// Use a `RequestBuilder` as the transport.
    ///
    /// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
    /// will be set, along with the correct `Content-Type` and `Content-Length`.
    impl Transport for RequestBuilder {
        type Stream = reqwest::Response;

        fn transmit(mut self, request: &Request) -> Result<Self::Stream, Box<Error + Send + Sync>> {
            // First, build the body XML
            let mut body = Vec::new();
            // This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
            // and not doing anything else that could return an `Err` in `write_as_xml()`.
            request.write_as_xml(&mut body).unwrap();

            build_headers(&mut self, body.len() as u64);

            let response = self
                .body(body)
                .send()?;

            check_response(&response)?;

            Ok(response)
        }
    }
}
<commit_msg>Add comment explaining why Content-Length isn't checked<commit_after>use Request;

use std::io::Read;
use std::error::Error;

/// Request and response transport abstraction.
///
/// The `Transport` trait provides a way to send a `Request` to a server and to receive the
/// corresponding response. A `Transport` implementor is passed to [`Request::call`] in order to use
/// it to perform that request.
///
/// The most commonly used transport is simple HTTP: If the `reqwest` feature is enabled (it is by
/// default), the reqwest `RequestBuilder` will implement this trait and send the XML-RPC
/// [`Request`] via HTTP.
///
/// You can implement this trait for your own types if you want to customize how requests are sent.
/// You can modify HTTP headers or wrap requests in a completely different protocol.
///
/// [`Request::call`]: struct.Request.html#method.call
/// [`Request`]: struct.Request.html
pub trait Transport {
    // FIXME replace with `impl Trait` when stable
    /// The response stream returned by `transmit`.
    type Stream: Read;

    /// Transmits an XML-RPC request and returns the server's response.
    ///
    /// The response is returned as a `Self::Stream` - some type implementing the `Read` trait. The
    /// library will read all of the data and parse it as a response. It must be UTF-8 encoded XML,
    /// otherwise the call will fail.
    ///
    /// # Errors
    ///
    /// If a transport error occurs, it should be returned as a boxed error - the library will then
    /// return an appropriate [`Error`] to the caller.
    ///
    /// [`Error`]: struct.Error.html
    fn transmit(self, request: &Request) -> Result<Self::Stream, Box<Error + Send + Sync>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
// everything and abs. links don't work locally.
/// Provides helpers for implementing custom `Transport`s using reqwest.
///
/// This module will be disabled if the `reqwest` feature is not enabled.
///
/// The default [`Transport`] implementation for `RequestBuilder` looks roughly like
/// this:
///
/// ```notrust
/// // serialize request into `body` (a `Vec<u8>`)
///
/// build_headers(builder, body.len());
///
/// // send `body` using `builder` and get response
///
/// check_response(&response)?;
/// ```
///
/// From this, you can build your own custom transports.
///
/// [`Transport`]: ../trait.Transport.html
#[cfg(feature = "reqwest")]
pub mod http {
    extern crate reqwest;

    use {Request, Transport};
    use self::reqwest::{RequestBuilder, mime};
    use self::reqwest::header::{ContentType, ContentLength, UserAgent};

    use std::error::Error;

    /// Appends all HTTP headers required by the XML-RPC specification to the `RequestBuilder`.
    ///
    /// More specifically, the following headers are set:
    ///
    /// ```notrust
    /// User-Agent: Rust xmlrpc
    /// Content-Type: text/xml; charset=utf-8
    /// Content-Length: $body_len
    /// ```
    pub fn build_headers(builder: &mut RequestBuilder, body_len: u64) {
        // Set all required request headers
        // NB: The `Host` header is also required, but reqwest adds it automatically, since
        // HTTP/1.1 requires it.
        builder
            .header(UserAgent::new("Rust xmlrpc"))
            .header(ContentType("text/xml; charset=utf-8".parse().unwrap()))
            .header(ContentLength(body_len));
    }

    /// Checks that a reqwest `Response` has a status code indicating success and verifies certain
    /// headers.
    pub fn check_response(response: &reqwest::Response) -> Result<(), Box<Error + Send + Sync>> {
        // This is essentially an open-coded version of `Response::error_for_status` that does not
        // consume the response.
        if response.status().is_client_error() || response.status().is_server_error() {
            return Err(format!("server response indicates error: {}", response.status()).into());
        }

        // Check response headers
        // "The Content-Type is text/xml. Content-Length must be present and correct."
        if let Some(content) = response.headers().get::<ContentType>() {
            // (we ignore this if the header is missing completely)
            match (content.type_(), content.subtype()) {
                (mime::TEXT, mime::XML) => {},
                (ty, sub) => return Err(
                    format!("expected Content-Type 'text/xml', got '{}/{}'", ty, sub).into()
                ),
            }
        }

        // We ignore the Content-Length header because it doesn't matter for the parser and reqwest
        // will remove it when the response is gzip compressed.

        Ok(())
    }

    /// Use a `RequestBuilder` as the transport.
    ///
    /// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
    /// will be set, along with the correct `Content-Type` and `Content-Length`.
    impl Transport for RequestBuilder {
        type Stream = reqwest::Response;

        fn transmit(mut self, request: &Request) -> Result<Self::Stream, Box<Error + Send + Sync>> {
            // First, build the body XML
            let mut body = Vec::new();
            // This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
            // and not doing anything else that could return an `Err` in `write_as_xml()`.
            request.write_as_xml(&mut body).unwrap();

            build_headers(&mut self, body.len() as u64);

            let response = self
                .body(body)
                .send()?;

            check_response(&response)?;

            Ok(response)
        }
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Joseph Crail <jbcrail@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

#[cfg(unix)]
use super::libc;
use std::env;
use std::fs;
use std::io::{Error, ErrorKind};
use std::io::Result as IOResult;
use std::path::{Component, Path, PathBuf};
use std::borrow::Cow;

pub fn resolve_relative_path<'a>(path: &'a Path) -> Cow<'a, Path> {
    if path.components().all(|e| e != Component::ParentDir) {
        return path.into();
    }
    let root = Component::RootDir.as_os_str();
    let mut result = env::current_dir().unwrap_or(PathBuf::from(root));
    for comp in path.components() {
        match comp {
            Component::ParentDir => {
                result.pop();
            }
            Component::CurDir => (),
            Component::RootDir |
            Component::Normal(_) |
            Component::Prefix(_) => result.push(comp.as_os_str()),
        }
    }
    result.into()
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode {
    None,
    Normal,
    Existing,
    Missing,
}

fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
    const MAX_LINKS_FOLLOWED: u32 = 255;
    let mut followed = 0;
    let mut result = original.as_ref().to_path_buf();
    loop {
        if followed == MAX_LINKS_FOLLOWED {
            return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed"));
        }

        match fs::symlink_metadata(&result) {
            Err(e) => return Err(e),
            Ok(ref m) if !m.file_type().is_symlink() => break,
            Ok(..) => {
                followed += 1;
                match fs::read_link(&result) {
                    Ok(path) => {
                        result.pop();
                        result.push(path);
                    }
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }
    }
    Ok(result)
}

pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> IOResult<PathBuf> {
    // Create an absolute path
    let original = original.as_ref();
    let original = if original.is_absolute() {
        original.to_path_buf()
    } else {
        env::current_dir().unwrap().join(original)
    };

    let mut result = PathBuf::new();
    let mut parts = vec![];

    // Split path by directory separator; add prefix (Windows-only) and root
    // directory to final path buffer; add remaining parts to temporary
    // vector for canonicalization.
    for part in original.components() {
        match part {
            Component::Prefix(_) |
            Component::RootDir => {
                result.push(part.as_os_str());
            }
            Component::CurDir => (),
            Component::ParentDir => {
                parts.pop();
            }
            Component::Normal(_) => {
                parts.push(part.as_os_str());
            }
        }
    }

    // Resolve the symlinks where possible
    if !parts.is_empty() {
        for part in parts[..parts.len() - 1].iter() {
            result.push(part);

            if can_mode == CanonicalizeMode::None {
                continue;
            }

            match resolve(&result) {
                Err(e) => {
                    match can_mode {
                        CanonicalizeMode::Missing => continue,
                        _ => return Err(e),
                    }
                }
                Ok(path) => {
                    result.pop();
                    result.push(path);
                }
            }
        }

        result.push(parts.last().unwrap());

        match resolve(&result) {
            Err(e) => {
                if can_mode == CanonicalizeMode::Existing {
                    return Err(e);
                }
            }
            Ok(path) => {
                result.pop();
                result.push(path);
            }
        }
    }
    Ok(result)
}

#[cfg(unix)]
pub fn is_stdin_interactive() -> bool {
    unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdin_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stdout_interactive() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdout_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stderr_interactive() -> bool {
    unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stderr_interactive() -> bool {
    false
}
<commit_msg>Fix a number of Windows build warnings<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Joseph Crail <jbcrail@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

#[cfg(unix)]
use super::libc;
use std::env;
use std::fs;
use std::io::{Error, ErrorKind};
use std::io::Result as IOResult;
use std::path::{Component, Path, PathBuf};
#[cfg(unix)]
use std::borrow::Cow;

pub fn resolve_relative_path<'a>(path: &'a Path) -> Cow<'a, Path> {
    if path.components().all(|e| e != Component::ParentDir) {
        return path.into();
    }
    let root = Component::RootDir.as_os_str();
    let mut result = env::current_dir().unwrap_or(PathBuf::from(root));
    for comp in path.components() {
        match comp {
            Component::ParentDir => {
                result.pop();
            }
            Component::CurDir => (),
            Component::RootDir |
            Component::Normal(_) |
            Component::Prefix(_) => result.push(comp.as_os_str()),
        }
    }
    result.into()
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode {
    None,
    Normal,
    Existing,
    Missing,
}

fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
    const MAX_LINKS_FOLLOWED: u32 = 255;
    let mut followed = 0;
    let mut result = original.as_ref().to_path_buf();
    loop {
        if followed == MAX_LINKS_FOLLOWED {
            return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed"));
        }

        match fs::symlink_metadata(&result) {
            Err(e) => return Err(e),
            Ok(ref m) if !m.file_type().is_symlink() => break,
            Ok(..) => {
                followed += 1;
                match fs::read_link(&result) {
                    Ok(path) => {
                        result.pop();
                        result.push(path);
                    }
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }
    }
    Ok(result)
}

pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> IOResult<PathBuf> {
    // Create an absolute path
    let original = original.as_ref();
    let original = if original.is_absolute() {
        original.to_path_buf()
    } else {
        env::current_dir().unwrap().join(original)
    };

    let mut result = PathBuf::new();
    let mut parts = vec![];

    // Split path by directory separator; add prefix (Windows-only) and root
    // directory to final path buffer; add remaining parts to temporary
    // vector for canonicalization.
    for part in original.components() {
        match part {
            Component::Prefix(_) |
            Component::RootDir => {
                result.push(part.as_os_str());
            }
            Component::CurDir => (),
            Component::ParentDir => {
                parts.pop();
            }
            Component::Normal(_) => {
                parts.push(part.as_os_str());
            }
        }
    }

    // Resolve the symlinks where possible
    if !parts.is_empty() {
        for part in parts[..parts.len() - 1].iter() {
            result.push(part);

            if can_mode == CanonicalizeMode::None {
                continue;
            }

            match resolve(&result) {
                Err(e) => {
                    match can_mode {
                        CanonicalizeMode::Missing => continue,
                        _ => return Err(e),
                    }
                }
                Ok(path) => {
                    result.pop();
                    result.push(path);
                }
            }
        }

        result.push(parts.last().unwrap());

        match resolve(&result) {
            Err(e) => {
                if can_mode == CanonicalizeMode::Existing {
                    return Err(e);
                }
            }
            Ok(path) => {
                result.pop();
                result.push(path);
            }
        }
    }
    Ok(result)
}

#[cfg(unix)]
pub fn is_stdin_interactive() -> bool {
    unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdin_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stdout_interactive() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdout_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stderr_interactive() -> bool {
    unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stderr_interactive() -> bool {
    false
}
<|endoftext|>