<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://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::error;
use std::fmt;

macro_rules! features {
    {
        $($member:ident => {
            doc: $doc:expr,
			ffi_name: $ffi_field:ident,
            ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)?),+],
            requires_features: [$($requires_feature:ident),*],
            conflicts_features: [$($conflicts_feature:ident),*],
            required_by_extensions: [$($required_by_extension:ident),*],
        },)*
    } => {
        /// Represents all the features that are available on a physical device or enabled on
        /// a logical device.
        ///
        /// Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan
        /// implementations.
        ///
        /// # Example
        ///
        /// ```
        /// use vulkano::device::Features;
        /// # let physical_device: vulkano::device::physical::PhysicalDevice = return;
        /// let minimal_features = Features {
        ///     geometry_shader: true,
        ///     .. Features::none()
        /// };
        ///
        /// let optimal_features = vulkano::device::Features {
        ///     geometry_shader: true,
        ///     tessellation_shader: true,
        ///     .. Features::none()
        /// };
        ///
        /// if !physical_device.supported_features().is_superset_of(&minimal_features) {
        ///     panic!("The physical device is not good enough for this application.");
        /// }
        ///
        /// assert!(optimal_features.is_superset_of(&minimal_features));
        /// let features_to_request = optimal_features.intersection(physical_device.supported_features());
        /// ```
        ///
        #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
        #[allow(missing_docs)]
        pub struct Features {
            $(
                #[doc = $doc]
                pub $member: bool,
            )*
        }

        impl Features {
            /// Checks enabled features against the device version, device extensions and each other.
            pub(super) fn check_requirements(
                &self,
                supported: &Features,
                api_version:
                crate::Version,
                extensions: &crate::device::DeviceExtensions,
            ) -> Result<(), crate::device::features::FeatureRestrictionError> {
                $(
                    if self.$member {
                        if !supported.$member {
                            return Err(crate::device::features::FeatureRestrictionError {
                                feature: stringify!($member),
                                restriction: crate::device::features::FeatureRestriction::NotSupported,
                            });
                        }

                        $(
                            if !self.$requires_feature {
                                return Err(crate::device::features::FeatureRestrictionError {
                                    feature: stringify!($member),
                                    restriction: crate::device::features::FeatureRestriction::RequiresFeature(stringify!($requires_feature)),
                                });
                            }
                        )*

                        $(
                            if self.$conflicts_feature {
                                return Err(crate::device::features::FeatureRestrictionError {
                                    feature: stringify!($member),
                                    restriction: crate::device::features::FeatureRestriction::ConflictsFeature(stringify!($conflicts_feature)),
                                });
                            }
                        )*
                    } else {
                        $(
                            if extensions.$required_by_extension {
                                return Err(crate::device::features::FeatureRestrictionError {
                                    feature: stringify!($member),
                                    restriction: crate::device::features::FeatureRestriction::RequiredByExtension(stringify!($required_by_extension)),
                                });
                            }
                        )*
                    }
                )*
                Ok(())
            }

            /// Builds a `Features` object with all values to false.
            pub fn none() -> Features {
                Features {
                    $($member: false,)*
                }
            }

            /// Builds a `Features` object with all values to true.
            ///
            /// > **Note**: This function is used for testing purposes, and is probably useless in
            /// > a real code.
            pub fn all() -> Features {
                Features {
                    $($member: true,)*
                }
            }

            /// Returns true if `self` is a superset of the parameter.
            ///
            /// That is, for each feature of the parameter that is true, the corresponding value
            /// in self is true as well.
            pub fn is_superset_of(&self, other: &Features) -> bool {
                $((self.$member == true || other.$member == false))&&+
            }

            /// Builds a `Features` that is the intersection of `self` and another `Features`
            /// object.
            ///
            /// The result's field will be true if it is also true in both `self` and `other`.
            pub fn intersection(&self, other: &Features) -> Features {
                Features {
                    $($member: self.$member && other.$member,)*
                }
            }

            /// Builds a `Features` that is the difference of another `Features` object from `self`.
            ///
            /// The result's field will be true if it is true in `self` but not `other`.
            pub fn difference(&self, other: &Features) -> Features {
                Features {
                    $($member: self.$member && !other.$member,)*
                }
            }
        }

        impl FeaturesFfi {
            pub(crate) fn write(&mut self, features: &Features) {
                $(
                    std::array::IntoIter::new([
                        $(self.$ffi_struct.as_mut().map(|s| &mut s$(.$ffi_struct_field)?.$ffi_field)),+
                    ]).flatten().next().map(|f| *f = features.$member as ash::vk::Bool32);
                )*
            }
        }

        impl From<&FeaturesFfi> for Features {
            fn from(features_ffi: &FeaturesFfi) -> Self {
                Features {
                    $(
                        $member: std::array::IntoIter::new([
                            $(features_ffi.$ffi_struct.map(|s| s$(.$ffi_struct_field)?.$ffi_field)),+
                        ]).flatten().next().unwrap_or(0) != 0,
                    )*
                }
            }
        }
    };
}

pub use crate::autogen::Features;
pub(crate) use features;

/// An error that can happen when enabling a feature on a device.
#[derive(Clone, Copy, Debug)]
pub struct FeatureRestrictionError {
    /// The feature in question.
    pub feature: &'static str,
    /// The restriction that was not met.
    pub restriction: FeatureRestriction,
}

impl error::Error for FeatureRestrictionError {}

impl fmt::Display for FeatureRestrictionError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            fmt,
            "a restriction for the feature {} was not met: {}",
            self.feature, self.restriction,
        )
    }
}

#[derive(Clone, Copy, Debug)]
pub enum FeatureRestriction {
    /// Not supported by the physical device.
    NotSupported,
    /// Requires a feature to be enabled.
    RequiresFeature(&'static str),
    /// Requires a feature to be disabled.
    ConflictsFeature(&'static str),
    /// An extension requires this feature to be enabled.
    RequiredByExtension(&'static str),
}

impl fmt::Display for FeatureRestriction {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            FeatureRestriction::NotSupported => {
                write!(fmt, "not supported by the physical device")
            }
            FeatureRestriction::RequiresFeature(feat) => {
                write!(fmt, "requires feature {} to be enabled", feat)
            }
            FeatureRestriction::ConflictsFeature(feat) => {
                write!(fmt, "requires feature {} to be disabled", feat)
            }
            FeatureRestriction::RequiredByExtension(ext) => {
                write!(fmt, "required to be enabled by extension {}", ext)
            }
        }
    }
}

macro_rules! features_ffi {
    {
        $api_version:ident,
        $device_extensions:ident,
        $instance_extensions:ident,
        $($member:ident => {
            ty: $ty:ident,
            provided_by: [$($provided_by:expr),+],
            conflicts: [$($conflicts:ident),*],
        },)+
    } => {
        #[derive(Default)]
        pub(crate) struct FeaturesFfi {
            features_vulkan10: Option<ash::vk::PhysicalDeviceFeatures2KHR>,

            $(
                $member: Option<ash::vk::$ty>,
            )+
        }

        impl FeaturesFfi {
            pub(crate) fn make_chain(
                &mut self,
                $api_version: crate::Version,
                $device_extensions: &DeviceExtensions,
                $instance_extensions: &InstanceExtensions,
            ) {
                self.features_vulkan10 = Some(Default::default());
                let head = self.features_vulkan10.as_mut().unwrap();

                $(
                    if std::array::IntoIter::new([$($provided_by),+]).any(|x| x) &&
                        std::array::IntoIter::new([$(self.$conflicts.is_none()),*]).all(|x| x) {
                        self.$member = Some(Default::default());
                        let member = self.$member.as_mut().unwrap();
                        member.p_next = head.p_next;
                        head.p_next = member as *mut _ as _;
                    }
                )+
            }

            pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
                self.features_vulkan10.as_ref().unwrap()
            }

            pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
                self.features_vulkan10.as_mut().unwrap()
            }
        }
    };
}

pub(crate) use {crate::autogen::FeaturesFfi, features_ffi};
<commit_msg>make Features::all and Features::none const fn (#1663)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://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::error;
use std::fmt;

macro_rules! features {
    {
        $($member:ident => {
            doc: $doc:expr,
			ffi_name: $ffi_field:ident,
            ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)?),+],
            requires_features: [$($requires_feature:ident),*],
            conflicts_features: [$($conflicts_feature:ident),*],
            required_by_extensions: [$($required_by_extension:ident),*],
        },)*
    } => {
        /// Represents all the features that are available on a physical device or enabled on
        /// a logical device.
        ///
        /// Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan
        /// implementations.
        ///
        /// # Example
        ///
        /// ```
        /// use vulkano::device::Features;
        /// # let physical_device: vulkano::device::physical::PhysicalDevice = return;
        /// let minimal_features = Features {
        ///     geometry_shader: true,
        ///     .. Features::none()
        /// };
        ///
        /// let optimal_features = vulkano::device::Features {
        ///     geometry_shader: true,
        ///     tessellation_shader: true,
        ///     .. Features::none()
        /// };
        ///
        /// if !physical_device.supported_features().is_superset_of(&minimal_features) {
        ///     panic!("The physical device is not good enough for this application.");
        /// }
        ///
        /// assert!(optimal_features.is_superset_of(&minimal_features));
        /// let features_to_request = optimal_features.intersection(physical_device.supported_features());
        /// ```
        ///
        #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
        #[allow(missing_docs)]
        pub struct Features {
            $(
                #[doc = $doc]
                pub $member: bool,
            )*
        }

        impl Features {
            /// Checks enabled features against the device version, device extensions and each other.
            pub(super) fn check_requirements(
                &self,
                supported: &Features,
                api_version:
                crate::Version,
                extensions: &crate::device::DeviceExtensions,
            ) -> Result<(), crate::device::features::FeatureRestrictionError> {
                $(
                    if self.$member {
                        if !supported.$member {
                            return Err(crate::device::features::FeatureRestrictionError {
                                feature: stringify!($member),
                                restriction: crate::device::features::FeatureRestriction::NotSupported,
                            });
                        }

                        $(
                            if !self.$requires_feature {
                                return Err(crate::device::features::FeatureRestrictionError {
                                    feature: stringify!($member),
                                    restriction: crate::device::features::FeatureRestriction::RequiresFeature(stringify!($requires_feature)),
                                });
                            }
                        )*

                        $(
                            if self.$conflicts_feature {
                                return Err(crate::device::features::FeatureRestrictionError {
                                    feature: stringify!($member),
                                    restriction: crate::device::features::FeatureRestriction::ConflictsFeature(stringify!($conflicts_feature)),
                                });
                            }
                        )*
                    } else {
                        $(
                            if extensions.$required_by_extension {
                                return Err(crate::device::features::FeatureRestrictionError {
                                    feature: stringify!($member),
                                    restriction: crate::device::features::FeatureRestriction::RequiredByExtension(stringify!($required_by_extension)),
                                });
                            }
                        )*
                    }
                )*
                Ok(())
            }

            /// Builds a `Features` object with all values to false.
            pub const fn none() -> Features {
                Features {
                    $($member: false,)*
                }
            }

            /// Builds a `Features` object with all values to true.
            ///
            /// > **Note**: This function is used for testing purposes, and is probably useless in
            /// > a real code.
            pub const fn all() -> Features {
                Features {
                    $($member: true,)*
                }
            }

            /// Returns true if `self` is a superset of the parameter.
            ///
            /// That is, for each feature of the parameter that is true, the corresponding value
            /// in self is true as well.
            pub fn is_superset_of(&self, other: &Features) -> bool {
                $((self.$member == true || other.$member == false))&&+
            }

            /// Builds a `Features` that is the intersection of `self` and another `Features`
            /// object.
            ///
            /// The result's field will be true if it is also true in both `self` and `other`.
            pub fn intersection(&self, other: &Features) -> Features {
                Features {
                    $($member: self.$member && other.$member,)*
                }
            }

            /// Builds a `Features` that is the difference of another `Features` object from `self`.
            ///
            /// The result's field will be true if it is true in `self` but not `other`.
            pub fn difference(&self, other: &Features) -> Features {
                Features {
                    $($member: self.$member && !other.$member,)*
                }
            }
        }

        impl FeaturesFfi {
            pub(crate) fn write(&mut self, features: &Features) {
                $(
                    std::array::IntoIter::new([
                        $(self.$ffi_struct.as_mut().map(|s| &mut s$(.$ffi_struct_field)?.$ffi_field)),+
                    ]).flatten().next().map(|f| *f = features.$member as ash::vk::Bool32);
                )*
            }
        }

        impl From<&FeaturesFfi> for Features {
            fn from(features_ffi: &FeaturesFfi) -> Self {
                Features {
                    $(
                        $member: std::array::IntoIter::new([
                            $(features_ffi.$ffi_struct.map(|s| s$(.$ffi_struct_field)?.$ffi_field)),+
                        ]).flatten().next().unwrap_or(0) != 0,
                    )*
                }
            }
        }
    };
}

pub use crate::autogen::Features;
pub(crate) use features;

/// An error that can happen when enabling a feature on a device.
#[derive(Clone, Copy, Debug)]
pub struct FeatureRestrictionError {
    /// The feature in question.
    pub feature: &'static str,
    /// The restriction that was not met.
    pub restriction: FeatureRestriction,
}

impl error::Error for FeatureRestrictionError {}

impl fmt::Display for FeatureRestrictionError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            fmt,
            "a restriction for the feature {} was not met: {}",
            self.feature, self.restriction,
        )
    }
}

#[derive(Clone, Copy, Debug)]
pub enum FeatureRestriction {
    /// Not supported by the physical device.
    NotSupported,
    /// Requires a feature to be enabled.
    RequiresFeature(&'static str),
    /// Requires a feature to be disabled.
    ConflictsFeature(&'static str),
    /// An extension requires this feature to be enabled.
    RequiredByExtension(&'static str),
}

impl fmt::Display for FeatureRestriction {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            FeatureRestriction::NotSupported => {
                write!(fmt, "not supported by the physical device")
            }
            FeatureRestriction::RequiresFeature(feat) => {
                write!(fmt, "requires feature {} to be enabled", feat)
            }
            FeatureRestriction::ConflictsFeature(feat) => {
                write!(fmt, "requires feature {} to be disabled", feat)
            }
            FeatureRestriction::RequiredByExtension(ext) => {
                write!(fmt, "required to be enabled by extension {}", ext)
            }
        }
    }
}

macro_rules! features_ffi {
    {
        $api_version:ident,
        $device_extensions:ident,
        $instance_extensions:ident,
        $($member:ident => {
            ty: $ty:ident,
            provided_by: [$($provided_by:expr),+],
            conflicts: [$($conflicts:ident),*],
        },)+
    } => {
        #[derive(Default)]
        pub(crate) struct FeaturesFfi {
            features_vulkan10: Option<ash::vk::PhysicalDeviceFeatures2KHR>,

            $(
                $member: Option<ash::vk::$ty>,
            )+
        }

        impl FeaturesFfi {
            pub(crate) fn make_chain(
                &mut self,
                $api_version: crate::Version,
                $device_extensions: &DeviceExtensions,
                $instance_extensions: &InstanceExtensions,
            ) {
                self.features_vulkan10 = Some(Default::default());
                let head = self.features_vulkan10.as_mut().unwrap();

                $(
                    if std::array::IntoIter::new([$($provided_by),+]).any(|x| x) &&
                        std::array::IntoIter::new([$(self.$conflicts.is_none()),*]).all(|x| x) {
                        self.$member = Some(Default::default());
                        let member = self.$member.as_mut().unwrap();
                        member.p_next = head.p_next;
                        head.p_next = member as *mut _ as _;
                    }
                )+
            }

            pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
                self.features_vulkan10.as_ref().unwrap()
            }

            pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
                self.features_vulkan10.as_mut().unwrap()
            }
        }
    };
}

pub(crate) use {crate::autogen::FeaturesFfi, features_ffi};
<|endoftext|>


<commit_before>//! Concurrent, atomic options.

use std::{mem, ptr};
use std::sync::atomic::{self, AtomicPtr};

use local;
use garbage::Garbage;
use guard::Guard;

/// A concurrently accessible and updatable optional pointer.
///
/// This acts as a kind of concurrent `Option<T>`.  It can be compared to `std::cell::RefCell` in
/// some ways: It allows accessing, referencing, updating, etc., however contrary to `RefCell`,
/// this is concurrent and has no aliasing restrictions. It is further distinguished from
/// `std::sync::AtomicPtr` in that it allows references to the inner data without the ABA problem
/// or any variant thereof.
///
/// It conveniently wraps this crates API in a seemless manner.
#[derive(Default)]
pub struct Atomic<T> {
    /// The inner atomic pointer.
    inner: AtomicPtr<T>,
}

impl<T> Atomic<T> {
    /// Create a new concurrent option.
    pub fn new(init: Option<Box<T>>) -> Atomic<T> {
        Atomic {
            // Convert the box to a raw pointer.
            inner: AtomicPtr::new(init.map_or(ptr::null_mut(), Box::into_raw)),
        }
    }

    /// Get a reference to the current content of the option.
    ///
    /// This returns a `Guard<T>`, which "protects" the inner value such that it is not dropped
    /// before the guard is no longer active. This is all handled automatically through RAII.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn load(&self, ordering: atomic::Ordering) -> Option<Guard<T>> {
        // Load the inner and wrap it in a guard.
        Guard::maybe_new(|| unsafe {
            self.inner.load(ordering).as_ref()
        })
    }

    /// Store a new value in the option.
    ///
    /// The old value of `self` will eventually be dropped, at some point after all the guarding
    /// references are gone.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn store(&self, new: Option<Box<T>>, ordering: atomic::Ordering) {
        // Transform the optional box to a (possibly null) pointer.
        // TODO: Use coercions.
        let new = new.map_or(ptr::null_mut(), |new| Box::into_raw(new));
        // Swap the contents with the new value.
        let ptr = self.inner.swap(new, ordering);
        if !ptr.is_null() {
            // Queue the deletion of the content.
            local::add_garbage(unsafe { Garbage::new_box(ptr) });
        }
    }

    /// Swap the old value with a new.
    ///
    /// This returns a `Guard<T>` as readers of the old values might exist. The old value will be
    /// queued for destruction.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Performance
    ///
    /// This is slower than `store` as it requires initializing a new guard, which requires at
    /// least two atomic operations. Thus, when possible, you should use `store`.
    pub fn swap(&self, new: Option<Box<T>>, ordering: atomic::Ordering) -> Option<Guard<T>> {
        // Convert `new` into a raw pointer.
        // TODO: Use coercions.
        let new_ptr = new.map_or(ptr::null_mut(), Box::into_raw);

        // Create the guard. It is very important that this is done before the garbage is added,
        // otherwise we might introduce premature frees.
        Guard::maybe_new(|| unsafe {
            // Swap the atomic pointer with the new one.
            self.inner.swap(new_ptr, ordering).as_ref()
        }).map(|guard| {
            // Since the pointer is now unreachable from the option, it can safely be queued for
            // deletion.
            local::add_garbage(unsafe { Garbage::new_box(&*guard) });

            guard
        })
    }

    /// Store a (raw) pointer if the current matches the specified pointer.
    ///
    /// This compares `self` to `old`. If they match, the value is set to `new` and `Ok(())` is
    /// returned. Otherwise, `Err(())` is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Safety
    ///
    /// As this accepts a raw pointer, it is necessary to mark it as `unsafe`. To uphold the
    /// invariants, ensure that `new` isn't used after this function has been called.
    pub unsafe fn compare_and_store_raw(&self, old: *const T, new: *mut T, ordering: atomic::Ordering)
    -> Result<(), ()> {

        // Compare-and-swap the value and check if it was successful.
        if self.inner.compare_and_swap(old as *mut T, new, ordering) as *const T == old {
            // It was. `self` is now `new`.

            // Queue the deletion of now-unreachable `old` (unless it's `None`).
            if !old.is_null() {
                local::add_garbage(Garbage::new_box(old));
            }

            Ok(())
        } else {
            // It failed.
            Err(())
        }
    }

    /// Store a pointer if the current matches the specified pointer.
    ///
    /// This compares `self` to `old`. If they match, the value is set to `new` and `Ok(())` is
    /// returned. Otherwise, `Err(new)` is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn compare_and_store(&self, old: Option<*const T>, new: Option<Box<T>>, ordering: atomic::Ordering)
    -> Result<(), Option<Box<T>>> {
        // Run the CAS.
        if unsafe {
            self.compare_and_store_raw(
                // Convert the input to raw pointers.
                old.unwrap_or(ptr::null()),
                // TODO: Does this break NOALIAS if it is enabled on `Box` in the future in `rustc`
                //       (see also `compare_and_swap`)?
                new.as_ref().map_or(ptr::null_mut(), |x| &**x as *const T as *mut T),
                ordering,
            )
        }.is_ok() {
            // `new` is now in `self`. We must thus ensure that the destructor isn't called, as
            // that might cause use-after-free.
            mem::forget(new);

            Ok(())
        } else {
            // Hand back the box.
            Err(new)
        }
    }

    /// Swap a (raw) pointer if it matches the specified pointer.
    ///
    /// This compares `self` to `old`. If they match, it is swapped with `new` and a guard to the
    /// old value is returned wrapped in `Ok`. If not, a tuple containing the guard to the actual
    /// (non-matching) value, wrapped in `Err()` is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Safety
    ///
    /// As this accepts a raw pointer, it is necessary to mark it as `unsafe`. To uphold the
    /// invariants, ensure that `new` isn't used after this function has been called.
    pub unsafe fn compare_and_swap_raw(
        &self,
        old: *const T,
        new: *mut T,
        ordering: atomic::Ordering
    ) -> Result<Option<Guard<T>>, Option<Guard<T>>> {
        // Create the guard beforehand to avoid premature frees.
        let guard = Guard::maybe_new(|| {
            // The guard is active, so we can do the CAS now.
            self.inner.compare_and_swap(old as *mut T, new, ordering).as_ref()
        });

        // Convert the guard to a raw pointer.
        // TODO: Use coercions.
        let guard_ptr = guard.as_ref().map_or(ptr::null_mut(), |x| &**x as *const T as *mut T);

        // Check if the CAS was successful.
        if guard_ptr as *const T == old {
            // It was. `self` is now `new`.

            // Queue the deletion of now-unreachable `old` (unless it's `None`).
            if !old.is_null() {
                local::add_garbage(Garbage::new_box(old));
            }

            Ok(guard)
        } else {
            Err(guard)
        }
    }

    /// Swap a pointer if it matches the specified pointer.
    ///
    /// This compares `self` to `old`. If they match, it is swapped with `new` and a guard to the
    /// old value is returned wrapped in `Ok`. If not, a tuple containing the guard to the actual
    /// (non-matching) value and the box of `new` — wrapped in `Err` — is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Performance
    ///
    /// This is slower than `compare_and_store` as it requires initializing a new guard, which
    /// requires at least two atomic operations. Thus, when possible, you should use
    /// `compare_and_store`.
    pub fn compare_and_swap(&self, old: Option<*const T>, new: Option<Box<T>>, ordering: atomic::Ordering)
    -> Result<Option<Guard<T>>, (Option<Guard<T>>, Option<Box<T>>)> {
        // Run the CAS.
        match unsafe {
            self.compare_and_swap_raw(
                // Convert the input to raw pointers.
                old.unwrap_or(ptr::null()),
                new.as_ref().map_or(ptr::null_mut(), |x| &**x as *const T as *mut T),
                ordering,
            )
        } {
            Ok(guard) => {
                // `new` is now in `self`. We must thus ensure that the destructor isn't called, as
                // that might cause use-after-free.
                mem::forget(new);

                Ok(guard)
            },
            // Hand back the box too.
            Err(guard) => Err((guard, new))
        }
    }
}

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

    use std::sync::{atomic, Arc};
    use std::sync::atomic::AtomicUsize;
    use std::thread;

    struct Basic;

    impl Drop for Basic {
        fn drop(&mut self) {
            basic();
        }
    }

    thread_local! {
        static BASIC: Basic = Basic;
    }

    fn basic() {
        let opt = Atomic::default();
        assert!(opt.load(atomic::Ordering::Relaxed).is_none());
        assert!(opt.swap(None, atomic::Ordering::Relaxed).is_none());
        assert!(opt.load(atomic::Ordering::Relaxed).is_none());
        assert!(opt.swap(Some(Box::new(42)), atomic::Ordering::Relaxed).is_none());
        assert_eq!(*opt.load(atomic::Ordering::Relaxed).unwrap(), 42);
        assert_eq!(*opt.swap(Some(Box::new(43)), atomic::Ordering::Relaxed).unwrap(), 42);
        assert_eq!(*opt.load(atomic::Ordering::Relaxed).unwrap(), 43);
    }

    #[test]
    fn basic_properties() {
        basic()
    }

    #[test]
    fn cas() {
        let bx1 = Box::new(1);
        let ptr1 = &*bx1 as *const usize;
        let bx2 = Box::new(1);
        let ptr2 = &*bx2 as *const usize;

        let opt = Atomic::new(Some(bx1));
        assert_eq!(ptr1, &*opt.compare_and_swap(Some(ptr2), None, atomic::Ordering::Relaxed).unwrap_err().0.unwrap());
        assert_eq!(ptr1, &*opt.load(atomic::Ordering::Relaxed).unwrap());

        assert_eq!(ptr1, &*opt.compare_and_swap(None, Some(Box::new(2)), atomic::Ordering::Relaxed).unwrap_err().0.unwrap());
        assert_eq!(ptr1, &*opt.load(atomic::Ordering::Relaxed).unwrap());

        opt.compare_and_swap(Some(ptr1), None, atomic::Ordering::Relaxed).unwrap();
        assert!(opt.load(atomic::Ordering::Relaxed).is_none());

        opt.compare_and_swap(None, Some(bx2), atomic::Ordering::Relaxed).unwrap();
        assert_eq!(ptr2, &*opt.load(atomic::Ordering::Relaxed).unwrap());

        opt.compare_and_store(Some(ptr2), None, atomic::Ordering::Relaxed).unwrap();
        opt.compare_and_store(Some(Box::into_raw(Box::new(2))), None, atomic::Ordering::Relaxed).unwrap_err();

        assert!(opt.load(atomic::Ordering::Relaxed).is_none());

        // To check that GC doesn't segfault or something.
        ::gc();
        ::gc();
        ::gc();
        ::gc();
    }

    #[test]
    fn spam() {
        let opt = Arc::new(Atomic::default());

        let mut j = Vec::new();
        for _ in 0..16 {
            let opt = opt.clone();
            j.push(thread::spawn(move || {
                for i in 0..1_000_001 {
                    let _ = opt.load(atomic::Ordering::Relaxed);
                    opt.store(Some(Box::new(i)), atomic::Ordering::Relaxed);
                }
                opt
            }))
        }

        ::gc();
        ::gc();

        for i in j {
            i.join().unwrap();
        }

        assert_eq!(*opt.load(atomic::Ordering::Relaxed).unwrap(), 1_000_000);
    }

    #[test]
    fn drop() {
        #[derive(Clone)]
        struct Dropper {
            d: Arc<AtomicUsize>,
        }

        impl Drop for Dropper {
            fn drop(&mut self) {
                self.d.fetch_add(1, atomic::Ordering::Relaxed);
            }
        }

        let drops = Arc::new(AtomicUsize::default());
        let opt = Arc::new(Atomic::new(None));

        let d = Dropper {
            d: drops.clone(),
        };

        let mut j = Vec::new();
        for _ in 0..16 {
            let d = d.clone();
            let opt = opt.clone();

            j.push(thread::spawn(move || {
                for _ in 0..1_000_000 {
                    opt.store(Some(Box::new(d.clone())), atomic::Ordering::Relaxed);
                }
            }))
        }

        for i in j {
            i.join().unwrap();
        }

        opt.store(None, atomic::Ordering::Relaxed);

        ::gc();

        // The 16 are for the `d` variable in the loop above.
        assert_eq!(drops.load(atomic::Ordering::Relaxed), 16_000_000 + 16);
    }

    #[test]
    fn tls() {
        thread::spawn(|| BASIC.with(|_| {})).join().unwrap();
        thread::spawn(|| BASIC.with(|_| {})).join().unwrap();
        thread::spawn(|| BASIC.with(|_| {})).join().unwrap();
        thread::spawn(|| BASIC.with(|_| {})).join().unwrap();
    }
}
<commit_msg>Add tests for `compare_and_swap_raw`.<commit_after>//! Concurrent, atomic options.

use std::{mem, ptr};
use std::sync::atomic::{self, AtomicPtr};

use local;
use garbage::Garbage;
use guard::Guard;

/// A concurrently accessible and updatable optional pointer.
///
/// This acts as a kind of concurrent `Option<T>`.  It can be compared to `std::cell::RefCell` in
/// some ways: It allows accessing, referencing, updating, etc., however contrary to `RefCell`,
/// this is concurrent and has no aliasing restrictions. It is further distinguished from
/// `std::sync::AtomicPtr` in that it allows references to the inner data without the ABA problem
/// or any variant thereof.
///
/// It conveniently wraps this crates API in a seemless manner.
#[derive(Default)]
pub struct Atomic<T> {
    /// The inner atomic pointer.
    inner: AtomicPtr<T>,
}

impl<T> Atomic<T> {
    /// Create a new concurrent option.
    pub fn new(init: Option<Box<T>>) -> Atomic<T> {
        Atomic {
            // Convert the box to a raw pointer.
            inner: AtomicPtr::new(init.map_or(ptr::null_mut(), Box::into_raw)),
        }
    }

    /// Get a reference to the current content of the option.
    ///
    /// This returns a `Guard<T>`, which "protects" the inner value such that it is not dropped
    /// before the guard is no longer active. This is all handled automatically through RAII.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn load(&self, ordering: atomic::Ordering) -> Option<Guard<T>> {
        // Load the inner and wrap it in a guard.
        Guard::maybe_new(|| unsafe {
            self.inner.load(ordering).as_ref()
        })
    }

    /// Store a new value in the option.
    ///
    /// The old value of `self` will eventually be dropped, at some point after all the guarding
    /// references are gone.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn store(&self, new: Option<Box<T>>, ordering: atomic::Ordering) {
        // Transform the optional box to a (possibly null) pointer.
        // TODO: Use coercions.
        let new = new.map_or(ptr::null_mut(), |new| Box::into_raw(new));
        // Swap the contents with the new value.
        let ptr = self.inner.swap(new, ordering);
        if !ptr.is_null() {
            // Queue the deletion of the content.
            local::add_garbage(unsafe { Garbage::new_box(ptr) });
        }
    }

    /// Swap the old value with a new.
    ///
    /// This returns a `Guard<T>` as readers of the old values might exist. The old value will be
    /// queued for destruction.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Performance
    ///
    /// This is slower than `store` as it requires initializing a new guard, which requires at
    /// least two atomic operations. Thus, when possible, you should use `store`.
    pub fn swap(&self, new: Option<Box<T>>, ordering: atomic::Ordering) -> Option<Guard<T>> {
        // Convert `new` into a raw pointer.
        // TODO: Use coercions.
        let new_ptr = new.map_or(ptr::null_mut(), Box::into_raw);

        // Create the guard. It is very important that this is done before the garbage is added,
        // otherwise we might introduce premature frees.
        Guard::maybe_new(|| unsafe {
            // Swap the atomic pointer with the new one.
            self.inner.swap(new_ptr, ordering).as_ref()
        }).map(|guard| {
            // Since the pointer is now unreachable from the option, it can safely be queued for
            // deletion.
            local::add_garbage(unsafe { Garbage::new_box(&*guard) });

            guard
        })
    }

    /// Store a (raw) pointer if the current matches the specified pointer.
    ///
    /// This compares `self` to `old`. If they match, the value is set to `new` and `Ok(())` is
    /// returned. Otherwise, `Err(())` is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Safety
    ///
    /// As this accepts a raw pointer, it is necessary to mark it as `unsafe`. To uphold the
    /// invariants, ensure that `new` isn't used after this function has been called.
    pub unsafe fn compare_and_store_raw(&self, old: *const T, new: *mut T, ordering: atomic::Ordering)
    -> Result<(), ()> {

        // Compare-and-swap the value and check if it was successful.
        if self.inner.compare_and_swap(old as *mut T, new, ordering) as *const T == old {
            // It was. `self` is now `new`.

            // Queue the deletion of now-unreachable `old` (unless it's `None`).
            if !old.is_null() {
                local::add_garbage(Garbage::new_box(old));
            }

            Ok(())
        } else {
            // It failed.
            Err(())
        }
    }

    /// Store a pointer if the current matches the specified pointer.
    ///
    /// This compares `self` to `old`. If they match, the value is set to `new` and `Ok(())` is
    /// returned. Otherwise, `Err(new)` is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn compare_and_store(&self, old: Option<*const T>, new: Option<Box<T>>, ordering: atomic::Ordering)
    -> Result<(), Option<Box<T>>> {
        // Run the CAS.
        if unsafe {
            self.compare_and_store_raw(
                // Convert the input to raw pointers.
                old.unwrap_or(ptr::null()),
                // TODO: Does this break NOALIAS if it is enabled on `Box` in the future in `rustc`
                //       (see also `compare_and_swap`)?
                new.as_ref().map_or(ptr::null_mut(), |x| &**x as *const T as *mut T),
                ordering,
            )
        }.is_ok() {
            // `new` is now in `self`. We must thus ensure that the destructor isn't called, as
            // that might cause use-after-free.
            mem::forget(new);

            Ok(())
        } else {
            // Hand back the box.
            Err(new)
        }
    }

    /// Swap a (raw) pointer if it matches the specified pointer.
    ///
    /// This compares `self` to `old`. If they match, it is swapped with `new` and a guard to the
    /// old value is returned wrapped in `Ok`. If not, a tuple containing the guard to the actual
    /// (non-matching) value, wrapped in `Err()` is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Safety
    ///
    /// As this accepts a raw pointer, it is necessary to mark it as `unsafe`. To uphold the
    /// invariants, ensure that `new` isn't used after this function has been called.
    pub unsafe fn compare_and_swap_raw(
        &self,
        old: *const T,
        new: *mut T,
        ordering: atomic::Ordering
    ) -> Result<Option<Guard<T>>, Option<Guard<T>>> {
        // Create the guard beforehand to avoid premature frees.
        let guard = Guard::maybe_new(|| {
            // The guard is active, so we can do the CAS now.
            self.inner.compare_and_swap(old as *mut T, new, ordering).as_ref()
        });

        // Convert the guard to a raw pointer.
        // TODO: Use coercions.
        let guard_ptr = guard.as_ref().map_or(ptr::null_mut(), |x| &**x as *const T as *mut T);

        // Check if the CAS was successful.
        if guard_ptr as *const T == old {
            // It was. `self` is now `new`.

            // Queue the deletion of now-unreachable `old` (unless it's `None`).
            if !old.is_null() {
                local::add_garbage(Garbage::new_box(old));
            }

            Ok(guard)
        } else {
            Err(guard)
        }
    }

    /// Swap a pointer if it matches the specified pointer.
    ///
    /// This compares `self` to `old`. If they match, it is swapped with `new` and a guard to the
    /// old value is returned wrapped in `Ok`. If not, a tuple containing the guard to the actual
    /// (non-matching) value and the box of `new` — wrapped in `Err` — is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Performance
    ///
    /// This is slower than `compare_and_store` as it requires initializing a new guard, which
    /// requires at least two atomic operations. Thus, when possible, you should use
    /// `compare_and_store`.
    pub fn compare_and_swap(&self, old: Option<*const T>, new: Option<Box<T>>, ordering: atomic::Ordering)
    -> Result<Option<Guard<T>>, (Option<Guard<T>>, Option<Box<T>>)> {
        // Run the CAS.
        match unsafe {
            self.compare_and_swap_raw(
                // Convert the input to raw pointers.
                old.unwrap_or(ptr::null()),
                new.as_ref().map_or(ptr::null_mut(), |x| &**x as *const T as *mut T),
                ordering,
            )
        } {
            Ok(guard) => {
                // `new` is now in `self`. We must thus ensure that the destructor isn't called, as
                // that might cause use-after-free.
                mem::forget(new);

                Ok(guard)
            },
            // Hand back the box too.
            Err(guard) => Err((guard, new))
        }
    }
}

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

    use std::sync::{atomic, Arc};
    use std::sync::atomic::AtomicUsize;
    use std::{thread, ptr};

    struct Basic;

    impl Drop for Basic {
        fn drop(&mut self) {
            basic();
        }
    }

    thread_local! {
        static BASIC: Basic = Basic;
    }

    fn basic() {
        let opt = Atomic::default();
        assert!(opt.load(atomic::Ordering::Relaxed).is_none());
        assert!(opt.swap(None, atomic::Ordering::Relaxed).is_none());
        assert!(opt.load(atomic::Ordering::Relaxed).is_none());
        assert!(opt.swap(Some(Box::new(42)), atomic::Ordering::Relaxed).is_none());
        assert_eq!(*opt.load(atomic::Ordering::Relaxed).unwrap(), 42);
        assert_eq!(*opt.swap(Some(Box::new(43)), atomic::Ordering::Relaxed).unwrap(), 42);
        assert_eq!(*opt.load(atomic::Ordering::Relaxed).unwrap(), 43);
    }

    #[test]
    fn basic_properties() {
        basic()
    }

    #[test]
    fn cas() {
        let bx1 = Box::new(1);
        let ptr1 = &*bx1 as *const usize;
        let bx2 = Box::new(1);
        let ptr2 = &*bx2 as *const usize;

        let opt = Atomic::new(Some(bx1));
        assert_eq!(ptr1, &*opt.compare_and_swap(Some(ptr2), None, atomic::Ordering::Relaxed).unwrap_err().0.unwrap());
        assert_eq!(ptr1, &*opt.load(atomic::Ordering::Relaxed).unwrap());

        assert_eq!(ptr1, &*opt.compare_and_swap(None, Some(Box::new(2)), atomic::Ordering::Relaxed).unwrap_err().0.unwrap());
        assert_eq!(ptr1, &*opt.load(atomic::Ordering::Relaxed).unwrap());

        opt.compare_and_swap(Some(ptr1), None, atomic::Ordering::Relaxed).unwrap();
        assert!(opt.load(atomic::Ordering::Relaxed).is_none());

        opt.compare_and_swap(None, Some(bx2), atomic::Ordering::Relaxed).unwrap();
        assert_eq!(ptr2, &*opt.load(atomic::Ordering::Relaxed).unwrap());

        opt.compare_and_store(Some(ptr2), None, atomic::Ordering::Relaxed).unwrap();
        opt.compare_and_store(Some(Box::into_raw(Box::new(2))), None, atomic::Ordering::Relaxed).unwrap_err();

        assert!(opt.load(atomic::Ordering::Relaxed).is_none());

        // To check that GC doesn't segfault or something.
        ::gc();
        ::gc();
        ::gc();
        ::gc();
    }

    #[test]
    fn cas_raw() {
        unsafe {
            let bx1 = Box::new(1);
            let ptr1 = &*bx1 as *const usize;
            let bx2 = Box::new(1);
            let ptr2 = &*bx2 as *const usize;

            let opt = Atomic::new(Some(bx1));
            assert_eq!(ptr1, &*opt.compare_and_swap_raw(ptr2, ptr::null_mut(), atomic::Ordering::Relaxed).unwrap_err().unwrap());
            assert_eq!(ptr1, &*opt.load(atomic::Ordering::Relaxed).unwrap());

            assert_eq!(ptr1, &*opt.compare_and_swap_raw(ptr::null(), Box::into_raw(Box::new(2)), atomic::Ordering::Relaxed).unwrap_err().unwrap());
            assert_eq!(ptr1, &*opt.load(atomic::Ordering::Relaxed).unwrap());

            opt.compare_and_swap_raw(ptr1, ptr::null_mut(), atomic::Ordering::Relaxed).unwrap();
            assert!(opt.load(atomic::Ordering::Relaxed).is_none());

            opt.compare_and_swap_raw(ptr::null(), Box::into_raw(bx2), atomic::Ordering::Relaxed).unwrap();
            assert_eq!(ptr2, &*opt.load(atomic::Ordering::Relaxed).unwrap());

            opt.compare_and_store_raw(ptr2, ptr::null_mut(), atomic::Ordering::Relaxed).unwrap();
            opt.compare_and_store_raw(Box::into_raw(Box::new(2)), ptr::null_mut(), atomic::Ordering::Relaxed).unwrap_err();

            assert!(opt.load(atomic::Ordering::Relaxed).is_none());

            // To check that GC doesn't segfault or something.
            ::gc();
            ::gc();
            ::gc();
            ::gc();
        }
    }

    #[test]
    fn spam() {
        let opt = Arc::new(Atomic::default());

        let mut j = Vec::new();
        for _ in 0..16 {
            let opt = opt.clone();
            j.push(thread::spawn(move || {
                for i in 0..1_000_001 {
                    let _ = opt.load(atomic::Ordering::Relaxed);
                    opt.store(Some(Box::new(i)), atomic::Ordering::Relaxed);
                }
                opt
            }))
        }

        ::gc();
        ::gc();

        for i in j {
            i.join().unwrap();
        }

        assert_eq!(*opt.load(atomic::Ordering::Relaxed).unwrap(), 1_000_000);
    }

    #[test]
    fn drop() {
        #[derive(Clone)]
        struct Dropper {
            d: Arc<AtomicUsize>,
        }

        impl Drop for Dropper {
            fn drop(&mut self) {
                self.d.fetch_add(1, atomic::Ordering::Relaxed);
            }
        }

        let drops = Arc::new(AtomicUsize::default());
        let opt = Arc::new(Atomic::new(None));

        let d = Dropper {
            d: drops.clone(),
        };

        let mut j = Vec::new();
        for _ in 0..16 {
            let d = d.clone();
            let opt = opt.clone();

            j.push(thread::spawn(move || {
                for _ in 0..1_000_000 {
                    opt.store(Some(Box::new(d.clone())), atomic::Ordering::Relaxed);
                }
            }))
        }

        for i in j {
            i.join().unwrap();
        }

        opt.store(None, atomic::Ordering::Relaxed);

        ::gc();

        // The 16 are for the `d` variable in the loop above.
        assert_eq!(drops.load(atomic::Ordering::Relaxed), 16_000_000 + 16);
    }

    #[test]
    fn tls() {
        thread::spawn(|| BASIC.with(|_| {})).join().unwrap();
        thread::spawn(|| BASIC.with(|_| {})).join().unwrap();
        thread::spawn(|| BASIC.with(|_| {})).join().unwrap();
        thread::spawn(|| BASIC.with(|_| {})).join().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate odbc_safe;
use odbc_safe::*;
use std::str::from_utf8;

struct LastError(String);
type MyResult<T> = Result<T, LastError>;

impl<D: Diagnostics> From<D> for LastError {
    fn from(source: D) -> Self {
        let mut buffer = [0; 512];
        match source.diagnostics(1, &mut buffer) {
            ReturnOption::Success(dr) | ReturnOption::Info(dr) => LastError(
                from_utf8(&buffer[0..(dr.text_length as usize)])
                    .unwrap()
                    .to_owned(),
            ),
            ReturnOption::Error(()) => panic!("Error during fetching diagnostic record"),
            ReturnOption::NoData(()) => panic!("No diagnostic record present"),
        }
    }
}

fn main() {

    let env = Environment::new().unwrap();
    let env = env.declare_version_3().unwrap();

    match run(&env) {
        Ok(()) => (),
        Err(LastError(message)) => println!("An error occurred: {}", message),
    }
}

fn run(env: &Environment<Odbc3>) -> MyResult<()> {

    let conn = connect(&env);
    print_fields(execute_query(&conn)?)?;
    conn.disconnect().success().map(|_| ())
}

fn connect<V>(env: &Environment<V>) -> Connection<Connected>
where
    V: Version,
{
    let conn = Connection::with_parent(env).unwrap();
    conn.connect("TestDataSource", "", "").unwrap()
}

fn execute_query<'a, 'b>(conn: &'a Connection<Connected>) -> MyResult<Statement<'a, 'b, Opened>> {
    let stmt = Statement::with_parent(conn).unwrap();
    match stmt.exec_direct("SELECT * FROM MOVIES") {
        ReturnOption::Success(s) | ReturnOption::Info(s) => Ok(s),
        ReturnOption::NoData(_) => Err(LastError(
            "Statement did not return a Result Set.".to_owned(),
        )),
        ReturnOption::Error(e) => Err(e.into()),
    }
}

fn print_fields(result_set: Statement<Opened>) -> MyResult<()> {
    let cols = result_set.num_result_cols().unwrap();
    let mut buffer = [0u8; 512];
    let mut cursor = match result_set.fetch() {
        ReturnOption::Success(r) | ReturnOption::Info(r) => r,
        ReturnOption::NoData(_) => return Ok(()),
        ReturnOption::Error(e) => return Err(e.into()),
    };
    loop {
        for index in 1..(cols + 1) {
            match cursor.get_data(index as u16, &mut buffer as &mut [u8]) {
                ReturnOption::Success(ind) | ReturnOption::Info(ind) => match ind {
                    Indicator::NoTotal => panic!("No Total"),
                    Indicator::Null => println!("NULL"),
                    Indicator::Length(l) => {
                        print!("{}", from_utf8(&buffer[0..l as usize]).unwrap());
                    }
                },
                ReturnOption::NoData(_) => panic!("No Field Data"),
                ReturnOption::Error(_) => return Err(cursor.into()),
            }
            print!(" | ");
        }
        cursor = match cursor.fetch() {
            ReturnOption::Success(r) | ReturnOption::Info(r) => r,
            ReturnOption::NoData(_) => break Ok(()),
            ReturnOption::Error(e) => break Err(e.into()),
        };
        println!("");
    }
}
<commit_msg>change panic to error<commit_after>extern crate odbc_safe;
use odbc_safe::*;
use std::str::from_utf8;

struct LastError(String);
type MyResult<T> = Result<T, LastError>;

impl<D: Diagnostics> From<D> for LastError {
    fn from(source: D) -> Self {
        let mut buffer = [0; 512];
        match source.diagnostics(1, &mut buffer) {
            ReturnOption::Success(dr) | ReturnOption::Info(dr) => LastError(
                from_utf8(&buffer[0..(dr.text_length as usize)])
                    .unwrap()
                    .to_owned(),
            ),
            ReturnOption::Error(()) => panic!("Error during fetching diagnostic record"),
            ReturnOption::NoData(()) => LastError("No Diagnostic Record present".to_owned()),
        }
    }
}

fn main() {

    let env = Environment::new().unwrap();
    let env = env.declare_version_3().unwrap();

    match run(&env) {
        Ok(()) => (),
        Err(LastError(message)) => println!("An error occurred: {}", message),
    }
}

fn run(env: &Environment<Odbc3>) -> MyResult<()> {

    let conn = connect(&env);
    print_fields(execute_query(&conn)?)?;
    conn.disconnect().success().map(|_| ())
}

fn connect<V>(env: &Environment<V>) -> Connection<Connected>
where
    V: Version,
{
    let conn = Connection::with_parent(env).unwrap();
    conn.connect("TestDataSource", "", "").unwrap()
}

fn execute_query<'a, 'b>(conn: &'a Connection<Connected>) -> MyResult<Statement<'a, 'b, Opened>> {
    let stmt = Statement::with_parent(conn).unwrap();
    match stmt.exec_direct("SELECT * FROM MOVIES") {
        ReturnOption::Success(s) | ReturnOption::Info(s) => Ok(s),
        ReturnOption::NoData(_) => Err(LastError(
            "Statement did not return a Result Set.".to_owned(),
        )),
        ReturnOption::Error(e) => Err(e.into()),
    }
}

fn print_fields(result_set: Statement<Opened>) -> MyResult<()> {
    let cols = result_set.num_result_cols().unwrap();
    let mut buffer = [0u8; 512];
    let mut cursor = match result_set.fetch() {
        ReturnOption::Success(r) | ReturnOption::Info(r) => r,
        ReturnOption::NoData(_) => return Ok(()),
        ReturnOption::Error(e) => return Err(e.into()),
    };
    loop {
        for index in 1..(cols + 1) {
            match cursor.get_data(index as u16, &mut buffer as &mut [u8]) {
                ReturnOption::Success(ind) | ReturnOption::Info(ind) => match ind {
                    Indicator::NoTotal => panic!("No Total"),
                    Indicator::Null => println!("NULL"),
                    Indicator::Length(l) => {
                        print!("{}", from_utf8(&buffer[0..l as usize]).unwrap());
                    }
                },
                ReturnOption::NoData(_) => panic!("No Field Data"),
                ReturnOption::Error(_) => return Err(cursor.into()),
            }
            print!(" | ");
        }
        cursor = match cursor.fetch() {
            ReturnOption::Success(r) | ReturnOption::Info(r) => r,
            ReturnOption::NoData(_) => break Ok(()),
            ReturnOption::Error(e) => break Err(e.into()),
        };
        println!("");
    }
}
<|endoftext|>


<commit_before>extern crate pkg_config;
extern crate prost;
extern crate prost_build;

use std::{env,
          fs,
          path::PathBuf};

fn main() {
    let mut config = prost_build::Config::new();
    config.type_attribute(".butterfly.newscast.Rumor.payload",
                          "#[allow(clippy::large_enum_variant)]");
    config.type_attribute(".", "#[derive(Serialize, Deserialize)]");
    config.compile_protos(&protocol_files(), &protocol_includes())
          .expect("Error compiling protobuf definitions");
    for file in generated_files() {
        fs::copy(&file,
                 // NB: src/generated is presumed to exist; if you delete
                 // it, this'll fail.
                 format!("src/generated/{}",
                         file.file_name().unwrap().to_string_lossy())).expect("Could not copy \
                                                                               generated code to \
                                                                               src/generated");
    }
}

fn generated_files() -> Vec<PathBuf> {
    let mut files = vec![];
    for entry in fs::read_dir(env::var("OUT_DIR").unwrap()).unwrap() {
        let file = entry.unwrap();
        if file.file_name().to_str().unwrap().ends_with(".rs") && file.metadata().unwrap().is_file()
        {
            files.push(file.path());
        }
    }
    files
}

fn protocol_includes() -> Vec<String> { vec!["protocols".to_string()] }

fn protocol_files() -> Vec<String> {
    let mut files = vec![];
    for entry in fs::read_dir("protocols").unwrap() {
        let file = entry.unwrap();
        // skip vim temp files
        if file.file_name().to_str().unwrap().starts_with('.') {
            continue;
        }
        if file.metadata().unwrap().is_file() {
            files.push(file.path().to_string_lossy().into_owned());
        }
    }
    files
}
<commit_msg>butterfly: Inline protocol file names<commit_after>use prost_build;

fn main() {
    let mut config = prost_build::Config::new();
    config.type_attribute(".butterfly.newscast.Rumor.payload",
                          "#[allow(clippy::large_enum_variant)]");
    config.type_attribute(".", "#[derive(Serialize, Deserialize)]");
    config.compile_protos(&["protocols/common.proto",
                            "protocols/newscast.proto",
                            "protocols/swim.proto"],
                          &["protocols/"])
          .expect("Couldn't compile protobufs!");
    for file in generated_files() {
        fs::copy(&file,
                 // NB: src/generated is presumed to exist; if you delete
                 // it, this'll fail.
                 format!("src/generated/{}",
                         file.file_name().unwrap().to_string_lossy())).expect("Could not copy \
                                                                               generated code to \
                                                                               src/generated");
    }
}

fn generated_files() -> Vec<PathBuf> {
    let mut files = vec![];
    for entry in fs::read_dir(env::var("OUT_DIR").unwrap()).unwrap() {
        let file = entry.unwrap();
        if file.file_name().to_str().unwrap().ends_with(".rs") && file.metadata().unwrap().is_file()
        {
            files.push(file.path());
        }
    }
    files
}
<|endoftext|>


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

use std::str;

use resource_task::{Done, Payload, Metadata, LoadData, LoadResponse, start_sending};

use serialize::base64::FromBase64;

use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType;
use url::{percent_decode, NonRelativeSchemeData};

pub fn factory(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    // NB: we don't spawn a new task.
    // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
    // Should be tested at some point.
    // Left in separate function to allow easy moving to a task, if desired.
    load(load_data, start_chan)
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    let url = load_data.url;
    assert!("data" == url.scheme.as_slice());

    let mut metadata = Metadata::default(url.clone());

    // Split out content type and data.
    let mut scheme_data = match url.scheme_data {
        NonRelativeSchemeData(scheme_data) => scheme_data,
        _ => fail!("Expected a non-relative scheme URL.")
    };
    match url.query {
        Some(query) => {
            scheme_data.push_str("?");
            scheme_data.push_str(query.as_slice());
        },
        None => ()
    }
    let parts: Vec<&str> = scheme_data.as_slice().splitn(',', 1).collect();
    if parts.len() != 2 {
        start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string())));
        return;
    }

    // ";base64" must come at the end of the content type, per RFC 2397.
    // rust-http will fail to parse it because there's no =value part.
    let mut is_base64 = false;
    let mut ct_str = parts[0];
    if ct_str.ends_with(";base64") {
        is_base64 = true;
        ct_str = ct_str.slice_to(ct_str.as_bytes().len() - 7);
    }

    // Parse the content type using rust-http.
    // FIXME: this can go into an infinite loop! (rust-http #25)
    let content_type: Option<MediaType> = from_stream_with_str(ct_str);
    metadata.set_content_type(&content_type);

    let progress_chan = start_sending(start_chan, metadata);
    let bytes = percent_decode(parts[1].as_bytes());

    if is_base64 {
        // FIXME(#2909): It’s unclear what to do with non-alphabet characters,
        // but Acid 3 apparently depends on spaces being ignored.
        let bytes = bytes.move_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>();
        match bytes.as_slice().from_base64() {
            Err(..) => {
                progress_chan.send(Done(Err("non-base64 data uri".to_string())));
            }
            Ok(data) => {
                progress_chan.send(Payload(data));
                progress_chan.send(Done(Ok(())));
            }
        }
    } else {
        progress_chan.send(Payload(bytes));
        progress_chan.send(Done(Ok(())));
    }
}

#[cfg(test)]
fn assert_parse(url:          &'static str,
                content_type: Option<(String, String)>,
                charset:      Option<String>,
                data:         Option<Vec<u8>>) {
    use std::comm;
    use url::Url;

    let (start_chan, start_port) = comm::channel();
    load(LoadData::new(Url::parse(url).unwrap()), start_chan);

    let response = start_port.recv();
    assert_eq!(&response.metadata.content_type, &content_type);
    assert_eq!(&response.metadata.charset,      &charset);

    let progress = response.progress_port.recv();

    match data {
        None => {
            assert_eq!(progress, Done(Err("invalid data uri".to_string())));
        }
        Some(dat) => {
            assert_eq!(progress, Payload(dat));
            assert_eq!(response.progress_port.recv(), Done(Ok(())));
        }
    }
}

#[test]
fn empty_invalid() {
    assert_parse("data:", None, None, None);
}

#[test]
fn plain() {
    assert_parse("data:,hello%20world", None, None, Some(b"hello world".iter().map(|&x| x).collect()));
}

#[test]
fn plain_ct() {
    assert_parse("data:text/plain,hello",
        Some(("text".to_string(), "plain".to_string())), None, Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn plain_charset() {
    assert_parse("data:text/plain;charset=latin1,hello",
        Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn base64() {
    assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_ct() {
    assert_parse("data:application/octet-stream;base64,C62+7w==",
        Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_charset() {
    assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
        Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
        Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
}
<commit_msg>Fix broken build after denying unused imports.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use resource_task::{Done, Payload, Metadata, LoadData, LoadResponse, start_sending};

use serialize::base64::FromBase64;

use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType;
use url::{percent_decode, NonRelativeSchemeData};

pub fn factory(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    // NB: we don't spawn a new task.
    // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
    // Should be tested at some point.
    // Left in separate function to allow easy moving to a task, if desired.
    load(load_data, start_chan)
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    let url = load_data.url;
    assert!("data" == url.scheme.as_slice());

    let mut metadata = Metadata::default(url.clone());

    // Split out content type and data.
    let mut scheme_data = match url.scheme_data {
        NonRelativeSchemeData(scheme_data) => scheme_data,
        _ => fail!("Expected a non-relative scheme URL.")
    };
    match url.query {
        Some(query) => {
            scheme_data.push_str("?");
            scheme_data.push_str(query.as_slice());
        },
        None => ()
    }
    let parts: Vec<&str> = scheme_data.as_slice().splitn(',', 1).collect();
    if parts.len() != 2 {
        start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string())));
        return;
    }

    // ";base64" must come at the end of the content type, per RFC 2397.
    // rust-http will fail to parse it because there's no =value part.
    let mut is_base64 = false;
    let mut ct_str = parts[0];
    if ct_str.ends_with(";base64") {
        is_base64 = true;
        ct_str = ct_str.slice_to(ct_str.as_bytes().len() - 7);
    }

    // Parse the content type using rust-http.
    // FIXME: this can go into an infinite loop! (rust-http #25)
    let content_type: Option<MediaType> = from_stream_with_str(ct_str);
    metadata.set_content_type(&content_type);

    let progress_chan = start_sending(start_chan, metadata);
    let bytes = percent_decode(parts[1].as_bytes());

    if is_base64 {
        // FIXME(#2909): It’s unclear what to do with non-alphabet characters,
        // but Acid 3 apparently depends on spaces being ignored.
        let bytes = bytes.move_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>();
        match bytes.as_slice().from_base64() {
            Err(..) => {
                progress_chan.send(Done(Err("non-base64 data uri".to_string())));
            }
            Ok(data) => {
                progress_chan.send(Payload(data));
                progress_chan.send(Done(Ok(())));
            }
        }
    } else {
        progress_chan.send(Payload(bytes));
        progress_chan.send(Done(Ok(())));
    }
}

#[cfg(test)]
fn assert_parse(url:          &'static str,
                content_type: Option<(String, String)>,
                charset:      Option<String>,
                data:         Option<Vec<u8>>) {
    use std::comm;
    use url::Url;

    let (start_chan, start_port) = comm::channel();
    load(LoadData::new(Url::parse(url).unwrap()), start_chan);

    let response = start_port.recv();
    assert_eq!(&response.metadata.content_type, &content_type);
    assert_eq!(&response.metadata.charset,      &charset);

    let progress = response.progress_port.recv();

    match data {
        None => {
            assert_eq!(progress, Done(Err("invalid data uri".to_string())));
        }
        Some(dat) => {
            assert_eq!(progress, Payload(dat));
            assert_eq!(response.progress_port.recv(), Done(Ok(())));
        }
    }
}

#[test]
fn empty_invalid() {
    assert_parse("data:", None, None, None);
}

#[test]
fn plain() {
    assert_parse("data:,hello%20world", None, None, Some(b"hello world".iter().map(|&x| x).collect()));
}

#[test]
fn plain_ct() {
    assert_parse("data:text/plain,hello",
        Some(("text".to_string(), "plain".to_string())), None, Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn plain_charset() {
    assert_parse("data:text/plain;charset=latin1,hello",
        Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn base64() {
    assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_ct() {
    assert_parse("data:application/octet-stream;base64,C62+7w==",
        Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_charset() {
    assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
        Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
        Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Lionel Flandrin <lionel@svkt.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! SPI configuration

/// Enables SPI interface on any of the 4 SSI (Synchronous Serial Interface)
/// modules in TM4C microcontrollers

use core::intrinsics::abort;
use hal::tiva_c::sysctl;
use util::support::get_reg_ref;

#[path="../../util/ioreg.rs"]
#[macro_use] mod ioreg;
#[path="../../util/wait_for.rs"]
#[macro_use] mod wait_for;

/// There are 4 SSI instances an SPI interface can use
/// See the TM4C123GH6PM datasheet page 954 for detailed signal to pin mappings
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub enum SpiId {
  /// SPI over SSI0, uses pins PA2:5
  Spi0,

  /// SPI over SSI1, uses pins PF0:3 or PD0:3
  Spi1,

  /// SPI over SSI2, uses pins PB4:7
  Spi2,

  /// SPI over SSI3, uses pins PD0:3
  Spi3,
}

/**
SPI configuration object

Configuration object used when instantiating an SPI instance

Note: The SPI GPIO pins must be set up correctly before using SPI. For example,
for a master-only TX and CK config on SSI0, the platformtree section might look
like the following (taken from a Tiva C configuration):

```
gpio {
  a {
    spi_ck@2 {
      direction = "out";
      function  = 2;
    }

    spi_tx@5 {
      direction = "out";
      function  = 2;
    }
  }
}
```
*/
pub struct SpiConf {
  /// Which SPI peripheral to use. The Tiva C has 4 SSI interfaces that can be used for SPI
  pub peripheral: SpiId,

  /// Bus frequency in Hz. Peripheral clock scaling is calculated from this value to a possibly non-exact match
  pub frequency: u32,
}

/**
Structure describing a single SPI interface

# Examples

Create an SPI interface on SSI0 with a run frequency of 4MHz

```
#![crate_type = "staticlib"]
#![feature(plugin, start, core_intrinsics)]
#![no_std]
#![plugin(macro_platformtree)]

extern crate zinc;

use zinc::hal::spi::Spi;
use zinc::hal::tiva_c::spi;

platformtree!(
  tiva_c@mcu {
    // Tiva C ends up with an 80MHz clock from 16MHz external xtal and x5 PLL
    clock {
      source = "MOSC";
      xtal   = "X16_0MHz";
      pll    = true;
      div    = 5;
    }

    gpio {
      a {
        spi_ck@2 {
          direction = "out";
          function  = 2;
        }

        spi_tx@5 {
          direction = "out";
          function  = 2;
        }
      }
    }
  }

  os {
    single_task {
      loop = "run";
    }
  }
);

fn run() {
  let spi = spi::Spi::new(spi::SpiConf {
    peripheral: spi::SpiId::Spi0,
    frequency: 4_000_000
  });

  loop {
    spi.write('a' as u8);
  }
}
```
*/
#[derive(Clone, Copy)]
pub struct Spi {
  /// SSI registers
  regs: &'static reg::Ssi,
}

impl Spi {
  /// Create and setup an SPI interface.
  pub fn new(config: SpiConf) -> Spi {

    let (periph, regs) = match config.peripheral {
      SpiId::Spi0 => (sysctl::periph::ssi::SSI_0, reg::SSI_0),
      SpiId::Spi1 => (sysctl::periph::ssi::SSI_1, reg::SSI_1),
      SpiId::Spi2 => (sysctl::periph::ssi::SSI_2, reg::SSI_2),
      SpiId::Spi3 => (sysctl::periph::ssi::SSI_3, reg::SSI_3),
    };

    let spi = Spi { regs: get_reg_ref(regs) };

    // Make sure peripheral clock gating is enabled
    periph.ensure_enabled();

    spi.configure(config);

    spi
  }

  /// Configure the SSI into SPI mode
  fn configure(&self, config: SpiConf) {
    // Disable peripheral so we can configure it
    self.regs.ssicr1.set_sse(false);

    self.regs.ssicr1
      .set_sse(false)
      .set_ms(false)
      .set_lbm(false);

    // Set clock rate
    self.set_frequency(config.frequency);

    self.regs.ssicr0
      .set_sph(false)
      .set_spo(false)
      .set_frf(0)     // Put SSI into SPI mode
      .set_dss(0x7);  // 8 bit frames

    // Turn on peripheral now that we've configured it
    self.regs.ssicr1.set_sse(true);
  }

  /// Set SPI frequency
  ///
  /// This function computes the divisor and exponent (for lack of a better name).
  /// These are stored in `ssicpsr.cpsdvsr` and `ssicr0.scr` respectively.
  /// The clock rate formula (taken from the datasheet is)
  /// `ClockRate = SysClk / (CPSDVSR * (1 + SCR))` where SysClk is the system clock in Hz.
  fn set_frequency(&self, freq: u32) {
    let sysclk = sysctl::clock::sysclk_get() as u32;

    let mut divisor: u32 = 2;

    while divisor <= 254 {
      let prescale_hz = sysclk / divisor;

      // Calculate exponent
      // TODO(jamwaffles) The below line crashes my Tiva,
      // presumably because floating point is broken?
      // let scr = ((prescale_hz as f32 / freq as f32) + 0.5f32) as u32;

      let scr = prescale_hz / freq;

      // Check we can support the divider
      if scr < 256 {
        self.regs.ssicpsr.set_cpsdvsr(divisor as u16);
        self.regs.ssicr0.set_scr((scr - 1) as u16);

        return
      }

      divisor += 2;
    }

    // TODO(jamwaffles): Return a Result from here as well as the calling
    // configure method
    unsafe { abort() };
  }

  /// Wait for SSI TX FIFO to be ready
  /// This checks the busy flag (0 = not busy) and the "transmit FIFO not full"
  /// flag (1 = not full)
  fn writeable(&self) -> bool {
    !self.regs.ssisr.bsy() && self.regs.ssisr.tnf()
  }

  /// Wait for SSI data buffer to be readable
  fn readable(&self) -> bool {
    !self.regs.ssisr.bsy()
  }
}

impl ::hal::spi::Spi for Spi {
  fn write(&self, value: u8) {
    wait_for!(self.writeable());

    self.regs.ssidr.set_data(value as u16);
  }

  fn read(&self) -> u8 {
    wait_for!(self.readable());

    self.regs.ssidr.data() as u8
  }
}

#[allow(missing_docs)]
pub mod reg {
  //! SSI registers definition
  use volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(Ssi = {
    /// SSI control register 0
    0x000 => reg16 ssicr0 {
      0..3 => dss: rw,    //= Data size select, 0x7 = 8 bits, see datasheet page
                          //= 970 for other values
      4..5 => frf: rw,    //= Frame format, 0 = SPI 1 = TI SSF 2 Microwire
      6    => spo: rw,    //= SSI polarity, 0 = steady staate low on
                          //= SSInCLK 1 = steady state high
      7    => sph: rw,    //= SSI clock phase, 1 = first edge 0 = second edge
      15..8 => scr: rw,   //= SSI clock rate, calculated from formula
                          //= `SysClk / (CPSDVSR * (1 + SCR))`
    },

    /// SSI control register 1
    0x004 => reg16 ssicr1 {
      0 => lbm: rw,       //= Loopback enable, 1 = enabled 0 = normal operation
      1 => sse: rw,       //= Serial port enable 1 = enabled 0 = disabled.
                          //= Must be cleared before SSI can be configured
      2 => ms: rw,        //= Master/slave select 0 = master 1 = slave
      4 => eot: rw,       //= End of transmission. Not sure what this is
    },

    /// SSI send/receive register
    ///
    /// When the SSIDR register is read, the entry in the receive FIFO that is
    /// pointed to by the current FIFO read pointer is accessed. When a data
    /// value is removed by the SSI receive logic from the incoming data frame,
    /// it is placed into the entry in the receive FIFO pointed to by the
    /// current FIFO write pointer.
    ///
    /// When the SSIDR register is written to, the entry in the transmit FIFO
    /// that is pointed to by the write pointer is written to. Data values are
    /// removed from the transmit FIFO one value at a time by the transmit
    /// logic. Each data value is loaded into the transmit serial shifter, then
    /// serially shifted out onto the SSInTx pin at the programmed bit rate.
    /// See page 973 in datasheet for more details
    0x008 => reg16 ssidr {
      0..15 => data: rw   //= Receive/transmit data
    },

    /// SSI status register
    0x00c => reg16 ssisr {
      0 => tfe: ro,       //= TX FIFO empty 1 = empty 0 = not empty
      1 => tnf: ro,       //= TX FIFO full 1 = not full 0 = full
      2 => rne: ro,       //= RX FIFO 1 = not empty 0 = empty
      3 => rff: ro,       //= RX FIFO full 0 = not full 1 = full
      4 => bsy: ro,       //= SSI busy 0 = idle, can send data 1 = transmitting,
                          //= can't send data yet
    },

    /// SSI clock prescale register
    0x010 => reg16 ssicpsr {
      0..7 => cpsdvsr: rw //= SSI clock prescale divisor, 2 – 254 inclusive
    },

    /// SSI clock source configuration
    0xfc8 => reg16 ssicc {
      0..3 => cs: rw,     //= SSI baud clock source, 0x0 = system clock,
                          //= 0x5 = PIOSC
    },
  });

  pub const SSI_0: *const Ssi = 0x40008000 as *const Ssi;
  pub const SSI_1: *const Ssi = 0x40009000 as *const Ssi;
  pub const SSI_2: *const Ssi = 0x4000A000 as *const Ssi;
  pub const SSI_3: *const Ssi = 0x4000B000 as *const Ssi;
}<commit_msg>Added placement regs todo<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Lionel Flandrin <lionel@svkt.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! SPI configuration

/// Enables SPI interface on any of the 4 SSI (Synchronous Serial Interface)
/// modules in TM4C microcontrollers

use core::intrinsics::abort;
use hal::tiva_c::sysctl;
use util::support::get_reg_ref;

#[path="../../util/ioreg.rs"]
#[macro_use] mod ioreg;
#[path="../../util/wait_for.rs"]
#[macro_use] mod wait_for;

/// There are 4 SSI instances an SPI interface can use
/// See the TM4C123GH6PM datasheet page 954 for detailed signal to pin mappings
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub enum SpiId {
  /// SPI over SSI0, uses pins PA2:5
  Spi0,

  /// SPI over SSI1, uses pins PF0:3 or PD0:3
  Spi1,

  /// SPI over SSI2, uses pins PB4:7
  Spi2,

  /// SPI over SSI3, uses pins PD0:3
  Spi3,
}

/**
SPI configuration object

Configuration object used when instantiating an SPI instance

Note: The SPI GPIO pins must be set up correctly before using SPI. For example,
for a master-only TX and CK config on SSI0, the platformtree section might look
like the following (taken from a Tiva C configuration):

```
gpio {
  a {
    spi_ck@2 {
      direction = "out";
      function  = 2;
    }

    spi_tx@5 {
      direction = "out";
      function  = 2;
    }
  }
}
```
*/
pub struct SpiConf {
  /// Which SPI peripheral to use. The Tiva C has 4 SSI interfaces that can be used for SPI
  pub peripheral: SpiId,

  /// Bus frequency in Hz. Peripheral clock scaling is calculated from this value to a possibly non-exact match
  pub frequency: u32,
}

/**
Structure describing a single SPI interface

# Examples

Create an SPI interface on SSI0 with a run frequency of 4MHz

```
#![crate_type = "staticlib"]
#![feature(plugin, start, core_intrinsics)]
#![no_std]
#![plugin(macro_platformtree)]

extern crate zinc;

use zinc::hal::spi::Spi;
use zinc::hal::tiva_c::spi;

platformtree!(
  tiva_c@mcu {
    // Tiva C ends up with an 80MHz clock from 16MHz external xtal and x5 PLL
    clock {
      source = "MOSC";
      xtal   = "X16_0MHz";
      pll    = true;
      div    = 5;
    }

    gpio {
      a {
        spi_ck@2 {
          direction = "out";
          function  = 2;
        }

        spi_tx@5 {
          direction = "out";
          function  = 2;
        }
      }
    }
  }

  os {
    single_task {
      loop = "run";
    }
  }
);

fn run() {
  let spi = spi::Spi::new(spi::SpiConf {
    peripheral: spi::SpiId::Spi0,
    frequency: 4_000_000
  });

  loop {
    spi.write('a' as u8);
  }
}
```
*/
#[derive(Clone, Copy)]
pub struct Spi {
  /// SSI registers
  regs: &'static reg::Ssi,
}

impl Spi {
  /// Create and setup an SPI interface.
  pub fn new(config: SpiConf) -> Spi {

    let (periph, regs) = match config.peripheral {
      SpiId::Spi0 => (sysctl::periph::ssi::SSI_0, reg::SSI_0),
      SpiId::Spi1 => (sysctl::periph::ssi::SSI_1, reg::SSI_1),
      SpiId::Spi2 => (sysctl::periph::ssi::SSI_2, reg::SSI_2),
      SpiId::Spi3 => (sysctl::periph::ssi::SSI_3, reg::SSI_3),
    };

    let spi = Spi { regs: get_reg_ref(regs) };

    // Make sure peripheral clock gating is enabled
    periph.ensure_enabled();

    spi.configure(config);

    spi
  }

  /// Configure the SSI into SPI mode
  fn configure(&self, config: SpiConf) {
    // Disable peripheral so we can configure it
    self.regs.ssicr1.set_sse(false);

    self.regs.ssicr1
      .set_sse(false)
      .set_ms(false)
      .set_lbm(false);

    // Set clock rate
    self.set_frequency(config.frequency);

    self.regs.ssicr0
      .set_sph(false)
      .set_spo(false)
      .set_frf(0)     // Put SSI into SPI mode
      .set_dss(0x7);  // 8 bit frames

    // Turn on peripheral now that we've configured it
    self.regs.ssicr1.set_sse(true);
  }

  /// Set SPI frequency
  ///
  /// This function computes the divisor and exponent (for lack of a better name).
  /// These are stored in `ssicpsr.cpsdvsr` and `ssicr0.scr` respectively.
  /// The clock rate formula (taken from the datasheet is)
  /// `ClockRate = SysClk / (CPSDVSR * (1 + SCR))` where SysClk is the system clock in Hz.
  fn set_frequency(&self, freq: u32) {
    let sysclk = sysctl::clock::sysclk_get() as u32;

    let mut divisor: u32 = 2;

    while divisor <= 254 {
      let prescale_hz = sysclk / divisor;

      // Calculate exponent
      // TODO(jamwaffles) The below line crashes my Tiva,
      // presumably because floating point is broken?
      // let scr = ((prescale_hz as f32 / freq as f32) + 0.5f32) as u32;

      let scr = prescale_hz / freq;

      // Check we can support the divider
      if scr < 256 {
        self.regs.ssicpsr.set_cpsdvsr(divisor as u16);
        self.regs.ssicr0.set_scr((scr - 1) as u16);

        return
      }

      divisor += 2;
    }

    // TODO(jamwaffles): Return a Result from here as well as the calling
    // configure method
    unsafe { abort() };
  }

  /// Wait for SSI TX FIFO to be ready
  /// This checks the busy flag (0 = not busy) and the "transmit FIFO not full"
  /// flag (1 = not full)
  fn writeable(&self) -> bool {
    !self.regs.ssisr.bsy() && self.regs.ssisr.tnf()
  }

  /// Wait for SSI data buffer to be readable
  fn readable(&self) -> bool {
    !self.regs.ssisr.bsy()
  }
}

impl ::hal::spi::Spi for Spi {
  fn write(&self, value: u8) {
    wait_for!(self.writeable());

    self.regs.ssidr.set_data(value as u16);
  }

  fn read(&self) -> u8 {
    wait_for!(self.readable());

    self.regs.ssidr.data() as u8
  }
}

#[allow(missing_docs)]
pub mod reg {
  //! SSI registers definition
  use volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(Ssi = {
    /// SSI control register 0
    0x000 => reg16 ssicr0 {
      0..3 => dss: rw,    //= Data size select, 0x7 = 8 bits, see datasheet page
                          //= 970 for other values
      4..5 => frf: rw,    //= Frame format, 0 = SPI 1 = TI SSF 2 Microwire
      6    => spo: rw,    //= SSI polarity, 0 = steady staate low on
                          //= SSInCLK 1 = steady state high
      7    => sph: rw,    //= SSI clock phase, 1 = first edge 0 = second edge
      15..8 => scr: rw,   //= SSI clock rate, calculated from formula
                          //= `SysClk / (CPSDVSR * (1 + SCR))`
    },

    /// SSI control register 1
    0x004 => reg16 ssicr1 {
      0 => lbm: rw,       //= Loopback enable, 1 = enabled 0 = normal operation
      1 => sse: rw,       //= Serial port enable 1 = enabled 0 = disabled.
                          //= Must be cleared before SSI can be configured
      2 => ms: rw,        //= Master/slave select 0 = master 1 = slave
      4 => eot: rw,       //= End of transmission. Not sure what this is
    },

    /// SSI send/receive register
    ///
    /// When the SSIDR register is read, the entry in the receive FIFO that is
    /// pointed to by the current FIFO read pointer is accessed. When a data
    /// value is removed by the SSI receive logic from the incoming data frame,
    /// it is placed into the entry in the receive FIFO pointed to by the
    /// current FIFO write pointer.
    ///
    /// When the SSIDR register is written to, the entry in the transmit FIFO
    /// that is pointed to by the write pointer is written to. Data values are
    /// removed from the transmit FIFO one value at a time by the transmit
    /// logic. Each data value is loaded into the transmit serial shifter, then
    /// serially shifted out onto the SSInTx pin at the programmed bit rate.
    /// See page 973 in datasheet for more details
    0x008 => reg16 ssidr {
      0..15 => data: rw   //= Receive/transmit data
    },

    /// SSI status register
    0x00c => reg16 ssisr {
      0 => tfe: ro,       //= TX FIFO empty 1 = empty 0 = not empty
      1 => tnf: ro,       //= TX FIFO full 1 = not full 0 = full
      2 => rne: ro,       //= RX FIFO 1 = not empty 0 = empty
      3 => rff: ro,       //= RX FIFO full 0 = not full 1 = full
      4 => bsy: ro,       //= SSI busy 0 = idle, can send data 1 = transmitting,
                          //= can't send data yet
    },

    /// SSI clock prescale register
    0x010 => reg16 ssicpsr {
      0..7 => cpsdvsr: rw //= SSI clock prescale divisor, 2 – 254 inclusive
    },

    /// SSI clock source configuration
    0xfc8 => reg16 ssicc {
      0..3 => cs: rw,     //= SSI baud clock source, 0x0 = system clock,
                          //= 0x5 = PIOSC
    },
  });

  // TODO(jamwaffles): Change to placement ioregs
  pub const SSI_0: *const Ssi = 0x40008000 as *const Ssi;
  pub const SSI_1: *const Ssi = 0x40009000 as *const Ssi;
  pub const SSI_2: *const Ssi = 0x4000A000 as *const Ssi;
  pub const SSI_3: *const Ssi = 0x4000B000 as *const Ssi;
}<|endoftext|>


<commit_before><commit_msg>Improve AboutDialog window<commit_after><|endoftext|>