<commit_before>/// Gets the offset of a field. Used by container_of!
macro_rules! offset_of(
    ($ty:ty, $field:ident) => {
        &(*(0 as *const $ty)).$field as *const _ as usize
    }
);

/// Gets the parent struct from a pointer.
/// VERY unsafe. The parent struct _must_ be repr(C), and the
/// type passed to this macro _must_ match the type of the parent.
macro_rules! container_of (
    ($ptr: expr, $container: ty, $field: ident) => {
        ($ptr as *mut u8).offset(-(offset_of!($container, $field) as isize)) as *mut $container
    }
);

/// Iterates over a wl_list.
///
/// # Safety
/// It is not safe to delete an element while iterating over the list,
/// so don't do it!
macro_rules! wl_list_for_each {
    ($ptr: expr, $field: ident, ($pos: ident : $container: ty) => $body: block) => {
        let mut $pos: *mut $container;
        $pos = container_of!($ptr.next, $container, $field);
        loop {
            if &(*$pos).$field as *const _ == &$ptr as *const _ {
                break
            }
            { $body }
            $pos = container_of!((*$pos).$field.next, $container, $field);
        }
    }
}

/// Logs a message using wlroots' logging capability.
///
/// Example:
/// ```rust,no_run,ignore
/// #[macro_use]
/// use wlroots::log::{init_logging, L_DEBUG, L_ERROR};
///
/// // Call this once, at the beginning of your program.
/// init_logging(WLR_DEBUG, None);
///
/// wlr_log!(L_DEBUG, "Hello world");
/// wlr_log!(L_ERROR, "Could not {:#?} the {}", foo, bar);
/// ```
#[macro_export]
macro_rules! wlr_log {
    ($verb: expr, $($msg:tt)*) => {{
        /// Convert a literal string to a C string.
        /// Note: Does not check for internal nulls, nor does it do any conversions on
        /// the grapheme clustors. Just passes the bytes as is.
        /// So probably only works on ASCII.
        macro_rules! c_str {
            ($s:expr) => {
                concat!($s, "\0").as_ptr()
                    as *const $crate::wlroots_sys::libc::c_char
            }
        }
        use $crate::wlroots_sys::_wlr_log;
        use $crate::wlroots_sys::wlr_log_importance::*;
        use ::std::ffi::CString;
        unsafe {
            let fmt = CString::new(format!($($msg)*))
                .expect("Could not convert log message to C string");
            let raw = fmt.into_raw();
            _wlr_log($verb, c_str!("[%s:%lu] %s"),
                    c_str!(file!()), line!(), raw);
            // Deallocate string
            CString::from_raw(raw);
        }
    }}
}

/// Defines a new struct that contains a variable number of listeners that
/// will trigger unsafe user-defined callbacks.
///
/// The structure that is defined is repr(C), has one `data` field with the
/// given user type, and a field for each `$listener`.
///
/// Each `$listener` has a getter method that lets you get the pointer to the
/// listener. This method is unsafe, since it returns a raw pointer.
/// To use it correctly, you need to ensure that the data it refers to never
/// moves (e.g keep it in a box). The primary purpose of this method is to pass
/// the listener pointer to other methods to register it for a Wayland event.
/// **A listener can only be registered to one event at a time**.
///
/// Finally, it also takes in a body for each `$listener` that is called
/// every time the event that is later hooked up to it is fired.
/// This method is inherently unsafe, because the user data hasn't been cast
/// from the void pointer yet. It is the user's job to write this safely.
/// To highlight this fact, the body of the function must be prefixed with
/// `unsafe`.
///
/// # Example
/// ```rust,no_run,ignore
/// #[macro_use] extern crate wlroots;
/// extern crate wlroots_sys;
/// #[macro_use] extern crate wayland_sys;
/// extern crate libc;
///
/// use wlroots::InputDevice;
/// use wlroots_sys::wlr_input_device;
///
/// // Handles input addition and removal.
/// pub trait InputManagerHandler {
///     // Callback triggered when an input device is added.
///     fn input_added(&mut self, InputDevice);
/// }
///
/// wayland_listener!(
///     // The name of the structure that will be defined.
///     pub(crate) InputManager,
///     // The type that's stored in the `data` field.
///     // Note that we use a Box here to achieve dynamic dispatch,
///     // it's not required for this type to be in a box.
///     Box<InputManagerHandler>,
///     [
///         // Adds a new listener called `add_listener`.
///         // Adds an unsafe function called `add_notify` that is triggered
///         // whenever add_listener is activated from a Wayland event.
///         add_listener => add_notify: |this: &mut InputManager, data: *mut libc::c_void,| unsafe {
///             let ref mut manager = this.data;
///             // Call the method defined above, wrapping it in a safe interface.
///             // It is your job to ensure that the code in here doesn't trigger UB!
///             manager.input_added(InputDevice::from_ptr(data as *mut wlr_input_device))
///         };
///     ]
/// );
/// # fn main() {}
/// ```
///
/// # Unsafety
/// Note that the purpose of this macro is to make it easy to generate unsafe
/// boiler plate for using listeners with Rust data.
///
/// However, there are a few things this macro doesn't protect against.
///
/// First and foremost, the data cannot move. The listeners assume that the
/// structure will never move, so in order to defend against this the generated
/// `new` method returns a Box version. **Do not move out of the box**.
///
/// Second, this macro doesn't protect against the stored data being unsized.
/// Passing a pointer of unsized data to C is UB, don't do it.
macro_rules! wayland_listener {
    ($pub: vis $struct_name: ident, $data: ty, $([
        $($listener: ident => $listener_func: ident :
          |$($func_arg:ident: $func_type:ty,)*| unsafe $body: block;)*])+) => {
        #[repr(C)]
        #[doc(hidden)]
        $pub struct $struct_name {
            data: $data,
            $($($listener: $crate::wlroots_sys::wl_listener),*)*
        }

        impl $struct_name {
            pub(crate) fn new(data: $data) -> Box<$struct_name> {
                use $crate::wlroots_sys::server::WAYLAND_SERVER_HANDLE;
                Box::new($struct_name {
                    data,
                    $($($listener: unsafe {
                        // NOTE Rationale for zeroed memory:
                        // * Need to pass a pointer to wl_list_init
                        // * The list is initialized by Wayland, which doesn't "drop"
                        // * The listener is written to without dropping any of the data
                        let mut listener: $crate::wlroots_sys::wl_listener = ::std::mem::zeroed();
                        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                      wl_list_init,
                                      &mut listener.link as *mut _ as _);
                        ::std::ptr::write(&mut listener.notify, Some($struct_name::$listener_func));
                        listener
                    }),*)*
                })
            }

            $($(pub(crate) unsafe extern "C" fn $listener(&mut self)
                                                   -> *mut $crate::wlroots_sys::wl_listener {
                &mut self.$listener as *mut _
            })*)*

            $($(pub(crate) unsafe extern "C" fn $listener_func(listener:
                                                        *mut $crate::wlroots_sys::wl_listener,
                                                        data: *mut $crate::libc::c_void) {
                let manager: &mut $struct_name = &mut (*container_of!(listener,
                                                                      $struct_name,
                                                                      $listener));
                $crate::utils::handle_unwind(
                    ::std::panic::catch_unwind(
                        ::std::panic::AssertUnwindSafe(|| {
                            (|$($func_arg: $func_type,)*| { $body })(manager, data)
                        })));
            })*)*
        }
    }
}

macro_rules! wayland_listener_static {
    (static mut $static_manager: ident;
     $(($manager: ident, $builder: ident):
       $([
           $(
               $([$($extra_callback_name: ident: $extra_callback_type: ty),+])*
               ($fn_type: ty, $listener: ident, $builder_func: ident) => ($notify: ident, $callback: ident):
               |$($func_arg: ident: $func_type: ty,)*| unsafe $body: block;
           )*
       ])+
     )+
    ) => {
        $(
            #[derive(Default)]
            #[allow(dead_code)]
            pub struct $builder {
                $($($callback: ::std::option::Option<$fn_type>,)*
                  $($($($extra_callback_name: ::std::option::Option<$extra_callback_type>,)*)*)*)*
            }

            impl $builder {
                $($(
                    pub fn $builder_func(mut self, $callback: $fn_type) -> Self {
                        self.$callback = ::std::option::Option::Some($callback);
                        self
                    }
                    $($(
                        pub fn $extra_callback_name(mut self, $extra_callback_name: $extra_callback_type) -> Self {
                            self.$extra_callback_name = ::std::option::Option::Some($extra_callback_name);
                            self
                        }
                    )*)*
                )*)*
            }
        )*

        $(
            #[repr(C)]
            pub(crate) struct $manager {
                $($(
                    pub(crate) $listener: $crate::wlroots_sys::wl_listener,
                    $callback: ::std::option::Option<$fn_type>,
                    $($($extra_callback_name: ::std::option::Option<$extra_callback_type>),*)*
                )*)*
            }

            pub(crate) static mut $static_manager: $manager = $manager {
                $($(
                    $listener: $crate::wlroots_sys::wl_listener {
                        link: {
                            $crate::wlroots_sys::wl_list {
                                prev: ::std::ptr::null_mut(),
                                next: ::std::ptr::null_mut()}},
                        notify: ::std::option::Option::None },
                    $callback: ::std::option::Option::None,
                    $($($extra_callback_name: ::std::option::Option::None),*)*
                )*)*
            };

            impl Manager {
                /// Sets the functions on the builder as the global manager functions.
                ///
                /// # Safety
                /// Returns a mutable reference to static data, which is unsafe to have
                /// multiple of. Do all your mutation through this reference and don't
                /// call this function multiple times.
                pub(crate) unsafe fn build(builder: $builder) -> &'static mut $manager {
                    $($(
                        $static_manager.$listener = {
                            // NOTE Rationale for zeroed memory:
                            // * Need to pass a pointer to wl_list_init
                            // * The list is initialized by Wayland, which doesn't "drop"
                            // * The listener is written to without dropping any of the data
                            let mut listener: $crate::wlroots_sys::wl_listener = ::std::mem::zeroed();
                            use $crate::wlroots_sys::server::WAYLAND_SERVER_HANDLE;
                            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                          wl_list_init,
                                          &mut listener.link as *mut _ as _);
                            ::std::ptr::write(&mut listener.notify, std::option::Option::Some($notify));
                            listener
                        };
                        $static_manager.$callback = builder.$callback;
                        $($(
                            $static_manager.$extra_callback_name = builder.$extra_callback_name;
                        )*)*
                    )*)*
                    &mut $static_manager
                }
            }
        )*

        $(
            $(
                $(
                    unsafe extern "C" fn $notify(listener: *mut $crate::wlroots_sys::wl_listener,
                                                 data: *mut $crate::libc::c_void) {
                        let manager: &mut $manager = &mut *container_of!(listener,
                                                                         $manager,
                                                                         $listener);
                        $crate::utils::handle_unwind(
                            ::std::panic::catch_unwind(
                                ::std::panic::AssertUnwindSafe(|| {
                                    (|$($func_arg: $func_type,)*| { $body })(manager, data)
                                })))
                    }
                )*
            )*
        )*
    }
}

/// Used to indicate what data is global compositor data.
/// It will automatically implement the CompositorData trait for the struct,
/// and also add a method to `Compositor` to unwrap the data from the fat
/// pointer.
#[cfg(feature = "unstable")]
#[macro_export]
macro_rules! compositor_data {
    ($struct_name: ty) => {
        impl<'a>::std::convert::From<&'a mut $crate::compositor::Compositor> for &'a mut $struct_name {
            fn from(compositor: &'a mut $crate::compositor::Compositor) -> &'a mut $struct_name {
                &mut *compositor.data.downcast_mut::<$struct_name>()
                    .unwrap_or_else(|| {
                        wlr_log!(WLR_ERROR, "Could not cast compositor state to {:#?}",
                                 stringify!($struct_name));
                        panic!("Could not cast compositor state to correct value")
                    })
            }
        }
    }
}

/// A convenience macro designed for use with Handle types.
///
/// This allows you to avoid the rightward drift of death that is often found
/// with heavily nested callback systems.
///
/// Any `HandleResult`s are flattened and the first one encountered is immediately
/// returned before any of the `$body` code is executed.
///
/// Order of evaluation is from left to right. It is possible to refer to the previous
/// result, as commonly found in Lisp's `let*` macro.
///
/// An example of simple use:
///
/// ```rust,ignore
/// with_handles!([(compositor: {compositor}),
///    (output: {&mut result.output_handle})] => {
///    ...
/// })
/// ```
///
/// A more complex use:
///
/// ```rust,ignore
/// with_handles!([(shell: {shell_handle}),
///    // Notice how we use the previous result to get the surface.
///    (surface: {shell.surface_handle})] => {
///    ...
/// })
/// ```
///
#[cfg(feature = "unstable")]
#[macro_export]
macro_rules! with_handles {
    ([($handle_name: ident: $unhandle_name: block)] => $body: block) => {
        $unhandle_name.run(|$handle_name| {
            $body
        })
    };
    ([($handle_name1: ident: $unhandle_name1: block),
      ($handle_name2: ident: $unhandle_name2: block),
      $($rest: tt)*] => $body: block) => {
        $unhandle_name1.run(|$handle_name1| {
            with_handles!([($handle_name2: $unhandle_name2), $($rest)*] => $body)
        }).and_then(|n: $crate::utils::HandleResult<_>| n)
    };
    ([($handle_name: ident: $unhandle_name: block), $($rest: tt)*] => $body: block) => {
        $unhandle_name.run(|$handle_name| {
            with_handles!([$($rest)*] => $body)
        }).and_then(|n: $crate::utils::HandleResult<_>| n)
    };
}
<commit_msg>Documented the auto generated types<commit_after>/// Gets the offset of a field. Used by container_of!
macro_rules! offset_of(
    ($ty:ty, $field:ident) => {
        &(*(0 as *const $ty)).$field as *const _ as usize
    }
);

/// Gets the parent struct from a pointer.
/// VERY unsafe. The parent struct _must_ be repr(C), and the
/// type passed to this macro _must_ match the type of the parent.
macro_rules! container_of (
    ($ptr: expr, $container: ty, $field: ident) => {
        ($ptr as *mut u8).offset(-(offset_of!($container, $field) as isize)) as *mut $container
    }
);

/// Iterates over a wl_list.
///
/// # Safety
/// It is not safe to delete an element while iterating over the list,
/// so don't do it!
macro_rules! wl_list_for_each {
    ($ptr: expr, $field: ident, ($pos: ident : $container: ty) => $body: block) => {
        let mut $pos: *mut $container;
        $pos = container_of!($ptr.next, $container, $field);
        loop {
            if &(*$pos).$field as *const _ == &$ptr as *const _ {
                break
            }
            { $body }
            $pos = container_of!((*$pos).$field.next, $container, $field);
        }
    }
}

/// Logs a message using wlroots' logging capability.
///
/// Example:
/// ```rust,no_run,ignore
/// #[macro_use]
/// use wlroots::log::{init_logging, L_DEBUG, L_ERROR};
///
/// // Call this once, at the beginning of your program.
/// init_logging(WLR_DEBUG, None);
///
/// wlr_log!(L_DEBUG, "Hello world");
/// wlr_log!(L_ERROR, "Could not {:#?} the {}", foo, bar);
/// ```
#[macro_export]
macro_rules! wlr_log {
    ($verb: expr, $($msg:tt)*) => {{
        /// Convert a literal string to a C string.
        /// Note: Does not check for internal nulls, nor does it do any conversions on
        /// the grapheme clustors. Just passes the bytes as is.
        /// So probably only works on ASCII.
        macro_rules! c_str {
            ($s:expr) => {
                concat!($s, "\0").as_ptr()
                    as *const $crate::wlroots_sys::libc::c_char
            }
        }
        use $crate::wlroots_sys::_wlr_log;
        use $crate::wlroots_sys::wlr_log_importance::*;
        use ::std::ffi::CString;
        unsafe {
            let fmt = CString::new(format!($($msg)*))
                .expect("Could not convert log message to C string");
            let raw = fmt.into_raw();
            _wlr_log($verb, c_str!("[%s:%lu] %s"),
                    c_str!(file!()), line!(), raw);
            // Deallocate string
            CString::from_raw(raw);
        }
    }}
}

/// Defines a new struct that contains a variable number of listeners that
/// will trigger unsafe user-defined callbacks.
///
/// The structure that is defined is repr(C), has one `data` field with the
/// given user type, and a field for each `$listener`.
///
/// Each `$listener` has a getter method that lets you get the pointer to the
/// listener. This method is unsafe, since it returns a raw pointer.
/// To use it correctly, you need to ensure that the data it refers to never
/// moves (e.g keep it in a box). The primary purpose of this method is to pass
/// the listener pointer to other methods to register it for a Wayland event.
/// **A listener can only be registered to one event at a time**.
///
/// Finally, it also takes in a body for each `$listener` that is called
/// every time the event that is later hooked up to it is fired.
/// This method is inherently unsafe, because the user data hasn't been cast
/// from the void pointer yet. It is the user's job to write this safely.
/// To highlight this fact, the body of the function must be prefixed with
/// `unsafe`.
///
/// # Example
/// ```rust,no_run,ignore
/// #[macro_use] extern crate wlroots;
/// extern crate wlroots_sys;
/// #[macro_use] extern crate wayland_sys;
/// extern crate libc;
///
/// use wlroots::InputDevice;
/// use wlroots_sys::wlr_input_device;
///
/// // Handles input addition and removal.
/// pub trait InputManagerHandler {
///     // Callback triggered when an input device is added.
///     fn input_added(&mut self, InputDevice);
/// }
///
/// wayland_listener!(
///     // The name of the structure that will be defined.
///     pub(crate) InputManager,
///     // The type that's stored in the `data` field.
///     // Note that we use a Box here to achieve dynamic dispatch,
///     // it's not required for this type to be in a box.
///     Box<InputManagerHandler>,
///     [
///         // Adds a new listener called `add_listener`.
///         // Adds an unsafe function called `add_notify` that is triggered
///         // whenever add_listener is activated from a Wayland event.
///         add_listener => add_notify: |this: &mut InputManager, data: *mut libc::c_void,| unsafe {
///             let ref mut manager = this.data;
///             // Call the method defined above, wrapping it in a safe interface.
///             // It is your job to ensure that the code in here doesn't trigger UB!
///             manager.input_added(InputDevice::from_ptr(data as *mut wlr_input_device))
///         };
///     ]
/// );
/// # fn main() {}
/// ```
///
/// # Unsafety
/// Note that the purpose of this macro is to make it easy to generate unsafe
/// boiler plate for using listeners with Rust data.
///
/// However, there are a few things this macro doesn't protect against.
///
/// First and foremost, the data cannot move. The listeners assume that the
/// structure will never move, so in order to defend against this the generated
/// `new` method returns a Box version. **Do not move out of the box**.
///
/// Second, this macro doesn't protect against the stored data being unsized.
/// Passing a pointer of unsized data to C is UB, don't do it.
macro_rules! wayland_listener {
    ($pub: vis $struct_name: ident, $data: ty, $([
        $($listener: ident => $listener_func: ident :
          |$($func_arg:ident: $func_type:ty,)*| unsafe $body: block;)*])+) => {
        #[repr(C)]
        #[doc(hidden)]
        $pub struct $struct_name {
            data: $data,
            $($($listener: $crate::wlroots_sys::wl_listener),*)*
        }

        impl $struct_name {
            pub(crate) fn new(data: $data) -> Box<$struct_name> {
                use $crate::wlroots_sys::server::WAYLAND_SERVER_HANDLE;
                Box::new($struct_name {
                    data,
                    $($($listener: unsafe {
                        // NOTE Rationale for zeroed memory:
                        // * Need to pass a pointer to wl_list_init
                        // * The list is initialized by Wayland, which doesn't "drop"
                        // * The listener is written to without dropping any of the data
                        let mut listener: $crate::wlroots_sys::wl_listener = ::std::mem::zeroed();
                        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                      wl_list_init,
                                      &mut listener.link as *mut _ as _);
                        ::std::ptr::write(&mut listener.notify, Some($struct_name::$listener_func));
                        listener
                    }),*)*
                })
            }

            $($(pub(crate) unsafe extern "C" fn $listener(&mut self)
                                                   -> *mut $crate::wlroots_sys::wl_listener {
                &mut self.$listener as *mut _
            })*)*

            $($(pub(crate) unsafe extern "C" fn $listener_func(listener:
                                                        *mut $crate::wlroots_sys::wl_listener,
                                                        data: *mut $crate::libc::c_void) {
                let manager: &mut $struct_name = &mut (*container_of!(listener,
                                                                      $struct_name,
                                                                      $listener));
                $crate::utils::handle_unwind(
                    ::std::panic::catch_unwind(
                        ::std::panic::AssertUnwindSafe(|| {
                            (|$($func_arg: $func_type,)*| { $body })(manager, data)
                        })));
            })*)*
        }
    }
}

macro_rules! wayland_listener_static {
    (static mut $static_manager: ident;
     $(($manager: ident, $builder: ident):
       $([
           $(
               $([$($extra_callback_name: ident: $extra_callback_type: ty),+])*
               ($fn_type: ty, $listener: ident, $builder_func: ident) => ($notify: ident, $callback: ident):
               |$($func_arg: ident: $func_type: ty,)*| unsafe $body: block;
           )*
       ])+
     )+
    ) => {
        $(
            #[derive(Default)]
            #[allow(dead_code)]
            /// A builder of static functions to manage and create resources.
            ///
            /// Implement the functions with the necessary signature, pass them
            /// to the builder, and then give the builder to the necessary
            /// structure in order to utilize them (usually it's `compositor::Builder`).
            pub struct $builder {
                $($($callback: ::std::option::Option<$fn_type>,)*
                  $($($($extra_callback_name: ::std::option::Option<$extra_callback_type>,)*)*)*)*
            }

            impl $builder {
                $($(
                    /// Uses the provided callback as the receiver for the
                    /// event the type signature describes.
                    pub fn $builder_func(mut self, $callback: $fn_type) -> Self {
                        self.$callback = ::std::option::Option::Some($callback);
                        self
                    }
                    $($(
                        /// Uses the provided callback as the receiver for the
                        /// event the type signature describes.
                        pub fn $extra_callback_name(mut self, $extra_callback_name: $extra_callback_type) -> Self {
                            self.$extra_callback_name = ::std::option::Option::Some($extra_callback_name);
                            self
                        }
                    )*)*
                )*)*
            }
        )*

        $(
            #[repr(C)]
            pub(crate) struct $manager {
                $($(
                    pub(crate) $listener: $crate::wlroots_sys::wl_listener,
                    $callback: ::std::option::Option<$fn_type>,
                    $($($extra_callback_name: ::std::option::Option<$extra_callback_type>),*)*
                )*)*
            }

            pub(crate) static mut $static_manager: $manager = $manager {
                $($(
                    $listener: $crate::wlroots_sys::wl_listener {
                        link: {
                            $crate::wlroots_sys::wl_list {
                                prev: ::std::ptr::null_mut(),
                                next: ::std::ptr::null_mut()}},
                        notify: ::std::option::Option::None },
                    $callback: ::std::option::Option::None,
                    $($($extra_callback_name: ::std::option::Option::None),*)*
                )*)*
            };

            impl Manager {
                /// Sets the functions on the builder as the global manager functions.
                ///
                /// # Safety
                /// Returns a mutable reference to static data, which is unsafe to have
                /// multiple of. Do all your mutation through this reference and don't
                /// call this function multiple times.
                pub(crate) unsafe fn build(builder: $builder) -> &'static mut $manager {
                    $($(
                        $static_manager.$listener = {
                            // NOTE Rationale for zeroed memory:
                            // * Need to pass a pointer to wl_list_init
                            // * The list is initialized by Wayland, which doesn't "drop"
                            // * The listener is written to without dropping any of the data
                            let mut listener: $crate::wlroots_sys::wl_listener = ::std::mem::zeroed();
                            use $crate::wlroots_sys::server::WAYLAND_SERVER_HANDLE;
                            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                          wl_list_init,
                                          &mut listener.link as *mut _ as _);
                            ::std::ptr::write(&mut listener.notify, std::option::Option::Some($notify));
                            listener
                        };
                        $static_manager.$callback = builder.$callback;
                        $($(
                            $static_manager.$extra_callback_name = builder.$extra_callback_name;
                        )*)*
                    )*)*
                    &mut $static_manager
                }
            }
        )*

        $(
            $(
                $(
                    unsafe extern "C" fn $notify(listener: *mut $crate::wlroots_sys::wl_listener,
                                                 data: *mut $crate::libc::c_void) {
                        let manager: &mut $manager = &mut *container_of!(listener,
                                                                         $manager,
                                                                         $listener);
                        $crate::utils::handle_unwind(
                            ::std::panic::catch_unwind(
                                ::std::panic::AssertUnwindSafe(|| {
                                    (|$($func_arg: $func_type,)*| { $body })(manager, data)
                                })))
                    }
                )*
            )*
        )*
    }
}

/// Used to indicate what data is global compositor data.
/// It will automatically implement the CompositorData trait for the struct,
/// and also add a method to `Compositor` to unwrap the data from the fat
/// pointer.
#[cfg(feature = "unstable")]
#[macro_export]
macro_rules! compositor_data {
    ($struct_name: ty) => {
        impl<'a>::std::convert::From<&'a mut $crate::compositor::Compositor> for &'a mut $struct_name {
            fn from(compositor: &'a mut $crate::compositor::Compositor) -> &'a mut $struct_name {
                &mut *compositor.data.downcast_mut::<$struct_name>()
                    .unwrap_or_else(|| {
                        wlr_log!(WLR_ERROR, "Could not cast compositor state to {:#?}",
                                 stringify!($struct_name));
                        panic!("Could not cast compositor state to correct value")
                    })
            }
        }
    }
}

/// A convenience macro designed for use with Handle types.
///
/// This allows you to avoid the rightward drift of death that is often found
/// with heavily nested callback systems.
///
/// Any `HandleResult`s are flattened and the first one encountered is immediately
/// returned before any of the `$body` code is executed.
///
/// Order of evaluation is from left to right. It is possible to refer to the previous
/// result, as commonly found in Lisp's `let*` macro.
///
/// An example of simple use:
///
/// ```rust,ignore
/// with_handles!([(compositor: {compositor}),
///    (output: {&mut result.output_handle})] => {
///    ...
/// })
/// ```
///
/// A more complex use:
///
/// ```rust,ignore
/// with_handles!([(shell: {shell_handle}),
///    // Notice how we use the previous result to get the surface.
///    (surface: {shell.surface_handle})] => {
///    ...
/// })
/// ```
///
#[cfg(feature = "unstable")]
#[macro_export]
macro_rules! with_handles {
    ([($handle_name: ident: $unhandle_name: block)] => $body: block) => {
        $unhandle_name.run(|$handle_name| {
            $body
        })
    };
    ([($handle_name1: ident: $unhandle_name1: block),
      ($handle_name2: ident: $unhandle_name2: block),
      $($rest: tt)*] => $body: block) => {
        $unhandle_name1.run(|$handle_name1| {
            with_handles!([($handle_name2: $unhandle_name2), $($rest)*] => $body)
        }).and_then(|n: $crate::utils::HandleResult<_>| n)
    };
    ([($handle_name: ident: $unhandle_name: block), $($rest: tt)*] => $body: block) => {
        $unhandle_name.run(|$handle_name| {
            with_handles!([$($rest)*] => $body)
        }).and_then(|n: $crate::utils::HandleResult<_>| n)
    };
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Div};
use std::collections::HashMap;
use std::iter::FromIterator;
use std::iter::repeat;
use std::fmt::{Debug, Formatter, Error};
use std::cmp::Ordering::Equal;
use std::ops::Drop;
use std::cmp;

#[derive(Clone,)]
pub struct WordVec {
    pub word: String,
    pub count: u64,
    vec: Vec<f32>,
}

impl PartialEq for WordVec {
    fn eq(&self, other: &WordVec) -> bool {
        self.vec == other.vec
    }
}

impl Debug for WordVec {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        try!(self.word.fmt(fmt));
        try!(fmt.write_str(": "));
        try!(self.count.fmt(fmt));
        try!(fmt.write_str(", "));
        self.vec.iter().take(5).collect::<Vec<_>>().fmt(fmt)
    }
}

impl WordVec {

    fn dot_prod(&self, other: &WordVec) -> f32 {
        self.vec.iter()
                .zip(other.vec.iter())
                .map(|(x, y)| x * y)
                .fold(0.0, |x, y| x + y)
    }

    fn magnitude(&self) -> f32 {
        self.vec.iter()
                .map(|x| x * x)
                .fold(0.0, |x, y| x + y)
                .sqrt()
    }

    pub fn distance(&self, other: &WordVec) -> f32 {
        self.vec.iter().zip(other.vec.iter())
                .map(|(x, y)| (x - y)*(x - y))
                .fold(0.0, |x, y| x + y)
                .abs().sqrt()
    }

    fn new(word: String, num_words: usize) -> WordVec {
        WordVec {
            word: word,
            count: 0,
            vec: repeat(0.0).take(num_words).collect(),
        }
    }

    fn normalize(&mut self) {
        let count = self.count as f32;
        for f in &mut self.vec {
            *f /= count;
        }
    }

    fn inc(&mut self, i: usize) {
        self.vec[i] += 1.0;
    }

}

impl Div<i32> for WordVec {
    type Output = WordVec;

    fn div(mut self, i: i32) -> WordVec {
        for f in &mut self.vec {
            *f /= i as f32;
        }

        self
    }
}

impl<'a> Add<&'a WordVec> for WordVec {
    type Output = WordVec;

    fn add(self, other: &WordVec) -> WordVec {
        debug_assert!(self.vec.len() == other.vec.len());
        let mut newvec = WordVec {
            word: format!("{} + {}", &self.word, &other.word),
            count: 0,
            vec: self.vec,
        };

        for i in 0..newvec.vec.len() {
            newvec.vec[i] += other.vec[i];
        }

        newvec
    }
}

impl<'a> Sub<&'a WordVec> for WordVec {
    type Output = WordVec;

    fn sub(self, other: &WordVec) -> WordVec {
        debug_assert!(self.vec.len() == other.vec.len());
        let mut newvec = WordVec {
            word: format!("{} - {}", &self.word, &other.word),
            count: 0,
            vec: self.vec,
        };

        for i in 0..(newvec.vec.len()) {
            newvec.vec[i] -= other.vec[i];
        }

        newvec
    }
}

pub struct LanguageModel {
    words: HashMap<String, usize>,
    word_vecs: Vec<WordVec>,
}

pub struct LanguageModelBuilder {
    window_radius: usize,
    words: HashMap<String, usize>,
    word_vecs: Vec<WordVec>,
}

pub struct WordAcceptor<'a> {
    sentence: Vec<Option<usize>>,
    builder: &'a mut LanguageModelBuilder,
}

impl LanguageModelBuilder {
    pub fn new(window_radius: usize, words: Vec<String>) -> LanguageModelBuilder {

        let word_vecs = words.iter()
                             .map(|s| WordVec::new(s.clone(), words.len()))
                             .collect();

        let words = HashMap::from_iter(
                        words.into_iter()
                             .enumerate()
                             .map(|(a, b)| (b, a)));

        LanguageModelBuilder {
            window_radius: window_radius,
            words: words,
            word_vecs: word_vecs,
        }
    }

    pub fn build(mut self) -> LanguageModel {
        for vec in self.word_vecs.iter_mut() {
            vec.normalize();
        }

        LanguageModel {
            words: self.words,
            word_vecs: self.word_vecs,
        }
    }

    pub fn new_sentence<'a>(&'a mut self) -> WordAcceptor<'a> {
        WordAcceptor {
            sentence: Vec::new(),
            builder: self,
        }
    }

    fn word_seen(&mut self, word: usize) {
        self.word_vecs[word].count += 1;
    }
}

impl<'a> WordAcceptor<'a> {
    pub fn add_word(&mut self, word: &str) {
        let idx_opt = self.builder.words.get(word).map(|w| *w);

        if let Some(next_idx) = idx_opt {
            self.builder.word_seen(next_idx);
            self.sentence.push(Some(next_idx));
        }
        else {
            self.sentence.push(None);
        }
    }
}

impl<'a> Drop for WordAcceptor<'a> {
    fn drop(&mut self) {
        let WordAcceptor {
            ref sentence,
            ref mut builder
        } = *self;

        for (i, &word_idx) in self.sentence.iter().enumerate() {
            let start = cmp::max(0, i as isize- builder.window_radius as isize) as usize;
            let end = cmp::min(sentence.len(), i + builder.window_radius + 1);
            for &j in &sentence[start..end] {
                match (word_idx, j) {
                    (Some(w), Some(j)) if w != j =>
                        builder.word_vecs[w].inc(j),
                    _ => {},
                }
            }
        }

        drop(sentence); // not actually sure if this is necessary
    }
}

impl LanguageModel {
    pub fn get(&self, word: &str) -> Option<&WordVec> {
        self.words.get(word).map(|i| &self.word_vecs[*i])
    }

    pub fn nearest_words(&self, word: &WordVec) -> Vec<&WordVec> {
        let mut vec_refs = self.word_vecs.iter().filter_map(|w| {
            let dist = w.distance(word);
            if w.word != word.word {
                Some((dist, w))
            } else {
                None
            }
        }).collect::<Vec<_>>();
        vec_refs.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or_else(|| {
            println!("bad vector: {:?}, {:?}", a, b);
            Equal
        }));
        vec_refs.into_iter().map(|x| x.1).collect()
    }
}

#[cfg(test)]
mod test {
    use super::{WordVec, LanguageModel, LanguageModelBuilder};

    #[test]
    fn test_accept_sentences() {
        let words = "foo bar baz blort".words().map(|w| w.to_string()).collect::<Vec<_>>();
        let mut builder = LanguageModelBuilder::new(1, words);

        let input = "x foo bar baz x x x x x x x blort".words();

        {
            let mut acc = builder.new_sentence();
            for word in input {
                acc.add_word(word);
            }
        }

        let model = builder.build();
        let foo = model.get("foo").unwrap();
        let baz = model.get("baz").unwrap();
        let bar = model.get("bar").unwrap();
        let blort = model.get("blort").unwrap();

        assert!(foo.distance(baz) < foo.distance(blort));
        assert!(foo.distance(bar) == bar.distance(baz));

    }
}<commit_msg>remove superfluous .abs<commit_after>use std::ops::{Add, Sub, Div};
use std::collections::HashMap;
use std::iter::FromIterator;
use std::iter::repeat;
use std::fmt::{Debug, Formatter, Error};
use std::cmp::Ordering::Equal;
use std::ops::Drop;
use std::cmp;

#[derive(Clone,)]
pub struct WordVec {
    pub word: String,
    pub count: u64,
    vec: Vec<f32>,
}

impl PartialEq for WordVec {
    fn eq(&self, other: &WordVec) -> bool {
        self.vec == other.vec
    }
}

impl Debug for WordVec {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        try!(self.word.fmt(fmt));
        try!(fmt.write_str(": "));
        try!(self.count.fmt(fmt));
        try!(fmt.write_str(", "));
        self.vec.iter().take(5).collect::<Vec<_>>().fmt(fmt)
    }
}

impl WordVec {

    fn dot_prod(&self, other: &WordVec) -> f32 {
        self.vec.iter()
                .zip(other.vec.iter())
                .map(|(x, y)| x * y)
                .fold(0.0, |x, y| x + y)
    }

    fn magnitude(&self) -> f32 {
        self.vec.iter()
                .map(|x| x * x)
                .fold(0.0, |x, y| x + y)
                .sqrt()
    }

    pub fn distance(&self, other: &WordVec) -> f32 {
        self.vec.iter().zip(other.vec.iter())
                .map(|(x, y)| (x - y)*(x - y))
                .fold(0.0, |x, y| x + y)
                .sqrt()
    }

    fn new(word: String, num_words: usize) -> WordVec {
        WordVec {
            word: word,
            count: 0,
            vec: repeat(0.0).take(num_words).collect(),
        }
    }

    fn normalize(&mut self) {
        let count = self.count as f32;
        for f in &mut self.vec {
            *f /= count;
        }
    }

    fn inc(&mut self, i: usize) {
        self.vec[i] += 1.0;
    }

}

impl Div<i32> for WordVec {
    type Output = WordVec;

    fn div(mut self, i: i32) -> WordVec {
        for f in &mut self.vec {
            *f /= i as f32;
        }

        self
    }
}

impl<'a> Add<&'a WordVec> for WordVec {
    type Output = WordVec;

    fn add(self, other: &WordVec) -> WordVec {
        debug_assert!(self.vec.len() == other.vec.len());
        let mut newvec = WordVec {
            word: format!("{} + {}", &self.word, &other.word),
            count: 0,
            vec: self.vec,
        };

        for i in 0..newvec.vec.len() {
            newvec.vec[i] += other.vec[i];
        }

        newvec
    }
}

impl<'a> Sub<&'a WordVec> for WordVec {
    type Output = WordVec;

    fn sub(self, other: &WordVec) -> WordVec {
        debug_assert!(self.vec.len() == other.vec.len());
        let mut newvec = WordVec {
            word: format!("{} - {}", &self.word, &other.word),
            count: 0,
            vec: self.vec,
        };

        for i in 0..(newvec.vec.len()) {
            newvec.vec[i] -= other.vec[i];
        }

        newvec
    }
}

pub struct LanguageModel {
    words: HashMap<String, usize>,
    word_vecs: Vec<WordVec>,
}

pub struct LanguageModelBuilder {
    window_radius: usize,
    words: HashMap<String, usize>,
    word_vecs: Vec<WordVec>,
}

pub struct WordAcceptor<'a> {
    sentence: Vec<Option<usize>>,
    builder: &'a mut LanguageModelBuilder,
}

impl LanguageModelBuilder {
    pub fn new(window_radius: usize, words: Vec<String>) -> LanguageModelBuilder {

        let word_vecs = words.iter()
                             .map(|s| WordVec::new(s.clone(), words.len()))
                             .collect();

        let words = HashMap::from_iter(
                        words.into_iter()
                             .enumerate()
                             .map(|(a, b)| (b, a)));

        LanguageModelBuilder {
            window_radius: window_radius,
            words: words,
            word_vecs: word_vecs,
        }
    }

    pub fn build(mut self) -> LanguageModel {
        for vec in self.word_vecs.iter_mut() {
            vec.normalize();
        }

        LanguageModel {
            words: self.words,
            word_vecs: self.word_vecs,
        }
    }

    pub fn new_sentence<'a>(&'a mut self) -> WordAcceptor<'a> {
        WordAcceptor {
            sentence: Vec::new(),
            builder: self,
        }
    }

    fn word_seen(&mut self, word: usize) {
        self.word_vecs[word].count += 1;
    }
}

impl<'a> WordAcceptor<'a> {
    pub fn add_word(&mut self, word: &str) {
        let idx_opt = self.builder.words.get(word).map(|w| *w);

        if let Some(next_idx) = idx_opt {
            self.builder.word_seen(next_idx);
            self.sentence.push(Some(next_idx));
        }
        else {
            self.sentence.push(None);
        }
    }
}

impl<'a> Drop for WordAcceptor<'a> {
    fn drop(&mut self) {
        let WordAcceptor {
            ref sentence,
            ref mut builder
        } = *self;

        for (i, &word_idx) in self.sentence.iter().enumerate() {
            let start = cmp::max(0, i as isize- builder.window_radius as isize) as usize;
            let end = cmp::min(sentence.len(), i + builder.window_radius + 1);
            for &j in &sentence[start..end] {
                match (word_idx, j) {
                    (Some(w), Some(j)) if w != j =>
                        builder.word_vecs[w].inc(j),
                    _ => {},
                }
            }
        }

        drop(sentence); // not actually sure if this is necessary
    }
}

impl LanguageModel {
    pub fn get(&self, word: &str) -> Option<&WordVec> {
        self.words.get(word).map(|i| &self.word_vecs[*i])
    }

    pub fn nearest_words(&self, word: &WordVec) -> Vec<&WordVec> {
        let mut vec_refs = self.word_vecs.iter().filter_map(|w| {
            let dist = w.distance(word);
            if w.word != word.word {
                Some((dist, w))
            } else {
                None
            }
        }).collect::<Vec<_>>();
        vec_refs.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or_else(|| {
            println!("bad vector: {:?}, {:?}", a, b);
            Equal
        }));
        vec_refs.into_iter().map(|x| x.1).collect()
    }
}

#[cfg(test)]
mod test {
    use super::{WordVec, LanguageModel, LanguageModelBuilder};

    #[test]
    fn test_accept_sentences() {
        let words = "foo bar baz blort".words().map(|w| w.to_string()).collect::<Vec<_>>();
        let mut builder = LanguageModelBuilder::new(1, words);

        let input = "x foo bar baz x x x x x x x blort".words();

        {
            let mut acc = builder.new_sentence();
            for word in input {
                acc.add_word(word);
            }
        }

        let model = builder.build();
        let foo = model.get("foo").unwrap();
        let baz = model.get("baz").unwrap();
        let bar = model.get("bar").unwrap();
        let blort = model.get("blort").unwrap();

        assert!(foo.distance(baz) < foo.distance(blort));
        assert!(foo.distance(bar) == bar.distance(baz));

    }
}<|endoftext|>


<commit_before>//! Due to netlink's loose treatment of types, parsing attributes can be hard to model in
//! Rust. `neli`'s current solution is the following:
//!
//! ```no_run
//! // This was received from the socket
//! let nlmsg = neli::nl::Nlmsghdr::new(None, neli::consts::GenlId::Ctrl, Vec::new(), None, None,
//!         neli::genl::Genlmsghdr::new::<u16>(neli::consts::CtrlCmd::Unspec, 2, Vec::new()).unwrap());
//!
//! // Get parsing handler for the attributes in this message where the next call
//! // to either get_nested_attributes() or get_payload_with() will expect a u16 type
//! // to be provided
//! let mut handle = nlmsg.nl_payload.get_attr_handle::<u16>();
//!
//! // Get the nested attribute where the Nlattr field of nla_type is equal to 1 and return
//! // a handler containing only this nested attribute internally
//! let mut next = handle.get_nested_attributes::<u16>(1).unwrap();
//!
//! // Get the nested attribute where the Nlattr field of nla_type is equal to 1 and return
//! // the payload of this attribute as a u32
//! let thirty_two_bit_integer = next.get_payload::<u32>(1, None).unwrap();
//! ```

use std::io::{Read,Write};
use std::slice;

use buffering::copy::{StreamReadBuffer,StreamWriteBuffer};
use libc;

use Nl;
use err::{SerError,DeError};
use consts::{alignto,NlAttrType};

/// Struct representing netlink attributes and payloads
#[derive(Debug,PartialEq)]
pub struct Nlattr<T> {
    /// Length of the attribute header and payload together
    pub nla_len: u16,
    /// Enum representing the type of the attribute payload
    pub nla_type: T,
    /// Payload of the attribute - either parsed or a binary buffer
    pub payload: Vec<u8>,
}

impl<T> Nlattr<T> where T: NlAttrType {
    /// Create new netlink attribute with a payload
    pub fn new_binary_payload(nla_len: Option<u16>, nla_type: T, payload: Vec<u8>)
            -> Self {
        let mut nla = Nlattr {
            nla_type,
            payload,
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        nla
    }

    /// Create new netlink attribute with a payload from an object implementing `Nl`
    pub fn new_nl_payload<P>(nla_len: Option<u16>, nla_type: T, payload: P)
            -> Result<Self, SerError> where P: Nl {
        let mut mem = StreamWriteBuffer::new_growable(Some(payload.asize()));
        payload.serialize(&mut mem)?;
        let mut nla = Nlattr {
            nla_type,
            payload: mem.as_ref().to_vec(),
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        Ok(nla)
    }

    /// Create new netlink attribute with a nested payload
    pub fn new_nested<P>(nla_len: Option<u16>, nla_type: T, mut payload: Vec<Nlattr<P>>)
            -> Result<Self, SerError> where P: NlAttrType {
        let mut nla = Nlattr {
            nla_type,
            payload: {
                let mut mem = StreamWriteBuffer::new_growable(Some(payload.iter().fold(0, |acc, item| {
                    acc + item.asize()
                })));
                for item in payload.iter_mut() {
                    item.serialize(&mut mem)?;
                    if item.payload.asize() != item.payload.size() {
                        [0u8; libc::NLA_ALIGNTO as usize]
                            [0..item.payload.asize() - item.payload.size()]
                            .as_ref().serialize(&mut mem)?;
                    }
                }
                mem.as_ref().to_vec()
            },
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        Ok(nla)
    }

    /// Create new netlink attribute payload from string, handling null byte termination
    pub fn new_string_payload(nla_len: Option<u16>, nla_type: T, string_payload: String)
            -> Result<Self, SerError> {
        let nla = Nlattr {
            nla_len: nla_len.unwrap_or((0u16.size() + nla_type.size() + string_payload.size())
                                       as u16),
            nla_type,
            payload: {
                let mut mem = StreamWriteBuffer::new_growable(Some(string_payload.asize()));
                string_payload.serialize(&mut mem)?;
                if string_payload.asize() != string_payload.size() {
                    [0u8; libc::NLA_ALIGNTO as usize]
                        [0..string_payload.asize() - string_payload.size()]
                        .as_ref().serialize(&mut mem)?;
                }
                mem.as_ref().to_vec()
            },
        };
        Ok(nla)
    }

    /// Create new netlink attribute payload from string, handling null byte termination
    pub fn new_str_payload(nla_len: Option<u16>, nla_type: T, str_payload: &str)
            -> Result<Self, SerError> {
        let string_payload = str_payload.to_string();
        Self::new_string_payload(nla_len, nla_type, string_payload)
    }

    /// Get handle for attribute parsing and traversal
    pub fn get_attr_handle<'a, P>(&'a self) -> AttrHandle<'a, P> where P: NlAttrType {
        AttrHandle::Bin(self.payload.as_slice())
    }
}

impl<T> Nl for Nlattr<T> where T: NlAttrType {
    fn serialize(&self, mem: &mut StreamWriteBuffer) -> Result<(), SerError> {
        self.nla_len.serialize(mem)?;
        self.nla_type.serialize(mem)?;
        self.payload.serialize(mem)?;
        let padding_len = alignto(self.nla_len as usize) - self.nla_len as usize;
        mem.write(&mut [0u8; 4][0..padding_len])?;
        Ok(())
    }

    fn deserialize<B>(mem: &mut StreamReadBuffer<B>) -> Result<Self, DeError> where B: AsRef<[u8]> {
        let nla_len = u16::deserialize(mem)?;
        let nla_type = T::deserialize(mem)?;
        mem.set_size_hint(nla_len as usize - (nla_len.size() + nla_type.size()));
        let payload = Vec::<u8>::deserialize(mem)?;
        let padding_len = alignto(nla_len as usize) - nla_len as usize;
        let padding = &mut [0u8; libc::NLA_ALIGNTO as usize][0..padding_len];
        let _ = mem.read_exact(padding)?;
        let nla = Nlattr {
            nla_len,
            nla_type,
            payload,
        };
        Ok(nla)
    }

    fn size(&self) -> usize {
        self.nla_len.size() + self.nla_type.size() + self.payload.size()
    }
}

/// Handle returned by `Genlmsghdr` for traversing nested attribute structures
pub enum AttrHandle<'a, P> where P: NlAttrType {
    /// Binary internal representation of attributes
    Bin(&'a [u8]),
    /// Rust representation of attributes
    Parsed(Vec<Nlattr<P>>),
}

impl<'a, P> AttrHandle<'a, P> where P: NlAttrType {
    /// Get length if attribute handle has been parsed
    pub fn len(&self) -> Option<usize> {
        match *self {
            AttrHandle::Parsed(ref v) => Some(v.len()),
            _ => None,
        }
    }

    /// If attributes are parsed, pass back iterator over attributes
    pub fn iter(&self) -> Option<slice::Iter<Nlattr<P>>> {
        match *self {
            AttrHandle::Parsed(ref v) => Some(v.iter()),
            _ => None,
        }
    }

    /// Parse a binary payload into nested attributes
    pub fn parse_nested_attributes(&mut self) -> Result<&mut AttrHandle<'a, P>, DeError> {
        let opt_v = match *self {
            AttrHandle::Bin(v) => {
                let mut len = v.asize();
                let mut attrs = Vec::new();
                let mut mem = StreamReadBuffer::new(v);
                while len > 0 {
                    let hdr = Nlattr::deserialize(&mut mem)?;
                    len -= hdr.asize();
                    attrs.push(hdr);
                }
                Some(attrs)
            },
            _ => None,
        };
        match opt_v {
            Some(v) => { *self = AttrHandle::Parsed(v); },
            None => (),
        };
        Ok(self)
    }

    /// Get the payload of an attribute as a handle for parsing nested attributes
    pub fn get_nested_attributes<S>(&mut self, payload: P) -> Result<AttrHandle<S>, DeError>
            where S: NlAttrType {
        let nested = self.parse_nested_attributes()?.get_attribute(payload);
        match nested {
            Some(a) => Ok(AttrHandle::Bin(a.payload.as_slice())),
            None => Err(DeError::new("Failed to find requested attribute")),
        }
    }

    /// Get nested attributes from a parsed handle
    pub fn get_attribute(&'a self, p: P) -> Option<&'a Nlattr<P>> {
        match *self {
            AttrHandle::Parsed(ref parsed) => {
                for item in parsed {
                    if item.nla_type == p {
                        return Some(&item);
                    }
                }
                None
            },
            _ => None,
        }
    }

    /// Mutably get nested attributes from a parsed handle
    pub fn get_attribute_mut(&'a mut self, p: P) -> Option<&'a mut Nlattr<P>> {
        match *self {
            AttrHandle::Parsed(ref mut parsed) => {
                for item in parsed {
                    if item.nla_type == p {
                        return Some(item);
                    }
                }
                None
            },
            _ => None,
        }
    }

    /// Parse binary payload as a type that implements `Nl` using `deserialize` with an option size
    /// hint
    pub fn get_payload<R>(&mut self, attr: P, size_hint: Option<usize>) -> Result<R, DeError>
            where R: Nl {
        match self.parse_nested_attributes()?.get_attribute(attr) {
            Some(ref a) => {
                let mut mem = StreamReadBuffer::new(&a.payload);
                if let Some(w) = size_hint {
                    mem.set_size_hint(w);
                }
                R::deserialize(&mut mem)
            },
            _ => Err(DeError::new("Failed to find specified attribute")),
        }
    }
}
<commit_msg>Attempt to track down bug potentially related to padding resulting in 'Failed to fill whole buffer' error<commit_after>//! Due to netlink's loose treatment of types, parsing attributes can be hard to model in
//! Rust. `neli`'s current solution is the following:
//!
//! ```no_run
//! // This was received from the socket
//! let nlmsg = neli::nl::Nlmsghdr::new(None, neli::consts::GenlId::Ctrl, Vec::new(), None, None,
//!         neli::genl::Genlmsghdr::new::<u16>(neli::consts::CtrlCmd::Unspec, 2, Vec::new()).unwrap());
//!
//! // Get parsing handler for the attributes in this message where the next call
//! // to either get_nested_attributes() or get_payload_with() will expect a u16 type
//! // to be provided
//! let mut handle = nlmsg.nl_payload.get_attr_handle::<u16>();
//!
//! // Get the nested attribute where the Nlattr field of nla_type is equal to 1 and return
//! // a handler containing only this nested attribute internally
//! let mut next = handle.get_nested_attributes::<u16>(1).unwrap();
//!
//! // Get the nested attribute where the Nlattr field of nla_type is equal to 1 and return
//! // the payload of this attribute as a u32
//! let thirty_two_bit_integer = next.get_payload::<u32>(1, None).unwrap();
//! ```

use std::io::{Read,Write};
use std::slice;

use buffering::copy::{StreamReadBuffer,StreamWriteBuffer};
use libc;

use Nl;
use err::{SerError,DeError};
use consts::{alignto,NlAttrType};

/// Struct representing netlink attributes and payloads
#[derive(Debug,PartialEq)]
pub struct Nlattr<T> {
    /// Length of the attribute header and payload together
    pub nla_len: u16,
    /// Enum representing the type of the attribute payload
    pub nla_type: T,
    /// Payload of the attribute - either parsed or a binary buffer
    pub payload: Vec<u8>,
}

impl<T> Nlattr<T> where T: NlAttrType {
    /// Create new netlink attribute with a payload
    pub fn new_binary_payload(nla_len: Option<u16>, nla_type: T, payload: Vec<u8>)
            -> Self {
        let mut nla = Nlattr {
            nla_type,
            payload,
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        nla
    }

    /// Create new netlink attribute with a payload from an object implementing `Nl`
    pub fn new_nl_payload<P>(nla_len: Option<u16>, nla_type: T, payload: P)
            -> Result<Self, SerError> where P: Nl {
        let mut mem = StreamWriteBuffer::new_growable(Some(payload.asize()));
        payload.serialize(&mut mem)?;
        let mut nla = Nlattr {
            nla_type,
            payload: mem.as_ref().to_vec(),
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        Ok(nla)
    }

    /// Create new netlink attribute with a nested payload
    pub fn new_nested<P>(nla_len: Option<u16>, nla_type: T, mut payload: Vec<Nlattr<P>>)
            -> Result<Self, SerError> where P: NlAttrType {
        let mut nla = Nlattr {
            nla_type,
            payload: {
                let mut mem = StreamWriteBuffer::new_growable(Some(payload.iter().fold(0, |acc, item| {
                    acc + item.asize()
                })));
                for item in payload.iter_mut() {
                    item.serialize(&mut mem)?;
                    if item.payload.asize() != item.payload.size() {
                        [0u8; libc::NLA_ALIGNTO as usize]
                            [0..item.payload.asize() - item.payload.size()]
                            .as_ref().serialize(&mut mem)?;
                    }
                }
                mem.as_ref().to_vec()
            },
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        Ok(nla)
    }

    /// Create new netlink attribute payload from string, handling null byte termination
    pub fn new_string_payload(nla_len: Option<u16>, nla_type: T, string_payload: String)
            -> Result<Self, SerError> {
        let nla = Nlattr {
            nla_len: nla_len.unwrap_or((0u16.size() + nla_type.size() + string_payload.size())
                                       as u16),
            nla_type,
            payload: {
                let mut mem = StreamWriteBuffer::new_growable(Some(string_payload.asize()));
                string_payload.serialize(&mut mem)?;
                if string_payload.asize() != string_payload.size() {
                    [0u8; libc::NLA_ALIGNTO as usize]
                        [0..string_payload.asize() - string_payload.size()]
                        .as_ref().serialize(&mut mem)?;
                }
                mem.as_ref().to_vec()
            },
        };
        Ok(nla)
    }

    /// Create new netlink attribute payload from string, handling null byte termination
    pub fn new_str_payload(nla_len: Option<u16>, nla_type: T, str_payload: &str)
            -> Result<Self, SerError> {
        let string_payload = str_payload.to_string();
        Self::new_string_payload(nla_len, nla_type, string_payload)
    }

    /// Get handle for attribute parsing and traversal
    pub fn get_attr_handle<'a, P>(&'a self) -> AttrHandle<'a, P> where P: NlAttrType {
        AttrHandle::Bin(self.payload.as_slice())
    }
}

impl<T> Nl for Nlattr<T> where T: NlAttrType {
    fn serialize(&self, mem: &mut StreamWriteBuffer) -> Result<(), SerError> {
        self.nla_len.serialize(mem)?;
        self.nla_type.serialize(mem)?;
        self.payload.serialize(mem)?;
        let padding_len = alignto(self.nla_len as usize) - self.nla_len as usize;
        if padding_len > 0 {
            mem.write(&mut [0u8; 4][0..padding_len])?;
        }
        Ok(())
    }

    fn deserialize<B>(mem: &mut StreamReadBuffer<B>) -> Result<Self, DeError> where B: AsRef<[u8]> {
        let nla_len = u16::deserialize(mem)?;
        let nla_type = T::deserialize(mem)?;
        mem.set_size_hint(nla_len as usize - (nla_len.size() + nla_type.size()));
        let payload = Vec::<u8>::deserialize(mem)?;
        let padding_len = alignto(nla_len as usize) - nla_len as usize;
        let padding = &mut [0u8; libc::NLA_ALIGNTO as usize][0..padding_len];
        if padding_len > 0 {
            let _ = mem.read_exact(padding)?;
        }
        let nla = Nlattr {
            nla_len,
            nla_type,
            payload,
        };
        Ok(nla)
    }

    fn size(&self) -> usize {
        self.nla_len.size() + self.nla_type.size() + self.payload.size()
    }
}

/// Handle returned by `Genlmsghdr` for traversing nested attribute structures
pub enum AttrHandle<'a, P> where P: NlAttrType {
    /// Binary internal representation of attributes
    Bin(&'a [u8]),
    /// Rust representation of attributes
    Parsed(Vec<Nlattr<P>>),
}

impl<'a, P> AttrHandle<'a, P> where P: NlAttrType {
    /// Get length if attribute handle has been parsed
    pub fn len(&self) -> Option<usize> {
        match *self {
            AttrHandle::Parsed(ref v) => Some(v.len()),
            _ => None,
        }
    }

    /// If attributes are parsed, pass back iterator over attributes
    pub fn iter(&self) -> Option<slice::Iter<Nlattr<P>>> {
        match *self {
            AttrHandle::Parsed(ref v) => Some(v.iter()),
            _ => None,
        }
    }

    /// Parse a binary payload into nested attributes
    pub fn parse_nested_attributes(&mut self) -> Result<&mut AttrHandle<'a, P>, DeError> {
        let opt_v = match *self {
            AttrHandle::Bin(v) => {
                let mut len = v.asize();
                let mut attrs = Vec::new();
                let mut mem = StreamReadBuffer::new(v);
                while len > 0 {
                    let hdr = Nlattr::deserialize(&mut mem)?;
                    len -= hdr.asize();
                    attrs.push(hdr);
                }
                Some(attrs)
            },
            _ => None,
        };
        match opt_v {
            Some(v) => { *self = AttrHandle::Parsed(v); },
            None => (),
        };
        Ok(self)
    }

    /// Get the payload of an attribute as a handle for parsing nested attributes
    pub fn get_nested_attributes<S>(&mut self, payload: P) -> Result<AttrHandle<S>, DeError>
            where S: NlAttrType {
        let nested = self.parse_nested_attributes()?.get_attribute(payload);
        match nested {
            Some(a) => Ok(AttrHandle::Bin(a.payload.as_slice())),
            None => Err(DeError::new("Failed to find requested attribute")),
        }
    }

    /// Get nested attributes from a parsed handle
    pub fn get_attribute(&'a self, p: P) -> Option<&'a Nlattr<P>> {
        match *self {
            AttrHandle::Parsed(ref parsed) => {
                for item in parsed {
                    if item.nla_type == p {
                        return Some(&item);
                    }
                }
                None
            },
            _ => None,
        }
    }

    /// Mutably get nested attributes from a parsed handle
    pub fn get_attribute_mut(&'a mut self, p: P) -> Option<&'a mut Nlattr<P>> {
        match *self {
            AttrHandle::Parsed(ref mut parsed) => {
                for item in parsed {
                    if item.nla_type == p {
                        return Some(item);
                    }
                }
                None
            },
            _ => None,
        }
    }

    /// Parse binary payload as a type that implements `Nl` using `deserialize` with an option size
    /// hint
    pub fn get_payload<R>(&mut self, attr: P, size_hint: Option<usize>) -> Result<R, DeError>
            where R: Nl {
        match self.parse_nested_attributes()?.get_attribute(attr) {
            Some(ref a) => {
                let mut mem = StreamReadBuffer::new(&a.payload);
                if let Some(w) = size_hint {
                    mem.set_size_hint(w);
                }
                R::deserialize(&mut mem)
            },
            _ => Err(DeError::new("Failed to find specified attribute")),
        }
    }
}
<|endoftext|>


<commit_before>//! A parser for lambda expressions

use term::{Term, Notation, abs, app};
use term::Term::*;
use self::Token::*;
use self::CToken::*;
use self::Error::*;
use self::Expression::*;
pub use term::Notation::*;

/// A type to represent a parsing error.
#[derive(Debug, PartialEq)]
pub enum Error {
    /// an invalid character was encountered
    InvalidCharacter((usize, char)),
    /// the expression is invalid
    InvalidExpression,
    /// the expression is empty
    EmptyExpression
}

#[derive(Debug, PartialEq)]
enum Token {
    /// λ or \
    Lambda,
    /// left parenthesis
    Lparen,
    /// right parenthesis
    Rparen,
    /// a number
    Number(usize)
}

#[derive(Debug, PartialEq)]
enum CToken {
    /// an abstraction with a bound variable
    CLambda(String),
    /// left parenthesis
    CLparen,
    /// right parenthesis
    CRparen,
    /// a variable with an identifier
    CName(String)
}

fn tokenize_dbr(input: &str) -> Result<Vec<Token>, Error> {
    let chars = input.chars().enumerate();
    let mut tokens = Vec::new();

    for (i, c) in chars {
        match c {
     '\\' | 'λ' => { tokens.push(Lambda) },
            '(' => { tokens.push(Lparen) },
            ')' => { tokens.push(Rparen) },
             _  => {
                if let Some(n) = c.to_digit(16) {
                    tokens.push(Number(n as usize))
                } else if c.is_whitespace() {
                    ()
                } else {
                    return Err(InvalidCharacter((i + 1, c)))
                }
            }
        }
    }

    Ok(tokens)
}

fn tokenize_cla(input: &str) -> Result<Vec<CToken>, Error> {
    let mut chars = input.chars().enumerate().peekable();
    let mut tokens = Vec::new();
    let valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    while let Some((i, c)) = chars.next() {
        match c {
            '\\' | 'λ' => {
                let mut name = String::new();
                while let Some((i, c)) = chars.next() {
                    if c == '.' {
                        break
                    } else if valid_chars.contains(c) {
                        name.push(c)
                    } else {
                        return Err(InvalidCharacter((i + 1, c)))
                    }
                }
                tokens.push(CLambda(name))
            },
            '(' => { tokens.push(CLparen) },
            ')' => { tokens.push(CRparen) },
             _  => {
                if c.is_whitespace() {
                    ()
                } else if valid_chars.contains(c) {
                    let mut name = c.to_string();
                    while let Some(&(_, c)) = chars.peek() {
                        if c.is_whitespace() || c == '(' || c == ')' {
                            break
                        } else {
                            name.push(c);
                            chars.next();
                        }
                    }
                    tokens.push(CName(name))
                } else {
                    return Err(InvalidCharacter((i + 1, c)))
                }
            }
        }
    }

    Ok(tokens)
}

fn convert_classic_tokens(tokens: &[CToken]) -> Vec<Token> {
    _convert_classic_tokens(tokens, &mut Vec::new(), &mut 0)
}

fn _convert_classic_tokens(tokens: &[CToken], stack: &mut Vec<String>, pos: &mut usize) -> Vec<Token>
{
    let mut output = Vec::with_capacity(tokens[*pos..].len());
    let mut inner_stack_count = 0;

    while let Some(token) = tokens.get(*pos) {
        match *token {
            CLambda(ref name) => {
                output.push(Lambda);
                stack.push(name.to_owned());
                inner_stack_count += 1;
            },
            CLparen => {
                output.push(Lparen);
                *pos += 1;
                output.append(&mut _convert_classic_tokens(tokens, stack, pos));
            },
            CRparen => {
                output.push(Rparen);
                for _ in 0..inner_stack_count { stack.pop(); }
                return output
            },
            CName(ref name) => {
                if let Some(index) = stack.iter().rev().position(|t| t == name) {
                    output.push(Number(index + 1))
                } else {
                    output.push(Number(stack.len() + 1))
                }
            }
        }
        *pos += 1;
    }

    output
}

#[derive(Debug, PartialEq)]
enum Expression {
    /// an abstraction
    Abstraction,
    /// a sequence of Expressions
    Sequence(Vec<Expression>),
    /// a variable with a De Bruijn index
    Variable(usize)
}

fn get_ast(tokens: &[Token]) -> Result<Expression, Error> {
    _get_ast(tokens, &mut 0)
}

fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result<Expression, Error> {
    if tokens.is_empty() { return Err(EmptyExpression) }

    let mut expr = Vec::new();

    while let Some(token) = tokens.get(*pos) {
        match *token {
            Lambda => {
                expr.push(Abstraction)
            },
            Number(i) => {
                expr.push(Variable(i))
            },
            Lparen => {
                *pos += 1;
                let subtree = try!(_get_ast(tokens, pos));
                expr.push(subtree);
            },
            Rparen => {
                return Ok(Sequence(expr))
            }
        }
        *pos += 1;
    }

    Ok(Sequence(expr))
}

/// Parses the input `&str` as a lambda `Term`.
///
/// - lambdas can be represented either with the greek letter (λ) or a backslash (\\ -
/// less aesthetic, but only one byte in size)
/// - the identifiers in `Classic` mode are `String`s of ASCII alphabetic characters
/// - `Classic` mode ignores whitespaces where unambiguous
/// - `DeBruijn` mode ignores all whitespaces (since indices > 15 are very unlikely)
/// - the indices in the `DeBruijn` notation mode start with 1 and are hexadecimal digits
///
/// # Example
/// ```
/// use lambda_calculus::parser::*;
/// use lambda_calculus::church::numerals::{succ, pred};
///
/// assert_eq!(parse(&"λn. λf. λx. n (λg. λh. h (g f)) (λu. x) (λu. u)", Classic), Ok(pred()));
/// assert_eq!(parse(&"λn.λf.λx.n(λg.λh.h(g f))(λu.x)(λu.u)", Classic), Ok(pred()));
///
/// assert_eq!(parse(  &"λλλ2(321)",  DeBruijn), Ok(succ()));
/// assert_eq!(parse(&r#"\\\2(321)"#, DeBruijn), Ok(succ()));
/// ```
pub fn parse(input: &str, notation: Notation) -> Result<Term, Error> {
    let tokens = if notation == DeBruijn {
        try!(tokenize_dbr(input))
    } else {
        convert_classic_tokens(&try!(tokenize_cla(input)))
    };
    let ast = try!(get_ast(&tokens));

    let exprs = try!(if let Sequence(exprs) = ast { Ok(exprs) } else { Err(InvalidExpression) });

    fold_exprs(&exprs)
}

fn fold_exprs(exprs: &[Expression]) -> Result<Term, Error> {
    let mut depth  = 0;
    let mut output = Vec::new();

    for expr in exprs.iter() {
        match *expr {
            Variable(i) => output.push(Var(i)),
            Abstraction => depth += 1,
            Sequence(ref exprs) => {
                let subexpr = try!(fold_exprs(exprs));
                output.push(subexpr)
            }
        }
    }

    let mut ret = try!(fold_terms(output));

    for _ in 0..depth {
        ret = abs(ret);
    }

    Ok(ret)
}

fn fold_terms(mut terms: Vec<Term>) -> Result<Term, Error> {
    if terms.len() > 1 {
        let fst = terms.remove(0);
        Ok( terms.into_iter().fold(fst, app) )
    } else if terms.len() == 1 {
        Ok( terms.pop().unwrap() ) // safe; ensured above
    } else {
        Err(EmptyExpression)
    }
}

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

    #[test]
    fn tokenization_error() {
        assert_eq!(tokenize_dbr(&"λλx2"),    Err(InvalidCharacter((3, 'x'))));
        assert_eq!(tokenize_cla(&"λa.λb a"), Err(InvalidCharacter((6, ' '))));
    }

    #[test]
    fn tokenization_success() {
        let quine = "λ 1 ( (λ 1 1) (λ λ λ λ λ 1 4 (3 (5 5) 2) ) ) 1";
        let tokens = tokenize_dbr(&quine);

        assert!(tokens.is_ok());
        assert_eq!(tokens.unwrap(), vec![Lambda, Number(1), Lparen, Lparen, Lambda, Number(1),
            Number(1), Rparen, Lparen, Lambda, Lambda, Lambda, Lambda, Lambda, Number(1),
            Number(4), Lparen, Number(3), Lparen, Number(5), Number(5), Rparen, Number(2),
            Rparen, Rparen, Rparen, Number(1)]);
    }

    #[test]
    fn tokenization_success_classic() {
        let blc_dbr = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
            (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        let blc_cla = format!("{}", parse(&blc_dbr, DeBruijn).unwrap());

        let tokens_cla = tokenize_cla(&blc_cla);
        let tokens_dbr = tokenize_dbr(&blc_dbr);

        assert!(tokens_cla.is_ok());
        assert!(tokens_dbr.is_ok());

        assert_eq!(convert_classic_tokens(&tokens_cla.unwrap()), tokens_dbr.unwrap());
    }

    #[test]
    fn alternative_lambda_parsing() {
        assert_eq!(parse(&r#"\\\2(321)"#, DeBruijn), parse(&"λλλ2(321)", DeBruijn))
    }

    #[test]
    fn succ_ast() {
        let tokens = tokenize_dbr(&"λλλ2(321)").unwrap();
        let ast = get_ast(&tokens);

        assert_eq!(ast,
            Ok(Sequence(vec![
                Abstraction,
                Abstraction,
                Abstraction,
                Variable(2),
                Sequence(vec![
                    Variable(3),
                    Variable(2),
                    Variable(1)
                ])
            ])
        ));
    }

    #[test]
    fn parse_y() {
        let y = "λ(λ2(11))(λ2(11))";
        assert_eq!(parse(&y, DeBruijn).unwrap(),
            abs(
                app(
                    abs(app(Var(2), app(Var(1), Var(1)))),
                    abs(app(Var(2), app(Var(1), Var(1))))
                )
            )
        );
    }

    #[test]
    fn parse_quine() {
        let quine = "λ1((λ11)(λλλλλ14(3(55)2)))1";
        assert_eq!(parse(&quine, DeBruijn).unwrap(),
            abs(app(app(Var(1), app(abs(app(Var(1), Var(1))), abs(abs(abs(abs(abs(app(app(Var(1),
            Var(4)), app(app(Var(3), app(Var(5), Var(5))), Var(2)))))))))), Var(1)))
        );
    }

    #[test]
    fn parse_blc() {
        let blc = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
                   (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        assert_eq!(parse(&blc, DeBruijn).unwrap(),
            app(app(abs(app(Var(1), Var(1))), abs(abs(abs(app(app(app(Var(1),
            abs(abs(abs(abs(app(Var(3), abs(app(app(Var(5), app(Var(3), abs(app(app(Var(2),
            app(Var(3), abs(abs(app(Var(3), abs(app(app(Var(1), Var(2)), Var(3)))))))), app(Var(4),
            abs(app(Var(4), abs(app(app(Var(3), Var(1)), app(Var(2), Var(1))))))))))),
            app(app(Var(1), app(Var(2), abs(app(Var(1), Var(2))))), abs(app(app(Var(4),
            abs(app(Var(4), abs(app(Var(2), app(Var(1), Var(4))))))), Var(5)))))))))))),
            app(Var(3), Var(3))), Var(2)))))), abs(app(Var(1), app(abs(app(Var(1), Var(1))),
            abs(app(Var(1), Var(1)))))))
        );
    }
}
<commit_msg>parser doctest is now Church-independent<commit_after>//! A parser for lambda expressions

use term::{Term, Notation, abs, app};
use term::Term::*;
use self::Token::*;
use self::CToken::*;
use self::Error::*;
use self::Expression::*;
pub use term::Notation::*;

/// A type to represent a parsing error.
#[derive(Debug, PartialEq)]
pub enum Error {
    /// an invalid character was encountered
    InvalidCharacter((usize, char)),
    /// the expression is invalid
    InvalidExpression,
    /// the expression is empty
    EmptyExpression
}

#[derive(Debug, PartialEq)]
enum Token {
    /// λ or \
    Lambda,
    /// left parenthesis
    Lparen,
    /// right parenthesis
    Rparen,
    /// a number
    Number(usize)
}

#[derive(Debug, PartialEq)]
enum CToken {
    /// an abstraction with a bound variable
    CLambda(String),
    /// left parenthesis
    CLparen,
    /// right parenthesis
    CRparen,
    /// a variable with an identifier
    CName(String)
}

fn tokenize_dbr(input: &str) -> Result<Vec<Token>, Error> {
    let chars = input.chars().enumerate();
    let mut tokens = Vec::new();

    for (i, c) in chars {
        match c {
     '\\' | 'λ' => { tokens.push(Lambda) },
            '(' => { tokens.push(Lparen) },
            ')' => { tokens.push(Rparen) },
             _  => {
                if let Some(n) = c.to_digit(16) {
                    tokens.push(Number(n as usize))
                } else if c.is_whitespace() {
                    ()
                } else {
                    return Err(InvalidCharacter((i + 1, c)))
                }
            }
        }
    }

    Ok(tokens)
}

fn tokenize_cla(input: &str) -> Result<Vec<CToken>, Error> {
    let mut chars = input.chars().enumerate().peekable();
    let mut tokens = Vec::new();
    let valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    while let Some((i, c)) = chars.next() {
        match c {
            '\\' | 'λ' => {
                let mut name = String::new();
                while let Some((i, c)) = chars.next() {
                    if c == '.' {
                        break
                    } else if valid_chars.contains(c) {
                        name.push(c)
                    } else {
                        return Err(InvalidCharacter((i + 1, c)))
                    }
                }
                tokens.push(CLambda(name))
            },
            '(' => { tokens.push(CLparen) },
            ')' => { tokens.push(CRparen) },
             _  => {
                if c.is_whitespace() {
                    ()
                } else if valid_chars.contains(c) {
                    let mut name = c.to_string();
                    while let Some(&(_, c)) = chars.peek() {
                        if c.is_whitespace() || c == '(' || c == ')' {
                            break
                        } else {
                            name.push(c);
                            chars.next();
                        }
                    }
                    tokens.push(CName(name))
                } else {
                    return Err(InvalidCharacter((i + 1, c)))
                }
            }
        }
    }

    Ok(tokens)
}

fn convert_classic_tokens(tokens: &[CToken]) -> Vec<Token> {
    _convert_classic_tokens(tokens, &mut Vec::new(), &mut 0)
}

fn _convert_classic_tokens(tokens: &[CToken], stack: &mut Vec<String>, pos: &mut usize) -> Vec<Token>
{
    let mut output = Vec::with_capacity(tokens[*pos..].len());
    let mut inner_stack_count = 0;

    while let Some(token) = tokens.get(*pos) {
        match *token {
            CLambda(ref name) => {
                output.push(Lambda);
                stack.push(name.to_owned());
                inner_stack_count += 1;
            },
            CLparen => {
                output.push(Lparen);
                *pos += 1;
                output.append(&mut _convert_classic_tokens(tokens, stack, pos));
            },
            CRparen => {
                output.push(Rparen);
                for _ in 0..inner_stack_count { stack.pop(); }
                return output
            },
            CName(ref name) => {
                if let Some(index) = stack.iter().rev().position(|t| t == name) {
                    output.push(Number(index + 1))
                } else {
                    output.push(Number(stack.len() + 1))
                }
            }
        }
        *pos += 1;
    }

    output
}

#[derive(Debug, PartialEq)]
enum Expression {
    /// an abstraction
    Abstraction,
    /// a sequence of Expressions
    Sequence(Vec<Expression>),
    /// a variable with a De Bruijn index
    Variable(usize)
}

fn get_ast(tokens: &[Token]) -> Result<Expression, Error> {
    _get_ast(tokens, &mut 0)
}

fn _get_ast(tokens: &[Token], pos: &mut usize) -> Result<Expression, Error> {
    if tokens.is_empty() { return Err(EmptyExpression) }

    let mut expr = Vec::new();

    while let Some(token) = tokens.get(*pos) {
        match *token {
            Lambda => {
                expr.push(Abstraction)
            },
            Number(i) => {
                expr.push(Variable(i))
            },
            Lparen => {
                *pos += 1;
                let subtree = try!(_get_ast(tokens, pos));
                expr.push(subtree);
            },
            Rparen => {
                return Ok(Sequence(expr))
            }
        }
        *pos += 1;
    }

    Ok(Sequence(expr))
}

/// Parses the input `&str` as a lambda `Term`.
///
/// - lambdas can be represented either with the greek letter (λ) or a backslash (\\ -
/// less aesthetic, but only one byte in size)
/// - the identifiers in `Classic` mode are `String`s of ASCII alphabetic characters
/// - `Classic` mode ignores whitespaces where unambiguous
/// - `DeBruijn` mode ignores all whitespaces (since indices > 15 are very unlikely)
/// - the indices in the `DeBruijn` notation mode start with 1 and are hexadecimal digits
///
/// # Example
/// ```
/// use lambda_calculus::parser::*;
/// use lambda_calculus::combinators::{s, y};
///
/// assert_eq!(parse(&"λf.(λx.f (x x)) (λx.f (x x))", Classic), Ok(y()));
/// assert_eq!(parse(&"λf.(λx.f(x x))(λx.f(x x))", Classic),    Ok(y()));
///
/// assert_eq!(parse(  &"λλλ31(21)",     DeBruijn), Ok(s()));
/// assert_eq!(parse(&r#"\\\3 1 (2 1)"#, DeBruijn), Ok(s()));
/// ```
pub fn parse(input: &str, notation: Notation) -> Result<Term, Error> {
    let tokens = if notation == DeBruijn {
        try!(tokenize_dbr(input))
    } else {
        convert_classic_tokens(&try!(tokenize_cla(input)))
    };
    let ast = try!(get_ast(&tokens));

    let exprs = try!(if let Sequence(exprs) = ast { Ok(exprs) } else { Err(InvalidExpression) });

    fold_exprs(&exprs)
}

fn fold_exprs(exprs: &[Expression]) -> Result<Term, Error> {
    let mut depth  = 0;
    let mut output = Vec::new();

    for expr in exprs.iter() {
        match *expr {
            Variable(i) => output.push(Var(i)),
            Abstraction => depth += 1,
            Sequence(ref exprs) => {
                let subexpr = try!(fold_exprs(exprs));
                output.push(subexpr)
            }
        }
    }

    let mut ret = try!(fold_terms(output));

    for _ in 0..depth {
        ret = abs(ret);
    }

    Ok(ret)
}

fn fold_terms(mut terms: Vec<Term>) -> Result<Term, Error> {
    if terms.len() > 1 {
        let fst = terms.remove(0);
        Ok( terms.into_iter().fold(fst, app) )
    } else if terms.len() == 1 {
        Ok( terms.pop().unwrap() ) // safe; ensured above
    } else {
        Err(EmptyExpression)
    }
}

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

    #[test]
    fn tokenization_error() {
        assert_eq!(tokenize_dbr(&"λλx2"),    Err(InvalidCharacter((3, 'x'))));
        assert_eq!(tokenize_cla(&"λa.λb a"), Err(InvalidCharacter((6, ' '))));
    }

    #[test]
    fn tokenization_success() {
        let quine = "λ 1 ( (λ 1 1) (λ λ λ λ λ 1 4 (3 (5 5) 2) ) ) 1";
        let tokens = tokenize_dbr(&quine);

        assert!(tokens.is_ok());
        assert_eq!(tokens.unwrap(), vec![Lambda, Number(1), Lparen, Lparen, Lambda, Number(1),
            Number(1), Rparen, Lparen, Lambda, Lambda, Lambda, Lambda, Lambda, Number(1),
            Number(4), Lparen, Number(3), Lparen, Number(5), Number(5), Rparen, Number(2),
            Rparen, Rparen, Rparen, Number(1)]);
    }

    #[test]
    fn tokenization_success_classic() {
        let blc_dbr = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
            (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        let blc_cla = format!("{}", parse(&blc_dbr, DeBruijn).unwrap());

        let tokens_cla = tokenize_cla(&blc_cla);
        let tokens_dbr = tokenize_dbr(&blc_dbr);

        assert!(tokens_cla.is_ok());
        assert!(tokens_dbr.is_ok());

        assert_eq!(convert_classic_tokens(&tokens_cla.unwrap()), tokens_dbr.unwrap());
    }

    #[test]
    fn alternative_lambda_parsing() {
        assert_eq!(parse(&r#"\\\2(321)"#, DeBruijn), parse(&"λλλ2(321)", DeBruijn))
    }

    #[test]
    fn succ_ast() {
        let tokens = tokenize_dbr(&"λλλ2(321)").unwrap();
        let ast = get_ast(&tokens);

        assert_eq!(ast,
            Ok(Sequence(vec![
                Abstraction,
                Abstraction,
                Abstraction,
                Variable(2),
                Sequence(vec![
                    Variable(3),
                    Variable(2),
                    Variable(1)
                ])
            ])
        ));
    }

    #[test]
    fn parse_y() {
        let y = "λ(λ2(11))(λ2(11))";
        assert_eq!(parse(&y, DeBruijn).unwrap(),
            abs(
                app(
                    abs(app(Var(2), app(Var(1), Var(1)))),
                    abs(app(Var(2), app(Var(1), Var(1))))
                )
            )
        );
    }

    #[test]
    fn parse_quine() {
        let quine = "λ1((λ11)(λλλλλ14(3(55)2)))1";
        assert_eq!(parse(&quine, DeBruijn).unwrap(),
            abs(app(app(Var(1), app(abs(app(Var(1), Var(1))), abs(abs(abs(abs(abs(app(app(Var(1),
            Var(4)), app(app(Var(3), app(Var(5), Var(5))), Var(2)))))))))), Var(1)))
        );
    }

    #[test]
    fn parse_blc() {
        let blc = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))(1(2(λ12))\
                   (λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";
        assert_eq!(parse(&blc, DeBruijn).unwrap(),
            app(app(abs(app(Var(1), Var(1))), abs(abs(abs(app(app(app(Var(1),
            abs(abs(abs(abs(app(Var(3), abs(app(app(Var(5), app(Var(3), abs(app(app(Var(2),
            app(Var(3), abs(abs(app(Var(3), abs(app(app(Var(1), Var(2)), Var(3)))))))), app(Var(4),
            abs(app(Var(4), abs(app(app(Var(3), Var(1)), app(Var(2), Var(1))))))))))),
            app(app(Var(1), app(Var(2), abs(app(Var(1), Var(2))))), abs(app(app(Var(4),
            abs(app(Var(4), abs(app(Var(2), app(Var(1), Var(4))))))), Var(5)))))))))))),
            app(Var(3), Var(3))), Var(2)))))), abs(app(Var(1), app(abs(app(Var(1), Var(1))),
            abs(app(Var(1), Var(1)))))))
        );
    }
}
<|endoftext|>