<commit_before>//! The `Compositor` implements distortion, prediction, synchronization and other subtle issues that can be a challenge to
//! get operating properly for a solid VR experience.
//!
//! Applications call WaitGetPoses to get the set of poses used to render the camera and other tracked objects, render
//! the left and right eyes as normal (using the info provided by `System`) and finally `submit` those undistorted
//! textures for the `Compositor` to display on the output device.
//!
//! It is recommended that you continue presenting your application's own window, reusing either the left or right eye
//! camera render target to draw a single quad (perhaps cropped to a lower fov to hide the hidden area mask).

use std::ffi::CString;
use std::{error, fmt, mem, ptr};

use openvr_sys as sys;

pub mod texture;

pub use self::texture::Texture;

use super::*;

impl Compositor {
    pub fn vulkan_instance_extensions_required(&self) -> Vec<CString> {
        let temp = unsafe {
            get_string(|ptr, n| self.0.GetVulkanInstanceExtensionsRequired.unwrap()(ptr, n))
        }
        .unwrap();
        temp.as_bytes()
            .split(|&x| x == b' ')
            .map(|x| CString::new(x.to_vec()).expect("extension name contained null byte"))
            .collect()
    }

    /// Safety: physical_device must be a valid VkPhysicalDevice
    pub unsafe fn vulkan_device_extensions_required(
        &self,
        physical_device: *mut VkPhysicalDevice_T,
    ) -> Vec<CString> {
        let temp = get_string(|ptr, n| {
            self.0.GetVulkanDeviceExtensionsRequired.unwrap()(physical_device, ptr, n)
        })
        .unwrap();
        temp.as_bytes()
            .split(|&x| x == b' ')
            .map(|x| CString::new(x.to_vec()).expect("extension name contained null byte"))
            .collect()
    }

    /// Sets tracking space returned by WaitGetPoses
    pub fn set_tracking_space(&self, origin: TrackingUniverseOrigin) {
        unsafe { self.0.SetTrackingSpace.unwrap()(origin as sys::ETrackingUniverseOrigin) }
    }

    /// Block until a few milliseconds before the next vsync, then return poses for the next step of rendering and game
    /// logic.
    ///
    /// Poses are relative to the origin set by `set_tracking_space`.
    pub fn wait_get_poses(&self) -> Result<WaitPoses, CompositorError> {
        unsafe {
            let mut result: WaitPoses = mem::uninitialized();
            let e = self.0.WaitGetPoses.unwrap()(
                result.render.as_mut().as_mut_ptr() as *mut _,
                result.render.len() as u32,
                result.game.as_mut().as_mut_ptr() as *mut _,
                result.game.len() as u32,
            );
            if e == sys::EVRCompositorError_VRCompositorError_None {
                Ok(result)
            } else {
                Err(CompositorError(e))
            }
        }
    }

    /// Display the supplied texture for the next frame.
    ///
    /// If `bounds` is None, the entire texture will be used. Lens distortion is handled by the OpenVR implementation.
    ///
    /// # Safety
    ///
    /// The handles you supply must be valid and comply with the graphics API's synchronization requirements.
    pub unsafe fn submit(
        &self,
        eye: Eye,
        texture: &Texture,
        bounds: Option<&texture::Bounds>,
        pose: Option<[[f32; 4]; 3]>,
    ) -> Result<(), CompositorError> {
        use self::texture::Handle::*;
        let flags = match texture.handle {
            Vulkan(_) => sys::EVRSubmitFlags_Submit_Default,
            OpenGLTexture(_) => sys::EVRSubmitFlags_Submit_Default,
            OpenGLRenderBuffer(_) => sys::EVRSubmitFlags_Submit_GlRenderBuffer,
        } | if pose.is_some() {
            sys::EVRSubmitFlags_Submit_TextureWithPose
        } else {
            0
        };
        let texture = sys::VRTextureWithPose_t_real {
            handle: match texture.handle {
                Vulkan(ref x) => x as *const _ as *mut _,
                OpenGLTexture(x) => x as *mut _,
                OpenGLRenderBuffer(x) => x as *mut _,
            },
            eType: match texture.handle {
                Vulkan(_) => sys::ETextureType_TextureType_Vulkan,
                OpenGLTexture(_) => sys::ETextureType_TextureType_OpenGL,
                OpenGLRenderBuffer(_) => sys::ETextureType_TextureType_OpenGL,
            },
            eColorSpace: texture.color_space as sys::EColorSpace,
            mDeviceToAbsoluteTracking: sys::HmdMatrix34_t {
                m: pose.unwrap_or([[0.0; 4]; 3]),
            },
        };
        let e = self.0.Submit.unwrap()(
            eye as sys::EVREye,
            &texture as *const _ as *mut _,
            bounds
                .map(|x| x as *const _ as *mut texture::Bounds as *mut _)
                .unwrap_or(ptr::null_mut()),
            flags,
        );
        if e == sys::EVRCompositorError_VRCompositorError_None {
            Ok(())
        } else {
            Err(CompositorError(e))
        }
    }

    /// Call immediately after presenting your app's window (i.e. companion window) to unblock the compositor.
    ///
    /// This is an optional call, which only needs to be used if you can't instead call `wait_get_poses` immediately
    /// after submitting frames.  For example, if your engine's render and game loop are not on separate threads, or
    /// blocking the render thread until 3ms before the next vsync would introduce a deadlock of some sort.  This
    /// function tells the compositor that you have finished all rendering after having Submitted buffers for both eyes,
    /// and it is free to start its rendering work.  This should only be called from the same thread you are rendering
    /// on.
    pub fn post_present_handoff(&self) {
        unsafe { (self.0.PostPresentHandoff.unwrap())() };
    }

    /// Return whether the compositor is fullscreen.
    pub fn is_fullscreen(&self) -> bool {
        unsafe { (self.0.IsFullscreen.unwrap())() }
    }

    /// Clears the frame that was sent with the last call to `submit.
    ///
    /// This will cause the compositor to show the grid until `submit` is called again.
    pub fn clear_last_submitted_frame(&self) {
        unsafe { self.0.ClearLastSubmittedFrame.unwrap()() }
    }

    /// Controls whether the application should flag the time at which the frame begins explicitly
    ///
    /// *Vulkan/D3D12 Only*
    /// There are two purposes for SetExplicitTimingMode:
    ///	1. To get a more accurate GPU timestamp for when the frame begins in Vulkan/D3D12 applications.
    ///	2. (Optional) To avoid having WaitGetPoses access the Vulkan queue so that the queue can be accessed from
    ///	another thread while WaitGetPoses is executing.
    ///
    /// More accurate GPU timestamp for the start of the frame is achieved by the application calling
    /// SubmitExplicitTimingData immediately before its first submission to the Vulkan/D3D12 queue.  This is more
    /// accurate because normally this GPU timestamp is recorded during WaitGetPoses.  In D3D11, WaitGetPoses queues a
    /// GPU timestamp write, but it does not actually get submitted to the GPU until the application flushes.  By using
    /// SubmitExplicitTimingData, the timestamp is recorded at the same place for Vulkan/D3D12 as it is for D3D11,
    /// resulting in a more accurate GPU time measurement for the frame.
    ///
    /// Avoiding WaitGetPoses accessing the Vulkan queue can be achieved using SetExplicitTimingMode as well.  If this
    /// is desired, the application *MUST* call PostPresentHandoff itself prior to WaitGetPoses.  If
    /// SetExplicitTimingMode is true and the application calls PostPresentHandoff, then WaitGetPoses is guaranteed not
    /// to access the queue.  Note that PostPresentHandoff and SubmitExplicitTimingData will access the queue, so only
    /// WaitGetPoses becomes safe for accessing the queue from another thread.
    pub fn set_explicit_timing_mode(&self, mode: bool) {
        unsafe { self.0.SetExplicitTimingMode.unwrap()(mode as sys::EVRCompositorTimingMode) }
    }

    pub fn submit_explicit_timing_data(&self) -> Result<(), CompositorError> {
        let e = unsafe { self.0.SubmitExplicitTimingData.unwrap()() };
        if e == sys::EVRCompositorError_VRCompositorError_None {
            Ok(())
        } else {
            Err(CompositorError(e))
        }
    }
}

#[derive(Copy, Clone)]
pub struct WaitPoses {
    /// Predicted to the point they will be at the upcoming frame.
    pub render: TrackedDevicePoses,
    /// Predicted to the point they will be at the frame after the upcoming frame, for use in game logic.
    pub game: TrackedDevicePoses,
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct CompositorError(sys::EVRCompositorError);

pub mod compositor_error {
    use super::*;

    pub const REQUEST_FAILED: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_RequestFailed);
    pub const INCOMPATIBLE_VERSION: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_IncompatibleVersion);
    pub const DO_NOT_HAVE_FOCUS: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_DoNotHaveFocus);
    pub const INVALID_TEXTURE: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_InvalidTexture);
    pub const IS_NOT_SCENE_APPLICATION: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_IsNotSceneApplication);
    pub const TEXTURE_IS_ON_WRONG_DEVICE: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_TextureIsOnWrongDevice);
    pub const TEXTURE_USES_UNSUPPORTED_FORMAT: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_TextureUsesUnsupportedFormat);
    pub const SHARED_TEXTURES_NOT_SUPPORTED: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_SharedTexturesNotSupported);
    pub const INDEX_OUT_OF_RANGE: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_IndexOutOfRange);
    pub const ALREADY_SUBMITTED: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_AlreadySubmitted);
    pub const INVALID_BOUNDS: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_InvalidBounds);
}

impl fmt::Debug for CompositorError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(error::Error::description(self))
    }
}

impl error::Error for CompositorError {
    fn description(&self) -> &str {
        use self::compositor_error::*;
        match *self {
            REQUEST_FAILED => "REQUEST_FAILED",
            INCOMPATIBLE_VERSION => "INCOMPATIBLE_VERSION",
            DO_NOT_HAVE_FOCUS => "DO_NOT_HAVE_FOCUS",
            INVALID_TEXTURE => "INVALID_TEXTURE",
            IS_NOT_SCENE_APPLICATION => "IS_NOT_SCENE_APPLICATION",
            TEXTURE_IS_ON_WRONG_DEVICE => "TEXTURE_IS_ON_WRONG_DEVICE",
            TEXTURE_USES_UNSUPPORTED_FORMAT => "TEXTURE_USES_UNSUPPORTED_FORMAT",
            SHARED_TEXTURES_NOT_SUPPORTED => "SHARED_TEXTURES_NOT_SUPPORTED",
            INDEX_OUT_OF_RANGE => "INDEX_OUT_OF_RANGE",
            ALREADY_SUBMITTED => "ALREADY_SUBMITTED",
            INVALID_BOUNDS => "INVALID_BOUNDS",
            _ => "UNKNOWN",
        }
    }
}

impl fmt::Display for CompositorError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(error::Error::description(self))
    }
}
<commit_msg>Fix panic when no vulkan extensions are required<commit_after>//! The `Compositor` implements distortion, prediction, synchronization and other subtle issues that can be a challenge to
//! get operating properly for a solid VR experience.
//!
//! Applications call WaitGetPoses to get the set of poses used to render the camera and other tracked objects, render
//! the left and right eyes as normal (using the info provided by `System`) and finally `submit` those undistorted
//! textures for the `Compositor` to display on the output device.
//!
//! It is recommended that you continue presenting your application's own window, reusing either the left or right eye
//! camera render target to draw a single quad (perhaps cropped to a lower fov to hide the hidden area mask).

use std::ffi::CString;
use std::{error, fmt, mem, ptr};

use openvr_sys as sys;

pub mod texture;

pub use self::texture::Texture;

use super::*;

impl Compositor {
    pub fn vulkan_instance_extensions_required(&self) -> Vec<CString> {
        let temp = match unsafe {
            get_string(|ptr, n| self.0.GetVulkanInstanceExtensionsRequired.unwrap()(ptr, n))
        } {
            Some(x) => x,
            None => return Vec::new(),
        };
        temp.as_bytes()
            .split(|&x| x == b' ')
            .map(|x| CString::new(x.to_vec()).expect("extension name contained null byte"))
            .collect()
    }

    /// Safety: physical_device must be a valid VkPhysicalDevice
    pub unsafe fn vulkan_device_extensions_required(
        &self,
        physical_device: *mut VkPhysicalDevice_T,
    ) -> Vec<CString> {
        let temp = match get_string(|ptr, n| {
            self.0.GetVulkanDeviceExtensionsRequired.unwrap()(physical_device, ptr, n)
        }) {
            Some(x) => x,
            None => return Vec::new(),
        };
        temp.as_bytes()
            .split(|&x| x == b' ')
            .map(|x| CString::new(x.to_vec()).expect("extension name contained null byte"))
            .collect()
    }

    /// Sets tracking space returned by WaitGetPoses
    pub fn set_tracking_space(&self, origin: TrackingUniverseOrigin) {
        unsafe { self.0.SetTrackingSpace.unwrap()(origin as sys::ETrackingUniverseOrigin) }
    }

    /// Block until a few milliseconds before the next vsync, then return poses for the next step of rendering and game
    /// logic.
    ///
    /// Poses are relative to the origin set by `set_tracking_space`.
    pub fn wait_get_poses(&self) -> Result<WaitPoses, CompositorError> {
        unsafe {
            let mut result: WaitPoses = mem::uninitialized();
            let e = self.0.WaitGetPoses.unwrap()(
                result.render.as_mut().as_mut_ptr() as *mut _,
                result.render.len() as u32,
                result.game.as_mut().as_mut_ptr() as *mut _,
                result.game.len() as u32,
            );
            if e == sys::EVRCompositorError_VRCompositorError_None {
                Ok(result)
            } else {
                Err(CompositorError(e))
            }
        }
    }

    /// Display the supplied texture for the next frame.
    ///
    /// If `bounds` is None, the entire texture will be used. Lens distortion is handled by the OpenVR implementation.
    ///
    /// # Safety
    ///
    /// The handles you supply must be valid and comply with the graphics API's synchronization requirements.
    pub unsafe fn submit(
        &self,
        eye: Eye,
        texture: &Texture,
        bounds: Option<&texture::Bounds>,
        pose: Option<[[f32; 4]; 3]>,
    ) -> Result<(), CompositorError> {
        use self::texture::Handle::*;
        let flags = match texture.handle {
            Vulkan(_) => sys::EVRSubmitFlags_Submit_Default,
            OpenGLTexture(_) => sys::EVRSubmitFlags_Submit_Default,
            OpenGLRenderBuffer(_) => sys::EVRSubmitFlags_Submit_GlRenderBuffer,
        } | if pose.is_some() {
            sys::EVRSubmitFlags_Submit_TextureWithPose
        } else {
            0
        };
        let texture = sys::VRTextureWithPose_t_real {
            handle: match texture.handle {
                Vulkan(ref x) => x as *const _ as *mut _,
                OpenGLTexture(x) => x as *mut _,
                OpenGLRenderBuffer(x) => x as *mut _,
            },
            eType: match texture.handle {
                Vulkan(_) => sys::ETextureType_TextureType_Vulkan,
                OpenGLTexture(_) => sys::ETextureType_TextureType_OpenGL,
                OpenGLRenderBuffer(_) => sys::ETextureType_TextureType_OpenGL,
            },
            eColorSpace: texture.color_space as sys::EColorSpace,
            mDeviceToAbsoluteTracking: sys::HmdMatrix34_t {
                m: pose.unwrap_or([[0.0; 4]; 3]),
            },
        };
        let e = self.0.Submit.unwrap()(
            eye as sys::EVREye,
            &texture as *const _ as *mut _,
            bounds
                .map(|x| x as *const _ as *mut texture::Bounds as *mut _)
                .unwrap_or(ptr::null_mut()),
            flags,
        );
        if e == sys::EVRCompositorError_VRCompositorError_None {
            Ok(())
        } else {
            Err(CompositorError(e))
        }
    }

    /// Call immediately after presenting your app's window (i.e. companion window) to unblock the compositor.
    ///
    /// This is an optional call, which only needs to be used if you can't instead call `wait_get_poses` immediately
    /// after submitting frames.  For example, if your engine's render and game loop are not on separate threads, or
    /// blocking the render thread until 3ms before the next vsync would introduce a deadlock of some sort.  This
    /// function tells the compositor that you have finished all rendering after having Submitted buffers for both eyes,
    /// and it is free to start its rendering work.  This should only be called from the same thread you are rendering
    /// on.
    pub fn post_present_handoff(&self) {
        unsafe { (self.0.PostPresentHandoff.unwrap())() };
    }

    /// Return whether the compositor is fullscreen.
    pub fn is_fullscreen(&self) -> bool {
        unsafe { (self.0.IsFullscreen.unwrap())() }
    }

    /// Clears the frame that was sent with the last call to `submit.
    ///
    /// This will cause the compositor to show the grid until `submit` is called again.
    pub fn clear_last_submitted_frame(&self) {
        unsafe { self.0.ClearLastSubmittedFrame.unwrap()() }
    }

    /// Controls whether the application should flag the time at which the frame begins explicitly
    ///
    /// *Vulkan/D3D12 Only*
    /// There are two purposes for SetExplicitTimingMode:
    ///	1. To get a more accurate GPU timestamp for when the frame begins in Vulkan/D3D12 applications.
    ///	2. (Optional) To avoid having WaitGetPoses access the Vulkan queue so that the queue can be accessed from
    ///	another thread while WaitGetPoses is executing.
    ///
    /// More accurate GPU timestamp for the start of the frame is achieved by the application calling
    /// SubmitExplicitTimingData immediately before its first submission to the Vulkan/D3D12 queue.  This is more
    /// accurate because normally this GPU timestamp is recorded during WaitGetPoses.  In D3D11, WaitGetPoses queues a
    /// GPU timestamp write, but it does not actually get submitted to the GPU until the application flushes.  By using
    /// SubmitExplicitTimingData, the timestamp is recorded at the same place for Vulkan/D3D12 as it is for D3D11,
    /// resulting in a more accurate GPU time measurement for the frame.
    ///
    /// Avoiding WaitGetPoses accessing the Vulkan queue can be achieved using SetExplicitTimingMode as well.  If this
    /// is desired, the application *MUST* call PostPresentHandoff itself prior to WaitGetPoses.  If
    /// SetExplicitTimingMode is true and the application calls PostPresentHandoff, then WaitGetPoses is guaranteed not
    /// to access the queue.  Note that PostPresentHandoff and SubmitExplicitTimingData will access the queue, so only
    /// WaitGetPoses becomes safe for accessing the queue from another thread.
    pub fn set_explicit_timing_mode(&self, mode: bool) {
        unsafe { self.0.SetExplicitTimingMode.unwrap()(mode as sys::EVRCompositorTimingMode) }
    }

    pub fn submit_explicit_timing_data(&self) -> Result<(), CompositorError> {
        let e = unsafe { self.0.SubmitExplicitTimingData.unwrap()() };
        if e == sys::EVRCompositorError_VRCompositorError_None {
            Ok(())
        } else {
            Err(CompositorError(e))
        }
    }
}

#[derive(Copy, Clone)]
pub struct WaitPoses {
    /// Predicted to the point they will be at the upcoming frame.
    pub render: TrackedDevicePoses,
    /// Predicted to the point they will be at the frame after the upcoming frame, for use in game logic.
    pub game: TrackedDevicePoses,
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct CompositorError(sys::EVRCompositorError);

pub mod compositor_error {
    use super::*;

    pub const REQUEST_FAILED: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_RequestFailed);
    pub const INCOMPATIBLE_VERSION: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_IncompatibleVersion);
    pub const DO_NOT_HAVE_FOCUS: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_DoNotHaveFocus);
    pub const INVALID_TEXTURE: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_InvalidTexture);
    pub const IS_NOT_SCENE_APPLICATION: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_IsNotSceneApplication);
    pub const TEXTURE_IS_ON_WRONG_DEVICE: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_TextureIsOnWrongDevice);
    pub const TEXTURE_USES_UNSUPPORTED_FORMAT: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_TextureUsesUnsupportedFormat);
    pub const SHARED_TEXTURES_NOT_SUPPORTED: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_SharedTexturesNotSupported);
    pub const INDEX_OUT_OF_RANGE: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_IndexOutOfRange);
    pub const ALREADY_SUBMITTED: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_AlreadySubmitted);
    pub const INVALID_BOUNDS: CompositorError =
        CompositorError(sys::EVRCompositorError_VRCompositorError_InvalidBounds);
}

impl fmt::Debug for CompositorError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(error::Error::description(self))
    }
}

impl error::Error for CompositorError {
    fn description(&self) -> &str {
        use self::compositor_error::*;
        match *self {
            REQUEST_FAILED => "REQUEST_FAILED",
            INCOMPATIBLE_VERSION => "INCOMPATIBLE_VERSION",
            DO_NOT_HAVE_FOCUS => "DO_NOT_HAVE_FOCUS",
            INVALID_TEXTURE => "INVALID_TEXTURE",
            IS_NOT_SCENE_APPLICATION => "IS_NOT_SCENE_APPLICATION",
            TEXTURE_IS_ON_WRONG_DEVICE => "TEXTURE_IS_ON_WRONG_DEVICE",
            TEXTURE_USES_UNSUPPORTED_FORMAT => "TEXTURE_USES_UNSUPPORTED_FORMAT",
            SHARED_TEXTURES_NOT_SUPPORTED => "SHARED_TEXTURES_NOT_SUPPORTED",
            INDEX_OUT_OF_RANGE => "INDEX_OUT_OF_RANGE",
            ALREADY_SUBMITTED => "ALREADY_SUBMITTED",
            INVALID_BOUNDS => "INVALID_BOUNDS",
            _ => "UNKNOWN",
        }
    }
}

impl fmt::Display for CompositorError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(error::Error::description(self))
    }
}
<|endoftext|>


<commit_before>//! Types which represent various database backends

use byteorder::ByteOrder;

use crate::query_builder::bind_collector::BindCollector;
use crate::query_builder::QueryBuilder;
use crate::sql_types::{self, HasSqlType};

/// A database backend
///
/// This trait represents the concept of a backend (e.g. "MySQL" vs "SQLite").
/// It is separate from a [`Connection`](../connection/trait.Connection.html)
/// to that backend.
/// One backend may have multiple concrete connection implementations.
///
/// Implementations of this trait should not assume details about how the
/// connection is implemented.
/// For example, the `Pg` backend does not assume that `libpq` is being used.
/// Implementations of this trait can and should care about details of the wire
/// protocol used to communicated with the database.
pub trait Backend
where
    Self: Sized,
    Self: HasSqlType<sql_types::SmallInt>,
    Self: HasSqlType<sql_types::Integer>,
    Self: HasSqlType<sql_types::BigInt>,
    Self: HasSqlType<sql_types::Float>,
    Self: HasSqlType<sql_types::Double>,
    Self: HasSqlType<sql_types::VarChar>,
    Self: HasSqlType<sql_types::Text>,
    Self: HasSqlType<sql_types::Binary>,
    Self: HasSqlType<sql_types::Date>,
    Self: HasSqlType<sql_types::Time>,
    Self: HasSqlType<sql_types::Timestamp>,
    Self: for<'a> HasRawValue<'a>,
{
    /// The concrete `QueryBuilder` implementation for this backend.
    type QueryBuilder: QueryBuilder<Self>;
    /// The concrete `BindCollector` implementation for this backend.
    ///
    /// Most backends should use [`RawBytesBindCollector`].
    ///
    /// [`RawBytesBindCollector`]: ../query_builder/bind_collector/struct.RawBytesBindCollector.html
    type BindCollector: BindCollector<Self>;
    /// What byte order is used to transmit integers?
    ///
    /// This type is only used if `RawValue` is `[u8]`.
    type ByteOrder: ByteOrder;
}

/// The raw representation of a database value given to `FromSql`.
///
/// This trait is separate from `Backend` to imitate `type RawValue<'a>`. It
/// should only be referenced directly by implementors. Users of this type
/// should instead use the [`RawValue`](type.RawValue.html) helper type instead.
pub trait HasRawValue<'a> {
    /// The actual type given to `FromSql`, with lifetimes applied. This type
    /// should not be used directly. Use the [`RawValue`](type.RawValue.html)
    /// helper type instead.
    type RawValue;
}

/// A trait indicating that the provided raw value uses a binary representation internally
pub trait BinaryRawValue<'a>: HasRawValue<'a> {
    /// Get the underlying binary representation of the raw value
    fn as_bytes(value: Self::RawValue) -> &'a [u8];
}

/// A helper type to get the raw representation of a database type given to
/// `FromSql`. Equivalent to `<DB as Backend>::RawValue<'a>`.
pub type RawValue<'a, DB> = <DB as HasRawValue<'a>>::RawValue;

/// Does this backend support `RETURNING` clauses?
pub trait SupportsReturningClause {}
/// Does this backend support 'ON CONFLICT' clause?
pub trait SupportsOnConflictClause {}
/// Does this backend support 'WHERE' clauses on 'ON CONFLICT' clauses?
pub trait SupportsOnConflictTargetDecorations {}
/// Does this backend support the bare `DEFAULT` keyword?
pub trait SupportsDefaultKeyword {}
/// Does this backend use the standard `SAVEPOINT` syntax?
pub trait UsesAnsiSavepointSyntax {}
<commit_msg>Expand documentation for SupportsReturningClause trait<commit_after>//! Types which represent various database backends

use byteorder::ByteOrder;

use crate::query_builder::bind_collector::BindCollector;
use crate::query_builder::QueryBuilder;
use crate::sql_types::{self, HasSqlType};

/// A database backend
///
/// This trait represents the concept of a backend (e.g. "MySQL" vs "SQLite").
/// It is separate from a [`Connection`](../connection/trait.Connection.html)
/// to that backend.
/// One backend may have multiple concrete connection implementations.
///
/// Implementations of this trait should not assume details about how the
/// connection is implemented.
/// For example, the `Pg` backend does not assume that `libpq` is being used.
/// Implementations of this trait can and should care about details of the wire
/// protocol used to communicated with the database.
pub trait Backend
where
    Self: Sized,
    Self: HasSqlType<sql_types::SmallInt>,
    Self: HasSqlType<sql_types::Integer>,
    Self: HasSqlType<sql_types::BigInt>,
    Self: HasSqlType<sql_types::Float>,
    Self: HasSqlType<sql_types::Double>,
    Self: HasSqlType<sql_types::VarChar>,
    Self: HasSqlType<sql_types::Text>,
    Self: HasSqlType<sql_types::Binary>,
    Self: HasSqlType<sql_types::Date>,
    Self: HasSqlType<sql_types::Time>,
    Self: HasSqlType<sql_types::Timestamp>,
    Self: for<'a> HasRawValue<'a>,
{
    /// The concrete `QueryBuilder` implementation for this backend.
    type QueryBuilder: QueryBuilder<Self>;
    /// The concrete `BindCollector` implementation for this backend.
    ///
    /// Most backends should use [`RawBytesBindCollector`].
    ///
    /// [`RawBytesBindCollector`]: ../query_builder/bind_collector/struct.RawBytesBindCollector.html
    type BindCollector: BindCollector<Self>;
    /// What byte order is used to transmit integers?
    ///
    /// This type is only used if `RawValue` is `[u8]`.
    type ByteOrder: ByteOrder;
}

/// The raw representation of a database value given to `FromSql`.
///
/// This trait is separate from `Backend` to imitate `type RawValue<'a>`. It
/// should only be referenced directly by implementors. Users of this type
/// should instead use the [`RawValue`](type.RawValue.html) helper type instead.
pub trait HasRawValue<'a> {
    /// The actual type given to `FromSql`, with lifetimes applied. This type
    /// should not be used directly. Use the [`RawValue`](type.RawValue.html)
    /// helper type instead.
    type RawValue;
}

/// A trait indicating that the provided raw value uses a binary representation internally
pub trait BinaryRawValue<'a>: HasRawValue<'a> {
    /// Get the underlying binary representation of the raw value
    fn as_bytes(value: Self::RawValue) -> &'a [u8];
}

/// A helper type to get the raw representation of a database type given to
/// `FromSql`. Equivalent to `<DB as Backend>::RawValue<'a>`.
pub type RawValue<'a, DB> = <DB as HasRawValue<'a>>::RawValue;

/// A trait indicating that implementing backend provides support for
/// `RETURNING` clauses.
///
/// This trait has to be implemented in order to be able to use methods such as
/// `get_results` and `returning`. Namely, any method which leads to usage of
/// `RETURNING` clauses in SQL sent to backend will require that this trait
/// be implemented for used backend.
pub trait SupportsReturningClause {}
/// Does this backend support 'ON CONFLICT' clause?
pub trait SupportsOnConflictClause {}
/// Does this backend support 'WHERE' clauses on 'ON CONFLICT' clauses?
pub trait SupportsOnConflictTargetDecorations {}
/// Does this backend support the bare `DEFAULT` keyword?
pub trait SupportsDefaultKeyword {}
/// Does this backend use the standard `SAVEPOINT` syntax?
pub trait UsesAnsiSavepointSyntax {}
<|endoftext|>


<commit_before>//! Linear Regression module
//!
//! Contains implementation of linear regression models.
//! Allows training and prediction of linear regression model
//! using least squares optimization.
//!
//! Currently only OLS solution - gradient descent not yet implemented.

use learning::Model;
use linalg::matrix::Matrix;
use linalg::vector::Vector;

pub struct LinRegressor {
	pub b: Option<Vector<f64>>
}

impl LinRegressor {

	/// Constructs untrained linear regression model.
	///
	/// # Examples
	///
	/// ```
	/// use rusty_machine::learning::lin_reg::LinRegressor;
	///
	/// let mut lin_mod = LinRegressor::new();
	/// ```
	pub fn new() -> LinRegressor {
		LinRegressor { b: None }
	}
}

impl Model<Matrix<f64>, Vector<f64>> for LinRegressor {

	/// Train the linear regression model.
	///
	/// Takes training data and output values as input.
	///
	/// # Examples
	///
	/// ```
	/// let mut lin_mod = LinRegressor::new();
	/// let data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
	/// let values = Vector::new(vec![5.0, 6.0, 7.0]);
	///
	/// lin_mod.train(data, values);
	/// ```
	fn train(&mut self, data: Matrix<f64>, values: Vector<f64>) {
		let xt = data.transpose();

		self.b = Some(((&xt * data).inverse() * &xt) * values);
	}

	/// Predict output value from input data.
	///
	/// Model must be trained before prediction can be made.
	fn predict(&self, data: Matrix<f64>) -> Vector<f64> {
		match self.b {
			Some(ref v) => data * v,
			None => panic!("Model has not been trained.")
		}
	}
}
<commit_msg>Fixing example bug.<commit_after>//! Linear Regression module
//!
//! Contains implementation of linear regression models.
//! Allows training and prediction of linear regression model
//! using least squares optimization.
//!
//! Currently only OLS solution - gradient descent not yet implemented.

use learning::Model;
use linalg::matrix::Matrix;
use linalg::vector::Vector;

pub struct LinRegressor {
	pub b: Option<Vector<f64>>
}

impl LinRegressor {

	/// Constructs untrained linear regression model.
	///
	/// # Examples
	///
	/// ```
	/// use rusty_machine::learning::lin_reg::LinRegressor;
	///
	/// let mut lin_mod = LinRegressor::new();
	/// ```
	pub fn new() -> LinRegressor {
		LinRegressor { b: None }
	}
}

impl Model<Matrix<f64>, Vector<f64>> for LinRegressor {

	/// Train the linear regression model.
	///
	/// Takes training data and output values as input.
	///
	/// # Examples
	///
	/// ```
	/// use rusty_machine::learning::lin_reg::LinRegressor;
	/// use rusty_machine::linalg::matrix::Matrix;
	/// use rusty_machine::linalg::vector::Vector;
	/// use rusty_machine::learning::Model;
	///
	/// let mut lin_mod = LinRegressor::new();
	/// let data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
	/// let values = Vector::new(vec![5.0, 6.0, 7.0]);
	///
	/// lin_mod.train(data, values);
	/// ```
	fn train(&mut self, data: Matrix<f64>, values: Vector<f64>) {
		let xt = data.transpose();

		self.b = Some(((&xt * data).inverse() * &xt) * values);
	}

	/// Predict output value from input data.
	///
	/// Model must be trained before prediction can be made.
	fn predict(&self, data: Matrix<f64>) -> Vector<f64> {
		match self.b {
			Some(ref v) => data * v,
			None => panic!("Model has not been trained.")
		}
	}
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;

use runtime::{Class, Object, Sel, self};
use {encode, Encode, EncodePtr};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message: Sized + EncodePtr { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to a pointer to a type that may be sent Objective-C
/// messages.
pub trait ToMessage : Encode {
    type Target: Message;

    fn as_ptr(&self) -> *mut Self::Target;

    fn is_nil(&self) -> bool {
        self.as_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *mut T
    }
}

impl<T> ToMessage for *mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *const T as *mut T
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for Option<&'a T> where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        match *self {
            None => ptr::null_mut(),
            Some(ref obj) => obj.as_ptr(),
        }
    }
}

impl<'a, T> ToMessage for Option<&'a mut T> where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        match *self {
            None => ptr::null_mut(),
            Some(ref obj) => obj.as_ptr(),
        }
    }
}

fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    unsafe {
        mem::transmute(runtime::objc_msgSend)
    }
}

pub trait MessageArguments {
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_ptr() as *mut Object;
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

fn verify_message_signature<T, A, R>(obj: Option<&T>, sel: Sel, _args: &A) ->
        Result<(), String> where T: Message, A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = unsafe {
        let obj = &*(obj as *const _ as *const Object);
        obj.class()
    };
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if expected_ret.as_slice() != ret && !(expected_ret.as_slice() == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, expected_ret.as_slice(), sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => s.as_slice() == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => s.as_slice() == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    Ok(())
}

pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

pub unsafe fn send_message_verified<T, A, R>(obj: &T, sel: Sel, args: A) ->
        Result<R, String> where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_ptr().as_ref();
    verify_message_signature::<_, _, R>(obj_ref, sel, &args).and_then(
        move |()| Ok(args.send(obj, sel)))
}
<commit_msg>Added MessageArguments::verify method.<commit_after>use std::mem;
use std::ptr;

use runtime::{Class, Method, Object, Sel, self};
use {encode, Encode, EncodePtr};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message: Sized + EncodePtr { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to a pointer to a type that may be sent Objective-C
/// messages.
pub trait ToMessage : Encode {
    type Target: Message;

    fn as_ptr(&self) -> *mut Self::Target;

    fn is_nil(&self) -> bool {
        self.as_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *mut T
    }
}

impl<T> ToMessage for *mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *const T as *mut T
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for Option<&'a T> where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        match *self {
            None => ptr::null_mut(),
            Some(ref obj) => obj.as_ptr(),
        }
    }
}

impl<'a, T> ToMessage for Option<&'a mut T> where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        match *self {
            None => ptr::null_mut(),
            Some(ref obj) => obj.as_ptr(),
        }
    }
}

fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    unsafe {
        mem::transmute(runtime::objc_msgSend)
    }
}

pub trait MessageArguments {
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;

    fn verify(&self, method: &Method) -> Result<(), String>;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t: Encode),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_ptr() as *mut Object;
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }

            fn verify(&self, method: &Method) -> Result<(), String> {
                let types = [$(encode::<$t>()),*];
                // So rust can infer the type of the empty array:
                let _: &[&str] = &types;

                let count = 2 + types.len();
                let expected_count = method.arguments_count();
                if count != expected_count {
                    return Err(format!("Method {:?} accepts {} arguments, but {} were given",
                        method.name(), expected_count, count));
                }

                let expected_types = range(2, expected_count).map(
                    |i| method.argument_type(i));
                for (&arg, expected) in types.iter().zip(expected_types) {
                    let expected = match expected {
                        Some(s) => s,
                        None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                            method.name(), arg)),
                    };
                    if arg != expected.as_slice() {
                        return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                            method.name(), expected.as_slice(), arg));
                    }
                }

                Ok(())
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

fn verify_message_signature<T, A, R>(obj: Option<&T>, sel: Sel, args: &A) ->
        Result<(), String> where T: Message, A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = unsafe {
        let obj = &*(obj as *const _ as *const Object);
        obj.class()
    };
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if expected_ret.as_slice() != ret && !(expected_ret.as_slice() == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, expected_ret.as_slice(), sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => s.as_slice() == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => s.as_slice() == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    args.verify(method)
}

pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

pub unsafe fn send_message_verified<T, A, R>(obj: &T, sel: Sel, args: A) ->
        Result<R, String> where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_ptr().as_ref();
    verify_message_signature::<_, _, R>(obj_ref, sel, &args).and_then(
        move |()| Ok(args.send(obj, sel)))
}
<|endoftext|>


<commit_before>use super::{allocate_shapes, allocate_states, Boundary, Find, Mesh};
use crate::shapes::{Shape, StateOfShape};
use crate::StrError;

/// Holds all data related to a Mesh
pub struct Region {
    pub mesh: Mesh,
    pub shapes: Vec<Shape>,
    pub states: Vec<StateOfShape>,
    pub boundary: Boundary,
    pub find: Find,
}

impl Region {
    /// Allocates a new instance with a given Mesh
    pub fn with(mesh: Mesh) -> Result<Self, StrError> {
        let shapes = allocate_shapes(&mesh)?;
        let states = allocate_states(&mesh, &shapes)?;
        let boundary = Boundary::new(&mesh, &shapes)?;
        let find = Find::new(&mesh, &boundary)?;
        Ok(Region {
            mesh,
            shapes,
            states,
            boundary,
            find,
        })
    }
}
<commit_msg>Improve Region<commit_after>use super::{allocate_shapes, allocate_states, Boundary, Find, Mesh};
use crate::shapes::{Shape, StateOfShape};
use crate::StrError;
use std::ffi::OsStr;

/// Holds all data related to a mesh including element shapes, states, boundaries, and functions to find entities
///
/// This struct is a (high-level) convenience that calls the necessary functions to generate all derived data from a mesh struct.
///
/// The Region basically calls the following functions:
///
/// ```text
/// let shapes = allocate_shapes(&mesh)?;
/// let states = allocate_states(&mesh, &shapes)?;
/// let boundary = Boundary::new(&mesh, &shapes)?;
/// let find = Find::new(&mesh, &boundary)?;
/// ```
pub struct Region {
    /// Holds the raw mesh data
    pub mesh: Mesh,

    /// Holds all shapes of all cells (len = **number of cells**)
    pub shapes: Vec<Shape>,

    /// Holds all states of shapes of all cells (len = **number of cells**)
    pub states: Vec<StateOfShape>,

    /// Holds the boundary data such as points, edges, and faces on boundary
    pub boundary: Boundary,

    /// Allows finding points, edges, and faces on the boundary by giving coordinates or keys
    pub find: Find,
}

impl Region {
    /// Allocates and prepares a new region with a given mesh
    ///
    /// # Examples
    ///
    /// ```
    /// use gemlab::mesh::{At, Cell, Mesh, Point, Region};
    /// use gemlab::shapes::GeoKind;
    /// use gemlab::StrError;
    ///
    /// fn main() -> Result<(), StrError> {
    ///     //  3---------2---------5
    ///     //  |         |         |
    ///     //  |   [0]   |   [1]   |
    ///     //  |         |         |
    ///     //  0---------1---------4
    ///     let mesh = Mesh {
    ///         space_ndim: 2,
    ///         points: vec![
    ///             Point { id: 0, coords: vec![0.0, 0.0] },
    ///             Point { id: 1, coords: vec![1.0, 0.0] },
    ///             Point { id: 2, coords: vec![1.0, 1.0] },
    ///             Point { id: 3, coords: vec![0.0, 1.0] },
    ///             Point { id: 4, coords: vec![2.0, 0.0] },
    ///             Point { id: 5, coords: vec![2.0, 1.0] },
    ///         ],
    ///         cells: vec![
    ///             Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: vec![0, 1, 2, 3] },
    ///             Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 4, 5, 2] },
    ///         ],
    ///     };
    ///     let region = Region::with(mesh)?;
    ///     assert_eq!(region.mesh.space_ndim, 2);
    ///     assert_eq!(region.shapes.len(), 2);
    ///     assert_eq!(region.states.len(), 2);
    ///     assert_eq!(region.shapes[0].kind, GeoKind::Qua4);
    ///     assert_eq!(region.boundary.points.len(), 6);
    ///     assert_eq!(region.boundary.edges.len(), 6);
    ///     assert_eq!(region.boundary.faces.len(), 0);
    ///     assert_eq!(region.boundary.min, &[0.0, 0.0]);
    ///     assert_eq!(region.boundary.max, &[2.0, 1.0]);
    ///     assert_eq!(region.find.points(At::XY(0.0, 0.0))?.len(), 1);
    ///     Ok(())
    /// }
    /// ```
    pub fn with(mesh: Mesh) -> Result<Self, StrError> {
        let shapes = allocate_shapes(&mesh)?;
        let states = allocate_states(&mesh, &shapes)?;
        let boundary = Boundary::new(&mesh, &shapes)?;
        let find = Find::new(&mesh, &boundary)?;
        Ok(Region {
            mesh,
            shapes,
            states,
            boundary,
            find,
        })
    }

    /// Allocates and prepares a new region with a mesh defined in a text string
    #[inline]
    pub fn with_text(mesh_text: &str) -> Result<Self, StrError> {
        let mesh = Mesh::from_text(mesh_text)?;
        Region::with(mesh)
    }

    /// Allocates and prepares a new region with a mesh read from a text file
    ///
    /// # Input
    ///
    /// * `full_path` -- may be a String, &str, or Path
    #[inline]
    pub fn with_text_file<P>(full_path: &P) -> Result<Self, StrError>
    where
        P: AsRef<OsStr> + ?Sized,
    {
        let mesh = Mesh::from_text_file(full_path)?;
        Region::with(mesh)
    }

    /// Allocates and prepares a new region with a mesh read from a binary file
    ///
    /// # Input
    ///
    /// * `full_path` -- may be a String, &str, or Path
    #[inline]
    pub fn with_binary_file<P>(full_path: &P) -> Result<Self, StrError>
    where
        P: AsRef<OsStr> + ?Sized,
    {
        let mesh = Mesh::read(full_path)?;
        Region::with(mesh)
    }
}

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

#[cfg(test)]
mod tests {
    use super::{Mesh, Region};
    use crate::mesh::{At, Samples};
    use crate::StrError;

    #[test]
    fn with_works() -> Result<(), StrError> {
        //  3---------2---------5
        //  |         |         |
        //  |   [0]   |   [1]   |
        //  |         |         |
        //  0---------1---------4
        let mesh = Samples::two_quads_horizontal();
        let region = Region::with(mesh)?;
        // println!("{:?}", mesh); // WRONG: mesh has been moved into region
        assert_eq!(region.mesh.space_ndim, 2);
        assert_eq!(region.shapes.len(), 2);
        assert_eq!(region.states.len(), 2);
        assert_eq!(region.boundary.points.len(), 6);
        assert_eq!(region.boundary.edges.len(), 6);
        assert_eq!(region.boundary.faces.len(), 0);
        assert_eq!(region.find.points(At::XY(0.0, 0.0))?.len(), 1);
        Ok(())
    }

    #[test]
    fn with_text_works() -> Result<(), StrError> {
        let mesh = Mesh::from_text(
            "# 1.0  3-----------2-----------5
             #      |           |           |
             #      |    [0]    |    [1]    |  [*] indicates id
             #      |    (1)    |    (2)    |  (*) indicates attribute_id
             #      |           |           |
             # 0.0  0-----------1-----------4
             #     0.0         1.0         2.0
             #
             # header
             # space_ndim npoint ncell
                     2      6     2

             # points
             # id    x   y
             0  0.0 0.0
             1  1.0 0.0
             2  1.0 1.0
             3  0.0 1.0
             4  2.0 0.0
             5  2.0 1.0

             # cells
             # id att geo_ndim nnode  point_ids...
             0   1        2     4  0 1 2 3
             1   2        2     4  1 4 5 2
             ",
        )?;
        let region = Region::with(mesh)?;
        assert_eq!(region.mesh.space_ndim, 2);
        assert_eq!(region.shapes.len(), 2);
        assert_eq!(region.states.len(), 2);
        assert_eq!(region.boundary.points.len(), 6);
        assert_eq!(region.boundary.edges.len(), 6);
        assert_eq!(region.boundary.faces.len(), 0);
        assert_eq!(region.find.points(At::XY(0.0, 0.0))?.len(), 1);
        Ok(())
    }

    #[test]
    fn with_text_file_works() -> Result<(), StrError> {
        //  3---------2---------5
        //  |         |         |
        //  |   [0]   |   [1]   |
        //  |         |         |
        //  0---------1---------4
        let mesh = Mesh::from_text_file("./data/meshes/two_quads_horizontal.msh")?;
        let region = Region::with(mesh)?;
        assert_eq!(region.mesh.space_ndim, 2);
        assert_eq!(region.shapes.len(), 2);
        assert_eq!(region.states.len(), 2);
        assert_eq!(region.boundary.points.len(), 6);
        assert_eq!(region.boundary.edges.len(), 6);
        assert_eq!(region.boundary.faces.len(), 0);
        assert_eq!(region.find.points(At::XY(0.0, 0.0))?.len(), 1);
        Ok(())
    }

    #[test]
    fn with_binary_file_works() -> Result<(), StrError> {
        //  3---------2---------5
        //  |         |         |
        //  |   [0]   |   [1]   |
        //  |         |         |
        //  0---------1---------4
        let full_path = "/tmp/gemlab/test_region_two_quads_horizontal.dat";
        let mesh = Samples::two_quads_horizontal();
        mesh.write(full_path)?;
        let region = Region::with_binary_file(full_path)?;
        assert_eq!(region.mesh.space_ndim, 2);
        assert_eq!(region.shapes.len(), 2);
        assert_eq!(region.states.len(), 2);
        assert_eq!(region.boundary.points.len(), 6);
        assert_eq!(region.boundary.edges.len(), 6);
        assert_eq!(region.boundary.faces.len(), 0);
        assert_eq!(region.find.points(At::XY(0.0, 0.0))?.len(), 1);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Vertex types yielded by the mesh adaptors and their implementations.

use crate::geom::graph::node::{self, ApplyTransform};
use crate::geom::{self, Point2, Point3};
use crate::math::BaseFloat;
use std::ops::{Deref, DerefMut};

/// A vertex with a specified color.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct WithColor<V, C> {
    pub vertex: V,
    pub color: C,
}

/// A vertex with some specified texture coordinates.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct WithTexCoords<V, T = Point2<geom::scalar::Default>> {
    pub vertex: V,
    pub tex_coords: T,
}

/// A vertex with its normal vector.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct WithNormal<V, N = geom::vertex::Default> {
    pub vertex: V,
    pub normal: N,
}

// Node Transform application implementations.

impl<S, V, C> ApplyTransform<S> for WithColor<V, C>
where
    V: ApplyTransform<S>,
    S: BaseFloat,
{
    fn apply_transform(self, transform: &node::PreparedTransform<S>) -> Self {
        let WithColor { mut vertex, color } = self;
        vertex = vertex.apply_transform(transform);
        WithColor { vertex, color }
    }
}

impl<S, V, T> ApplyTransform<S> for WithTexCoords<V, T>
where
    V: ApplyTransform<S>,
    S: BaseFloat,
{
    fn apply_transform(self, transform: &node::PreparedTransform<S>) -> Self {
        let WithTexCoords {
            mut vertex,
            tex_coords,
        } = self;
        vertex = vertex.apply_transform(transform);
        WithTexCoords { vertex, tex_coords }
    }
}

impl<S, V, N> ApplyTransform<S> for WithNormal<V, N>
where
    V: ApplyTransform<S>,
    S: BaseFloat,
{
    fn apply_transform(self, _transform: &node::PreparedTransform<S>) -> Self {
        //let WithNormal { mut vertex, mut normal } = self;
        //vertex = vertex.apply_transform(transform);
        // TODO: Apply transform to the `normal`.
        unimplemented!();
        //WithNormal { vertex, normal }
    }
}

// Deref implementations for each vertex adaptor to their inner vertex type.

impl<V, C> Deref for WithColor<V, C> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.vertex
    }
}

impl<V, C> DerefMut for WithColor<V, C> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.vertex
    }
}

impl<V, T> Deref for WithTexCoords<V, T> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.vertex
    }
}

impl<V, T> DerefMut for WithTexCoords<V, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.vertex
    }
}

impl<V, N> Deref for WithNormal<V, N> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.vertex
    }
}

impl<V, N> DerefMut for WithNormal<V, N> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.vertex
    }
}

// Geometry vertex implementations.

impl<V, C> geom::Vertex for WithColor<V, C>
where
    V: geom::Vertex,
    C: Clone + Copy + PartialEq,
{
    type Scalar = V::Scalar;
}

impl<V, T> geom::Vertex for WithTexCoords<V, T>
where
    V: geom::Vertex,
    T: Clone + Copy + PartialEq,
{
    type Scalar = V::Scalar;
}

impl<V, N> geom::Vertex for WithNormal<V, N>
where
    V: geom::Vertex,
    N: Clone + Copy + PartialEq,
{
    type Scalar = V::Scalar;
}

impl<V, C> geom::Vertex2d for WithColor<V, C>
where
    V: geom::Vertex2d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point2(self) -> Point2<Self::Scalar> {
        self.vertex.point2()
    }
}

impl<V, T> geom::Vertex2d for WithTexCoords<V, T>
where
    V: geom::Vertex2d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point2(self) -> Point2<Self::Scalar> {
        self.vertex.point2()
    }
}

impl<V, N> geom::Vertex2d for WithNormal<V, N>
where
    V: geom::Vertex2d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point2(self) -> Point2<Self::Scalar> {
        self.vertex.point2()
    }
}

impl<V, C> geom::Vertex3d for WithColor<V, C>
where
    V: geom::Vertex3d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point3(self) -> Point3<Self::Scalar> {
        self.vertex.point3()
    }
}

impl<V, T> geom::Vertex3d for WithTexCoords<V, T>
where
    V: geom::Vertex3d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point3(self) -> Point3<Self::Scalar> {
        self.vertex.point3()
    }
}

impl<V, N> geom::Vertex3d for WithNormal<V, N>
where
    V: geom::Vertex3d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point3(self) -> Point3<Self::Scalar> {
        self.vertex.point3()
    }
}

// For converting from a tuples to vertices.

impl<A, V, C> From<(A, C)> for WithColor<V, C>
where
    A: Into<V>,
{
    fn from((vertex, color): (A, C)) -> Self {
        let vertex = vertex.into();
        WithColor { vertex, color }
    }
}

impl<A, V, T> From<(A, T)> for WithTexCoords<V, T>
where
    A: Into<V>,
{
    fn from((vertex, tex_coords): (A, T)) -> Self {
        let vertex = vertex.into();
        WithTexCoords { vertex, tex_coords }
    }
}

impl<A, V, N> From<(A, N)> for WithNormal<V, N>
where
    A: Into<V>,
{
    fn from((vertex, normal): (A, N)) -> Self {
        let vertex = vertex.into();
        WithNormal { vertex, normal }
    }
}

#[test]
fn test_tuple_conv() {
    use crate::color::named::GREEN;
    let _: Point2<_> = [0.0, 0.0].into();
    let _: WithColor<Point2<_>, _> = ([0.0, 0.0], GREEN).into();
}
<commit_msg>Make `From` tuple impl more flexible for `WithColor`<commit_after>//! Vertex types yielded by the mesh adaptors and their implementations.

use crate::draw::properties::IntoLinSrgba;
use crate::geom::graph::node::{self, ApplyTransform};
use crate::geom::{self, Point2, Point3};
use crate::math::BaseFloat;
use std::ops::{Deref, DerefMut};

/// A vertex with a specified color.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct WithColor<V, C> {
    pub vertex: V,
    pub color: C,
}

/// A vertex with some specified texture coordinates.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct WithTexCoords<V, T = Point2<geom::scalar::Default>> {
    pub vertex: V,
    pub tex_coords: T,
}

/// A vertex with its normal vector.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct WithNormal<V, N = geom::vertex::Default> {
    pub vertex: V,
    pub normal: N,
}

// Node Transform application implementations.

impl<S, V, C> ApplyTransform<S> for WithColor<V, C>
where
    V: ApplyTransform<S>,
    S: BaseFloat,
{
    fn apply_transform(self, transform: &node::PreparedTransform<S>) -> Self {
        let WithColor { mut vertex, color } = self;
        vertex = vertex.apply_transform(transform);
        WithColor { vertex, color }
    }
}

impl<S, V, T> ApplyTransform<S> for WithTexCoords<V, T>
where
    V: ApplyTransform<S>,
    S: BaseFloat,
{
    fn apply_transform(self, transform: &node::PreparedTransform<S>) -> Self {
        let WithTexCoords {
            mut vertex,
            tex_coords,
        } = self;
        vertex = vertex.apply_transform(transform);
        WithTexCoords { vertex, tex_coords }
    }
}

impl<S, V, N> ApplyTransform<S> for WithNormal<V, N>
where
    V: ApplyTransform<S>,
    S: BaseFloat,
{
    fn apply_transform(self, _transform: &node::PreparedTransform<S>) -> Self {
        //let WithNormal { mut vertex, mut normal } = self;
        //vertex = vertex.apply_transform(transform);
        // TODO: Apply transform to the `normal`.
        unimplemented!();
        //WithNormal { vertex, normal }
    }
}

// Deref implementations for each vertex adaptor to their inner vertex type.

impl<V, C> Deref for WithColor<V, C> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.vertex
    }
}

impl<V, C> DerefMut for WithColor<V, C> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.vertex
    }
}

impl<V, T> Deref for WithTexCoords<V, T> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.vertex
    }
}

impl<V, T> DerefMut for WithTexCoords<V, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.vertex
    }
}

impl<V, N> Deref for WithNormal<V, N> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.vertex
    }
}

impl<V, N> DerefMut for WithNormal<V, N> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.vertex
    }
}

// Geometry vertex implementations.

impl<V, C> geom::Vertex for WithColor<V, C>
where
    V: geom::Vertex,
    C: Clone + Copy + PartialEq,
{
    type Scalar = V::Scalar;
}

impl<V, T> geom::Vertex for WithTexCoords<V, T>
where
    V: geom::Vertex,
    T: Clone + Copy + PartialEq,
{
    type Scalar = V::Scalar;
}

impl<V, N> geom::Vertex for WithNormal<V, N>
where
    V: geom::Vertex,
    N: Clone + Copy + PartialEq,
{
    type Scalar = V::Scalar;
}

impl<V, C> geom::Vertex2d for WithColor<V, C>
where
    V: geom::Vertex2d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point2(self) -> Point2<Self::Scalar> {
        self.vertex.point2()
    }
}

impl<V, T> geom::Vertex2d for WithTexCoords<V, T>
where
    V: geom::Vertex2d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point2(self) -> Point2<Self::Scalar> {
        self.vertex.point2()
    }
}

impl<V, N> geom::Vertex2d for WithNormal<V, N>
where
    V: geom::Vertex2d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point2(self) -> Point2<Self::Scalar> {
        self.vertex.point2()
    }
}

impl<V, C> geom::Vertex3d for WithColor<V, C>
where
    V: geom::Vertex3d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point3(self) -> Point3<Self::Scalar> {
        self.vertex.point3()
    }
}

impl<V, T> geom::Vertex3d for WithTexCoords<V, T>
where
    V: geom::Vertex3d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point3(self) -> Point3<Self::Scalar> {
        self.vertex.point3()
    }
}

impl<V, N> geom::Vertex3d for WithNormal<V, N>
where
    V: geom::Vertex3d,
    Self: geom::Vertex<Scalar = V::Scalar>,
{
    fn point3(self) -> Point3<Self::Scalar> {
        self.vertex.point3()
    }
}

// For converting from a tuples to vertices.

impl<A, V, B, C> From<(A, B)> for WithColor<V, C>
where
    A: Into<V>,
    B: IntoLinSrgba<f32>,
    C: From<crate::color::LinSrgba<f32>>,
{
    fn from((vertex, color): (A, B)) -> Self {
        let vertex = vertex.into();
        // TODO: Using `into_lin_srgba` solely because palette's conversion implementations (e.g.
        // `From` and `Into`) are not exhaustive. Using this gives more flexibility in terms of
        // supported color conversions, but these conversions should really be added upstream to
        // palette itself.
        let lin_srgba = color.into_lin_srgba();
        let color = lin_srgba.into();
        WithColor { vertex, color }
    }
}

impl<A, V, T> From<(A, T)> for WithTexCoords<V, T>
where
    A: Into<V>,
{
    fn from((vertex, tex_coords): (A, T)) -> Self {
        let vertex = vertex.into();
        WithTexCoords { vertex, tex_coords }
    }
}

impl<A, V, N> From<(A, N)> for WithNormal<V, N>
where
    A: Into<V>,
{
    fn from((vertex, normal): (A, N)) -> Self {
        let vertex = vertex.into();
        WithNormal { vertex, normal }
    }
}

#[test]
fn test_tuple_conv() {
    use crate::color::named::GREEN;
    let _: Point2<_> = [0.0, 0.0].into();
    let _: WithColor<Point2<_>, _> = ([0.0, 0.0], GREEN).into();
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! IPv4 packet abstraction

use packet::HasPseudoheader;
use packet::PrimitiveValues;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::Ipv4Addr;

/// Represents an IPv4 Packet
#[packet]
pub struct Ipv4 {
    version: u4,
    header_length: u4,
    dscp: u6,
    ecn: u2,
    total_length: u16be,
    identification: u16be,
    flags: u3,
    fragment_offset: u13be,
    ttl: u8,
    #[construct_with(u8)]
    next_level_protocol: IpNextHeaderProtocol,
    checksum: u16be,
    #[construct_with(u8, u8, u8, u8)]
    source: Ipv4Addr,
    #[construct_with(u8, u8, u8, u8)]
    destination: Ipv4Addr,
    #[length_fn = "ipv4_options_length"]
    options: Vec<Ipv4Option>,
    #[payload]
    payload: Vec<u8>,
}

impl <'p> HasPseudoheader for Ipv4Packet <'p> {
    fn pseudoheader_checksum(&self) -> u32 {
        let mut sum = 0u32;

        // Checksum pseudo-header
        // IPv4 source
        let source = self.get_source();
        match source.octets() {
            [a, b, c, d] => {
                sum = sum + ((a as u32) << 8 | b as u32);
                sum = sum + ((c as u32) << 8 | d as u32);
            }
        }

        // IPv4 destination
        let destination = self.get_destination();
        match destination.octets() {
            [a, b, c, d] => {
                sum = sum + ((a as u32) << 8 | b as u32);
                sum = sum + ((c as u32) << 8 | d as u32);
            }
        }

        // IPv4 Next level protocol
        let next_level_protocol = self.get_next_level_protocol();
        let (fu,) = next_level_protocol.to_primitive_values();
        sum = sum + fu as u32;
        return sum;
    }
}

/// Calculates the checksum of an IPv4 packet
pub fn checksum<'a>(packet: &Ipv4Packet<'a>) -> u16be {
    use packet::Packet;

    let len = packet.get_header_length() as usize * 4;
    let mut sum = 0u32;
    let mut i = 0;
    while i < len {
        let word = (packet.packet()[i] as u32) << 8 | packet.packet()[i + 1] as u32;
        sum = sum + word;
        i = i + 2;
    }
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    return !sum as u16;
}

fn ipv4_options_length<'a>(ipv4: &Ipv4Packet<'a>) -> usize {
    ipv4.get_header_length() as usize - 5
}

#[test]
fn ipv4_options_length_test() {
    let mut packet = [0u8; 20];
    let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
    ip_header.set_header_length(5);
    assert_eq!(ipv4_options_length(&ip_header.to_immutable()), 0);
}

/// Represents the IPv4 Option field
#[packet]
pub struct Ipv4Option {
    copied: u1,
    class: u2,
    number: u5,
    length: u8,
    #[payload]
    data: Vec<u8>
}

#[test]
fn ipv4_packet_test() {
    use packet::ip::IpNextHeaderProtocols;

    let mut packet = [0u8; 20];
    {
        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
        ip_header.set_version(4);
        assert_eq!(ip_header.get_version(), 4);

        ip_header.set_header_length(5);
        assert_eq!(ip_header.get_header_length(), 5);

        ip_header.set_dscp(4);
        assert_eq!(ip_header.get_dscp(), 4);

        ip_header.set_ecn(1);
        assert_eq!(ip_header.get_ecn(), 1);

        ip_header.set_total_length(115);
        assert_eq!(ip_header.get_total_length(), 115);

        ip_header.set_identification(257);
        assert_eq!(ip_header.get_identification(), 257);

        ip_header.set_flags(2);
        assert_eq!(ip_header.get_flags(), 2);

        ip_header.set_fragment_offset(257);
        assert_eq!(ip_header.get_fragment_offset(), 257);

        ip_header.set_ttl(64);
        assert_eq!(ip_header.get_ttl(), 64);

        ip_header.set_next_level_protocol(IpNextHeaderProtocols::Udp);
        assert_eq!(ip_header.get_next_level_protocol(), IpNextHeaderProtocols::Udp);

        ip_header.set_source(Ipv4Addr::new(192, 168, 0, 1));
        assert_eq!(ip_header.get_source(), Ipv4Addr::new(192, 168, 0, 1));

        ip_header.set_destination(Ipv4Addr::new(192, 168, 0, 199));
        assert_eq!(ip_header.get_destination(), Ipv4Addr::new(192, 168, 0, 199));

        let imm_header = checksum(&ip_header.to_immutable());
        ip_header.set_checksum(imm_header);
        assert_eq!(ip_header.get_checksum(), 0xb64e);
    }

    let ref_packet = [0x45,           /* ver/ihl */
                     0x11,           /* dscp/ecn */
                     0x00, 0x73,     /* total len */
                     0x01, 0x01,     /* identification */
                     0x41, 0x01,     /* flags/frag offset */
                     0x40,           /* ttl */
                     0x11,           /* proto */
                     0xb6, 0x4e,     /* checksum */
                     0xc0, 0xa8, 0x00, 0x01, /* source ip */
                     0xc0, 0xa8, 0x00, 0xc7  /* dest ip */];
    assert_eq!(&ref_packet[..], &packet[..]);
}

<commit_msg>slight cleanup of pseudoheader_checksum for ipv4<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! IPv4 packet abstraction

use packet::HasPseudoheader;
use packet::PrimitiveValues;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::Ipv4Addr;

/// Represents an IPv4 Packet
#[packet]
pub struct Ipv4 {
    version: u4,
    header_length: u4,
    dscp: u6,
    ecn: u2,
    total_length: u16be,
    identification: u16be,
    flags: u3,
    fragment_offset: u13be,
    ttl: u8,
    #[construct_with(u8)]
    next_level_protocol: IpNextHeaderProtocol,
    checksum: u16be,
    #[construct_with(u8, u8, u8, u8)]
    source: Ipv4Addr,
    #[construct_with(u8, u8, u8, u8)]
    destination: Ipv4Addr,
    #[length_fn = "ipv4_options_length"]
    options: Vec<Ipv4Option>,
    #[payload]
    payload: Vec<u8>,
}

impl <'p> HasPseudoheader for Ipv4Packet <'p> {
    fn pseudoheader_checksum(&self) -> u32 {
        let mut sum = 0u32;

        // Checksum pseudo-header
        // IPv4 source
        let source = self.get_source();
        match source.octets() {
            [a, b, c, d] => {
                sum = sum + ((a as u32) << 8 | b as u32);
                sum = sum + ((c as u32) << 8 | d as u32);
            }
        }

        // IPv4 destination
        let destination = self.get_destination();
        match destination.octets() {
            [a, b, c, d] => {
                sum = sum + ((a as u32) << 8 | b as u32);
                sum = sum + ((c as u32) << 8 | d as u32);
            }
        }

        // IPv4 Next level protocol
        let next_level_protocol = self.get_next_level_protocol();
        let (next_proto,) = next_level_protocol.to_primitive_values();
        sum = sum + next_proto as u32;
        return sum;
    }
}

/// Calculates the checksum of an IPv4 packet
pub fn checksum<'a>(packet: &Ipv4Packet<'a>) -> u16be {
    use packet::Packet;

    let len = packet.get_header_length() as usize * 4;
    let mut sum = 0u32;
    let mut i = 0;
    while i < len {
        let word = (packet.packet()[i] as u32) << 8 | packet.packet()[i + 1] as u32;
        sum = sum + word;
        i = i + 2;
    }
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    return !sum as u16;
}

fn ipv4_options_length<'a>(ipv4: &Ipv4Packet<'a>) -> usize {
    ipv4.get_header_length() as usize - 5
}

#[test]
fn ipv4_options_length_test() {
    let mut packet = [0u8; 20];
    let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
    ip_header.set_header_length(5);
    assert_eq!(ipv4_options_length(&ip_header.to_immutable()), 0);
}

/// Represents the IPv4 Option field
#[packet]
pub struct Ipv4Option {
    copied: u1,
    class: u2,
    number: u5,
    length: u8,
    #[payload]
    data: Vec<u8>
}

#[test]
fn ipv4_packet_test() {
    use packet::ip::IpNextHeaderProtocols;

    let mut packet = [0u8; 20];
    {
        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
        ip_header.set_version(4);
        assert_eq!(ip_header.get_version(), 4);

        ip_header.set_header_length(5);
        assert_eq!(ip_header.get_header_length(), 5);

        ip_header.set_dscp(4);
        assert_eq!(ip_header.get_dscp(), 4);

        ip_header.set_ecn(1);
        assert_eq!(ip_header.get_ecn(), 1);

        ip_header.set_total_length(115);
        assert_eq!(ip_header.get_total_length(), 115);

        ip_header.set_identification(257);
        assert_eq!(ip_header.get_identification(), 257);

        ip_header.set_flags(2);
        assert_eq!(ip_header.get_flags(), 2);

        ip_header.set_fragment_offset(257);
        assert_eq!(ip_header.get_fragment_offset(), 257);

        ip_header.set_ttl(64);
        assert_eq!(ip_header.get_ttl(), 64);

        ip_header.set_next_level_protocol(IpNextHeaderProtocols::Udp);
        assert_eq!(ip_header.get_next_level_protocol(), IpNextHeaderProtocols::Udp);

        ip_header.set_source(Ipv4Addr::new(192, 168, 0, 1));
        assert_eq!(ip_header.get_source(), Ipv4Addr::new(192, 168, 0, 1));

        ip_header.set_destination(Ipv4Addr::new(192, 168, 0, 199));
        assert_eq!(ip_header.get_destination(), Ipv4Addr::new(192, 168, 0, 199));

        let imm_header = checksum(&ip_header.to_immutable());
        ip_header.set_checksum(imm_header);
        assert_eq!(ip_header.get_checksum(), 0xb64e);
    }

    let ref_packet = [0x45,           /* ver/ihl */
                     0x11,           /* dscp/ecn */
                     0x00, 0x73,     /* total len */
                     0x01, 0x01,     /* identification */
                     0x41, 0x01,     /* flags/frag offset */
                     0x40,           /* ttl */
                     0x11,           /* proto */
                     0xb6, 0x4e,     /* checksum */
                     0xc0, 0xa8, 0x00, 0x01, /* source ip */
                     0xc0, 0xa8, 0x00, 0xc7  /* dest ip */];
    assert_eq!(&ref_packet[..], &packet[..]);
}

<|endoftext|>