<commit_before>use libc::c_char;
use std::error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::mem::transmute;
use std::rc::Rc;

use crate::sys;

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = sys::SDL_errorcode::SDL_ENOMEM as i32,
    ReadError = sys::SDL_errorcode::SDL_EFREAD as i32,
    WriteError = sys::SDL_errorcode::SDL_EFWRITE as i32,
    SeekError = sys::SDL_errorcode::SDL_EFSEEK as i32,
    UnsupportedError = sys::SDL_errorcode::SDL_UNSUPPORTED as i32,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            NoMemError => write!(f, "Out of memory"),
            ReadError => write!(f, "Error reading from datastream"),
            WriteError => write!(f, "Error writing to datastream"),
            SeekError => write!(f, "Error seeking in datastream"),
            UnsupportedError => write!(f, "Unknown SDL error"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            NoMemError => "out of memory",
            ReadError => "error reading from datastream",
            WriteError => "error writing to datastream",
            SeekError => "error seeking in datastream",
            UnsupportedError => "unknown SDL error",
        }
    }
}

use std::sync::atomic::AtomicBool;
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = AtomicBool::new(false);

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: Rc<SdlDrop>,
}

impl Sdl {
    #[inline]
    #[doc(alias = "SDL_Init")]
    fn new() -> Result<Sdl, String> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err("Cannot initialize `Sdl` more than once at a time.".to_owned())
            } else if sys::SDL_Init(0) == 0 {
                // Initialize SDL without any explicit subsystems (flags = 0).
                Ok(Sdl {
                    sdldrop: Rc::new(SdlDrop),
                })
            } else {
                IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                Err(get_error())
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> Result<AudioSubsystem, String> {
        AudioSubsystem::new(self)
    }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> Result<EventSubsystem, String> {
        EventSubsystem::new(self)
    }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> Result<JoystickSubsystem, String> {
        JoystickSubsystem::new(self)
    }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> Result<HapticSubsystem, String> {
        HapticSubsystem::new(self)
    }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> Result<GameControllerSubsystem, String> {
        GameControllerSubsystem::new(self)
    }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> Result<TimerSubsystem, String> {
        TimerSubsystem::new(self)
    }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> Result<VideoSubsystem, String> {
        VideoSubsystem::new(self)
    }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> Result<EventPump, String> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> Rc<SdlDrop> {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
#[doc(hidden)]
#[derive(Debug)]
pub struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    #[doc(alias = "SDL_Quit")]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe {
            sys::SDL_Quit();
        }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => {
        impl $name {
            #[inline]
            #[doc(alias = "SDL_InitSubSystem")]
            fn new(sdl: &Sdl) -> Result<$name, String> {
                let result = unsafe { sys::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag,
                        }),
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    };
    ($name:ident, $flag:expr, nosync) => {
        #[derive(Debug, Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>,
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl {
                    sdldrop: self._subsystem_drop._sdldrop.clone(),
                }
            }
        }

        subsystem!($name, $flag);
    };
    ($name:ident, $flag:expr, sync) => {
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>,
        }
        unsafe impl Sync for $name {}

        impl std::clone::Clone for $name {
            #[inline]
            fn clone(&self) -> $name {
                $name {
                    _subsystem_drop: self._subsystem_drop.clone(),
                }
            }
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl {
                    sdldrop: self._subsystem_drop._sdldrop.clone(),
                }
            }
        }

        subsystem!($name, $flag);
    };
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Debug, Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: u32,
}

impl Drop for SubsystemDrop {
    #[inline]
    #[doc(alias = "SDL_QuitSubSystem")]
    fn drop(&mut self) {
        unsafe {
            sys::SDL_QuitSubSystem(self.flag);
        }
    }
}

subsystem!(AudioSubsystem, sys::SDL_INIT_AUDIO, nosync);
subsystem!(
    GameControllerSubsystem,
    sys::SDL_INIT_GAMECONTROLLER,
    nosync
);
subsystem!(HapticSubsystem, sys::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, sys::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, sys::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, sys::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, sys::SDL_INIT_EVENTS, sync);

static mut IS_EVENT_PUMP_ALIVE: bool = false;

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _sdldrop: Rc<SdlDrop>,
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    #[doc(alias = "SDL_InitSubSystem")]
    fn new(sdl: &Sdl) -> Result<EventPump, String> {
        // Called on the main SDL thread.

        unsafe {
            if IS_EVENT_PUMP_ALIVE {
                Err("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".to_owned())
            } else {
                // Initialize the events subsystem, just in case none of the other subsystems have done it yet.
                let result = sys::SDL_InitSubSystem(sys::SDL_INIT_EVENTS);

                if result == 0 {
                    IS_EVENT_PUMP_ALIVE = true;

                    Ok(EventPump {
                        _sdldrop: sdl.sdldrop.clone(),
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    }
}

impl Drop for EventPump {
    #[inline]
    #[doc(alias = "SDL_QuitSubSystem")]
    fn drop(&mut self) {
        // Called on the main SDL thread.

        unsafe {
            assert!(IS_EVENT_PUMP_ALIVE);
            sys::SDL_QuitSubSystem(sys::SDL_INIT_EVENTS);
            IS_EVENT_PUMP_ALIVE = false;
        }
    }
}

/// Get platform name
#[inline]
#[doc(alias = "SDL_GetPlatform")]
pub fn get_platform() -> &'static str {
    unsafe { CStr::from_ptr(sys::SDL_GetPlatform()).to_str().unwrap() }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
#[doc(alias = "SDL_GetError")]
pub fn init() -> Result<Sdl, String> {
    Sdl::new()
}

pub fn get_error() -> String {
    unsafe {
        let err = sys::SDL_GetError();
        CStr::from_ptr(err as *const _).to_str().unwrap().to_owned()
    }
}

#[doc(alias = "SDL_SetError")]
pub fn set_error(err: &str) -> Result<(), NulError> {
    let c_string = CString::new(err)?;
    unsafe {
        sys::SDL_SetError(b"%s\0".as_ptr() as *const c_char, c_string.as_ptr() as *const c_char);
    }
    Ok(())
}

#[doc(alias = "SDL_Error")]
pub fn set_error_from_code(err: Error) {
    unsafe {
        sys::SDL_Error(transmute(err));
    }
}

#[doc(alias = "SDL_ClearError")]
pub fn clear_error() {
    unsafe {
        sys::SDL_ClearError();
    }
}
<commit_msg>sdl.rs: fix formatting<commit_after>use libc::c_char;
use std::error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::mem::transmute;
use std::rc::Rc;

use crate::sys;

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = sys::SDL_errorcode::SDL_ENOMEM as i32,
    ReadError = sys::SDL_errorcode::SDL_EFREAD as i32,
    WriteError = sys::SDL_errorcode::SDL_EFWRITE as i32,
    SeekError = sys::SDL_errorcode::SDL_EFSEEK as i32,
    UnsupportedError = sys::SDL_errorcode::SDL_UNSUPPORTED as i32,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            NoMemError => write!(f, "Out of memory"),
            ReadError => write!(f, "Error reading from datastream"),
            WriteError => write!(f, "Error writing to datastream"),
            SeekError => write!(f, "Error seeking in datastream"),
            UnsupportedError => write!(f, "Unknown SDL error"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            NoMemError => "out of memory",
            ReadError => "error reading from datastream",
            WriteError => "error writing to datastream",
            SeekError => "error seeking in datastream",
            UnsupportedError => "unknown SDL error",
        }
    }
}

use std::sync::atomic::AtomicBool;
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = AtomicBool::new(false);

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: Rc<SdlDrop>,
}

impl Sdl {
    #[inline]
    #[doc(alias = "SDL_Init")]
    fn new() -> Result<Sdl, String> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err("Cannot initialize `Sdl` more than once at a time.".to_owned())
            } else if sys::SDL_Init(0) == 0 {
                // Initialize SDL without any explicit subsystems (flags = 0).
                Ok(Sdl {
                    sdldrop: Rc::new(SdlDrop),
                })
            } else {
                IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                Err(get_error())
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> Result<AudioSubsystem, String> {
        AudioSubsystem::new(self)
    }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> Result<EventSubsystem, String> {
        EventSubsystem::new(self)
    }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> Result<JoystickSubsystem, String> {
        JoystickSubsystem::new(self)
    }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> Result<HapticSubsystem, String> {
        HapticSubsystem::new(self)
    }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> Result<GameControllerSubsystem, String> {
        GameControllerSubsystem::new(self)
    }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> Result<TimerSubsystem, String> {
        TimerSubsystem::new(self)
    }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> Result<VideoSubsystem, String> {
        VideoSubsystem::new(self)
    }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> Result<EventPump, String> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> Rc<SdlDrop> {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
#[doc(hidden)]
#[derive(Debug)]
pub struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    #[doc(alias = "SDL_Quit")]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe {
            sys::SDL_Quit();
        }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => {
        impl $name {
            #[inline]
            #[doc(alias = "SDL_InitSubSystem")]
            fn new(sdl: &Sdl) -> Result<$name, String> {
                let result = unsafe { sys::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag,
                        }),
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    };
    ($name:ident, $flag:expr, nosync) => {
        #[derive(Debug, Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>,
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl {
                    sdldrop: self._subsystem_drop._sdldrop.clone(),
                }
            }
        }

        subsystem!($name, $flag);
    };
    ($name:ident, $flag:expr, sync) => {
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>,
        }
        unsafe impl Sync for $name {}

        impl std::clone::Clone for $name {
            #[inline]
            fn clone(&self) -> $name {
                $name {
                    _subsystem_drop: self._subsystem_drop.clone(),
                }
            }
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl {
                    sdldrop: self._subsystem_drop._sdldrop.clone(),
                }
            }
        }

        subsystem!($name, $flag);
    };
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Debug, Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: u32,
}

impl Drop for SubsystemDrop {
    #[inline]
    #[doc(alias = "SDL_QuitSubSystem")]
    fn drop(&mut self) {
        unsafe {
            sys::SDL_QuitSubSystem(self.flag);
        }
    }
}

subsystem!(AudioSubsystem, sys::SDL_INIT_AUDIO, nosync);
subsystem!(
    GameControllerSubsystem,
    sys::SDL_INIT_GAMECONTROLLER,
    nosync
);
subsystem!(HapticSubsystem, sys::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, sys::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, sys::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, sys::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, sys::SDL_INIT_EVENTS, sync);

static mut IS_EVENT_PUMP_ALIVE: bool = false;

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _sdldrop: Rc<SdlDrop>,
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    #[doc(alias = "SDL_InitSubSystem")]
    fn new(sdl: &Sdl) -> Result<EventPump, String> {
        // Called on the main SDL thread.

        unsafe {
            if IS_EVENT_PUMP_ALIVE {
                Err("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".to_owned())
            } else {
                // Initialize the events subsystem, just in case none of the other subsystems have done it yet.
                let result = sys::SDL_InitSubSystem(sys::SDL_INIT_EVENTS);

                if result == 0 {
                    IS_EVENT_PUMP_ALIVE = true;

                    Ok(EventPump {
                        _sdldrop: sdl.sdldrop.clone(),
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    }
}

impl Drop for EventPump {
    #[inline]
    #[doc(alias = "SDL_QuitSubSystem")]
    fn drop(&mut self) {
        // Called on the main SDL thread.

        unsafe {
            assert!(IS_EVENT_PUMP_ALIVE);
            sys::SDL_QuitSubSystem(sys::SDL_INIT_EVENTS);
            IS_EVENT_PUMP_ALIVE = false;
        }
    }
}

/// Get platform name
#[inline]
#[doc(alias = "SDL_GetPlatform")]
pub fn get_platform() -> &'static str {
    unsafe { CStr::from_ptr(sys::SDL_GetPlatform()).to_str().unwrap() }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
#[doc(alias = "SDL_GetError")]
pub fn init() -> Result<Sdl, String> {
    Sdl::new()
}

pub fn get_error() -> String {
    unsafe {
        let err = sys::SDL_GetError();
        CStr::from_ptr(err as *const _).to_str().unwrap().to_owned()
    }
}

#[doc(alias = "SDL_SetError")]
pub fn set_error(err: &str) -> Result<(), NulError> {
    let c_string = CString::new(err)?;
    unsafe {
        sys::SDL_SetError(
            b"%s\0".as_ptr() as *const c_char,
            c_string.as_ptr() as *const c_char,
        );
    }
    Ok(())
}

#[doc(alias = "SDL_Error")]
pub fn set_error_from_code(err: Error) {
    unsafe {
        sys::SDL_Error(transmute(err));
    }
}

#[doc(alias = "SDL_ClearError")]
pub fn clear_error() {
    unsafe {
        sys::SDL_ClearError();
    }
}
<|endoftext|>


<commit_before>use libc;
use uuid::Uuid;

macro_rules! gen_primitive_types_io {
    (
        $($t:ty: $tmod:ident);*
    ) => (
            $(
                pub mod $tmod {
                    use std::ptr;
                    use std::mem;
                    pub fn read(mem_ptr: usize) -> $t {
                         unsafe {
                            ptr::read(mem_ptr as *mut $t)
                        }
                    }
                    pub fn write(val: $t, mem_ptr: usize) {
                        unsafe {
                            ptr::write(mem_ptr as *mut $t, val)
                        }
                    }
                    pub fn size() -> usize {
                        mem::size_of::<$t>()
                    }
                }
            )*
    );
}

macro_rules! gen_compound_types_io {
    (
        $($t:ident, $tmod:ident, $reader:expr, $writer: expr, $size:expr);*
    ) => (
            $(
                mod $tmod {
                    use ram::types::*;
                    pub fn read(mem_ptr: usize) -> $t {
                        let read = $reader;
                        read(mem_ptr)
                    }
                    pub fn write(val: $t, mem_ptr: usize) {
                        let write = $writer;
                        write(val, mem_ptr)
                    }
                    pub fn size() -> usize {
                        $size
                    }
                }
            )*
    );
}

macro_rules! define_types {
    (
        $(
            [ $( $name:expr ),* ], $id:expr, $t:ty, $io:ident
         );*
    ) => (
        fn get_type_id (name: String) -> i32 {
           match name.as_ref() {
                $(
                    $($name => $id,)*
                )*
                _ => -1,
           }
        }
        fn get_id_type (id: i32) -> &'static str {
           match id {
                $(
                    $id => [$($name),*][0],
                )*
                _ => "N/A",
           }
        }
        fn get_size (id: i32) -> usize {
           match id {
                $(
                    $id => $io::size(),
                )*
                _ => 0,
           }
        }
    );
}

macro_rules! rc {
    (
        $read:ident
    ) => (
        $read
    );
}

macro_rules! wc {
    (
        $rwrite:ident
    ) => (
        $rwrite
    );
}

gen_primitive_types_io!(
    bool:   bool_io       ;
    char:   char_io       ;
    i8:     i8_io         ;
    i16:    i16_io        ;
    i32:    i32_io        ;
    i64:    i64_io        ;
    u8:     u8_io         ;
    u16:    u16_io        ;
    u32:    u32_io        ;
    u64:    u64_io        ;
    isize:  isize_io      ;
    usize:  usize_io      ;
    f32:    f32_io        ;
    f64:    f64_io
);

pub struct pos2d32 {
    pub x: f32,
    pub y: f32,
}

pub struct pos2d64 {
    pub x: f64,
    pub y: f64,
}

pub struct pos3d32 {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

pub struct pos3d64 {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

pub type uuid_ = Uuid;

gen_compound_types_io! (
    pos2d32, pos2d32_io, {
        |mem_ptr| {
            let x = f32_io::read(mem_ptr);
            let y = f32_io::read(mem_ptr + f32_io::size());
            pos2d32 {x: x, y: y}
        }
    }, {
        |val: pos2d32, mem_ptr| {
            f32_io::write(val.x, mem_ptr);
            f32_io::write(val.y, mem_ptr + f32_io::size());
        }
    }, {
        f32_io::size() * 2
    };

    pos2d64, pos2d64_io, {
        |mem_ptr| {
            let x = f64_io::read(mem_ptr);
            let y = f64_io::read(mem_ptr + f64_io::size());
            pos2d64 {x: x, y: y}
        }
    }, {
        |val: pos2d64, mem_ptr| {
            f64_io::write(val.x, mem_ptr);
            f64_io::write(val.y, mem_ptr + f64_io::size());
        }
    }, {
        f64_io::size() * 2
    };

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

    pos3d32, pos3d32_io, {
        |mem_ptr| {
            let x = f32_io::read(mem_ptr);
            let y = f32_io::read(mem_ptr + f32_io::size());
            let z = f32_io::read(mem_ptr + f32_io::size() * 2);
            pos3d32 {x: x, y: y, z: z}
        }
    }, {
        |val: pos3d32, mem_ptr| {
            f32_io::write(val.x, mem_ptr);
            f32_io::write(val.y, mem_ptr + f32_io::size());
            f32_io::write(val.z, mem_ptr + f32_io::size() * 2);
        }
    }, {
        f32_io::size() * 3
    };

    pos3d64, pos3d64_io, {
        |mem_ptr| {
            let x = f64_io::read(mem_ptr);
            let y = f64_io::read(mem_ptr + f64_io::size());
            let z = f64_io::read(mem_ptr + f64_io::size() * 2);
            pos3d64 {x: x, y: y, z: z}
        }
    }, {
        |val: pos3d64, mem_ptr| {
            f64_io::write(val.x, mem_ptr);
            f64_io::write(val.y, mem_ptr + f64_io::size());
            f64_io::write(val.z, mem_ptr + f64_io::size() * 2);
        }
    }, {
        f64_io::size() * 3
    };

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

    uuid_, uuid_io, {
        |mem_ptr| {
            use uuid::{UuidBytes, Uuid};
            use std::ptr;
            unsafe {
                Uuid::from_bytes(
                    ptr::read(mem_ptr as *mut &UuidBytes) as &[u8]
                ).unwrap()
            }
        }
    }, {
        use uuid::{UuidBytes, Uuid};
        |val: uuid_, mem_ptr: usize| {
            use std::ptr;
            unsafe {
                ptr::write(mem_ptr as *mut &UuidBytes, val.as_bytes());
            }
        }
    }, {
        16
    }
);

define_types!(
    ["bool", "bit"], 0, bool                            ,  bool_io       ;
    ["char"], 1, char                                   ,  char_io       ;
    ["i8"], 2, i8                                       ,  i8_io         ;
    ["i16", "int"], 3, i16                              ,  i16_io        ;
    ["i32", "long"], 4, i32                             ,  i32_io        ;
    ["i64", "longlong"], 5, i64                         ,  i64_io        ;
    ["u8", "byte"], 6, u8                               ,  u8_io         ;
    ["u16"], 7, u16                                     ,  u16_io        ;
    ["u32"], 8, u32                                     ,  u32_io        ;
    ["u64"], 9, u64                                     ,  u64_io        ;
    ["isize"], 10, isize                                ,  isize_io      ;
    ["usize"], 11, usize                                ,  usize_io      ;
    ["f32", "float"], 12, f32                           ,  f32_io        ;
    ["f64", "double"], 13, f64                          ,  f64_io        ;
    ["pos2d32", "pos2d", "pos", "pos32"], 14, pos2d32   ,  pos2d32_io    ;
    ["pos2d64", "pos64"], 15, pos2d64                   ,  pos2d64_io    ;
    ["pos3d32", "pos3d"], 16, pos3d32                   ,  pos3d32_io    ;
    ["pos3d64"], 17, pos3d64                            ,  pos3d64_io
);<commit_msg>register uuid type<commit_after>use libc;
use uuid::Uuid;

macro_rules! gen_primitive_types_io {
    (
        $($t:ty: $tmod:ident);*
    ) => (
            $(
                pub mod $tmod {
                    use std::ptr;
                    use std::mem;
                    pub fn read(mem_ptr: usize) -> $t {
                         unsafe {
                            ptr::read(mem_ptr as *mut $t)
                        }
                    }
                    pub fn write(val: $t, mem_ptr: usize) {
                        unsafe {
                            ptr::write(mem_ptr as *mut $t, val)
                        }
                    }
                    pub fn size() -> usize {
                        mem::size_of::<$t>()
                    }
                }
            )*
    );
}

macro_rules! gen_compound_types_io {
    (
        $($t:ident, $tmod:ident, $reader:expr, $writer: expr, $size:expr);*
    ) => (
            $(
                mod $tmod {
                    use ram::types::*;
                    pub fn read(mem_ptr: usize) -> $t {
                        let read = $reader;
                        read(mem_ptr)
                    }
                    pub fn write(val: $t, mem_ptr: usize) {
                        let write = $writer;
                        write(val, mem_ptr)
                    }
                    pub fn size() -> usize {
                        $size
                    }
                }
            )*
    );
}

macro_rules! define_types {
    (
        $(
            [ $( $name:expr ),* ], $id:expr, $t:ty, $io:ident
         );*
    ) => (
        fn get_type_id (name: String) -> i32 {
           match name.as_ref() {
                $(
                    $($name => $id,)*
                )*
                _ => -1,
           }
        }
        fn get_id_type (id: i32) -> &'static str {
           match id {
                $(
                    $id => [$($name),*][0],
                )*
                _ => "N/A",
           }
        }
        fn get_size (id: i32) -> usize {
           match id {
                $(
                    $id => $io::size(),
                )*
                _ => 0,
           }
        }
    );
}

macro_rules! rc {
    (
        $read:ident
    ) => (
        $read
    );
}

macro_rules! wc {
    (
        $rwrite:ident
    ) => (
        $rwrite
    );
}

gen_primitive_types_io!(
    bool:   bool_io       ;
    char:   char_io       ;
    i8:     i8_io         ;
    i16:    i16_io        ;
    i32:    i32_io        ;
    i64:    i64_io        ;
    u8:     u8_io         ;
    u16:    u16_io        ;
    u32:    u32_io        ;
    u64:    u64_io        ;
    isize:  isize_io      ;
    usize:  usize_io      ;
    f32:    f32_io        ;
    f64:    f64_io
);

pub struct pos2d32 {
    pub x: f32,
    pub y: f32,
}

pub struct pos2d64 {
    pub x: f64,
    pub y: f64,
}

pub struct pos3d32 {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

pub struct pos3d64 {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

pub type uuid_ = Uuid;

gen_compound_types_io! (
    pos2d32, pos2d32_io, {
        |mem_ptr| {
            let x = f32_io::read(mem_ptr);
            let y = f32_io::read(mem_ptr + f32_io::size());
            pos2d32 {x: x, y: y}
        }
    }, {
        |val: pos2d32, mem_ptr| {
            f32_io::write(val.x, mem_ptr);
            f32_io::write(val.y, mem_ptr + f32_io::size());
        }
    }, {
        f32_io::size() * 2
    };

    pos2d64, pos2d64_io, {
        |mem_ptr| {
            let x = f64_io::read(mem_ptr);
            let y = f64_io::read(mem_ptr + f64_io::size());
            pos2d64 {x: x, y: y}
        }
    }, {
        |val: pos2d64, mem_ptr| {
            f64_io::write(val.x, mem_ptr);
            f64_io::write(val.y, mem_ptr + f64_io::size());
        }
    }, {
        f64_io::size() * 2
    };

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

    pos3d32, pos3d32_io, {
        |mem_ptr| {
            let x = f32_io::read(mem_ptr);
            let y = f32_io::read(mem_ptr + f32_io::size());
            let z = f32_io::read(mem_ptr + f32_io::size() * 2);
            pos3d32 {x: x, y: y, z: z}
        }
    }, {
        |val: pos3d32, mem_ptr| {
            f32_io::write(val.x, mem_ptr);
            f32_io::write(val.y, mem_ptr + f32_io::size());
            f32_io::write(val.z, mem_ptr + f32_io::size() * 2);
        }
    }, {
        f32_io::size() * 3
    };

    pos3d64, pos3d64_io, {
        |mem_ptr| {
            let x = f64_io::read(mem_ptr);
            let y = f64_io::read(mem_ptr + f64_io::size());
            let z = f64_io::read(mem_ptr + f64_io::size() * 2);
            pos3d64 {x: x, y: y, z: z}
        }
    }, {
        |val: pos3d64, mem_ptr| {
            f64_io::write(val.x, mem_ptr);
            f64_io::write(val.y, mem_ptr + f64_io::size());
            f64_io::write(val.z, mem_ptr + f64_io::size() * 2);
        }
    }, {
        f64_io::size() * 3
    };

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

    uuid_, uuid_io, {
        |mem_ptr| {
            use uuid::{UuidBytes, Uuid};
            use std::ptr;
            unsafe {
                Uuid::from_bytes(
                    ptr::read(mem_ptr as *mut &UuidBytes) as &[u8]
                ).unwrap()
            }
        }
    }, {
        use uuid::{UuidBytes, Uuid};
        |val: uuid_, mem_ptr| {
            use std::ptr;
            unsafe {
                ptr::write(mem_ptr as *mut &UuidBytes, val.as_bytes());
            }
        }
    }, {
        16
    }
);

define_types!(
    ["bool", "bit"], 0, bool                            ,  bool_io       ;
    ["char"], 1, char                                   ,  char_io       ;
    ["i8"], 2, i8                                       ,  i8_io         ;
    ["i16", "int"], 3, i16                              ,  i16_io        ;
    ["i32", "long"], 4, i32                             ,  i32_io        ;
    ["i64", "longlong"], 5, i64                         ,  i64_io        ;
    ["u8", "byte"], 6, u8                               ,  u8_io         ;
    ["u16"], 7, u16                                     ,  u16_io        ;
    ["u32"], 8, u32                                     ,  u32_io        ;
    ["u64"], 9, u64                                     ,  u64_io        ;
    ["isize"], 10, isize                                ,  isize_io      ;
    ["usize"], 11, usize                                ,  usize_io      ;
    ["f32", "float"], 12, f32                           ,  f32_io        ;
    ["f64", "double"], 13, f64                          ,  f64_io        ;
    ["pos2d32", "pos2d", "pos", "pos32"], 14, pos2d32   ,  pos2d32_io    ;
    ["pos2d64", "pos64"], 15, pos2d64                   ,  pos2d64_io    ;
    ["pos3d32", "pos3d"], 16, pos3d32                   ,  pos3d32_io    ;
    ["pos3d64"], 17, pos3d64                            ,  pos3d64_io    ;
    ["uuid"], 18, uuid_                                 ,  uuid_io
);<|endoftext|>


<commit_before>//! The datum module provides a data structure, Datum, that implements the Unify trait.
//! Datum aims to be a drop-in for any algorithm in ai_kit that operates on the Unify trait.

#[cfg(feature = "with-constraint")]
use constraints::ConstraintValue;
use core;
use std;
use std::collections::HashMap;
use std::str;
use utils;

#[derive(Clone, Debug, Serialize, Deserialize, PartialOrd)]
pub enum Datum {
    #[serde(rename="null")]
    Nil,
    #[serde(rename="str")]
    String(String),
    #[serde(rename="int")]
    Int(i64),
    #[serde(rename="float")]
    Float(f64),
    #[serde(rename="var")]
    Variable(String),
    #[serde(rename="vec")]
    Vector(Vec<Datum>),
    #[serde(rename="fn")]
    Function { head: Box<Datum>, args: Vec<Datum> },
}

impl Datum {
    pub fn to_string(&self) -> Option<String> {
        match *self {
            Datum::String(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn to_int(&self) -> Option<i64> {
        match *self {
            Datum::Int(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn to_float(&self) -> Option<f64> {
        match *self {
            Datum::Float(ref f_value) => Some(f_value.clone()),
            Datum::Int(ref i_value) => Some((i_value.clone() as f64)),
            _ => None,
        }
    }

    pub fn to_variable(&self) -> Option<String> {
        match *self {
            Datum::Variable(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn pprint(&self) -> String {
        match *self {
            Datum::String(ref s) => format!("'{}'", s),
            Datum::Int(ref i) => format!("{}", i),
            Datum::Float(ref f) => format!("{}", f),
            Datum::Variable(ref v) => format!("{}", v),
            Datum::Vector(ref args) => {
                let elements: Vec<String> = args.iter().map(|e| e.pprint()).collect();
                format!("({})", elements.join(","))
            }
            Datum::Nil => format!("nil"),
            Datum::Function { ref head, ref args } => {
                let elements: Vec<String> = args.iter().map(|e| e.pprint()).collect();
                format!("({} ({}))", head, elements.join(","))
            }
        }
    }
}

impl Default for Datum {
    fn default() -> Self {
        Datum::Nil
    }
}

impl PartialEq for Datum {
    fn eq(&self, other: &Datum) -> bool {
        match *self {
            Datum::String(ref s) => {
                match *other {
                    Datum::String(ref s2) => s == s2,
                    _ => false,
                }
            }
            Datum::Int(ref i) => {
                match *other {
                    Datum::Int(ref i2) => i == i2,
                    _ => false,
                }
            }
            Datum::Float(ref f) => {
                match *other {
                    Datum::Float(ref f2) => f == f2,
                    _ => false,
                }
            }
            Datum::Variable(ref v) => {
                match *other {
                    Datum::Variable(ref v2) => v == v2,
                    _ => false,
                }
            }
            Datum::Vector(ref args) => {
                match *other {
                    Datum::Vector(ref args2) => args == args2,
                    _ => false,
                }
            }
            Datum::Nil => {
                match *other {
                    Datum::Nil => true,
                    _ => false,
                }
            }
            Datum::Function { ref head, ref args } => {
                match *other {
                    Datum::Function { head: ref head2, args: ref args2 } if args.len() == args2.len() => head == head2 && args == args2,
                    _ => false,
                }
            }
        }
    }
}

impl Eq for Datum {}
impl Ord for Datum {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl core::BindingsValue for Datum {
    fn variable(s: &String) -> Option<Self> {
        Some(Datum::Variable(s.clone()))
    }
    fn to_variable(&self) -> Option<String> {
        self.to_variable()
    }
}

#[cfg(feature = "with-constraint")]
impl ConstraintValue for Datum {
    fn to_float(&self) -> Option<f64> {
        self.to_float()
    }
    fn float(c: f64) -> Self {
        Datum::Float(c)
    }
}

impl core::Unify<Datum> for Datum {
    fn unify(&self, other: &Datum, bindings: &core::Bindings<Self>) -> Option<core::Bindings<Self>> {

        fn unify_args(args: &Vec<Datum>, args2: &Vec<Datum>, bindings: &core::Bindings<Datum>) -> Option<core::Bindings<Datum>> {
            utils::fold_while_some(bindings.clone(),
                                   &mut args.iter().zip(args2.iter()),
                                   &|bindings: core::Bindings<Datum>, (ref a, ref b): (&Datum, &Datum)| a.unify(&b, &bindings))
        }
        match *self {
            Datum::Variable(ref var_name) => bindings.update_bindings(var_name, other),
            Datum::Vector(ref args) => {
                match *other {
                    Datum::Vector(ref args2) if args.len() == args2.len() => unify_args(args, args2, &bindings),
                    _ => None,
                }
            }
            _ => {
                match *other {
                    Datum::Variable(ref var_name) => bindings.update_bindings(var_name, self),
                    _ => {
                        if self == other {
                            Some(bindings.clone())
                        } else {
                            None
                        }
                    }
                }
            }
        }
    }

    fn apply_bindings(&self, bindings: &core::Bindings<Self>) -> Option<Self> {
        fn apply_bindings_to_args(args: &Vec<Datum>, bindings: &core::Bindings<Datum>) -> Option<Vec<Datum>> {
            utils::map_while_some(&mut args.iter(), &|arg| arg.apply_bindings(bindings))
        }
        match *self {
            Datum::Variable(ref var_name) => bindings.get_binding(var_name).or_else(|| Some(self.clone())),
            Datum::Vector(ref args) => apply_bindings_to_args(args, bindings).and_then(|args| Some(Datum::Vector(args))),
            _ => Some(self.clone()),
        }
    }

    fn variables(&self) -> Vec<String> {
        match *self {
            Datum::Variable(ref v) => vec![v.clone()],
            Datum::Vector(ref args) => {
                let mut variables = Vec::new();
                for arg in args.iter() {
                    variables.extend(arg.variables().into_iter());
                }
                variables
            }
            _ => Vec::new(),
        }
    }

    fn rename_variables(&self, renamed_variables: &HashMap<String, String>) -> Self {
        match *self {
            Datum::Variable(ref v) => {
                renamed_variables.get(v)
                    .and_then(|new_v| Some(Datum::Variable(new_v.clone())))
                    .or_else(|| Some(self.clone()))
                    .unwrap()
            }
            Datum::Vector(ref args) => Datum::Vector(args.iter().map(|arg| arg.rename_variables(renamed_variables)).collect()),
            _ => self.clone(),
        }
    }

    fn nil() -> Self {
        Datum::Nil
    }
}

impl std::fmt::Display for Datum {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.pprint())
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Tweaked display of `Datum::String`<commit_after>//! The datum module provides a data structure, Datum, that implements the Unify trait.
//! Datum aims to be a drop-in for any algorithm in ai_kit that operates on the Unify trait.

#[cfg(feature = "with-constraint")]
use constraints::ConstraintValue;
use core;
use std;
use std::collections::HashMap;
use std::str;
use utils;

#[derive(Clone, Debug, Serialize, Deserialize, PartialOrd)]
pub enum Datum {
    #[serde(rename="null")]
    Nil,
    #[serde(rename="str")]
    String(String),
    #[serde(rename="int")]
    Int(i64),
    #[serde(rename="float")]
    Float(f64),
    #[serde(rename="var")]
    Variable(String),
    #[serde(rename="vec")]
    Vector(Vec<Datum>),
    #[serde(rename="fn")]
    Function { head: Box<Datum>, args: Vec<Datum> },
}

impl Datum {
    pub fn to_string(&self) -> Option<String> {
        match *self {
            Datum::String(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn to_int(&self) -> Option<i64> {
        match *self {
            Datum::Int(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn to_float(&self) -> Option<f64> {
        match *self {
            Datum::Float(ref f_value) => Some(f_value.clone()),
            Datum::Int(ref i_value) => Some((i_value.clone() as f64)),
            _ => None,
        }
    }

    pub fn to_variable(&self) -> Option<String> {
        match *self {
            Datum::Variable(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn pprint(&self) -> String {
        match *self {
            Datum::String(ref s) => format!("{}", s),
            Datum::Int(ref i) => format!("{}", i),
            Datum::Float(ref f) => format!("{}", f),
            Datum::Variable(ref v) => format!("{}", v),
            Datum::Vector(ref args) => {
                let elements: Vec<String> = args.iter().map(|e| e.pprint()).collect();
                format!("({})", elements.join(","))
            }
            Datum::Nil => format!("nil"),
            Datum::Function { ref head, ref args } => {
                let elements: Vec<String> = args.iter().map(|e| e.pprint()).collect();
                format!("({} ({}))", head, elements.join(","))
            }
        }
    }
}

impl Default for Datum {
    fn default() -> Self {
        Datum::Nil
    }
}

impl PartialEq for Datum {
    fn eq(&self, other: &Datum) -> bool {
        match *self {
            Datum::String(ref s) => {
                match *other {
                    Datum::String(ref s2) => s == s2,
                    _ => false,
                }
            }
            Datum::Int(ref i) => {
                match *other {
                    Datum::Int(ref i2) => i == i2,
                    _ => false,
                }
            }
            Datum::Float(ref f) => {
                match *other {
                    Datum::Float(ref f2) => f == f2,
                    _ => false,
                }
            }
            Datum::Variable(ref v) => {
                match *other {
                    Datum::Variable(ref v2) => v == v2,
                    _ => false,
                }
            }
            Datum::Vector(ref args) => {
                match *other {
                    Datum::Vector(ref args2) => args == args2,
                    _ => false,
                }
            }
            Datum::Nil => {
                match *other {
                    Datum::Nil => true,
                    _ => false,
                }
            }
            Datum::Function { ref head, ref args } => {
                match *other {
                    Datum::Function { head: ref head2, args: ref args2 } if args.len() == args2.len() => head == head2 && args == args2,
                    _ => false,
                }
            }
        }
    }
}

impl Eq for Datum {}
impl Ord for Datum {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl core::BindingsValue for Datum {
    fn variable(s: &String) -> Option<Self> {
        Some(Datum::Variable(s.clone()))
    }
    fn to_variable(&self) -> Option<String> {
        self.to_variable()
    }
}

#[cfg(feature = "with-constraint")]
impl ConstraintValue for Datum {
    fn to_float(&self) -> Option<f64> {
        self.to_float()
    }
    fn float(c: f64) -> Self {
        Datum::Float(c)
    }
}

impl core::Unify<Datum> for Datum {
    fn unify(&self, other: &Datum, bindings: &core::Bindings<Self>) -> Option<core::Bindings<Self>> {

        fn unify_args(args: &Vec<Datum>, args2: &Vec<Datum>, bindings: &core::Bindings<Datum>) -> Option<core::Bindings<Datum>> {
            utils::fold_while_some(bindings.clone(),
                                   &mut args.iter().zip(args2.iter()),
                                   &|bindings: core::Bindings<Datum>, (ref a, ref b): (&Datum, &Datum)| a.unify(&b, &bindings))
        }
        match *self {
            Datum::Variable(ref var_name) => bindings.update_bindings(var_name, other),
            Datum::Vector(ref args) => {
                match *other {
                    Datum::Vector(ref args2) if args.len() == args2.len() => unify_args(args, args2, &bindings),
                    _ => None,
                }
            }
            _ => {
                match *other {
                    Datum::Variable(ref var_name) => bindings.update_bindings(var_name, self),
                    _ => {
                        if self == other {
                            Some(bindings.clone())
                        } else {
                            None
                        }
                    }
                }
            }
        }
    }

    fn apply_bindings(&self, bindings: &core::Bindings<Self>) -> Option<Self> {
        fn apply_bindings_to_args(args: &Vec<Datum>, bindings: &core::Bindings<Datum>) -> Option<Vec<Datum>> {
            utils::map_while_some(&mut args.iter(), &|arg| arg.apply_bindings(bindings))
        }
        match *self {
            Datum::Variable(ref var_name) => bindings.get_binding(var_name).or_else(|| Some(self.clone())),
            Datum::Vector(ref args) => apply_bindings_to_args(args, bindings).and_then(|args| Some(Datum::Vector(args))),
            _ => Some(self.clone()),
        }
    }

    fn variables(&self) -> Vec<String> {
        match *self {
            Datum::Variable(ref v) => vec![v.clone()],
            Datum::Vector(ref args) => {
                let mut variables = Vec::new();
                for arg in args.iter() {
                    variables.extend(arg.variables().into_iter());
                }
                variables
            }
            _ => Vec::new(),
        }
    }

    fn rename_variables(&self, renamed_variables: &HashMap<String, String>) -> Self {
        match *self {
            Datum::Variable(ref v) => {
                renamed_variables.get(v)
                    .and_then(|new_v| Some(Datum::Variable(new_v.clone())))
                    .or_else(|| Some(self.clone()))
                    .unwrap()
            }
            Datum::Vector(ref args) => Datum::Vector(args.iter().map(|arg| arg.rename_variables(renamed_variables)).collect()),
            _ => self.clone(),
        }
    }

    fn nil() -> Self {
        Datum::Nil
    }
}

impl std::fmt::Display for Datum {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.pprint())
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use types::{Color, Viewport, BufferBits, GLError};
use buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use program::{ProgramBinder, ProgramAttrib};
use texture::{Texture2dBinder, TextureCubeMapBinder};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder,
    pub texture_2d: Texture2dBinder,
    pub texture_cube_map: TextureCubeMapBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder,
            texture_2d: Texture2dBinder,
            texture_cube_map: TextureCubeMapBinder
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
            dbg_gl_error! {
                GLError::InvalidValue => "`index` is >= GL_MAX_VERTEX_ATTRIBS",
                _ => "Unknown error"
            }
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`width` or `height` is negative",
                _ => "Unknown error"
            }
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}
<commit_msg>Replace texture binder fields in `Context` with a `TextureUnits` field<commit_after>use gl;
use gl::types::*;
use types::{Color, Viewport, BufferBits, GLError};
use buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use program::{ProgramBinder, ProgramAttrib};
use texture_units::{TextureUnits};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder,
    pub tex_units: TextureUnits
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder,
            tex_units: TextureUnits::current()
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
            dbg_gl_error! {
                GLError::InvalidValue => "`index` is >= GL_MAX_VERTEX_ATTRIBS",
                _ => "Unknown error"
            }
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`width` or `height` is negative",
                _ => "Unknown error"
            }
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}
<|endoftext|>


<commit_before>use crate::error::ContextError;
use crate::{Context, Error, StdError};
use core::convert::Infallible;
use core::fmt::{self, Debug, Display, Write};

#[cfg(backtrace)]
use std::any::Demand;

mod ext {
    use super::*;

    pub trait StdError {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static;
    }

    #[cfg(feature = "std")]
    impl<E> StdError for E
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static,
        {
            let backtrace = backtrace_if_absent!(&self);
            Error::from_context(context, self, backtrace)
        }
    }

    impl StdError for Error {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static,
        {
            self.context(context)
        }
    }
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: ext::StdError + Send + Sync + 'static,
{
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        // Not using map_err to save 2 useless frames off the captured backtrace
        // in ext_context.
        match self {
            Ok(ok) => Ok(ok),
            Err(error) => Err(error.ext_context(context)),
        }
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        match self {
            Ok(ok) => Ok(ok),
            Err(error) => Err(error.ext_context(context())),
        }
    }
}

/// ```
/// # type T = ();
/// #
/// use anyhow::{Context, Result};
///
/// fn maybe_get() -> Option<T> {
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
///
/// fn demo() -> Result<()> {
///     let t = maybe_get().context("there is no T")?;
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
/// ```
impl<T> Context<T, Infallible> for Option<T> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        // Not using ok_or_else to save 2 useless frames off the captured
        // backtrace.
        match self {
            Some(ok) => Ok(ok),
            None => Err(Error::from_display(context, backtrace!())),
        }
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        match self {
            Some(ok) => Ok(ok),
            None => Err(Error::from_display(context(), backtrace!())),
        }
    }
}

impl<C, E> Debug for ContextError<C, E>
where
    C: Display,
    E: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Error")
            .field("context", &Quoted(&self.context))
            .field("source", &self.error)
            .finish()
    }
}

impl<C, E> Display for ContextError<C, E>
where
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.context, f)
    }
}

impl<C, E> StdError for ContextError<C, E>
where
    C: Display,
    E: StdError + 'static,
{
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&self.error)
    }

    #[cfg(backtrace)]
    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
        self.error.provide(demand);
    }
}

impl<C> StdError for ContextError<C, Error>
where
    C: Display,
{
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) })
    }

    #[cfg(backtrace)]
    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
        demand.provide_ref(self.error.backtrace());
        self.error.provide(demand);
    }
}

struct Quoted<C>(C);

impl<C> Debug for Quoted<C>
where
    C: Display,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_char('"')?;
        Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?;
        formatter.write_char('"')?;
        Ok(())
    }
}

impl Write for Quoted<&mut fmt::Formatter<'_>> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        Display::fmt(&s.escape_debug(), self.0)
    }
}

pub(crate) mod private {
    use super::*;

    pub trait Sealed {}

    impl<T, E> Sealed for Result<T, E> where E: ext::StdError {}
    impl<T> Sealed for Option<T> {}
}
<commit_msg>Remove redundant Backtrace provide_ref from ContextError<commit_after>use crate::error::ContextError;
use crate::{Context, Error, StdError};
use core::convert::Infallible;
use core::fmt::{self, Debug, Display, Write};

#[cfg(backtrace)]
use std::any::Demand;

mod ext {
    use super::*;

    pub trait StdError {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static;
    }

    #[cfg(feature = "std")]
    impl<E> StdError for E
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static,
        {
            let backtrace = backtrace_if_absent!(&self);
            Error::from_context(context, self, backtrace)
        }
    }

    impl StdError for Error {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static,
        {
            self.context(context)
        }
    }
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: ext::StdError + Send + Sync + 'static,
{
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        // Not using map_err to save 2 useless frames off the captured backtrace
        // in ext_context.
        match self {
            Ok(ok) => Ok(ok),
            Err(error) => Err(error.ext_context(context)),
        }
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        match self {
            Ok(ok) => Ok(ok),
            Err(error) => Err(error.ext_context(context())),
        }
    }
}

/// ```
/// # type T = ();
/// #
/// use anyhow::{Context, Result};
///
/// fn maybe_get() -> Option<T> {
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
///
/// fn demo() -> Result<()> {
///     let t = maybe_get().context("there is no T")?;
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
/// ```
impl<T> Context<T, Infallible> for Option<T> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        // Not using ok_or_else to save 2 useless frames off the captured
        // backtrace.
        match self {
            Some(ok) => Ok(ok),
            None => Err(Error::from_display(context, backtrace!())),
        }
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        match self {
            Some(ok) => Ok(ok),
            None => Err(Error::from_display(context(), backtrace!())),
        }
    }
}

impl<C, E> Debug for ContextError<C, E>
where
    C: Display,
    E: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Error")
            .field("context", &Quoted(&self.context))
            .field("source", &self.error)
            .finish()
    }
}

impl<C, E> Display for ContextError<C, E>
where
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.context, f)
    }
}

impl<C, E> StdError for ContextError<C, E>
where
    C: Display,
    E: StdError + 'static,
{
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&self.error)
    }

    #[cfg(backtrace)]
    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
        self.error.provide(demand);
    }
}

impl<C> StdError for ContextError<C, Error>
where
    C: Display,
{
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) })
    }

    #[cfg(backtrace)]
    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
        self.error.provide(demand);
    }
}

struct Quoted<C>(C);

impl<C> Debug for Quoted<C>
where
    C: Display,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_char('"')?;
        Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?;
        formatter.write_char('"')?;
        Ok(())
    }
}

impl Write for Quoted<&mut fmt::Formatter<'_>> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        Display::fmt(&s.escape_debug(), self.0)
    }
}

pub(crate) mod private {
    use super::*;

    pub trait Sealed {}

    impl<T, E> Sealed for Result<T, E> where E: ext::StdError {}
    impl<T> Sealed for Option<T> {}
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Rectangles — Simple graphical data type

use std::mem;
use glib::translate::*;
use cairo::RectangleInt;
use ffi;

pub trait RectangleExt {
    fn intersect(&self, other: &Self) -> Option<Self>;
    fn union(&self, other: &Self) -> Self;
}

impl RectangleExt for RectangleInt {
    fn intersect(&self, other: &RectangleInt) -> Option<RectangleInt> {
        unsafe {
            let mut res = mem::uninitialized();
            if from_glib(ffi::gdk_rectangle_intersect(self, other, &mut res)) {
                Some(res)
            }
            else {
                None
            }
        }
    }

    fn union(&self, other: &RectangleInt) -> RectangleInt {
        unsafe {
            let mut res = mem::uninitialized();
            ffi::gdk_rectangle_union(self, other, &mut res);
            res
        }
    }
}
<commit_msg>Remove compilation warning<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Rectangles — Simple graphical data type

use std::mem;
use glib::translate::*;
use cairo::RectangleInt;
use ffi;

pub trait RectangleExt {
    fn intersect(&self, other: &Self) -> Option<Self>
        where Self: Sized;
    fn union(&self, other: &Self) -> Self;
}

impl RectangleExt for RectangleInt {
    fn intersect(&self, other: &RectangleInt) -> Option<RectangleInt> {
        unsafe {
            let mut res = mem::uninitialized();
            if from_glib(ffi::gdk_rectangle_intersect(self, other, &mut res)) {
                Some(res)
            }
            else {
                None
            }
        }
    }

    fn union(&self, other: &RectangleInt) -> RectangleInt {
        unsafe {
            let mut res = mem::uninitialized();
            ffi::gdk_rectangle_union(self, other, &mut res);
            res
        }
    }
}
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Closure::*;
use self::Expression::*;
use std::collections::VecDeque;

#[derive(Debug, PartialEq, Clone)]
enum Closure {
    Depth(usize),
    TermInEnv(Term, Environment)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Evaluation(Closure),
    Application(Box<Expression>, Term, Environment)
}

type Environment = VecDeque<Closure>;

fn whnf(term: Term, mut env: Environment) -> Expression {
    match term {
        Var(i) => match env.remove(i - 1) {
            Some(Depth(i)) => Evaluation(Depth(i)),
            Some(TermInEnv(t, e)) => whnf(t, e),
            None => unreachable!()
        },
        Abs(t) => Evaluation(TermInEnv(Abs(t), env)),
        App(lhs, rhs) => match whnf(*lhs, env.clone()) { // TODO: try to remove this clone()
            Evaluation(TermInEnv(Abs(lhs2), mut env2)) => {
                env2.push_front(TermInEnv(*rhs, env));
                whnf(*lhs2, env2)
            },
            expr => Application(Box::new(expr), *rhs, env)
        }
    }
}

fn reduce(depth: usize, exp: Expression) -> Term {
    match exp {
        Application(lhs, rhs, env) => app(reduce(depth, *lhs), nf(depth, rhs, env)),
        Evaluation(TermInEnv(Abs(term), mut env)) => {
            env.push_front(Depth(depth));
            abs(nf(depth + 1, *term, env))
        },
        Evaluation(TermInEnv(term, _)) => term,
        Evaluation(Depth(i)) => Var(depth - i)
    }
}

fn nf(depth: usize, term: Term, env: Environment) -> Term {
    reduce(depth, whnf(term, env))
}

/// Returns a term reduced to its normal form. Consumes its argument.
///
/// # Example
///
/// ```
/// use lambda_calculus::booleans::{if_else, tru};
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// assert_eq!(normalize(if_else().app(tru()).app(one()).app(zero())), one());
/// ```
pub fn normalize(term: Term) -> Term {
    nf(0, term, VecDeque::new())
}

/// Applies two terms with substitution and variable update, consuming them in the process.
///
/// # Example
/// ```
/// use lambda_calculus::term::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs; // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs.clone(), depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming them
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(abs(abs(Var(1)))));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, rhs)
    }

    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(&*format!("{}", succ_one), "λλ2((λλ21)21)");
    /// ```
    pub fn beta_once(&mut self) {
        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap().beta_once(),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    let reduced = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("    {} reduces to {}", self, reduced) };
                    *self = reduced;
                } else {
                    self.lhs_ref_mut().unwrap().beta_once();
                    self.rhs_ref_mut().unwrap().beta_once()
                }
            }
        }
    }

    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            let tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full normal-order β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single normal-order β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(&*format!("{}", beta_once(succ_one)), "λλ2((λλ21)21)");
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

#[cfg(test)]
mod test {

    #[test]
    fn weak_head_normal_form() {
        // TODO
    }
}
<commit_msg>deprecate normalize()<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

#![allow(dead_code)]

use term::*;
use term::Term::*;
use self::Closure::*;
use self::Expression::*;
use std::collections::VecDeque;

#[derive(Debug, PartialEq, Clone)]
enum Closure {
    Depth(usize),
    TermInEnv(Term, Environment)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Evaluation(Closure),
    Application(Box<Expression>, Term, Environment)
}

type Environment = VecDeque<Closure>;

fn whnf(term: Term, mut env: Environment) -> Expression {
    match term {
        Var(i) => match env.remove(i - 1) {
            Some(Depth(i)) => Evaluation(Depth(i)),
            Some(TermInEnv(t, e)) => whnf(t, e),
            None => unreachable!()
        },
        Abs(t) => Evaluation(TermInEnv(Abs(t), env)),
        App(lhs, rhs) => match whnf(*lhs, env.clone()) { // TODO: try to remove this clone()
            Evaluation(TermInEnv(Abs(lhs2), mut env2)) => {
                env2.push_front(TermInEnv(*rhs, env));
                whnf(*lhs2, env2)
            },
            expr => Application(Box::new(expr), *rhs, env)
        }
    }
}

fn reduce(depth: usize, exp: Expression) -> Term {
    match exp {
        Application(lhs, rhs, env) => app(reduce(depth, *lhs), nf(depth, rhs, env)),
        Evaluation(TermInEnv(Abs(term), mut env)) => {
            env.push_front(Depth(depth));
            abs(nf(depth + 1, *term, env))
        },
        Evaluation(TermInEnv(term, _)) => term,
        Evaluation(Depth(i)) => Var(depth - i)
    }
}

fn nf(depth: usize, term: Term, env: Environment) -> Term {
    reduce(depth, whnf(term, env))
}

/// Returns a term reduced to its normal form. Consumes its argument.
///
/// # Example
///
/// ```
/// use lambda_calculus::booleans::{if_else, tru};
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// assert_eq!(normalize(if_else().app(tru()).app(one()).app(zero())), one());
/// ```
fn normalize(term: Term) -> Term {
    nf(0, term, VecDeque::new())
}

/// Applies two terms with substitution and variable update, consuming them in the process.
///
/// # Example
/// ```
/// use lambda_calculus::term::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs; // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs.clone(), depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming them
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(abs(abs(Var(1)))));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, rhs)
    }

    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(&*format!("{}", succ_one), "λλ2((λλ21)21)");
    /// ```
    pub fn beta_once(&mut self) {
        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap().beta_once(),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    let reduced = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("    {} reduces to {}", self, reduced) };
                    *self = reduced;
                } else {
                    self.lhs_ref_mut().unwrap().beta_once();
                    self.rhs_ref_mut().unwrap().beta_once()
                }
            }
        }
    }

    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            let tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full normal-order β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single normal-order β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(&*format!("{}", beta_once(succ_one)), "λλ2((λλ21)21)");
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

#[cfg(test)]
mod test {

    #[test]
    fn weak_head_normal_form() {
        // TODO
    }
}
<|endoftext|>


<commit_before>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut has_first_segment : bool;
    let mut segment_num : usize;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    has_first_segment = false;
    segment_num = 0;
    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                if has_first_segment {
                    segment_num += 1;
                } else {
                    has_first_segment = true;
                }

                cur_x = x;
                cur_y = y;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                let seg = Segment::Degenerate {
                    x: cur_x,
                    y: cur_y
                };

                segments.push (seg);

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                let needs_new_segment : bool;
                let seg : Segment;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        segment_num += 1;
                        needs_new_segment = true;
                    }
                }

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                if needs_new_segment {
                    segments.push (seg);
                } else {
                    segments[segment_num] = seg;
                }
            },

            cairo::PathSegment::CurveTo ((mut x2, mut y2), (mut x3, mut y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                let x1 = last_x;
                let y1 = last_y;

                let needs_new_segment : bool;
                let seg : Segment;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        segment_num += 1;
                        needs_new_segment = true;
                    }
                }

                /* Fix the tangents for when the middle control points coincide with their respective endpoints */

                if double_equals (x2, x1) && double_equals (y2, y1) {
                    x2 = x3;
                    y2 = y3;
                }

                if double_equals (x3, x4) && double_equals (y3, y4) {
                    x3 = x2;
                    y3 = y2;
                }

                seg = Segment::LineOrCurve {
                    x1: x1,
                    y1: y1,

                    x2: x2,
                    y2: y2,

                    x3: x3,
                    y3: y3,

                    x4: x4,
                    y4: y4,
                };

                if needs_new_segment {
                    segments.push (seg);
                } else {
                    segments[segment_num] = seg;
                }
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                let needs_new_segment : bool;
                let seg: Segment;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                if needs_new_segment {
                    segments.push (seg);
                } else {
                    segments[segment_num] = seg;
                }
            }
        }
    }

    segments
}

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

    fn setup_open_path () -> cairo::Path {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            Segment::LineOrCurve { x1: 10.0, y1: 10.0, x2: 20.0, y2: 10.0, x3: 10.0, y3: 10.0, x4: 20.0, y4: 10.0 },
            Segment::LineOrCurve { x1: 20.0, y1: 10.0, x2: 20.0, y2: 20.0, x3: 20.0, y3: 10.0, x4: 20.0, y4: 20.0 }
        ];

        let path = setup_open_path ();
        let segments = path_to_segments (path);

        assert_eq! (expected_segments, segments);
    }
}
<commit_msg>marker.rs: Factor out replacement/creation of segments<commit_after>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                seg = Segment::Degenerate {
                    x: cur_x,
                    y: cur_y
                };
                needs_new_segment = true;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };
            },

            cairo::PathSegment::CurveTo ((mut x2, mut y2), (mut x3, mut y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                let x1 = last_x;
                let y1 = last_y;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }

                /* Fix the tangents for when the middle control points coincide with their respective endpoints */

                if double_equals (x2, x1) && double_equals (y2, y1) {
                    x2 = x3;
                    y2 = y3;
                }

                if double_equals (x3, x4) && double_equals (y3, y4) {
                    x3 = x2;
                    y3 = y2;
                }

                seg = Segment::LineOrCurve {
                    x1: x1,
                    y1: y1,

                    x2: x2,
                    y2: y2,

                    x3: x3,
                    y3: y3,

                    x4: x4,
                    y4: y4,
                };
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

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

    fn setup_open_path () -> cairo::Path {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            Segment::LineOrCurve { x1: 10.0, y1: 10.0, x2: 20.0, y2: 10.0, x3: 10.0, y3: 10.0, x4: 20.0, y4: 10.0 },
            Segment::LineOrCurve { x1: 20.0, y1: 10.0, x2: 20.0, y2: 20.0, x3: 20.0, y3: 10.0, x4: 20.0, y4: 20.0 }
        ];

        let path = setup_open_path ();
        let segments = path_to_segments (path);

        assert_eq! (expected_segments, segments);
    }
}
<|endoftext|>