<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::TypedBuffer;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor::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 {
    ($($name:ident: { $($field:ident: $ty:ty),* }),*) => {
        use std::sync::Arc;
        use std::vec::IntoIter as VecIntoIter;
        use $crate::OomError;
        use $crate::device::Device;
        use $crate::descriptor::descriptor::DescriptorDesc;
        use $crate::descriptor::pipeline_layout::PipelineLayout;
        use $crate::descriptor::pipeline_layout::PipelineLayoutDesc;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayout;

        pub struct CustomPipeline {
            inner: UnsafePipelineLayout
        }

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

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

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

        #[allow(unsafe_code)]
        unsafe impl PipelineLayout for CustomPipeline {
            #[inline]
            fn inner_pipeline_layout(&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),*})*}
    };

    (__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::DescriptorWrite;
            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::pipeline_layout::PipelineLayout;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::CombinedImageSampler;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::DescriptorMarker;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformBuffer;
            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 new<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field),*>)
                           -> Result<Arc<Set>, OomError>
                {
                    #![allow(unsafe_code)]
                    unsafe {
                        let layout = layout.inner_pipeline_layout().descriptor_set_layout($num).unwrap();
                        let mut set = try!(UnsafeDescriptorSet::uninitialized(pool, layout));
                        set.write(descriptors.writes());
                        Ok(Arc::new(Set { inner: set }))
                    }
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSet for Set {
                #[inline]
                fn inner_descriptor_set(&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)]
            pub fn build_set_layout(device: &Arc<Device>)
                                    -> Result<Arc<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:
                    });

                    binding += 1;
                )*

                UnsafeDescriptorSetLayout::new(device, descriptors.into_iter())
            }
        }

        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() -> DescriptorType;
}

pub struct UniformBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for UniformBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::UniformBuffer
    }
}

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 CombinedImageSampler;
unsafe impl DescriptorMarker for CombinedImageSampler {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::CombinedImageSampler
    }
}

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)
    }
}

#[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>Add StorageBuffer marker for pipeline_layout! macro<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::TypedBuffer;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor::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 {
    ($($name:ident: { $($field:ident: $ty:ty),* }),*) => {
        use std::sync::Arc;
        use std::vec::IntoIter as VecIntoIter;
        use $crate::OomError;
        use $crate::device::Device;
        use $crate::descriptor::descriptor::DescriptorDesc;
        use $crate::descriptor::pipeline_layout::PipelineLayout;
        use $crate::descriptor::pipeline_layout::PipelineLayoutDesc;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayout;

        pub struct CustomPipeline {
            inner: UnsafePipelineLayout
        }

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

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

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

        #[allow(unsafe_code)]
        unsafe impl PipelineLayout for CustomPipeline {
            #[inline]
            fn inner_pipeline_layout(&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),*})*}
    };

    (__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::DescriptorWrite;
            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::pipeline_layout::PipelineLayout;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::CombinedImageSampler;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::DescriptorMarker;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformBuffer;
            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 new<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field),*>)
                           -> Result<Arc<Set>, OomError>
                {
                    #![allow(unsafe_code)]
                    unsafe {
                        let layout = layout.inner_pipeline_layout().descriptor_set_layout($num).unwrap();
                        let mut set = try!(UnsafeDescriptorSet::uninitialized(pool, layout));
                        set.write(descriptors.writes());
                        Ok(Arc::new(Set { inner: set }))
                    }
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSet for Set {
                #[inline]
                fn inner_descriptor_set(&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)]
            pub fn build_set_layout(device: &Arc<Device>)
                                    -> Result<Arc<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:
                    });

                    binding += 1;
                )*

                UnsafeDescriptorSetLayout::new(device, descriptors.into_iter())
            }
        }

        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() -> DescriptorType;
}

pub struct UniformBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for UniformBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::UniformBuffer
    }
}

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() -> DescriptorType {
        DescriptorType::StorageBuffer
    }
}

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 CombinedImageSampler;
unsafe impl DescriptorMarker for CombinedImageSampler {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::CombinedImageSampler
    }
}

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)
    }
}

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

//! Android ABI-compatibility module
//!
//! The ABI of Android has changed quite a bit over time, and libstd attempts to
//! be both forwards and backwards compatible as much as possible. We want to
//! always work with the most recent version of Android, but we also want to
//! work with older versions of Android for whenever projects need to.
//!
//! Our current minimum supported Android version is `android-9`, e.g. Android
//! with API level 9. We then in theory want to work on that and all future
//! versions of Android!
//!
//! Some of the detection here is done at runtime via `dlopen` and
//! introspection. Other times no detection is performed at all and we just
//! provide a fallback implementation as some versions of Android we support
//! don't have the function.
//!
//! You'll find more details below about why each compatibility shim is needed.

#![cfg(target_os = "android")]

use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
use libc::{ftruncate, pread, pwrite};

use convert::TryInto;
use io;
use super::{cvt, cvt_r};

// The `log2` and `log2f` functions apparently appeared in android-18, or at
// least you can see they're not present in the android-17 header [1] and they
// are present in android-18 [2].
//
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
//                                       /android-17/arch-arm/usr/include/math.h
// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
//                                       /android-18/arch-arm/usr/include/math.h
//
// Note that these shims are likely less precise than directly calling `log2`,
// but hopefully that should be enough for now...
//
// Note that mathematically, for any arbitrary `y`:
//
//      log_2(x) = log_y(x) / log_y(2)
//               = log_y(x) / (1 / log_2(y))
//               = log_y(x) * log_2(y)
//
// Hence because `ln` (log_e) is available on all Android we just choose `y = e`
// and get:
//
//      log_2(x) = ln(x) * log_2(e)

#[cfg(not(test))]
pub fn log2f32(f: f32) -> f32 {
    f.ln() * ::f32::consts::LOG2_E
}

#[cfg(not(test))]
pub fn log2f64(f: f64) -> f64 {
    f.ln() * ::f64::consts::LOG2_E
}

// Back in the day [1] the `signal` function was just an inline wrapper
// around `bsd_signal`, but starting in API level android-20 the `signal`
// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was
// removed [3].
//
// Basically this means that if we want to be binary compatible with multiple
// Android releases (oldest being 9 and newest being 21) then we need to check
// for both symbols and not actually link against either.
//
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
//                                       /android-18/arch-arm/usr/include/signal.h
// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental
//                                       /platforms/android-20/arch-arm
//                                       /usr/include/signal.h
// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms
//                                       /android-21/arch-arm/usr/include/signal.h
pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
    weak!(fn signal(c_int, sighandler_t) -> sighandler_t);
    weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t);

    let f = signal.get().or_else(|| bsd_signal.get());
    let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
    f(signum, handler)
}

// The `ftruncate64` symbol apparently appeared in android-12, so we do some
// dynamic detection to see if we can figure out whether `ftruncate64` exists.
//
// If it doesn't we just fall back to `ftruncate`, generating an error for
// too-large values.
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
    weak!(fn ftruncate64(c_int, i64) -> c_int);

    unsafe {
        match ftruncate64.get() {
            Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()),
            None => {
                if size > i32::max_value() as u64 {
                    Err(io::Error::new(io::ErrorKind::InvalidInput,
                                       "cannot truncate >2GB"))
                } else {
                    cvt_r(|| ftruncate(fd, size as i32)).map(|_| ())
                }
            }
        }
    }
}

pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
    -> io::Result<ssize_t>
{
    weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
    pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
        if let Ok(o) = offset.try_into() {
            cvt(pread(fd, buf, count, o))
        } else {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "cannot pread >2GB"))
        }
    })
}

pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
    -> io::Result<ssize_t>
{
    weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
    pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
        if let Ok(o) = offset.try_into() {
            cvt(pwrite(fd, buf, count, o))
        } else {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "cannot pwrite >2GB"))
        }
    })
}
<commit_msg>Only use Android fallback for {ftruncate,pread,pwrite} on 32 bit<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Android ABI-compatibility module
//!
//! The ABI of Android has changed quite a bit over time, and libstd attempts to
//! be both forwards and backwards compatible as much as possible. We want to
//! always work with the most recent version of Android, but we also want to
//! work with older versions of Android for whenever projects need to.
//!
//! Our current minimum supported Android version is `android-9`, e.g. Android
//! with API level 9. We then in theory want to work on that and all future
//! versions of Android!
//!
//! Some of the detection here is done at runtime via `dlopen` and
//! introspection. Other times no detection is performed at all and we just
//! provide a fallback implementation as some versions of Android we support
//! don't have the function.
//!
//! You'll find more details below about why each compatibility shim is needed.

#![cfg(target_os = "android")]

use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
use libc::{ftruncate, pread, pwrite};

use convert::TryInto;
use io;
use super::{cvt, cvt_r};

// The `log2` and `log2f` functions apparently appeared in android-18, or at
// least you can see they're not present in the android-17 header [1] and they
// are present in android-18 [2].
//
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
//                                       /android-17/arch-arm/usr/include/math.h
// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
//                                       /android-18/arch-arm/usr/include/math.h
//
// Note that these shims are likely less precise than directly calling `log2`,
// but hopefully that should be enough for now...
//
// Note that mathematically, for any arbitrary `y`:
//
//      log_2(x) = log_y(x) / log_y(2)
//               = log_y(x) / (1 / log_2(y))
//               = log_y(x) * log_2(y)
//
// Hence because `ln` (log_e) is available on all Android we just choose `y = e`
// and get:
//
//      log_2(x) = ln(x) * log_2(e)

#[cfg(not(test))]
pub fn log2f32(f: f32) -> f32 {
    f.ln() * ::f32::consts::LOG2_E
}

#[cfg(not(test))]
pub fn log2f64(f: f64) -> f64 {
    f.ln() * ::f64::consts::LOG2_E
}

// Back in the day [1] the `signal` function was just an inline wrapper
// around `bsd_signal`, but starting in API level android-20 the `signal`
// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was
// removed [3].
//
// Basically this means that if we want to be binary compatible with multiple
// Android releases (oldest being 9 and newest being 21) then we need to check
// for both symbols and not actually link against either.
//
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
//                                       /android-18/arch-arm/usr/include/signal.h
// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental
//                                       /platforms/android-20/arch-arm
//                                       /usr/include/signal.h
// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms
//                                       /android-21/arch-arm/usr/include/signal.h
pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
    weak!(fn signal(c_int, sighandler_t) -> sighandler_t);
    weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t);

    let f = signal.get().or_else(|| bsd_signal.get());
    let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
    f(signum, handler)
}

// The `ftruncate64` symbol apparently appeared in android-12, so we do some
// dynamic detection to see if we can figure out whether `ftruncate64` exists.
//
// If it doesn't we just fall back to `ftruncate`, generating an error for
// too-large values.
#[cfg(target_pointer_width = "32")]
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
    weak!(fn ftruncate64(c_int, i64) -> c_int);

    unsafe {
        match ftruncate64.get() {
            Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()),
            None => {
                if size > i32::max_value() as u64 {
                    Err(io::Error::new(io::ErrorKind::InvalidInput,
                                       "cannot truncate >2GB"))
                } else {
                    cvt_r(|| ftruncate(fd, size as i32)).map(|_| ())
                }
            }
        }
    }
}

#[cfg(target_pointer_width = "64")]
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
    unsafe {
        cvt_r(|| ftruncate(fd, size as i64)).map(|_| ())
    }
}

#[cfg(target_pointer_width = "32")]
pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
    -> io::Result<ssize_t>
{
    weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
    pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
        if let Ok(o) = offset.try_into() {
            cvt(pread(fd, buf, count, o))
        } else {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "cannot pread >2GB"))
        }
    })
}

#[cfg(target_pointer_width = "32")]
pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
    -> io::Result<ssize_t>
{
    weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
    pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
        if let Ok(o) = offset.try_into() {
            cvt(pwrite(fd, buf, count, o))
        } else {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "cannot pwrite >2GB"))
        }
    })
}

#[cfg(target_pointer_width = "64")]
pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
    -> io::Result<ssize_t>
{
    cvt(pread(fd, buf, count, offset))
}

#[cfg(target_pointer_width = "64")]
pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
    -> io::Result<ssize_t>
{
    cvt(pwrite(fd, buf, count, offset))
}
<|endoftext|>


<commit_before>//!
//! These are black boxes to perform authenticated asymmetric
//! cryptography.
//!
//! TODO: Document me
//!
//! ## Usage
//! ```rust{.example}
//! use tweetnacl::cryptobox::{CryptoBox, Keypair};
//!
//! let key1 = Keypair::new();
//! let key2 = Keypair::new();
//!
//! let box1 = CryptoBox::from_key_pair(key1.sk, key2.pk);
//! let box2 = CryptoBox::from_key_pair(key2.sk, key1.pk);
//!
//! let msg = b"my secret message";
//!
//! let boxed = box1.encrypt(msg);
//!
//! let plain = box2.decrypt(boxed);
//! assert!(plain == Vec::from_slice(msg));
//! ```

use bindings::*;

/// Size of zero padding used in encrypted messages.
pub static ZERO_BYTES: uint = 32;
/// Size of encrypted message's nonce value.
pub static NONCE_BYTES: uint = 24;
/// Size of public key.
pub static PUBLICKEY_BYTES: uint = 32;
/// Size of secret key.
pub static SECRETKEY_BYTES: uint = 32;

/// A secret key used by CryptoBox
pub struct SecretKey ([u8, ..SECRETKEY_BYTES]);

/// A public key used by CryptoBox
pub struct PublicKey ([u8, ..PUBLICKEY_BYTES]);

impl PublicKey {
    /// Generate a public key matching a given secret key.
    pub fn from_secret_key(key: SecretKey) -> PublicKey {
        let mut pk = [0u8, ..PUBLICKEY_BYTES];
        let SecretKey(sk) = key;

        unsafe { crypto_scalarmult_base(pk.as_mut_ptr(), sk.as_ptr()); }

        PublicKey(pk)
    }
}

impl SecretKey {
    /// Generate a random new secret key.
    pub fn new() -> SecretKey {
        let mut sk = [0u8, ..SECRETKEY_BYTES];

        unsafe { randombytes(sk.as_mut_ptr(), SECRETKEY_BYTES as u64); }

        SecretKey(sk)
    }
}

/// A asymmetric keypair containing matching public and private keys.
pub struct Keypair {
    /// Public key
    pub pk: PublicKey,
    /// Private key
    pub sk: SecretKey
}

impl Keypair {
    /// Generate a random matching public and private key.
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBLICKEY_BYTES];
        let mut sk = [0u8, ..SECRETKEY_BYTES];

        unsafe {
            crypto_box_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());

            Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
        }
    }
}

pub struct BoxedMsg {
    pub nonce: [u8, ..NONCE_BYTES],
    pub cipher: Vec<u8>
}

/// TODO: document me
pub struct CryptoBox {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl CryptoBox {

    /// Generate a new CryptoBox using an existing keypair.
    pub fn from_key_pair(sendKey: SecretKey, recvKey: PublicKey) -> CryptoBox {
        CryptoBox { sk: sendKey, pk: recvKey }
    }

    /// Sign a message using this box's secret key and encrypt the
    /// message to the given recipient's PublicKey.
    pub fn encrypt(&self, msg: &[u8]) -> BoxedMsg {
        let mut stretched = Vec::from_elem(ZERO_BYTES, 0u8);
        stretched.push_all(msg);

        let SecretKey(sk) = self.sk;
        let PublicKey(pk) = self.pk;

        let mut nonce = [0u8, ..NONCE_BYTES];
        let mut cipher = Vec::from_elem(stretched.len(), 0u8);

        unsafe {
            randombytes(nonce.as_mut_ptr(), NONCE_BYTES as u64);

            match crypto_box(cipher.as_mut_ptr(),
                             stretched.as_ptr(),
                             stretched.len() as u64,
                             nonce.as_ptr(),
                             pk.as_ptr(),
                             sk.as_ptr()) {
                0 => BoxedMsg { nonce: nonce, cipher: cipher },
                _ => fail!("crypto_box failed")
            }
        }
    }

    pub fn decrypt(&self, boxMsg: BoxedMsg) -> Vec<u8> {
        let BoxedMsg { nonce, cipher } = boxMsg;

        let mut msg = Vec::from_elem(cipher.len(), 0u8);

        let SecretKey(sk) = self.sk;
        let PublicKey(pk) = self.pk;

        unsafe {
            // TODO: error handling.
            match crypto_box_open(msg.as_mut_ptr(),
                                  cipher.as_ptr(),
                                  cipher.len() as u64,
                                  nonce.as_ptr(),
                                  pk.as_ptr(),
                                  sk.as_ptr()) {
                0 => Vec::from_slice(msg.slice(ZERO_BYTES, msg.len())),
                _ => fail!("crypto_box_open failed")
            }
        }
    }
}

#[test]
fn test_cryptobox_sanity() {
    for i in range(0 as uint, 16) {
        let key1 = Keypair::new();
        let key2 = Keypair::new();

        let box1 = CryptoBox::from_key_pair(key1.sk, key2.pk);
        let box2 = CryptoBox::from_key_pair(key2.sk, key1.pk);

        let msg = Vec::from_elem(i * 4, i as u8);

        let boxed = box1.encrypt(msg.as_slice());

        print!("enc:\t{}\nnonce:\t{}\n", boxed.cipher, Vec::from_slice(boxed.nonce));

        let plain = box2.decrypt(boxed);

        print!("plain:\t{}\n", plain);
        print!("msg:\t{}\n", msg);

        assert!(msg == plain);
    }
}

#[test]
fn test_cryptobox_pubkey_from_keypair() {
    for _ in range(0i, 16) {
        let key = Keypair::new();
        let pubkey = PublicKey::from_secret_key(key.sk);

        let PublicKey(k1) = pubkey;
        let PublicKey(k2) = key.pk;

        assert!(k1 == k2);
    }
}

#[test]
fn test_cryptobox_pubkey_from_seckey() {
    for _ in range(0i, 16) {
        let key = SecretKey::new();
        let pk = PublicKey::from_secret_key(key);

        let msg = b"secret message";

        let cbox = CryptoBox::from_key_pair(key, pk);
        let boxed = cbox.encrypt(msg);
        let plain = cbox.decrypt(boxed);

        print!("plain:\t{}\n", plain);
        print!("msg:\t{}\n", msg);

        assert!(plain == Vec::from_slice(msg));
    }
}
<commit_msg>Return an Optional from CryptoBox::decrypt<commit_after>//!
//! These are black boxes to perform authenticated asymmetric
//! cryptography.
//!
//! TODO: Document me
//!
//! ## Usage
//! ```rust{.example}
//! use tweetnacl::cryptobox::{CryptoBox, Keypair};
//!
//! let key1 = Keypair::new();
//! let key2 = Keypair::new();
//!
//! let box1 = CryptoBox::from_key_pair(key1.sk, key2.pk);
//! let box2 = CryptoBox::from_key_pair(key2.sk, key1.pk);
//!
//! let msg = b"my secret message";
//!
//! let boxed = box1.encrypt(msg);
//!
//! let plain = box2.decrypt(boxed);
//! assert!(plain.unwrap() == Vec::from_slice(msg));
//! ```

use bindings::*;

/// Size of zero padding used in encrypted messages.
pub static ZERO_BYTES: uint = 32;
/// Size of encrypted message's nonce value.
pub static NONCE_BYTES: uint = 24;
/// Size of public key.
pub static PUBLICKEY_BYTES: uint = 32;
/// Size of secret key.
pub static SECRETKEY_BYTES: uint = 32;

/// A secret key used by CryptoBox
pub struct SecretKey ([u8, ..SECRETKEY_BYTES]);

/// A public key used by CryptoBox
pub struct PublicKey ([u8, ..PUBLICKEY_BYTES]);

impl PublicKey {
    /// Generate a public key matching a given secret key.
    pub fn from_secret_key(key: SecretKey) -> PublicKey {
        let mut pk = [0u8, ..PUBLICKEY_BYTES];
        let SecretKey(sk) = key;

        unsafe { crypto_scalarmult_base(pk.as_mut_ptr(), sk.as_ptr()); }

        PublicKey(pk)
    }
}

impl SecretKey {
    /// Generate a random new secret key.
    pub fn new() -> SecretKey {
        let mut sk = [0u8, ..SECRETKEY_BYTES];

        unsafe { randombytes(sk.as_mut_ptr(), SECRETKEY_BYTES as u64); }

        SecretKey(sk)
    }
}

/// A asymmetric keypair containing matching public and private keys.
pub struct Keypair {
    /// Public key
    pub pk: PublicKey,
    /// Private key
    pub sk: SecretKey
}

impl Keypair {
    /// Generate a random matching public and private key.
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBLICKEY_BYTES];
        let mut sk = [0u8, ..SECRETKEY_BYTES];

        unsafe {
            crypto_box_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());

            Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
        }
    }
}

pub struct BoxedMsg {
    pub nonce: [u8, ..NONCE_BYTES],
    pub cipher: Vec<u8>
}

/// TODO: document me
pub struct CryptoBox {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl CryptoBox {

    /// Generate a new CryptoBox using an existing keypair.
    pub fn from_key_pair(sendKey: SecretKey, recvKey: PublicKey) -> CryptoBox {
        CryptoBox { sk: sendKey, pk: recvKey }
    }

    /// Sign a message using this box's secret key and encrypt the
    /// message to the given recipient's PublicKey.
    pub fn encrypt(&self, msg: &[u8]) -> BoxedMsg {
        let mut stretched = Vec::from_elem(ZERO_BYTES, 0u8);
        stretched.push_all(msg);

        let SecretKey(sk) = self.sk;
        let PublicKey(pk) = self.pk;

        let mut nonce = [0u8, ..NONCE_BYTES];
        let mut cipher = Vec::from_elem(stretched.len(), 0u8);

        unsafe {
            randombytes(nonce.as_mut_ptr(), NONCE_BYTES as u64);

            match crypto_box(cipher.as_mut_ptr(),
                             stretched.as_ptr(),
                             stretched.len() as u64,
                             nonce.as_ptr(),
                             pk.as_ptr(),
                             sk.as_ptr()) {
                0 => BoxedMsg { nonce: nonce, cipher: cipher },
                _ => fail!("crypto_box failed")
            }
        }
    }

    pub fn decrypt(&self, boxMsg: BoxedMsg) -> Option<Vec<u8>> {
        let BoxedMsg { nonce, cipher } = boxMsg;

        let mut msg = Vec::from_elem(cipher.len(), 0u8);

        let SecretKey(sk) = self.sk;
        let PublicKey(pk) = self.pk;

        unsafe {
            match crypto_box_open(msg.as_mut_ptr(),
                                  cipher.as_ptr(),
                                  cipher.len() as u64,
                                  nonce.as_ptr(),
                                  pk.as_ptr(),
                                  sk.as_ptr()) {
                0 => Some(Vec::from_slice(msg.slice(ZERO_BYTES, msg.len()))),
                -2 => None,
                _ => fail!("crypto_box_open failed")
            }
        }
    }
}

#[test]
fn test_cryptobox_sanity() {
    for i in range(0 as uint, 16) {
        let key1 = Keypair::new();
        let key2 = Keypair::new();

        let box1 = CryptoBox::from_key_pair(key1.sk, key2.pk);
        let box2 = CryptoBox::from_key_pair(key2.sk, key1.pk);

        let msg = Vec::from_elem(i * 4, i as u8);

        let boxed = box1.encrypt(msg.as_slice());

        print!("enc:\t{}\nnonce:\t{}\n", boxed.cipher, Vec::from_slice(boxed.nonce));

        let plainOpt = box2.decrypt(boxed);

        assert!(plainOpt.is_some());

        let plain = plainOpt.unwrap();

        print!("plain:\t{}\n", plain);
        print!("msg:\t{}\n", msg);

        assert!(msg == plain);
    }
}

#[test]
fn test_cryptobox_pubkey_from_keypair() {
    for _ in range(0i, 16) {
        let key = Keypair::new();
        let pubkey = PublicKey::from_secret_key(key.sk);

        let PublicKey(k1) = pubkey;
        let PublicKey(k2) = key.pk;

        assert!(k1 == k2);
    }
}

#[test]
fn test_cryptobox_pubkey_from_seckey() {
    for _ in range(0i, 16) {
        let key = SecretKey::new();
        let pk = PublicKey::from_secret_key(key);

        let msg = b"secret message";

        let cbox = CryptoBox::from_key_pair(key, pk);
        let boxed = cbox.encrypt(msg);
        let plainOpt = cbox.decrypt(boxed);

        assert!(plainOpt.is_some());

        let plain = plainOpt.unwrap();

        print!("plain:\t{}\n", plain);
        print!("msg:\t{}\n", msg);

        assert!(plain == Vec::from_slice(msg));
    }
}

#[test]
fn test_cryptobox_mac_sanity() {
    for _ in range(0i, 16) {
        let kp1 = Keypair::new();
        let kp2 = Keypair::new();

        let cbox = CryptoBox::from_key_pair(kp1.sk, kp1.pk);

        for t in vec![(kp1.sk, kp2.pk),
                      (kp2.sk, kp1.pk),
                      (kp2.sk, kp2.pk)].iter() {
            let msg = b"secret message";
            let boxed = cbox.encrypt(msg);

            let &(sk, pk) = t;
            let dbox = CryptoBox::from_key_pair(sk, pk);

            let plainOpt = dbox.decrypt(boxed);
            assert!(plainOpt.is_none());
        }
    }
}
<|endoftext|>


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

use salsa::Database;
use ra_db::{FilesDatabase, CrateGraph, SourceRootId};
use relative_path::RelativePath;
use test_utils::assert_eq_text;

use crate::{
    ItemMap, Resolution,
    db::HirDatabase,
    mock::MockDatabase,
    module_tree::ModuleId,
};

fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
    let (db, pos) = MockDatabase::with_position(fixture);
    let source_root = db.file_source_root(pos.file_id);
    let module = crate::source_binder::module_from_position(&db, pos)
        .unwrap()
        .unwrap();
    let module_id = module.def_id.loc(&db).module_id;
    (db.item_map(source_root).unwrap(), module_id)
}

fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) {
    let mut lines = map.per_module[&module_id]
        .items
        .iter()
        .map(|(name, res)| format!("{}: {}", name, dump_resolution(res)))
        .collect::<Vec<_>>();
    lines.sort();
    let actual = lines.join("\n");
    let expected = expected
        .trim()
        .lines()
        .map(|it| it.trim())
        .collect::<Vec<_>>()
        .join("\n");
    assert_eq_text!(&expected, &actual);

    fn dump_resolution(resolution: &Resolution) -> &'static str {
        match (
            resolution.def_id.types.is_some(),
            resolution.def_id.values.is_some(),
        ) {
            (true, true) => "t v",
            (true, false) => "t",
            (false, true) => "v",
            (false, false) => "_",
        }
    }
}

#[test]
fn item_map_smoke_test() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::Baz;
        <|>

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

        //- /foo/bar.rs
        pub struct Baz;
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn use_trees() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::{Baz, Quux};
        <|>

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

        //- /foo/bar.rs
        pub struct Baz;
        pub enum Quux {};
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            Quux: t
            foo: t
        ",
    );
}

#[test]
fn re_exports() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use self::foo::Baz;
        <|>

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

        pub use self::bar::Baz;

        //- /foo/bar.rs
        pub struct Baz;
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn item_map_contains_items_from_expansions() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::Baz;
        <|>

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

        //- /foo/bar.rs
        salsa::query_group! {
            trait Baz {}
        }
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t
            foo: t
        ",
    );
}

#[test]
fn item_map_using_self() {
    let (item_map, module_id) = item_map(
        "
            //- /lib.rs
            mod foo;
            use crate::foo::bar::Baz::{self};
            <|>
            //- /foo/mod.rs
            pub mod bar;
            //- /foo/bar.rs
            pub struct Baz;
        ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn item_map_across_crates() {
    let (mut db, sr) = MockDatabase::with_files(
        "
        //- /main.rs
        use test_crate::Baz;

        //- /lib.rs
        pub struct Baz;
    ",
    );
    let main_id = sr.files[RelativePath::new("/main.rs")];
    let lib_id = sr.files[RelativePath::new("/lib.rs")];

    let mut crate_graph = CrateGraph::default();
    let main_crate = crate_graph.add_crate_root(main_id);
    let lib_crate = crate_graph.add_crate_root(lib_id);
    crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);

    db.set_crate_graph(crate_graph);

    let source_root = db.file_source_root(main_id);
    let module = crate::source_binder::module_from_file_id(&db, main_id)
        .unwrap()
        .unwrap();
    let module_id = module.def_id.loc(&db).module_id;
    let item_map = db.item_map(source_root).unwrap();

    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            test_crate: t
        ",
    );
}

#[test]
fn import_across_source_roots() {
    let (mut db, sr) = MockDatabase::with_files(
        "
        //- /lib.rs
        pub mod a {
            pub mod b {
                pub struct C;
            }
        }
    ",
    );
    let lib_id = sr.files[RelativePath::new("/lib.rs")];

    let source_root = SourceRootId(1);

    let (sr2, pos) = db.add_fixture(
        source_root,
        "
        //- /main.rs
        use test_crate::a::b::C;
    ",
    );
    assert!(pos.is_none());

    let main_id = sr2.files[RelativePath::new("/main.rs")];

    eprintln!("lib = {:?}, main = {:?}", lib_id, main_id);

    let mut crate_graph = CrateGraph::default();
    let main_crate = crate_graph.add_crate_root(main_id);
    let lib_crate = crate_graph.add_crate_root(lib_id);
    crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);

    db.set_crate_graph(crate_graph);

    let module = crate::source_binder::module_from_file_id(&db, main_id)
        .unwrap()
        .unwrap();
    let module_id = module.def_id.loc(&db).module_id;
    let item_map = db.item_map(source_root).unwrap();

    check_module_item_map(
        &item_map,
        module_id,
        "
            C: t v
            test_crate: t
        ",
    );
}

#[test]
fn reexport_across_crates() {
    let (mut db, sr) = MockDatabase::with_files(
        "
        //- /main.rs
        use test_crate::Baz;

        //- /lib.rs
        pub use foo::Baz;

        mod foo;

        //- /foo.rs
        pub struct Baz;
    ",
    );
    let main_id = sr.files[RelativePath::new("/main.rs")];
    let lib_id = sr.files[RelativePath::new("/lib.rs")];

    let mut crate_graph = CrateGraph::default();
    let main_crate = crate_graph.add_crate_root(main_id);
    let lib_crate = crate_graph.add_crate_root(lib_id);
    crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);

    db.set_crate_graph(crate_graph);

    let source_root = db.file_source_root(main_id);
    let module = crate::source_binder::module_from_file_id(&db, main_id)
        .unwrap()
        .unwrap();
    let module_id = module.def_id.loc(&db).module_id;
    let item_map = db.item_map(source_root).unwrap();

    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            test_crate: t
        ",
    );
}

fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
    let (mut db, pos) = MockDatabase::with_position(initial);
    let source_root = db.file_source_root(pos.file_id);
    {
        let events = db.log_executed(|| {
            db.item_map(source_root).unwrap();
        });
        assert!(format!("{:?}", events).contains("item_map"))
    }
    db.query_mut(ra_db::FileTextQuery)
        .set(pos.file_id, Arc::new(file_change.to_string()));

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

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

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

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

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

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

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

#[test]
fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
    check_item_map_is_not_recomputed(
        "
        //- /lib.rs
        mod foo;

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

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

        //- /foo/bar.rs
        <|>
        salsa::query_group! {
            trait Baz {
                fn foo() -> i32 { 1 + 1 }
            }
        }
        ",
        "
        salsa::query_group! {
            trait Baz {
                fn foo() -> i32 { 92 }
            }
        }
        ",
    );
}
<commit_msg>one more invalidation test<commit_after>use std::sync::Arc;

use salsa::Database;
use ra_db::{FilesDatabase, CrateGraph, SourceRootId};
use relative_path::RelativePath;
use test_utils::assert_eq_text;

use crate::{
    ItemMap, Resolution,
    db::HirDatabase,
    mock::MockDatabase,
    module_tree::ModuleId,
};

fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
    let (db, pos) = MockDatabase::with_position(fixture);
    let source_root = db.file_source_root(pos.file_id);
    let module = crate::source_binder::module_from_position(&db, pos)
        .unwrap()
        .unwrap();
    let module_id = module.def_id.loc(&db).module_id;
    (db.item_map(source_root).unwrap(), module_id)
}

fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) {
    let mut lines = map.per_module[&module_id]
        .items
        .iter()
        .map(|(name, res)| format!("{}: {}", name, dump_resolution(res)))
        .collect::<Vec<_>>();
    lines.sort();
    let actual = lines.join("\n");
    let expected = expected
        .trim()
        .lines()
        .map(|it| it.trim())
        .collect::<Vec<_>>()
        .join("\n");
    assert_eq_text!(&expected, &actual);

    fn dump_resolution(resolution: &Resolution) -> &'static str {
        match (
            resolution.def_id.types.is_some(),
            resolution.def_id.values.is_some(),
        ) {
            (true, true) => "t v",
            (true, false) => "t",
            (false, true) => "v",
            (false, false) => "_",
        }
    }
}

#[test]
fn item_map_smoke_test() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::Baz;
        <|>

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

        //- /foo/bar.rs
        pub struct Baz;
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn use_trees() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::{Baz, Quux};
        <|>

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

        //- /foo/bar.rs
        pub struct Baz;
        pub enum Quux {};
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            Quux: t
            foo: t
        ",
    );
}

#[test]
fn re_exports() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use self::foo::Baz;
        <|>

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

        pub use self::bar::Baz;

        //- /foo/bar.rs
        pub struct Baz;
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn item_map_contains_items_from_expansions() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::Baz;
        <|>

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

        //- /foo/bar.rs
        salsa::query_group! {
            trait Baz {}
        }
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t
            foo: t
        ",
    );
}

#[test]
fn item_map_using_self() {
    let (item_map, module_id) = item_map(
        "
            //- /lib.rs
            mod foo;
            use crate::foo::bar::Baz::{self};
            <|>
            //- /foo/mod.rs
            pub mod bar;
            //- /foo/bar.rs
            pub struct Baz;
        ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn item_map_across_crates() {
    let (mut db, sr) = MockDatabase::with_files(
        "
        //- /main.rs
        use test_crate::Baz;

        //- /lib.rs
        pub struct Baz;
    ",
    );
    let main_id = sr.files[RelativePath::new("/main.rs")];
    let lib_id = sr.files[RelativePath::new("/lib.rs")];

    let mut crate_graph = CrateGraph::default();
    let main_crate = crate_graph.add_crate_root(main_id);
    let lib_crate = crate_graph.add_crate_root(lib_id);
    crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);

    db.set_crate_graph(crate_graph);

    let source_root = db.file_source_root(main_id);
    let module = crate::source_binder::module_from_file_id(&db, main_id)
        .unwrap()
        .unwrap();
    let module_id = module.def_id.loc(&db).module_id;
    let item_map = db.item_map(source_root).unwrap();

    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            test_crate: t
        ",
    );
}

#[test]
fn import_across_source_roots() {
    let (mut db, sr) = MockDatabase::with_files(
        "
        //- /lib.rs
        pub mod a {
            pub mod b {
                pub struct C;
            }
        }
    ",
    );
    let lib_id = sr.files[RelativePath::new("/lib.rs")];

    let source_root = SourceRootId(1);

    let (sr2, pos) = db.add_fixture(
        source_root,
        "
        //- /main.rs
        use test_crate::a::b::C;
    ",
    );
    assert!(pos.is_none());

    let main_id = sr2.files[RelativePath::new("/main.rs")];

    eprintln!("lib = {:?}, main = {:?}", lib_id, main_id);

    let mut crate_graph = CrateGraph::default();
    let main_crate = crate_graph.add_crate_root(main_id);
    let lib_crate = crate_graph.add_crate_root(lib_id);
    crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);

    db.set_crate_graph(crate_graph);

    let module = crate::source_binder::module_from_file_id(&db, main_id)
        .unwrap()
        .unwrap();
    let module_id = module.def_id.loc(&db).module_id;
    let item_map = db.item_map(source_root).unwrap();

    check_module_item_map(
        &item_map,
        module_id,
        "
            C: t v
            test_crate: t
        ",
    );
}

#[test]
fn reexport_across_crates() {
    let (mut db, sr) = MockDatabase::with_files(
        "
        //- /main.rs
        use test_crate::Baz;

        //- /lib.rs
        pub use foo::Baz;

        mod foo;

        //- /foo.rs
        pub struct Baz;
    ",
    );
    let main_id = sr.files[RelativePath::new("/main.rs")];
    let lib_id = sr.files[RelativePath::new("/lib.rs")];

    let mut crate_graph = CrateGraph::default();
    let main_crate = crate_graph.add_crate_root(main_id);
    let lib_crate = crate_graph.add_crate_root(lib_id);
    crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);

    db.set_crate_graph(crate_graph);

    let source_root = db.file_source_root(main_id);
    let module = crate::source_binder::module_from_file_id(&db, main_id)
        .unwrap()
        .unwrap();
    let module_id = module.def_id.loc(&db).module_id;
    let item_map = db.item_map(source_root).unwrap();

    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            test_crate: t
        ",
    );
}

fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
    let (mut db, pos) = MockDatabase::with_position(initial);
    let source_root = db.file_source_root(pos.file_id);
    {
        let events = db.log_executed(|| {
            db.item_map(source_root).unwrap();
        });
        assert!(format!("{:?}", events).contains("item_map"))
    }
    db.query_mut(ra_db::FileTextQuery)
        .set(pos.file_id, Arc::new(file_change.to_string()));

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

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

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

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

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

        use crate::foo::bar::Baz;
{
        fn foo() -> i32 { 92 }
        ",
    );
}

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

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

#[test]
fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
    check_item_map_is_not_recomputed(
        "
        //- /lib.rs
        mod foo;

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

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

        //- /foo/bar.rs
        <|>
        salsa::query_group! {
            trait Baz {
                fn foo() -> i32 { 1 + 1 }
            }
        }
        ",
        "
        salsa::query_group! {
            trait Baz {
                fn foo() -> i32 { 92 }
            }
        }
        ",
    );
}
<|endoftext|>


<commit_before>//! Config used by the language server.
//!
//! We currently get this config from `initialize` LSP request, which is not the
//! best way to do it, but was the simplest thing we could implement.
//!
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.

use lsp_types::TextDocumentClientCapabilities;
use ra_flycheck::FlycheckConfig;
use ra_ide::{CompletionConfig, InlayHintsConfig};
use ra_project_model::CargoConfig;
use serde::Deserialize;

#[derive(Debug, Clone)]
pub struct Config {
    pub client_caps: ClientCapsConfig,

    pub with_sysroot: bool,
    pub publish_diagnostics: bool,
    pub lru_capacity: Option<usize>,
    pub proc_macro_srv: Option<String>,
    pub files: FilesConfig,
    pub notifications: NotificationsConfig,

    pub cargo: CargoConfig,
    pub rustfmt: RustfmtConfig,
    pub check: Option<FlycheckConfig>,

    pub inlay_hints: InlayHintsConfig,
    pub completion: CompletionConfig,
    pub call_info_full: bool,
}

#[derive(Debug, Clone)]
pub struct FilesConfig {
    pub watcher: FilesWatcher,
    pub exclude: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum FilesWatcher {
    Client,
    Notify,
}

#[derive(Debug, Clone)]
pub struct NotificationsConfig {
    pub workspace_loaded: bool,
    pub cargo_toml_not_found: bool,
}

#[derive(Debug, Clone)]
pub enum RustfmtConfig {
    Rustfmt {
        extra_args: Vec<String>,
    },
    #[allow(unused)]
    CustomCommand {
        command: String,
        args: Vec<String>,
    },
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
    pub location_link: bool,
    pub line_folding_only: bool,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            client_caps: ClientCapsConfig::default(),

            with_sysroot: true,
            publish_diagnostics: true,
            lru_capacity: None,
            proc_macro_srv: None,
            files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
            notifications: NotificationsConfig {
                workspace_loaded: true,
                cargo_toml_not_found: true,
            },

            cargo: CargoConfig::default(),
            rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
            check: Some(FlycheckConfig::CargoCommand {
                command: "check".to_string(),
                all_targets: true,
                extra_args: Vec::new(),
            }),

            inlay_hints: InlayHintsConfig {
                type_hints: true,
                parameter_hints: true,
                chaining_hints: true,
                max_length: None,
            },
            completion: CompletionConfig {
                enable_postfix_completions: true,
                add_call_parenthesis: true,
                add_call_argument_snippets: true,
            },
            call_info_full: true,
        }
    }
}

impl Config {
    #[rustfmt::skip]
    pub fn update(&mut self, value: &serde_json::Value) {
        log::info!("Config::update({:#})", value);

        let client_caps = self.client_caps.clone();
        *self = Default::default();
        self.client_caps = client_caps;

        set(value, "/withSysroot", &mut self.with_sysroot);
        set(value, "/featureFlags/lsp.diagnostics", &mut self.publish_diagnostics);
        set(value, "/lruCapacity", &mut self.lru_capacity);
        if let Some(watcher) =  get::<String>(value, "/files/watcher") {
            self.files.watcher = match watcher.as_str() {
                "client" => FilesWatcher::Client,
                "notify"| _ => FilesWatcher::Notify,
            }
        }
        set(value, "/notifications/workspaceLoaded", &mut self.notifications.workspace_loaded);
        set(value, "/notifications/cargoTomlNotFound", &mut self.notifications.cargo_toml_not_found);

        set(value, "/cargo/noDefaultFeatures", &mut self.cargo.no_default_features);
        set(value, "/cargo/allFeatures", &mut self.cargo.all_features);
        set(value, "/cargo/features", &mut self.cargo.features);
        set(value, "/cargo/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
        if let Some(mut args) = get::<Vec<String>>(value, "/rustfmt/overrideCommand") {
            if !args.is_empty() {
                let command = args.remove(0);
                self.rustfmt = RustfmtConfig::CustomCommand {
                    command,
                    args,
                }
            }
        } else if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
            set(value, "/rustfmt/extraArgs", extra_args);
        }
        if let Some(false) = get(value, "/checkOnSave/enable") {
            self.check = None
        } else {
            if let Some(mut args) = get::<Vec<String>>(value, "/checkOnSave/overrideCommand") {
                if !args.is_empty() {
                    let command = args.remove(0);
                    self.check = Some(FlycheckConfig::CustomCommand {
                        command,
                        args,
                    })
                }

            } else if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check
            {
                set(value, "/checkOnSave/extraArgs", extra_args);
                set(value, "/checkOnSave/command", command);
                set(value, "/checkOnSave/allTargets", all_targets);
            }
        };

        set(value, "/inlayHints/typeHints", &mut self.inlay_hints.type_hints);
        set(value, "/inlayHints/parameterHints", &mut self.inlay_hints.parameter_hints);
        set(value, "/inlayHints/chainingHints", &mut self.inlay_hints.chaining_hints);
        set(value, "/inlayHints/maxLength", &mut self.inlay_hints.max_length);
        set(value, "/completion/postfix/enable", &mut self.completion.enable_postfix_completions);
        set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
        set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
        set(value, "/callInfo/full", &mut self.call_info_full);

        log::info!("Config::update() = {:#?}", self);

        fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
            value.pointer(pointer).and_then(|it| T::deserialize(it).ok())
        }

        fn set<'a, T: Deserialize<'a> + std::fmt::Debug>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) {
            if let Some(new_value) = get(value, pointer) {
                *slot = new_value
            }
        }
    }

    pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) {
        if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) {
            self.client_caps.location_link = value;
        }
        if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) {
            self.client_caps.line_folding_only = value
        }
    }
}
<commit_msg>Simplify config<commit_after>//! Config used by the language server.
//!
//! We currently get this config from `initialize` LSP request, which is not the
//! best way to do it, but was the simplest thing we could implement.
//!
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.

use lsp_types::TextDocumentClientCapabilities;
use ra_flycheck::FlycheckConfig;
use ra_ide::{CompletionConfig, InlayHintsConfig};
use ra_project_model::CargoConfig;
use serde::Deserialize;

#[derive(Debug, Clone)]
pub struct Config {
    pub client_caps: ClientCapsConfig,

    pub with_sysroot: bool,
    pub publish_diagnostics: bool,
    pub lru_capacity: Option<usize>,
    pub proc_macro_srv: Option<String>,
    pub files: FilesConfig,
    pub notifications: NotificationsConfig,

    pub cargo: CargoConfig,
    pub rustfmt: RustfmtConfig,
    pub check: Option<FlycheckConfig>,

    pub inlay_hints: InlayHintsConfig,
    pub completion: CompletionConfig,
    pub call_info_full: bool,
}

#[derive(Debug, Clone)]
pub struct FilesConfig {
    pub watcher: FilesWatcher,
    pub exclude: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum FilesWatcher {
    Client,
    Notify,
}

#[derive(Debug, Clone)]
pub struct NotificationsConfig {
    pub workspace_loaded: bool,
    pub cargo_toml_not_found: bool,
}

#[derive(Debug, Clone)]
pub enum RustfmtConfig {
    Rustfmt {
        extra_args: Vec<String>,
    },
    #[allow(unused)]
    CustomCommand {
        command: String,
        args: Vec<String>,
    },
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
    pub location_link: bool,
    pub line_folding_only: bool,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            client_caps: ClientCapsConfig::default(),

            with_sysroot: true,
            publish_diagnostics: true,
            lru_capacity: None,
            proc_macro_srv: None,
            files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
            notifications: NotificationsConfig {
                workspace_loaded: true,
                cargo_toml_not_found: true,
            },

            cargo: CargoConfig::default(),
            rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
            check: Some(FlycheckConfig::CargoCommand {
                command: "check".to_string(),
                all_targets: true,
                extra_args: Vec::new(),
            }),

            inlay_hints: InlayHintsConfig {
                type_hints: true,
                parameter_hints: true,
                chaining_hints: true,
                max_length: None,
            },
            completion: CompletionConfig {
                enable_postfix_completions: true,
                add_call_parenthesis: true,
                add_call_argument_snippets: true,
            },
            call_info_full: true,
        }
    }
}

impl Config {
    #[rustfmt::skip]
    pub fn update(&mut self, value: &serde_json::Value) {
        log::info!("Config::update({:#})", value);

        let client_caps = self.client_caps.clone();
        *self = Default::default();
        self.client_caps = client_caps;

        set(value, "/withSysroot", &mut self.with_sysroot);
        set(value, "/featureFlags/lsp.diagnostics", &mut self.publish_diagnostics);
        set(value, "/lruCapacity", &mut self.lru_capacity);
        self.files.watcher = match get::<&str>(value, "/files/watcher") {
            Some("client") => FilesWatcher::Client,
            Some("notify") | _ => FilesWatcher::Notify
        };
        set(value, "/notifications/workspaceLoaded", &mut self.notifications.workspace_loaded);
        set(value, "/notifications/cargoTomlNotFound", &mut self.notifications.cargo_toml_not_found);

        set(value, "/cargo/noDefaultFeatures", &mut self.cargo.no_default_features);
        set(value, "/cargo/allFeatures", &mut self.cargo.all_features);
        set(value, "/cargo/features", &mut self.cargo.features);
        set(value, "/cargo/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
        if let Some(mut args) = get::<Vec<String>>(value, "/rustfmt/overrideCommand") {
            if !args.is_empty() {
                let command = args.remove(0);
                self.rustfmt = RustfmtConfig::CustomCommand {
                    command,
                    args,
                }
            }
        } else if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
            set(value, "/rustfmt/extraArgs", extra_args);
        }

        if let Some(false) = get(value, "/checkOnSave/enable") {
            self.check = None;
        } else {
            if let Some(mut args) = get::<Vec<String>>(value, "/checkOnSave/overrideCommand") {
                if !args.is_empty() {
                    let command = args.remove(0);
                    self.check = Some(FlycheckConfig::CustomCommand {
                        command,
                        args,
                    });
                }

            } else if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check
            {
                set(value, "/checkOnSave/extraArgs", extra_args);
                set(value, "/checkOnSave/command", command);
                set(value, "/checkOnSave/allTargets", all_targets);
            }
        };

        set(value, "/inlayHints/typeHints", &mut self.inlay_hints.type_hints);
        set(value, "/inlayHints/parameterHints", &mut self.inlay_hints.parameter_hints);
        set(value, "/inlayHints/chainingHints", &mut self.inlay_hints.chaining_hints);
        set(value, "/inlayHints/maxLength", &mut self.inlay_hints.max_length);
        set(value, "/completion/postfix/enable", &mut self.completion.enable_postfix_completions);
        set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
        set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
        set(value, "/callInfo/full", &mut self.call_info_full);

        log::info!("Config::update() = {:#?}", self);

        fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
            value.pointer(pointer).and_then(|it| T::deserialize(it).ok())
        }

        fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) {
            if let Some(new_value) = get(value, pointer) {
                *slot = new_value
            }
        }
    }

    pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) {
        if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) {
            self.client_caps.location_link = value;
        }
        if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) {
            self.client_caps.line_folding_only = value
        }
    }
}
<|endoftext|>


<commit_before>//! Utilities to track object's life cycle

// All our AliveTracker usage is internal and only
// used, when the wayland_frontend feature is enabled.
// So we need to silence some warnings in other cases.
#![allow(dead_code)]

use std::sync::atomic::{AtomicBool, Ordering};

/// Util to track wayland object's life time
#[derive(Debug)]
pub struct AliveTracker {
    is_alive: AtomicBool,
}

impl Default for AliveTracker {
    fn default() -> Self {
        Self {
            is_alive: AtomicBool::new(true),
        }
    }
}

impl AliveTracker {
    /// Notify the tracker that object is dead
    pub fn destroy_notify(&self) {
        self.is_alive.store(false, Ordering::Release);
    }

    /// Check if object is alive
    pub fn alive(&self) -> bool {
        self.is_alive.load(Ordering::Acquire)
    }
}

/// Trait that is implemented on wayland objects tracked by Smithay
pub trait IsAlive {
    /// Check if object is alive
    fn alive(&self) -> bool;
}
<commit_msg>alive: Implement for references<commit_after>//! Utilities to track object's life cycle

// All our AliveTracker usage is internal and only
// used, when the wayland_frontend feature is enabled.
// So we need to silence some warnings in other cases.
#![allow(dead_code)]

use std::sync::atomic::{AtomicBool, Ordering};

/// Util to track wayland object's life time
#[derive(Debug)]
pub struct AliveTracker {
    is_alive: AtomicBool,
}

impl Default for AliveTracker {
    fn default() -> Self {
        Self {
            is_alive: AtomicBool::new(true),
        }
    }
}

impl AliveTracker {
    /// Notify the tracker that object is dead
    pub fn destroy_notify(&self) {
        self.is_alive.store(false, Ordering::Release);
    }

    /// Check if object is alive
    pub fn alive(&self) -> bool {
        self.is_alive.load(Ordering::Acquire)
    }
}

/// Trait that is implemented on wayland objects tracked by Smithay
pub trait IsAlive {
    /// Check if object is alive
    fn alive(&self) -> bool;
}

impl<T: IsAlive> IsAlive for &T {
    fn alive(&self) -> bool {
        IsAlive::alive(*self)
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "bigdecimal")]
mod bigdecimal {
    extern crate bigdecimal;
    extern crate num_bigint;
    extern crate num_integer;
    extern crate num_traits;

    use self::bigdecimal::BigDecimal;
    use self::num_bigint::{BigInt, BigUint, Sign};
    use self::num_integer::Integer;
    use self::num_traits::{Signed, ToPrimitive, Zero};
    use std::io::prelude::*;

    use deserialize::{self, FromSql};
    use pg::data_types::PgNumeric;
    use pg::Pg;
    use serialize::{self, Output, ToSql};
    use sql_types::Numeric;

    #[cfg(feature = "unstable")]
    use std::convert::{TryFrom, TryInto};
    #[cfg(feature = "unstable")]
    use std::error::Error;

    /// Iterator over the digits of a big uint in base 10k.
    /// The digits will be returned in little endian order.
    struct ToBase10000(Option<BigUint>);

    impl Iterator for ToBase10000 {
        type Item = i16;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().map(|v| {
                let (div, rem) = v.div_rem(&BigUint::from(10_000u16));
                if !div.is_zero() {
                    self.0 = Some(div);
                }
                rem.to_i16().expect("10000 always fits in an i16")
            })
        }
    }

    fn pg_decimal_to_bigdecimal(numeric: &PgNumeric) -> deserialize::Result<BigDecimal> {
        let (sign, weight, scale, digits) = match *numeric {
            PgNumeric::Positive {
                weight,
                scale,
                ref digits,
            } => (Sign::Plus, weight, scale, digits),
            PgNumeric::Negative {
                weight,
                scale,
                ref digits,
            } => (Sign::Minus, weight, scale, digits),
            PgNumeric::NaN => return Err(Box::from("NaN is not (yet) supported in BigDecimal")),
        };

        let mut result = BigUint::default();
        let count = digits.len() as i64;
        for digit in digits {
            result *= BigUint::from(10_000u64);
            result += BigUint::from(*digit as u64);
        }
        // First digit got factor 10_000^(digits.len() - 1), but should get 10_000^weight
        let correction_exp = 4 * (i64::from(weight) - count + 1);
        let result = BigDecimal::new(BigInt::from_biguint(sign, result), -correction_exp)
            .with_scale(i64::from(scale));
        Ok(result)
    }

    #[cfg(feature = "unstable")]
    impl<'a> TryFrom<&'a PgNumeric> for BigDecimal {
        type Error = Box<Error + Send + Sync>;

        fn try_from(numeric: &'a PgNumeric) -> deserialize::Result<Self> {
            pg_decimal_to_bigdecimal(numeric)
        }
    }

    #[cfg(feature = "unstable")]
    impl TryFrom<PgNumeric> for BigDecimal {
        type Error = Box<Error + Send + Sync>;

        fn try_from(numeric: PgNumeric) -> deserialize::Result<Self> {
            (&numeric).try_into()
        }
    }

    impl<'a> From<&'a BigDecimal> for PgNumeric {
        // NOTE(clippy): No `std::ops::MulAssign` impl for `BigInt`
        #[allow(clippy::assign_op_pattern)]
        fn from(decimal: &'a BigDecimal) -> Self {
            let (mut integer, scale) = decimal.as_bigint_and_exponent();
            let scale = scale as u16;
            integer = integer.abs();

            // Ensure that the decimal will always lie on a digit boundary
            for _ in 0..(4 - scale % 4) {
                integer = integer * 10;
            }
            let integer = integer.to_biguint().expect("integer is always positive");

            let mut digits = ToBase10000(Some(integer)).collect::<Vec<_>>();
            digits.reverse();
            let digits_after_decimal = scale as u16 / 4 + 1;
            let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;

            let unnecessary_zeroes = if weight >= 0 {
                let index_of_decimal = (weight + 1) as usize;
                digits
                    .get(index_of_decimal..)
                    .expect("enough digits exist")
                    .iter()
                    .rev()
                    .take_while(|i| i.is_zero())
                    .count()
            } else {
                0
            };

            let relevant_digits = digits.len() - unnecessary_zeroes;
            digits.truncate(relevant_digits);

            match decimal.sign() {
                Sign::Plus => PgNumeric::Positive {
                    digits,
                    scale,
                    weight,
                },
                Sign::Minus => PgNumeric::Negative {
                    digits,
                    scale,
                    weight,
                },
                Sign::NoSign => PgNumeric::Positive {
                    digits: vec![0],
                    scale: 0,
                    weight: 0,
                },
            }
        }
    }

    impl From<BigDecimal> for PgNumeric {
        fn from(bigdecimal: BigDecimal) -> Self {
            (&bigdecimal).into()
        }
    }

    impl ToSql<Numeric, Pg> for BigDecimal {
        fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
            let numeric = PgNumeric::from(self);
            ToSql::<Numeric, Pg>::to_sql(&numeric, out)
        }
    }

    impl FromSql<Numeric, Pg> for BigDecimal {
        fn from_sql(numeric: Option<&[u8]>) -> deserialize::Result<Self> {
            // FIXME: Use the TryFrom impl when try_from is stable
            let numeric = PgNumeric::from_sql(numeric)?;
            pg_decimal_to_bigdecimal(&numeric)
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;
        use std::str::FromStr;

        #[test]
        fn bigdecimal_to_pgnumeric_converts_digits_to_base_10000() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![10],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10000").unwrap();
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 0],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 0,
                digits: vec![1, 0, 0],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_properly_adjusts_scale() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.0").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 1,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 1,
                digits: vec![1, 1000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.10").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 2,
                digits: vec![1, 1000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000.0001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 4,
                digits: vec![1, 0, 0, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("0.1").unwrap();
            let expected = PgNumeric::Positive {
                weight: -1,
                scale: 1,
                digits: vec![1000],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_retains_sign() {
            let decimal = BigDecimal::from_str("123.456").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("-123.456").unwrap();
            let expected = PgNumeric::Negative {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        #[cfg(feature = "unstable")]
        fn pg_numeric_to_bigdecimal_works() {
            let expected = BigDecimal::from_str("123.456").unwrap();
            let pg_numeric = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            let res: BigDecimal = pg_numeric.try_into().unwrap();
            assert_eq!(res, expected);

            let expected = BigDecimal::from_str("-56.78").unwrap();
            let pg_numeric = PgNumeric::Negative {
                weight: 0,
                scale: 2,
                digits: vec![56, 7800],
            };
            let res: BigDecimal = pg_numeric.try_into().unwrap();
            assert_eq!(res, expected);
        }
    }
}
<commit_msg>update FIXME comment<commit_after>#[cfg(feature = "bigdecimal")]
mod bigdecimal {
    extern crate bigdecimal;
    extern crate num_bigint;
    extern crate num_integer;
    extern crate num_traits;

    use self::bigdecimal::BigDecimal;
    use self::num_bigint::{BigInt, BigUint, Sign};
    use self::num_integer::Integer;
    use self::num_traits::{Signed, ToPrimitive, Zero};
    use std::io::prelude::*;

    use deserialize::{self, FromSql};
    use pg::data_types::PgNumeric;
    use pg::Pg;
    use serialize::{self, Output, ToSql};
    use sql_types::Numeric;

    #[cfg(feature = "unstable")]
    use std::convert::{TryFrom, TryInto};
    #[cfg(feature = "unstable")]
    use std::error::Error;

    /// Iterator over the digits of a big uint in base 10k.
    /// The digits will be returned in little endian order.
    struct ToBase10000(Option<BigUint>);

    impl Iterator for ToBase10000 {
        type Item = i16;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().map(|v| {
                let (div, rem) = v.div_rem(&BigUint::from(10_000u16));
                if !div.is_zero() {
                    self.0 = Some(div);
                }
                rem.to_i16().expect("10000 always fits in an i16")
            })
        }
    }

    fn pg_decimal_to_bigdecimal(numeric: &PgNumeric) -> deserialize::Result<BigDecimal> {
        let (sign, weight, scale, digits) = match *numeric {
            PgNumeric::Positive {
                weight,
                scale,
                ref digits,
            } => (Sign::Plus, weight, scale, digits),
            PgNumeric::Negative {
                weight,
                scale,
                ref digits,
            } => (Sign::Minus, weight, scale, digits),
            PgNumeric::NaN => return Err(Box::from("NaN is not (yet) supported in BigDecimal")),
        };

        let mut result = BigUint::default();
        let count = digits.len() as i64;
        for digit in digits {
            result *= BigUint::from(10_000u64);
            result += BigUint::from(*digit as u64);
        }
        // First digit got factor 10_000^(digits.len() - 1), but should get 10_000^weight
        let correction_exp = 4 * (i64::from(weight) - count + 1);
        let result = BigDecimal::new(BigInt::from_biguint(sign, result), -correction_exp)
            .with_scale(i64::from(scale));
        Ok(result)
    }

    #[cfg(feature = "unstable")]
    impl<'a> TryFrom<&'a PgNumeric> for BigDecimal {
        type Error = Box<Error + Send + Sync>;

        fn try_from(numeric: &'a PgNumeric) -> deserialize::Result<Self> {
            pg_decimal_to_bigdecimal(numeric)
        }
    }

    #[cfg(feature = "unstable")]
    impl TryFrom<PgNumeric> for BigDecimal {
        type Error = Box<Error + Send + Sync>;

        fn try_from(numeric: PgNumeric) -> deserialize::Result<Self> {
            (&numeric).try_into()
        }
    }

    impl<'a> From<&'a BigDecimal> for PgNumeric {
        // NOTE(clippy): No `std::ops::MulAssign` impl for `BigInt`
        #[allow(clippy::assign_op_pattern)]
        fn from(decimal: &'a BigDecimal) -> Self {
            let (mut integer, scale) = decimal.as_bigint_and_exponent();
            let scale = scale as u16;
            integer = integer.abs();

            // Ensure that the decimal will always lie on a digit boundary
            for _ in 0..(4 - scale % 4) {
                integer = integer * 10;
            }
            let integer = integer.to_biguint().expect("integer is always positive");

            let mut digits = ToBase10000(Some(integer)).collect::<Vec<_>>();
            digits.reverse();
            let digits_after_decimal = scale as u16 / 4 + 1;
            let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;

            let unnecessary_zeroes = if weight >= 0 {
                let index_of_decimal = (weight + 1) as usize;
                digits
                    .get(index_of_decimal..)
                    .expect("enough digits exist")
                    .iter()
                    .rev()
                    .take_while(|i| i.is_zero())
                    .count()
            } else {
                0
            };

            let relevant_digits = digits.len() - unnecessary_zeroes;
            digits.truncate(relevant_digits);

            match decimal.sign() {
                Sign::Plus => PgNumeric::Positive {
                    digits,
                    scale,
                    weight,
                },
                Sign::Minus => PgNumeric::Negative {
                    digits,
                    scale,
                    weight,
                },
                Sign::NoSign => PgNumeric::Positive {
                    digits: vec![0],
                    scale: 0,
                    weight: 0,
                },
            }
        }
    }

    impl From<BigDecimal> for PgNumeric {
        fn from(bigdecimal: BigDecimal) -> Self {
            (&bigdecimal).into()
        }
    }

    impl ToSql<Numeric, Pg> for BigDecimal {
        fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
            let numeric = PgNumeric::from(self);
            ToSql::<Numeric, Pg>::to_sql(&numeric, out)
        }
    }

    impl FromSql<Numeric, Pg> for BigDecimal {
        fn from_sql(numeric: Option<&[u8]>) -> deserialize::Result<Self> {
            // FIXME: Use the TryFrom impl after Rust 1.34 get released.
            let numeric = PgNumeric::from_sql(numeric)?;
            pg_decimal_to_bigdecimal(&numeric)
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;
        use std::str::FromStr;

        #[test]
        fn bigdecimal_to_pgnumeric_converts_digits_to_base_10000() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![10],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10000").unwrap();
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 0],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 0,
                digits: vec![1, 0, 0],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_properly_adjusts_scale() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.0").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 1,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 1,
                digits: vec![1, 1000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.10").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 2,
                digits: vec![1, 1000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000.0001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 4,
                digits: vec![1, 0, 0, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("0.1").unwrap();
            let expected = PgNumeric::Positive {
                weight: -1,
                scale: 1,
                digits: vec![1000],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_retains_sign() {
            let decimal = BigDecimal::from_str("123.456").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("-123.456").unwrap();
            let expected = PgNumeric::Negative {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        #[cfg(feature = "unstable")]
        fn pg_numeric_to_bigdecimal_works() {
            let expected = BigDecimal::from_str("123.456").unwrap();
            let pg_numeric = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            let res: BigDecimal = pg_numeric.try_into().unwrap();
            assert_eq!(res, expected);

            let expected = BigDecimal::from_str("-56.78").unwrap();
            let pg_numeric = PgNumeric::Negative {
                weight: 0,
                scale: 2,
                digits: vec![56, 7800],
            };
            let res: BigDecimal = pg_numeric.try_into().unwrap();
            assert_eq!(res, expected);
        }
    }
}
<|endoftext|>