<commit_before>//! TODO Documentation
use std::{fmt, panic};
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};

use errors::{UpgradeHandleErr, UpgradeHandleResult};
use wlroots_sys::{wlr_input_device, wlr_key_state, wlr_keyboard, wlr_keyboard_get_modifiers,
                  wlr_keyboard_led, wlr_keyboard_led_update, wlr_keyboard_modifier,
                  wlr_keyboard_set_keymap};

use xkbcommon::xkb::{self, Keymap};

use InputDevice;

/// The maximum number of keycodes stored in a `Keyboard`.
pub const WLR_KEYBOARD_KEYS_CAP: usize = 32;

pub type KeyState = wlr_key_state;

pub struct Keyboard {
    /// The structure that ensures weak handles to this structure are still alive.
    ///
    /// They contain weak handles, and will safely not use dead memory when this
    /// is freed by wlroots.
    ///
    /// If this is `None`, then this is from an upgraded `KeyboardHandle`, and
    /// the operations are **unchecked**.
    /// This is means safe operations might fail, but only if you use the unsafe
    /// marked function `upgrade` on a `KeyboardHandle`.
    liveliness: Option<Rc<AtomicBool>>,
    /// The device that refers to this keyboard.
    device: InputDevice,
    /// The underlying keyboard data.
    keyboard: *mut wlr_keyboard,
    /// The keymap used by wlroots.
    /// Stored here so that we can ensure you can only borrow the keymap
    /// as long as the keyboard.
    ///
    /// NOTE We have it marked as manually drop because otherwise
    /// we'd unref it twice (once here and again in wlroots).
    keymap: Option<ManuallyDrop<Keymap>>,
    /// The keyboard state used by wlroots.
    /// Stored here so that we can ensure you can only borrow the state
    /// as long as the keyboard.
    ///
    /// NOTE We have it marked as manually drop because otherwise
    /// we'd unref it twice (once here and again in wlroots).
    #[allow(dead_code)]
    xkb_state: Option<ManuallyDrop<xkb::State>>
}

pub struct KeyboardHandle {
    /// The Rc that ensures that this handle is still alive.
    ///
    /// When wlroots deallocates the keyboard associated with this handle,
    handle: Weak<AtomicBool>,
    /// The device that refers to this keyboard.
    device: InputDevice,
    /// The underlying keyboard data.
    keyboard: *mut wlr_keyboard,
    /// The keymap used by wlroots.
    /// Stored here so that we can ensure you can only borrow the keymap
    /// as long as the keyboard.
    ///
    /// NOTE We have it marked as manually drop because otherwise
    /// we'd unref it twice (once here and again in wlroots).
    #[allow(dead_code)]
    keymap: Option<ManuallyDrop<Keymap>>,
    /// The keyboard state used by wlroots.
    /// Stored here so that we can ensure you can only borrow the state
    /// as long as the keyboard.
    ///
    /// NOTE We have it marked as manually drop because otherwise
    /// we'd unref it twice (once here and again in wlroots).
    #[allow(dead_code)]
    xkb_state: Option<ManuallyDrop<xkb::State>>
}

impl Keyboard {
    /// Tries to convert an input device to a Keyboard
    ///
    /// Returns None if it is of a different type of input variant.
    ///
    /// # Safety
    /// This creates a totally new Keyboard (e.g with its own reference count)
    /// so only do this once per `wlr_input_device`!
    pub(crate) unsafe fn new_from_input_device(device: *mut wlr_input_device) -> Option<Self> {
        use wlroots_sys::wlr_input_device_type::*;
        match (*device).type_ {
            WLR_INPUT_DEVICE_KEYBOARD => {
                let keyboard = (*device).__bindgen_anon_1.keyboard;
                Some(Keyboard { liveliness: Some(Rc::new(AtomicBool::new(false))),
                                device: InputDevice::from_ptr(device),
                                keyboard,
                                keymap: None,
                                xkb_state: None })
            }
            _ => None
        }
    }

    unsafe fn from_handle(handle: &KeyboardHandle) -> Self {
        Keyboard { liveliness: None,
                   device: handle.input_device().clone(),
                   keyboard: handle.as_ptr(),
                   keymap: None,
                   xkb_state: None }
    }

    /// Gets the wlr_keyboard associated with this KeyboardHandle.
    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_keyboard {
        self.keyboard
    }

    /// Gets the wlr_input_device associated with this KeyboardHandle
    pub fn input_device(&self) -> &InputDevice {
        &self.device
    }

    /// Set the keymap for this Keyboard.
    pub fn set_keymap(&mut self, keymap: &Keymap) {
        unsafe {
            wlr_keyboard_set_keymap(self.keyboard, keymap.get_raw_ptr() as _);
        }
    }

    /// Get the XKB keymap associated with this `Keyboard`.
    pub fn get_keymap(&mut self) -> Option<&Keymap> {
        unsafe {
            let keymap_ptr = (*self.keyboard).keymap as *mut _;
            if keymap_ptr.is_null() {
                None
            } else {
                self.keymap = Some(ManuallyDrop::new(Keymap::from_raw_ptr(keymap_ptr)));
                self.keymap.as_ref().map(Deref::deref)
            }
        }
    }

    /// Get the XKB state associated with this `Keyboard`.
    pub fn get_xkb_state(&mut self) -> Option<&xkb::State> {
        unsafe {
            let xkb_state_ptr = (*self.keyboard).xkb_state as *mut _;
            if xkb_state_ptr.is_null() {
                None
            } else {
                self.xkb_state = Some(ManuallyDrop::new(xkb::State::from_raw_ptr(xkb_state_ptr)));
                self.xkb_state.as_ref().map(Deref::deref)
            }
        }
    }

    /// Update the LED lights using the provided bitmap.
    ///
    /// 1 means one, 0 means off.
    pub fn update_led(&mut self, leds: KeyboardLed) {
        unsafe {
            wlr_keyboard_led_update(self.keyboard, leds.bits() as u32);
        }
    }

    /// Get the modifiers that are currently pressed on the keyboard.
    pub fn get_modifiers(&self) -> KeyboardModifier {
        unsafe {
            KeyboardModifier::from_bits_truncate(wlr_keyboard_get_modifiers(self.keyboard))
        }
    }

    /// Creates a weak reference to a `Keyboard`.
    ///
    /// # Panics
    /// If this `Keyboard` is a previously upgraded `KeyboardHandle`,
    /// then this function will panic.
    pub fn weak_reference(&self) -> KeyboardHandle {
        let arc = self.liveliness.as_ref()
                      .expect("Cannot downgrade previously upgraded KeyboardHandle!");
        KeyboardHandle { handle: Rc::downgrade(arc),
                         // NOTE Rationale for cloning:
                         // We can't use the keyboard handle unless the keyboard is alive,
                         // which means the device pointer is still alive.
                         device: unsafe { self.device.clone() },
                         keyboard: self.keyboard,
                         keymap: None,
                         xkb_state: None }
    }

    /// Manually set the lock used to determine if a double-borrow is
    /// occuring on this structure.
    ///
    /// # Panics
    /// Panics when trying to set the lock on an upgraded handle.
    pub(crate) unsafe fn set_lock(&self, val: bool) {
        self.liveliness.as_ref()
            .expect("Tried to set lock on borrowed Keyboard")
            .store(val, Ordering::Release);
    }
}

impl Drop for Keyboard {
    fn drop(&mut self) {
        match self.liveliness {
            None => {}
            Some(ref liveliness) => {
                if Rc::strong_count(liveliness) == 1 {
                    wlr_log!(L_DEBUG, "Dropped Keyboard {:p}", self.keyboard);
                    let weak_count = Rc::weak_count(liveliness);
                    if weak_count > 0 {
                        wlr_log!(L_DEBUG,
                                 "Still {} weak pointers to Keyboard {:p}",
                                 weak_count,
                                 self.keyboard);
                    }
                }
            }
        }
    }
}

impl fmt::Debug for Keyboard {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f,
               "Keyboard {{ device: {:?}, keyboard: {:?} }}",
               self.device, self.keyboard)
    }
}

impl KeyboardHandle {
    /// Upgrades the keyboard handle to a reference to the backing `Keyboard`.
    ///
    /// # Unsafety
    /// This function is unsafe, because it creates an unbounded `Keyboard`
    /// which may live forever..
    /// But no keyboard lives forever and might be disconnected at any time.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    pub(crate) unsafe fn upgrade(&self) -> UpgradeHandleResult<Keyboard> {
        self.handle.upgrade()
            .ok_or(UpgradeHandleErr::DoubleUpgrade)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                let keyboard = Keyboard::from_handle(self);
                if check.load(Ordering::Acquire) {
                    return Err(UpgradeHandleErr::AlreadyBorrowed)
                }
                check.store(true, Ordering::Release);
                Ok(keyboard)
            })
    }

    /// Run a function on the referenced Keyboard, if it still exists
    ///
    /// Returns the result of the function, if successful
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the output
    /// to a short lived scope of an anonymous function,
    /// this function ensures the Keyboard does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if you run this function within the another run to the same `Output`.
    ///
    /// So don't nest `run` calls and everything will be ok :).
    pub fn run<F, R>(&mut self, runner: F) -> UpgradeHandleResult<Option<R>>
        where F: FnOnce(&mut Keyboard) -> R
    {
        let mut keyboard = unsafe { self.upgrade()? };
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| Some(runner(&mut keyboard))));
        self.handle.upgrade().map(|check| {
                                      // Sanity check that it hasn't been tampered with.
                                      if !check.load(Ordering::Acquire) {
                                          wlr_log!(L_ERROR,
                                                   "After running keyboard callback, mutable \
                                                    lock was false for: {:?}",
                                                   keyboard);
                                          panic!("Lock in incorrect state!");
                                      }
                                      check.store(false, Ordering::Release);
                                  });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }

    /// Gets the wlr_input_device associated with this KeyboardHandle
    pub fn input_device(&self) -> &InputDevice {
        &self.device
    }

    /// Gets the wlr_keyboard associated with this KeyboardHandle.
    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_keyboard {
        self.keyboard
    }
}

impl fmt::Debug for KeyboardHandle {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f,
               "Keyboard {{ device: {:?}, keyboard: {:?} }}",
               self.device, self.keyboard)
    }
}

bitflags! {
    pub struct KeyboardLed: u32 {
        const WLR_LED_NUM_LOCK = wlr_keyboard_led::WLR_LED_NUM_LOCK as u32;
        const WLR_LED_CAPS_LOCK = wlr_keyboard_led::WLR_LED_CAPS_LOCK as u32;
        const WLR_LED_SCROLL_LOCK = wlr_keyboard_led::WLR_LED_SCROLL_LOCK as u32;
    }
}

bitflags! {
    pub struct KeyboardModifier: u32 {
        const WLR_MODIFIER_SHIFT = wlr_keyboard_modifier::WLR_MODIFIER_SHIFT as u32;
        const WLR_MODIFIER_CAPS = wlr_keyboard_modifier::WLR_MODIFIER_CAPS as u32;
        const WLR_MODIFIER_CTRL = wlr_keyboard_modifier::WLR_MODIFIER_CTRL as u32;
        const WLR_MODIFIER_ALT = wlr_keyboard_modifier::WLR_MODIFIER_ALT as u32;
        const WLR_MODIFIER_MOD2 = wlr_keyboard_modifier::WLR_MODIFIER_MOD2 as u32;
        const WLR_MODIFIER_MOD3 = wlr_keyboard_modifier::WLR_MODIFIER_MOD3 as u32;
        const WLR_MODIFIER_LOGO = wlr_keyboard_modifier::WLR_MODIFIER_LOGO as u32;
        const WLR_MODIFIER_MOD5 = wlr_keyboard_modifier::WLR_MODIFIER_MOD5 as u32;
    }
}

impl fmt::Display for KeyboardModifier {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let mod_vec = vec![("Shift", KeyboardModifier::WLR_MODIFIER_SHIFT),
                           ("Caps lock", KeyboardModifier::WLR_MODIFIER_CAPS),
                           ("Ctrl", KeyboardModifier::WLR_MODIFIER_CTRL),
                           ("Alt", KeyboardModifier::WLR_MODIFIER_ALT),
                           ("Mod2", KeyboardModifier::WLR_MODIFIER_MOD2),
                           ("Mod3", KeyboardModifier::WLR_MODIFIER_MOD3),
                           ("Logo", KeyboardModifier::WLR_MODIFIER_LOGO),
                           ("Mod5", KeyboardModifier::WLR_MODIFIER_MOD5)];

        let mods: Vec<&str> = mod_vec.into_iter()
                                     .filter(|&(_, flag)| self.contains(flag))
                                     .map(|(st, _)| st)
                                     .collect();

        write!(formatter, "{:?}", mods)
    }
}
<commit_msg>Added rest of keyboard functions/attributes<commit_after>//! TODO Documentation
use std::{fmt, panic};
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};

use errors::{UpgradeHandleErr, UpgradeHandleResult};
use wlroots_sys::{wlr_input_device, wlr_key_state, wlr_keyboard, wlr_keyboard_get_modifiers,
                  wlr_keyboard_led, wlr_keyboard_led_update, wlr_keyboard_modifier,
                  wlr_keyboard_set_keymap};

use xkbcommon::xkb::{self, Keycode, Keymap, LedIndex, ModIndex, ModMask};

use InputDevice;

pub type KeyState = wlr_key_state;

/// The masks for each group of modifiers.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct ModifierMasks {
    pub depressed: ModMask,
    pub latched: ModMask,
    pub locked: ModMask,
    pub group: ModMask
}

/// Information about repeated keypresses for a particular Keyboard.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct RepeatInfo {
    /// The rate at which extended keypresses will fire more events.
    rate: i32,
    /// How long it takes for a keypress to register on this device.
    delay: i32
}

pub struct Keyboard {
    /// The structure that ensures weak handles to this structure are still alive.
    ///
    /// They contain weak handles, and will safely not use dead memory when this
    /// is freed by wlroots.
    ///
    /// If this is `None`, then this is from an upgraded `KeyboardHandle`, and
    /// the operations are **unchecked**.
    /// This is means safe operations might fail, but only if you use the unsafe
    /// marked function `upgrade` on a `KeyboardHandle`.
    liveliness: Option<Rc<AtomicBool>>,
    /// The device that refers to this keyboard.
    device: InputDevice,
    /// The underlying keyboard data.
    keyboard: *mut wlr_keyboard,
    /// The keymap used by wlroots.
    /// Stored here so that we can ensure you can only borrow the keymap
    /// as long as the keyboard.
    ///
    /// NOTE We have it marked as manually drop because otherwise
    /// we'd unref it twice (once here and again in wlroots).
    keymap: Option<ManuallyDrop<Keymap>>,
    /// The keyboard state used by wlroots.
    /// Stored here so that we can ensure you can only borrow the state
    /// as long as the keyboard.
    ///
    /// NOTE We have it marked as manually drop because otherwise
    /// we'd unref it twice (once here and again in wlroots).
    #[allow(dead_code)]
    xkb_state: Option<ManuallyDrop<xkb::State>>
}

pub struct KeyboardHandle {
    /// The Rc that ensures that this handle is still alive.
    ///
    /// When wlroots deallocates the keyboard associated with this handle,
    handle: Weak<AtomicBool>,
    /// The device that refers to this keyboard.
    device: InputDevice,
    /// The underlying keyboard data.
    keyboard: *mut wlr_keyboard,
    /// The keymap used by wlroots.
    /// Stored here so that we can ensure you can only borrow the keymap
    /// as long as the keyboard.
    ///
    /// NOTE We have it marked as manually drop because otherwise
    /// we'd unref it twice (once here and again in wlroots).
    #[allow(dead_code)]
    keymap: Option<ManuallyDrop<Keymap>>,
    /// The keyboard state used by wlroots.
    /// Stored here so that we can ensure you can only borrow the state
    /// as long as the keyboard.
    ///
    /// NOTE We have it marked as manually drop because otherwise
    /// we'd unref it twice (once here and again in wlroots).
    #[allow(dead_code)]
    xkb_state: Option<ManuallyDrop<xkb::State>>
}

impl Keyboard {
    /// Tries to convert an input device to a Keyboard
    ///
    /// Returns None if it is of a different type of input variant.
    ///
    /// # Safety
    /// This creates a totally new Keyboard (e.g with its own reference count)
    /// so only do this once per `wlr_input_device`!
    pub(crate) unsafe fn new_from_input_device(device: *mut wlr_input_device) -> Option<Self> {
        use wlroots_sys::wlr_input_device_type::*;
        match (*device).type_ {
            WLR_INPUT_DEVICE_KEYBOARD => {
                let keyboard = (*device).__bindgen_anon_1.keyboard;
                Some(Keyboard { liveliness: Some(Rc::new(AtomicBool::new(false))),
                                device: InputDevice::from_ptr(device),
                                keyboard,
                                keymap: None,
                                xkb_state: None })
            }
            _ => None
        }
    }

    unsafe fn from_handle(handle: &KeyboardHandle) -> Self {
        Keyboard { liveliness: None,
                   device: handle.input_device().clone(),
                   keyboard: handle.as_ptr(),
                   keymap: None,
                   xkb_state: None }
    }

    /// Gets the wlr_keyboard associated with this KeyboardHandle.
    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_keyboard {
        self.keyboard
    }

    /// Gets the wlr_input_device associated with this KeyboardHandle
    pub fn input_device(&self) -> &InputDevice {
        &self.device
    }

    /// Set the keymap for this Keyboard.
    pub fn set_keymap(&mut self, keymap: &Keymap) {
        unsafe {
            wlr_keyboard_set_keymap(self.keyboard, keymap.get_raw_ptr() as _);
        }
    }

    /// Get the XKB keymap associated with this Keyboard.
    pub fn get_keymap(&mut self) -> Option<&Keymap> {
        unsafe {
            let keymap_ptr = (*self.keyboard).keymap as *mut _;
            if keymap_ptr.is_null() {
                None
            } else {
                self.keymap = Some(ManuallyDrop::new(Keymap::from_raw_ptr(keymap_ptr)));
                self.keymap.as_ref().map(Deref::deref)
            }
        }
    }

    /// Get the keycodes for this keyboard as reported by XKB.
    ///
    /// # Limitations
    /// wlroots limits this list to `WLR_KEYBOARD_KEYS_CAP` elements,
    /// which at the time of writing is `32`.
    pub fn keycodes(&self) -> Vec<Keycode> {
        unsafe {
            let mut result = (*self.keyboard).keycodes.to_vec();
            result.truncate((*self.keyboard).num_keycodes);
            result
        }
    }

    /// Get the list of LEDs for this keyboard as reported by XKB.
    pub fn led_list(&self) -> Vec<LedIndex> {
        unsafe { (*self.keyboard).led_indexes.to_vec() }
    }

    /// Get the list of modifiers for this keyboard as reported by XKB.
    pub fn modifier_list(&self) -> Vec<ModIndex> {
        unsafe { (*self.keyboard).mod_indexes.to_vec() }
    }

    /// Get the size of the keymap.
    pub fn keymap_size(&self) -> usize {
        unsafe { (*self.keyboard).keymap_size }
    }

    /// Get the XKB state associated with this `Keyboard`.
    pub fn get_xkb_state(&mut self) -> Option<&xkb::State> {
        unsafe {
            let xkb_state_ptr = (*self.keyboard).xkb_state as *mut _;
            if xkb_state_ptr.is_null() {
                None
            } else {
                self.xkb_state = Some(ManuallyDrop::new(xkb::State::from_raw_ptr(xkb_state_ptr)));
                self.xkb_state.as_ref().map(Deref::deref)
            }
        }
    }

    /// Get the repeat info for this keyboard.
    pub fn repeat_info(&self) -> RepeatInfo {
        unsafe {
            RepeatInfo { rate: (*self.keyboard).repeat_info.rate,
                         delay: (*self.keyboard).repeat_info.delay }
        }
    }

    /// Update the LED lights using the provided bitmap.
    ///
    /// 1 means one, 0 means off.
    pub fn update_led(&mut self, leds: KeyboardLed) {
        unsafe {
            wlr_keyboard_led_update(self.keyboard, leds.bits() as u32);
        }
    }

    /// Get the modifiers that are currently pressed on the keyboard.
    pub fn get_modifiers(&self) -> KeyboardModifier {
        unsafe {
            KeyboardModifier::from_bits_truncate(wlr_keyboard_get_modifiers(self.keyboard))
        }
    }

    /// Get the modifier masks for each group.
    pub fn get_modifier_masks(&self) -> ModifierMasks {
        unsafe {
            ModifierMasks { depressed: (*self.keyboard).modifiers.depressed,
                            latched: (*self.keyboard).modifiers.latched,
                            locked: (*self.keyboard).modifiers.locked,
                            group: (*self.keyboard).modifiers.group }
        }
    }

    /// Creates a weak reference to a `Keyboard`.
    ///
    /// # Panics
    /// If this `Keyboard` is a previously upgraded `KeyboardHandle`,
    /// then this function will panic.
    pub fn weak_reference(&self) -> KeyboardHandle {
        let arc = self.liveliness.as_ref()
                      .expect("Cannot downgrade previously upgraded KeyboardHandle!");
        KeyboardHandle { handle: Rc::downgrade(arc),
                         // NOTE Rationale for cloning:
                         // We can't use the keyboard handle unless the keyboard is alive,
                         // which means the device pointer is still alive.
                         device: unsafe { self.device.clone() },
                         keyboard: self.keyboard,
                         keymap: None,
                         xkb_state: None }
    }

    /// Manually set the lock used to determine if a double-borrow is
    /// occuring on this structure.
    ///
    /// # Panics
    /// Panics when trying to set the lock on an upgraded handle.
    pub(crate) unsafe fn set_lock(&self, val: bool) {
        self.liveliness.as_ref()
            .expect("Tried to set lock on borrowed Keyboard")
            .store(val, Ordering::Release);
    }
}

impl Drop for Keyboard {
    fn drop(&mut self) {
        match self.liveliness {
            None => {}
            Some(ref liveliness) => {
                if Rc::strong_count(liveliness) == 1 {
                    wlr_log!(L_DEBUG, "Dropped Keyboard {:p}", self.keyboard);
                    let weak_count = Rc::weak_count(liveliness);
                    if weak_count > 0 {
                        wlr_log!(L_DEBUG,
                                 "Still {} weak pointers to Keyboard {:p}",
                                 weak_count,
                                 self.keyboard);
                    }
                }
            }
        }
    }
}

impl fmt::Debug for Keyboard {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f,
               "Keyboard {{ device: {:?}, keyboard: {:?} }}",
               self.device, self.keyboard)
    }
}

impl KeyboardHandle {
    /// Upgrades the keyboard handle to a reference to the backing `Keyboard`.
    ///
    /// # Unsafety
    /// This function is unsafe, because it creates an unbounded `Keyboard`
    /// which may live forever..
    /// But no keyboard lives forever and might be disconnected at any time.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    pub(crate) unsafe fn upgrade(&self) -> UpgradeHandleResult<Keyboard> {
        self.handle.upgrade()
            .ok_or(UpgradeHandleErr::DoubleUpgrade)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                let keyboard = Keyboard::from_handle(self);
                if check.load(Ordering::Acquire) {
                    return Err(UpgradeHandleErr::AlreadyBorrowed)
                }
                check.store(true, Ordering::Release);
                Ok(keyboard)
            })
    }

    /// Run a function on the referenced Keyboard, if it still exists
    ///
    /// Returns the result of the function, if successful
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the output
    /// to a short lived scope of an anonymous function,
    /// this function ensures the Keyboard does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if you run this function within the another run to the same `Output`.
    ///
    /// So don't nest `run` calls and everything will be ok :).
    pub fn run<F, R>(&mut self, runner: F) -> UpgradeHandleResult<Option<R>>
        where F: FnOnce(&mut Keyboard) -> R
    {
        let mut keyboard = unsafe { self.upgrade()? };
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| Some(runner(&mut keyboard))));
        self.handle.upgrade().map(|check| {
                                      // Sanity check that it hasn't been tampered with.
                                      if !check.load(Ordering::Acquire) {
                                          wlr_log!(L_ERROR,
                                                   "After running keyboard callback, mutable \
                                                    lock was false for: {:?}",
                                                   keyboard);
                                          panic!("Lock in incorrect state!");
                                      }
                                      check.store(false, Ordering::Release);
                                  });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }

    /// Gets the wlr_input_device associated with this KeyboardHandle
    pub fn input_device(&self) -> &InputDevice {
        &self.device
    }

    /// Gets the wlr_keyboard associated with this KeyboardHandle.
    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_keyboard {
        self.keyboard
    }
}

impl fmt::Debug for KeyboardHandle {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f,
               "Keyboard {{ device: {:?}, keyboard: {:?} }}",
               self.device, self.keyboard)
    }
}

bitflags! {
    pub struct KeyboardLed: u32 {
        const WLR_LED_NUM_LOCK = wlr_keyboard_led::WLR_LED_NUM_LOCK as u32;
        const WLR_LED_CAPS_LOCK = wlr_keyboard_led::WLR_LED_CAPS_LOCK as u32;
        const WLR_LED_SCROLL_LOCK = wlr_keyboard_led::WLR_LED_SCROLL_LOCK as u32;
    }
}

bitflags! {
    pub struct KeyboardModifier: u32 {
        const WLR_MODIFIER_SHIFT = wlr_keyboard_modifier::WLR_MODIFIER_SHIFT as u32;
        const WLR_MODIFIER_CAPS = wlr_keyboard_modifier::WLR_MODIFIER_CAPS as u32;
        const WLR_MODIFIER_CTRL = wlr_keyboard_modifier::WLR_MODIFIER_CTRL as u32;
        const WLR_MODIFIER_ALT = wlr_keyboard_modifier::WLR_MODIFIER_ALT as u32;
        const WLR_MODIFIER_MOD2 = wlr_keyboard_modifier::WLR_MODIFIER_MOD2 as u32;
        const WLR_MODIFIER_MOD3 = wlr_keyboard_modifier::WLR_MODIFIER_MOD3 as u32;
        const WLR_MODIFIER_LOGO = wlr_keyboard_modifier::WLR_MODIFIER_LOGO as u32;
        const WLR_MODIFIER_MOD5 = wlr_keyboard_modifier::WLR_MODIFIER_MOD5 as u32;
    }
}

impl fmt::Display for KeyboardModifier {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let mod_vec = vec![("Shift", KeyboardModifier::WLR_MODIFIER_SHIFT),
                           ("Caps lock", KeyboardModifier::WLR_MODIFIER_CAPS),
                           ("Ctrl", KeyboardModifier::WLR_MODIFIER_CTRL),
                           ("Alt", KeyboardModifier::WLR_MODIFIER_ALT),
                           ("Mod2", KeyboardModifier::WLR_MODIFIER_MOD2),
                           ("Mod3", KeyboardModifier::WLR_MODIFIER_MOD3),
                           ("Logo", KeyboardModifier::WLR_MODIFIER_LOGO),
                           ("Mod5", KeyboardModifier::WLR_MODIFIER_MOD5)];

        let mods: Vec<&str> = mod_vec.into_iter()
                                     .filter(|&(_, flag)| self.contains(flag))
                                     .map(|(st, _)| st)
                                     .collect();

        write!(formatter, "{:?}", mods)
    }
}
<|endoftext|>


<commit_before>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;
use std::ffi::OsStr;
// use std::io::Error;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
// use std::ptr::null_mut;
use std::mem;
use self::winapi::winuser::{WNDCLASSW,CS_HREDRAW,CS_VREDRAW,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,MSG,WS_VISIBLE,PM_REMOVE,WM_PAINT,WM_SIZE,WM_CLOSE,WM_ACTIVATEAPP,PAINTSTRUCT};
use self::winapi::windef::{HWND,HBRUSH,HMENU};
use self::winapi::minwindef::{UINT,WPARAM,LPARAM,LRESULT,LPVOID};
use self::winapi::wingdi::{WHITENESS,BLACKNESS, PATINVERT};

static mut GLOBAL_RUNNING: bool = true; //TODO: Whats the correct way to scope something like this?

pub fn main() {

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }
        }
    }
}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
        match msg {
            WM_SIZE => { println!("WM_SIZE"); },
            WM_CLOSE => {  GLOBAL_RUNNING = false; },
            WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
            WM_PAINT => {
                let mut paint: PAINTSTRUCT = mem::uninitialized();
                let hdc = user32::BeginPaint(hwnd, &mut paint);
                let x = paint.rcPaint.left;
                let y = paint.rcPaint.top;
                let width = paint.rcPaint.right - paint.rcPaint.left;
                let height = paint.rcPaint.bottom - paint.rcPaint.top;
                gdi32::PatBlt(hdc, x, y, width, height, PATINVERT);
            },
            _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
        };
        0
    }<commit_msg>Added destroy<commit_after>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;
use std::ffi::OsStr;
// use std::io::Error;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
// use std::ptr::null_mut;
use std::mem;
use self::winapi::winuser::{WNDCLASSW,CS_HREDRAW,CS_VREDRAW,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,MSG,WS_VISIBLE,PM_REMOVE,WM_PAINT,WM_SIZE,WM_CLOSE,WM_ACTIVATEAPP,WM_DESTROY,PAINTSTRUCT};
use self::winapi::windef::{HWND,HBRUSH,HMENU};
use self::winapi::minwindef::{UINT,WPARAM,LPARAM,LRESULT,LPVOID};
use self::winapi::wingdi::{WHITENESS,BLACKNESS, PATINVERT};

static mut GLOBAL_RUNNING: bool = true; //TODO: Whats the correct way to scope something like this?

pub fn main() {

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }
        }
    }
}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
        match msg {
            WM_SIZE => { println!("WM_SIZE"); },
            WM_CLOSE => {  GLOBAL_RUNNING = false;  },
            WM_DESTROY => { GLOBAL_RUNNING = false; },
            WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
            WM_PAINT => {
                let mut paint: PAINTSTRUCT = mem::uninitialized();
                let hdc = user32::BeginPaint(hwnd, &mut paint);
                let x = paint.rcPaint.left;
                let y = paint.rcPaint.top;
                let width = paint.rcPaint.right - paint.rcPaint.left;
                let height = paint.rcPaint.bottom - paint.rcPaint.top;
                gdi32::PatBlt(hdc, x, y, width, height, PATINVERT);
            },
            _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
        };
        0
    }<|endoftext|>


<commit_before>use rustc_serialize::json;

pub type XFlowEdge = [i32; 2];

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowStruct {
    pub id:           String,
    pub version:      i32,
    pub name:         String,
    pub requirements: Vec<XFlowRequirement>,
    pub variables:    XFlowVariables,
    pub nodes:        Vec<XFlowNode>,
    pub edges:        Vec<XFlowEdge>,
    pub branches:     Vec<XFlowBranch>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowRequirement {
    pub xtype:   String,
    pub version: i32,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariableDefinition {
    pub name:  String,
    pub vtype: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariable {
    pub name:  String,
    pub vtype: String,
    pub value: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariables {
    pub input:  Vec<XFlowVariable>,
    pub local:  Vec<XFlowVariable>,
    pub output: Vec<XFlowVariableDefinition>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowNode {
    pub id:       i32,
    pub nodetype: String,
    pub label:    String,
    pub action:   String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowBranch {
    pub name: String,
    pub edge: XFlowEdge,
}

impl XFlowStruct {
    /// Constructs a new `XFlowStruct`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// ```
    pub fn new() -> XFlowStruct {
        XFlowStruct {
            id:          "".to_string(),
            name:        "".to_string(),
            version:      1,
            requirements: Vec::<XFlowRequirement>::new(),
            variables:    XFlowVariables {
                input:  Vec::<XFlowVariable>::new(),
                local:  Vec::<XFlowVariable>::new(),
                output: Vec::<XFlowVariableDefinition>::new(),
            },
            nodes:        Vec::<XFlowNode>::new(),
            edges:        Vec::<XFlowEdge>::new(),
            branches:     Vec::<XFlowBranch>::new(),
        }
    }

    /// Return a string representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_string();
    /// ```
    pub fn to_string(&self) -> String {
        format!("xflow {}", self.id)
    }

    pub fn get_entry_nodes(&self) -> Vec<XFlowNode> {

        self.get_nodes_by(
            "flow".to_string(),
            "start".to_string()
            )
    }

    /// Get `XFlowNode`s of `nodetype` and `action`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_by("flow".to_string(), "start".to_string());
    /// ```
    pub fn get_nodes_by(&self, nodetype:String, action:String) -> Vec<XFlowNode> {

        let res:Vec<XFlowNode> = self.nodes.iter().cloned().filter({|node|
            node.nodetype == nodetype &&
                node.action == action
        }).collect();

        res
    }

    /// Get `XFlowNode`s of `nodetype`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_of_type("flow".to_string());
    /// ```
    pub fn get_nodes_of_type(&self, nodetype:String) -> Vec<XFlowNode> {

        let res:Vec<XFlowNode> = self.nodes.iter().cloned().filter({|node|
            node.nodetype == nodetype
        }).collect();

        res
    }

    /// Return a JSON representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_json();
    /// ```
    pub fn to_json(&self) -> String {
        json::encode(&self).unwrap()
    }

    /// Initialize a XFlowStruct from a JSON string
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    ///
    /// let empty_flow = "{\"id\":\"empty\",\"name\":\"empty\",\"version\":1,\"requirements\":[{\"xtype\":\"flow\",\"version\":1},{\"xtype\":\"flox\",\"version\":1}],\"variables\":{\"input\":[],\"output\":[],\"local\":[]},\"nodes\":[],\"edges\":[],\"branches\":[]}".to_string();
    ///
    /// let xfs = XFlowStruct::from_json(empty_flow);
    /// ```
    pub fn from_json(json_string:String) -> XFlowStruct {
        let xfs:XFlowStruct = json::decode(&json_string).unwrap();
        xfs
    }

    pub fn get_in_edges(&self, node:XFlowNode) -> Vec<XFlowEdge> {

        let res:Vec<XFlowEdge> = self.edges.iter().cloned().filter({|edge|
            edge[1] == node.id
        }).collect();

        res
    }

    pub fn get_out_edges(&self, node:XFlowNode) -> Vec<XFlowEdge> {

        let res:Vec<XFlowEdge> = self.edges.iter().cloned().filter({|edge|
            edge[0] == node.id
        }).collect();

        res
    }

    pub fn get_branches_for(&self, edge:XFlowEdge) -> Vec<XFlowBranch> {

        let res:Vec<XFlowBranch> = self.branches.iter().cloned().filter({|branch|
            edge[0] == branch.edge[0] &&
                edge[1] == branch.edge[1]
        }).collect();

        res

    }

}

<commit_msg>Use references for xfstruct impl functions<commit_after>use rustc_serialize::json;

pub type XFlowEdge = [i32; 2];

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowStruct {
    pub id:           String,
    pub version:      i32,
    pub name:         String,
    pub requirements: Vec<XFlowRequirement>,
    pub variables:    XFlowVariables,
    pub nodes:        Vec<XFlowNode>,
    pub edges:        Vec<XFlowEdge>,
    pub branches:     Vec<XFlowBranch>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowRequirement {
    pub xtype:   String,
    pub version: i32,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariableDefinition {
    pub name:  String,
    pub vtype: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariable {
    pub name:  String,
    pub vtype: String,
    pub value: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariables {
    pub input:  Vec<XFlowVariable>,
    pub local:  Vec<XFlowVariable>,
    pub output: Vec<XFlowVariableDefinition>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowNode {
    pub id:       i32,
    pub nodetype: String,
    pub label:    String,
    pub action:   String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowBranch {
    pub name: String,
    pub edge: XFlowEdge,
}

impl XFlowStruct {
    /// Constructs a new `XFlowStruct`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// ```
    pub fn new() -> XFlowStruct {
        XFlowStruct {
            id:          "".to_string(),
            name:        "".to_string(),
            version:      1,
            requirements: Vec::<XFlowRequirement>::new(),
            variables:    XFlowVariables {
                input:  Vec::<XFlowVariable>::new(),
                local:  Vec::<XFlowVariable>::new(),
                output: Vec::<XFlowVariableDefinition>::new(),
            },
            nodes:        Vec::<XFlowNode>::new(),
            edges:        Vec::<XFlowEdge>::new(),
            branches:     Vec::<XFlowBranch>::new(),
        }
    }

    /// Return a string representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_string();
    /// ```
    pub fn to_string(&self) -> String {
        format!("xflow {}", self.id)
    }

    pub fn get_entry_nodes(&self) -> Vec<&XFlowNode> {

        self.get_nodes_by(
            "flow".to_string(),
            "start".to_string()
            )
    }

    /// Get `XFlowNode`s of `nodetype` and `action`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_by("flow".to_string(), "start".to_string());
    /// ```
    pub fn get_nodes_by(&self, nodetype:String, action:String) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype &&
                node.action == action
        }).collect();

        res
    }

    /// Get `XFlowNode`s of `nodetype`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_of_type("flow".to_string());
    /// ```
    pub fn get_nodes_of_type(&self, nodetype:String) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype
        }).collect();

        res
    }

    /// Return a JSON representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_json();
    /// ```
    pub fn to_json(&self) -> String {
        json::encode(&self).unwrap()
    }

    /// Initialize a XFlowStruct from a JSON string
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    ///
    /// let empty_flow = "{\"id\":\"empty\",\"name\":\"empty\",\"version\":1,\"requirements\":[{\"xtype\":\"flow\",\"version\":1},{\"xtype\":\"flox\",\"version\":1}],\"variables\":{\"input\":[],\"output\":[],\"local\":[]},\"nodes\":[],\"edges\":[],\"branches\":[]}".to_string();
    ///
    /// let xfs = XFlowStruct::from_json(empty_flow);
    /// ```
    pub fn from_json(json_string:String) -> XFlowStruct {
        let xfs:XFlowStruct = json::decode(&json_string).unwrap();
        xfs
    }

    pub fn get_in_edges(&self, node:XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge[1] == node.id
        }).collect();

        res
    }

    pub fn get_out_edges(&self, node:XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge[0] == node.id
        }).collect();

        res
    }

    pub fn get_branches_for(&self, edge:XFlowEdge) -> Vec<&XFlowBranch> {

        let res:Vec<&XFlowBranch> = self.branches.iter().filter({|branch|
            edge[0] == branch.edge[0] &&
                edge[1] == branch.edge[1]
        }).collect();

        res

    }

}

<|endoftext|>


<commit_before>use regex::Regex;
use std::collections::HashSet;
use std::fmt;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR;
use std::str;
use tempfile::NamedTempFile;

use protobuf::descriptor::field_descriptor_proto;
use protobuf::descriptor::DescriptorProto;
use protobuf::descriptor::EnumDescriptorProto;
use protobuf::descriptor::FieldDescriptorProto;
use protobuf::descriptor::FileDescriptorProto;
use protobuf::descriptor::FileDescriptorSet;
use protobuf::descriptor::OneofDescriptorProto;
use protobuf::text_format::lexer::float::parse_protobuf_float;
use protobuf::RepeatedField;
use protobuf_test_common::build::copy_tests_v2_v3;
use protobuf_test_common::build::glob_simple;
use std::process::Command;
use std::process::Stdio;

fn to_paths(iter: impl IntoIterator<Item = impl Into<String>>) -> Vec<PathBuf> {
    iter.into_iter()
        .map(|item| item.into().replace(MAIN_SEPARATOR, "/").into())
        .collect()
}

#[derive(Default, Debug)]
struct TestStats {
    passed: u32,
    passed_marked_skip: u32,
    skipped: u32,
    failed: u32,
}

fn normalize_generated_file(contents: &str) -> String {
    let parsed_by = Regex::new("^// \\.proto file is parsed by.*").unwrap();

    let mut r = String::new();
    let mut inside_descriptor_data = false;
    for line in contents.lines() {
        let line = if inside_descriptor_data {
            if line == "\";" {
                inside_descriptor_data = false;
                line.to_owned()
            } else {
                continue;
            }
        } else if line.starts_with("static file_descriptor_proto_data") {
            inside_descriptor_data = true;
            line.to_owned()
        } else {
            parsed_by.replace(line, "").into_owned()
        };

        writeln!(&mut r, "{}", line).unwrap();
    }

    // sanity check
    assert!(!inside_descriptor_data);

    r
}

fn normalize_generated_file_in_place(path: &Path) {
    let contents = fs::read_to_string(path).unwrap();
    let contents = normalize_generated_file(&contents);
    fs::write(path, &contents).unwrap();
}

fn print_diff(dir: &Path, a: &Path, b: &Path) {
    if cfg!(windows) {
        // likely we don't have `diff` command on Windows
        return;
    }

    // sanity check
    let mut a_full = dir.to_path_buf();
    a_full.push(a);
    assert!(a_full.exists());
    let mut b_full = dir.to_path_buf();
    b_full.push(b);
    assert!(b_full.exists());

    // Not using difference crate because it's slow for large files
    let output = Command::new("diff")
        .current_dir(dir)
        .arg("-u")
        .arg(a)
        .arg(b)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .unwrap();

    print!("{}", str::from_utf8(&output.stdout).unwrap());
    print!("{}", str::from_utf8(&output.stderr).unwrap());
}

fn protoc_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut temp_file = NamedTempFile::new().unwrap();
    protoc::Protoc::from_env_path()
        .descriptor_set_out_args()
        .out(temp_file.path())
        .includes(includes)
        .inputs(inputs)
        .write_descriptor_set()
        .unwrap();
    protobuf::parse_from_reader(&mut temp_file).unwrap()
}

// TODO: expose this utility from protobuf-codegen-pure crate.
fn pure_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut codegen = protobuf_codegen_pure::parse_and_typecheck(includes, inputs).unwrap();
    let relative_paths: HashSet<_> = codegen
        .relative_paths
        .iter()
        .map(|path| path.to_string_lossy())
        .collect();
    codegen
        .file_descriptors
        .retain(|fd| relative_paths.contains(fd.get_name()));
    let mut fds = FileDescriptorSet::new();
    fds.file = RepeatedField::from_vec(codegen.file_descriptors);
    fds
}

fn normalize_descriptor_set(fds: &mut FileDescriptorSet) {
    for desc in &mut fds.file {
        normalize_file_descriptor(desc)
    }
}

fn normalize_file_descriptor(desc: &mut FileDescriptorProto) {
    if !desc.has_syntax() {
        desc.set_syntax("proto2".into())
    }
    for desc in &mut *desc.message_type {
        normalize_descriptor(desc)
    }
    for desc in &mut desc.enum_type {
        normalize_enum_descriptor(desc)
    }

    for desc in &mut desc.extension {
        desc.options.mut_or_default();
    }
    desc.options.mut_or_default();

    // TODO: don't clear services.
    desc.service.clear();

    // for unittest_custom_options.proto where a custom option
    // is an extension. Probably nobody outside of Google uses it.
    desc.options
        .mut_or_default()
        .unknown_fields
        .remove(15478479);
}

fn normalize_enum_descriptor(desc: &mut EnumDescriptorProto) {
    desc.options.mut_or_default();

    for value in &mut desc.value {
        value.options.mut_or_default();
    }
}

fn normalize_oneof_descriptor(desc: &mut OneofDescriptorProto) {
    desc.options.mut_or_default();
}

fn normalize_descriptor(desc: &mut DescriptorProto) {
    for desc in &mut desc.nested_type {
        normalize_descriptor(desc);
    }
    for desc in &mut desc.enum_type {
        normalize_enum_descriptor(desc);
    }
    for desc in &mut desc.oneof_decl {
        normalize_oneof_descriptor(desc);
    }

    // TODO: don't clear options.
    desc.options.clear();

    for field in &mut desc.field {
        normalize_field(field);
    }

    for ext in &mut desc.extension {
        ext.options.mut_or_default();
    }

    for ext in &mut desc.extension_range {
        // If ext range end exceeds max field number,
        // the actual upper limit does not matter.
        // protoc is not consistent in behavior thus flush
        // the value to some arbitrary compatible value.
        if ext.has_end() && ext.get_end() >= 0x20000000 {
            ext.set_end(0x20000000);
        }
    }
}

fn normalize_field(field: &mut FieldDescriptorProto) {
    field.options.mut_or_default();

    if field.has_default_value() {
        if field.get_field_type() == field_descriptor_proto::Type::TYPE_FLOAT {
            field.set_default_value(format!(
                "{}",
                parse_protobuf_float(field.get_default_value()).unwrap()
            ));
        }
    }
}

fn pretty_message<M: protobuf::Message>(message: &M) -> String {
    // TODO: pull this handy utility into the protobuf crate.
    struct FormatMessage<'a, M>(&'a M);

    impl<M: protobuf::Message> fmt::Display for FormatMessage<'_, M> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            protobuf::text_format::fmt(self.0, f)
        }
    }

    format!("{:#}", FormatMessage(message))
}

fn descriptor_for_file<'a>(fds: &'a FileDescriptorSet, file_name: &str) -> &'a FileDescriptorProto {
    for file in &fds.file {
        if Path::new(file.get_name()).file_name().unwrap()
            == Path::new(file_name).file_name().unwrap()
        {
            return file;
        }
    }
    panic!(
        "file not found: {}; all files: {}",
        file_name,
        fds.file
            .iter()
            .map(|f| f.get_name())
            .collect::<Vec<_>>()
            .join(", ")
    );
}

fn test_diff_in<F>(root: &str, sources_dir: &str, include: &str, should_skip: F)
where
    F: Fn(&str) -> bool,
{
    let mut stats = TestStats {
        passed: 0,
        passed_marked_skip: 0,
        skipped: 0,
        failed: 0,
    };

    let mut include_root = Path::new(root).to_path_buf();
    include_root.push(include);

    let include_full = format!("{}/{}", root, include);
    let s_full = format!("{}/{}", root, sources_dir);

    let inputs_glob = format!("{}/*.proto", s_full);
    let inputs = to_paths(glob_simple(&inputs_glob));
    assert!(!inputs.is_empty(), "glob is empty: {}", inputs_glob);
    let includes = to_paths(vec![include_full.as_str(), "../proto"]);

    let temp_dir = tempfile::Builder::new()
        .prefix("protobuf-codegen-identical-test")
        .tempdir()
        .unwrap();

    let protoc_dir = format!("{}/protoc", temp_dir.path().to_str().unwrap());
    let pure_dir = format!("{}/pure", temp_dir.path().to_str().unwrap());

    fs::create_dir(&protoc_dir).unwrap();
    fs::create_dir(&pure_dir).unwrap();

    protoc_rust::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&protoc_dir)
        .run()
        .unwrap();

    protobuf_codegen_pure::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&pure_dir)
        .run()
        .unwrap();

    let mut protoc_descriptors = protoc_descriptor_set(&includes, &inputs);
    let mut pure_descriptors = pure_descriptor_set(&includes, &inputs);
    normalize_descriptor_set(&mut protoc_descriptors);
    normalize_descriptor_set(&mut pure_descriptors);

    for input in &inputs {
        let label = input.strip_prefix(root).unwrap().to_str().unwrap();
        let proto_file_name = input.strip_prefix(&include_root).unwrap().to_str().unwrap();
        let proto_name = input.file_name().unwrap().to_str().unwrap();
        let rs_name = protobuf_codegen::proto_name_to_rs(proto_name);
        let protoc_rs = format!("{}/{}", protoc_dir, rs_name);
        let pure_rs = format!("{}/{}", pure_dir, rs_name);

        normalize_generated_file_in_place(Path::new(&protoc_rs));
        normalize_generated_file_in_place(Path::new(&pure_rs));

        let protoc_rs_contents =
            fs::read_to_string(&protoc_rs).expect(&format!("while reading {}", protoc_rs));
        let pure_rs_contents =
            fs::read_to_string(&pure_rs).expect(&format!("while reading {}", pure_rs));

        let protoc_descriptor_for_file = descriptor_for_file(&protoc_descriptors, &proto_file_name);
        let pure_descriptor_for_file = descriptor_for_file(&pure_descriptors, &proto_file_name);

        let skip = should_skip(input.to_str().unwrap());
        if protoc_rs_contents == pure_rs_contents
            && protoc_descriptor_for_file == pure_descriptor_for_file
        {
            if !skip {
                stats.passed += 1;
                println!("{}: PASSED", label);
            } else {
                stats.passed_marked_skip += 1;
                println!("{}: PASSED BUT MARKED SKIP", label);
            }
        } else {
            if skip {
                stats.skipped += 1;
                println!("{} SKIPPED", label);
            } else {
                stats.failed += 1;
                println!("{} FAILED", label);
            }

            print_diff(
                temp_dir.path(),
                Path::new(&protoc_rs).strip_prefix(temp_dir.path()).unwrap(),
                Path::new(&pure_rs).strip_prefix(temp_dir.path()).unwrap(),
            );

            fs::write(
                format!("{}/{}.descriptors", protoc_dir, proto_name),
                pretty_message(protoc_descriptor_for_file),
            )
            .unwrap();
            fs::write(
                format!("{}/{}.descriptors", pure_dir, proto_name),
                pretty_message(pure_descriptor_for_file),
            )
            .unwrap();
            print_diff(
                temp_dir.path(),
                Path::new(&format!("protoc/{}.descriptors", proto_name)),
                Path::new(&format!("pure/{}.descriptors", proto_name)),
            );
        }
    }

    println!("{:?}", stats);
    assert!(stats.failed == 0, "at least one test failed");
}

fn should_skip_with_marker(path: &str) -> bool {
    fs::read_to_string(path)
        .unwrap()
        .contains("@skip-codegen-identical-test")
}

#[test]
fn common_v2() {
    test_diff_in(
        "../protobuf-test",
        "src/common/v2",
        "src/common/v2",
        should_skip_with_marker,
    );
}

#[test]
fn common_v3() {
    let common_v3_root = tempfile::Builder::new()
        .prefix("common-v3")
        .tempdir()
        .unwrap();
    fs::create_dir_all(format!(
        "{}/src/common/v3",
        common_v3_root.path().to_str().unwrap()
    ))
    .unwrap();

    copy_tests_v2_v3(
        "../protobuf-test/src/common/v2",
        &format!("{}/src/common/v3", common_v3_root.path().to_str().unwrap()),
    );

    test_diff_in(
        common_v3_root.path().to_str().unwrap(),
        "src/common/v3",
        "src/common/v3",
        should_skip_with_marker,
    );
}

#[test]
fn v2() {
    test_diff_in(
        "../protobuf-test",
        "src/v2",
        "src/v2",
        should_skip_with_marker,
    );
}

#[test]
fn v3() {
    test_diff_in(
        "../protobuf-test",
        "src/v3",
        "src/v3",
        should_skip_with_marker,
    );
}

#[test]
fn interop() {
    test_diff_in(
        "../protobuf-test",
        "../interop/cxx",
        "../interop/cxx",
        should_skip_with_marker,
    );
}

#[test]
fn google() {
    test_diff_in("../protobuf-test", "src/google/protobuf", "src", |_| false);
}
<commit_msg>Fix identical codegen test compilation<commit_after>use regex::Regex;
use std::collections::HashSet;
use std::fmt;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR;
use std::str;
use tempfile::NamedTempFile;

use protobuf::descriptor::field_descriptor_proto;
use protobuf::descriptor::DescriptorProto;
use protobuf::descriptor::EnumDescriptorProto;
use protobuf::descriptor::FieldDescriptorProto;
use protobuf::descriptor::FileDescriptorProto;
use protobuf::descriptor::FileDescriptorSet;
use protobuf::descriptor::OneofDescriptorProto;
use protobuf::text_format::lexer::float::parse_protobuf_float;
use protobuf::Message;
use protobuf_test_common::build::copy_tests_v2_v3;
use protobuf_test_common::build::glob_simple;
use std::process::Command;
use std::process::Stdio;

fn to_paths(iter: impl IntoIterator<Item = impl Into<String>>) -> Vec<PathBuf> {
    iter.into_iter()
        .map(|item| item.into().replace(MAIN_SEPARATOR, "/").into())
        .collect()
}

#[derive(Default, Debug)]
struct TestStats {
    passed: u32,
    passed_marked_skip: u32,
    skipped: u32,
    failed: u32,
}

fn normalize_generated_file(contents: &str) -> String {
    let parsed_by = Regex::new("^// \\.proto file is parsed by.*").unwrap();

    let mut r = String::new();
    let mut inside_descriptor_data = false;
    for line in contents.lines() {
        let line = if inside_descriptor_data {
            if line == "\";" {
                inside_descriptor_data = false;
                line.to_owned()
            } else {
                continue;
            }
        } else if line.starts_with("static file_descriptor_proto_data") {
            inside_descriptor_data = true;
            line.to_owned()
        } else {
            parsed_by.replace(line, "").into_owned()
        };

        writeln!(&mut r, "{}", line).unwrap();
    }

    // sanity check
    assert!(!inside_descriptor_data);

    r
}

fn normalize_generated_file_in_place(path: &Path) {
    let contents = fs::read_to_string(path).unwrap();
    let contents = normalize_generated_file(&contents);
    fs::write(path, &contents).unwrap();
}

fn print_diff(dir: &Path, a: &Path, b: &Path) {
    if cfg!(windows) {
        // likely we don't have `diff` command on Windows
        return;
    }

    // sanity check
    let mut a_full = dir.to_path_buf();
    a_full.push(a);
    assert!(a_full.exists());
    let mut b_full = dir.to_path_buf();
    b_full.push(b);
    assert!(b_full.exists());

    // Not using difference crate because it's slow for large files
    let output = Command::new("diff")
        .current_dir(dir)
        .arg("-u")
        .arg(a)
        .arg(b)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .unwrap();

    print!("{}", str::from_utf8(&output.stdout).unwrap());
    print!("{}", str::from_utf8(&output.stderr).unwrap());
}

fn protoc_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut temp_file = NamedTempFile::new().unwrap();
    protoc::Protoc::from_env_path()
        .descriptor_set_out_args()
        .out(temp_file.path())
        .includes(includes)
        .inputs(inputs)
        .write_descriptor_set()
        .unwrap();
    FileDescriptorSet::parse_from_reader(&mut temp_file).unwrap()
}

// TODO: expose this utility from protobuf-codegen-pure crate.
fn pure_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut codegen = protobuf_codegen_pure::parse_and_typecheck(includes, inputs).unwrap();
    let relative_paths: HashSet<_> = codegen
        .relative_paths
        .iter()
        .map(|path| path.to_string_lossy())
        .collect();
    codegen
        .file_descriptors
        .retain(|fd| relative_paths.contains(fd.get_name()));
    let mut fds = FileDescriptorSet::new();
    fds.file = codegen.file_descriptors;
    fds
}

fn normalize_descriptor_set(fds: &mut FileDescriptorSet) {
    for desc in &mut fds.file {
        normalize_file_descriptor(desc)
    }
}

fn normalize_file_descriptor(desc: &mut FileDescriptorProto) {
    if !desc.has_syntax() {
        desc.set_syntax("proto2".into())
    }
    for desc in &mut *desc.message_type {
        normalize_descriptor(desc)
    }
    for desc in &mut desc.enum_type {
        normalize_enum_descriptor(desc)
    }

    for desc in &mut desc.extension {
        desc.options.mut_or_default();
    }
    desc.options.mut_or_default();

    // TODO: don't clear services.
    desc.service.clear();

    // for unittest_custom_options.proto where a custom option
    // is an extension. Probably nobody outside of Google uses it.
    desc.options
        .mut_or_default()
        .unknown_fields
        .remove(15478479);
}

fn normalize_enum_descriptor(desc: &mut EnumDescriptorProto) {
    desc.options.mut_or_default();

    for value in &mut desc.value {
        value.options.mut_or_default();
    }
}

fn normalize_oneof_descriptor(desc: &mut OneofDescriptorProto) {
    desc.options.mut_or_default();
}

fn normalize_descriptor(desc: &mut DescriptorProto) {
    for desc in &mut desc.nested_type {
        normalize_descriptor(desc);
    }
    for desc in &mut desc.enum_type {
        normalize_enum_descriptor(desc);
    }
    for desc in &mut desc.oneof_decl {
        normalize_oneof_descriptor(desc);
    }

    // TODO: don't clear options.
    desc.options.clear();

    for field in &mut desc.field {
        normalize_field(field);
    }

    for ext in &mut desc.extension {
        ext.options.mut_or_default();
    }

    for ext in &mut desc.extension_range {
        // If ext range end exceeds max field number,
        // the actual upper limit does not matter.
        // protoc is not consistent in behavior thus flush
        // the value to some arbitrary compatible value.
        if ext.has_end() && ext.get_end() >= 0x20000000 {
            ext.set_end(0x20000000);
        }
    }
}

fn normalize_field(field: &mut FieldDescriptorProto) {
    field.options.mut_or_default();

    if field.has_default_value() {
        if field.get_field_type() == field_descriptor_proto::Type::TYPE_FLOAT {
            field.set_default_value(format!(
                "{}",
                parse_protobuf_float(field.get_default_value()).unwrap()
            ));
        }
    }
}

fn pretty_message<M: protobuf::Message>(message: &M) -> String {
    // TODO: pull this handy utility into the protobuf crate.
    struct FormatMessage<'a, M>(&'a M);

    impl<M: protobuf::Message> fmt::Display for FormatMessage<'_, M> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            protobuf::text_format::fmt(self.0, f)
        }
    }

    format!("{:#}", FormatMessage(message))
}

fn descriptor_for_file<'a>(fds: &'a FileDescriptorSet, file_name: &str) -> &'a FileDescriptorProto {
    for file in &fds.file {
        if Path::new(file.get_name()).file_name().unwrap()
            == Path::new(file_name).file_name().unwrap()
        {
            return file;
        }
    }
    panic!(
        "file not found: {}; all files: {}",
        file_name,
        fds.file
            .iter()
            .map(|f| f.get_name())
            .collect::<Vec<_>>()
            .join(", ")
    );
}

fn test_diff_in<F>(root: &str, sources_dir: &str, include: &str, should_skip: F)
where
    F: Fn(&str) -> bool,
{
    let mut stats = TestStats {
        passed: 0,
        passed_marked_skip: 0,
        skipped: 0,
        failed: 0,
    };

    let mut include_root = Path::new(root).to_path_buf();
    include_root.push(include);

    let include_full = format!("{}/{}", root, include);
    let s_full = format!("{}/{}", root, sources_dir);

    let inputs_glob = format!("{}/*.proto", s_full);
    let inputs = to_paths(glob_simple(&inputs_glob));
    assert!(!inputs.is_empty(), "glob is empty: {}", inputs_glob);
    let includes = to_paths(vec![include_full.as_str(), "../proto"]);

    let temp_dir = tempfile::Builder::new()
        .prefix("protobuf-codegen-identical-test")
        .tempdir()
        .unwrap();

    let protoc_dir = format!("{}/protoc", temp_dir.path().to_str().unwrap());
    let pure_dir = format!("{}/pure", temp_dir.path().to_str().unwrap());

    fs::create_dir(&protoc_dir).unwrap();
    fs::create_dir(&pure_dir).unwrap();

    protoc_rust::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&protoc_dir)
        .run()
        .unwrap();

    protobuf_codegen_pure::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&pure_dir)
        .run()
        .unwrap();

    let mut protoc_descriptors = protoc_descriptor_set(&includes, &inputs);
    let mut pure_descriptors = pure_descriptor_set(&includes, &inputs);
    normalize_descriptor_set(&mut protoc_descriptors);
    normalize_descriptor_set(&mut pure_descriptors);

    for input in &inputs {
        let label = input.strip_prefix(root).unwrap().to_str().unwrap();
        let proto_file_name = input.strip_prefix(&include_root).unwrap().to_str().unwrap();
        let proto_name = input.file_name().unwrap().to_str().unwrap();
        let rs_name = protobuf_codegen::proto_name_to_rs(proto_name);
        let protoc_rs = format!("{}/{}", protoc_dir, rs_name);
        let pure_rs = format!("{}/{}", pure_dir, rs_name);

        normalize_generated_file_in_place(Path::new(&protoc_rs));
        normalize_generated_file_in_place(Path::new(&pure_rs));

        let protoc_rs_contents =
            fs::read_to_string(&protoc_rs).expect(&format!("while reading {}", protoc_rs));
        let pure_rs_contents =
            fs::read_to_string(&pure_rs).expect(&format!("while reading {}", pure_rs));

        let protoc_descriptor_for_file = descriptor_for_file(&protoc_descriptors, &proto_file_name);
        let pure_descriptor_for_file = descriptor_for_file(&pure_descriptors, &proto_file_name);

        let skip = should_skip(input.to_str().unwrap());
        if protoc_rs_contents == pure_rs_contents
            && protoc_descriptor_for_file == pure_descriptor_for_file
        {
            if !skip {
                stats.passed += 1;
                println!("{}: PASSED", label);
            } else {
                stats.passed_marked_skip += 1;
                println!("{}: PASSED BUT MARKED SKIP", label);
            }
        } else {
            if skip {
                stats.skipped += 1;
                println!("{} SKIPPED", label);
            } else {
                stats.failed += 1;
                println!("{} FAILED", label);
            }

            print_diff(
                temp_dir.path(),
                Path::new(&protoc_rs).strip_prefix(temp_dir.path()).unwrap(),
                Path::new(&pure_rs).strip_prefix(temp_dir.path()).unwrap(),
            );

            fs::write(
                format!("{}/{}.descriptors", protoc_dir, proto_name),
                pretty_message(protoc_descriptor_for_file),
            )
            .unwrap();
            fs::write(
                format!("{}/{}.descriptors", pure_dir, proto_name),
                pretty_message(pure_descriptor_for_file),
            )
            .unwrap();
            print_diff(
                temp_dir.path(),
                Path::new(&format!("protoc/{}.descriptors", proto_name)),
                Path::new(&format!("pure/{}.descriptors", proto_name)),
            );
        }
    }

    println!("{:?}", stats);
    assert!(stats.failed == 0, "at least one test failed");
}

fn should_skip_with_marker(path: &str) -> bool {
    fs::read_to_string(path)
        .unwrap()
        .contains("@skip-codegen-identical-test")
}

#[test]
fn common_v2() {
    test_diff_in(
        "../protobuf-test",
        "src/common/v2",
        "src/common/v2",
        should_skip_with_marker,
    );
}

#[test]
fn common_v3() {
    let common_v3_root = tempfile::Builder::new()
        .prefix("common-v3")
        .tempdir()
        .unwrap();
    fs::create_dir_all(format!(
        "{}/src/common/v3",
        common_v3_root.path().to_str().unwrap()
    ))
    .unwrap();

    copy_tests_v2_v3(
        "../protobuf-test/src/common/v2",
        &format!("{}/src/common/v3", common_v3_root.path().to_str().unwrap()),
    );

    test_diff_in(
        common_v3_root.path().to_str().unwrap(),
        "src/common/v3",
        "src/common/v3",
        should_skip_with_marker,
    );
}

#[test]
fn v2() {
    test_diff_in(
        "../protobuf-test",
        "src/v2",
        "src/v2",
        should_skip_with_marker,
    );
}

#[test]
fn v3() {
    test_diff_in(
        "../protobuf-test",
        "src/v3",
        "src/v3",
        should_skip_with_marker,
    );
}

#[test]
fn interop() {
    test_diff_in(
        "../protobuf-test",
        "../interop/cxx",
        "../interop/cxx",
        should_skip_with_marker,
    );
}

#[test]
fn google() {
    test_diff_in("../protobuf-test", "src/google/protobuf", "src", |_| false);
}
<|endoftext|>


<commit_before>use clap::{arg, Arg, ArgAction, Command};

#[test]
fn issue_1076() {
    let mut cmd = Command::new("myprog")
        .arg(
            Arg::new("GLOBAL_ARG")
                .long("global-arg")
                .help("Specifies something needed by the subcommands")
                .global(true)
                .takes_value(true)
                .default_value("default_value"),
        )
        .arg(
            Arg::new("GLOBAL_FLAG")
                .long("global-flag")
                .help("Specifies something needed by the subcommands")
                .global(true)
                .takes_value(true),
        )
        .subcommand(Command::new("outer").subcommand(Command::new("inner")));
    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
}

#[test]
fn propagate_global_arg_in_subcommand_to_subsubcommand_1385() {
    let m1 = Command::new("foo")
        .subcommand(
            Command::new("sub1")
                .arg(Arg::new("arg1").long("arg1").takes_value(true).global(true))
                .subcommand(Command::new("sub1a")),
        )
        .try_get_matches_from(&["foo", "sub1", "--arg1", "v1", "sub1a"])
        .unwrap();
    assert_eq!(
        "v1",
        m1.subcommand_matches("sub1")
            .unwrap()
            .subcommand_matches("sub1a")
            .unwrap()
            .get_one::<String>("arg1")
            .map(|v| v.as_str())
            .unwrap()
    );
}

#[test]
fn propagate_global_arg_to_subcommand_in_subsubcommand_2053() {
    let m = Command::new("opts")
        .arg(arg!(--"global-flag").global(true))
        .arg(arg!(--"global-str" <str>).required(false).global(true))
        .subcommand(
            Command::new("test")
                .arg(arg!(--"sub-flag").global(true))
                .arg(arg!(--"sub-str" <str>).required(false).global(true))
                .subcommand(Command::new("test")),
        )
        .try_get_matches_from(&[
            "cmd",
            "test",
            "test",
            "--global-flag",
            "--global-str",
            "hello",
            "--sub-flag",
            "--sub-str",
            "world",
        ])
        .unwrap();
    assert_eq!(
        Some("world"),
        m.subcommand_matches("test")
            .unwrap()
            .get_one::<String>("sub-str")
            .map(|v| v.as_str())
    );
}

#[test]
fn global_arg_available_in_subcommand() {
    let m = Command::new("opt")
        .args(&[
            Arg::new("global")
                .global(true)
                .long("global")
                .action(ArgAction::SetTrue),
            Arg::new("not")
                .global(false)
                .long("not")
                .action(ArgAction::SetTrue),
        ])
        .subcommand(Command::new("ping"))
        .try_get_matches_from(&["opt", "ping", "--global"])
        .unwrap();

    assert!(*m.get_one::<bool>("global").expect("defaulted by clap"));
    assert!(*m
        .subcommand_matches("ping")
        .unwrap()
        .get_one::<bool>("global")
        .expect("defaulted by clap"));
}

#[test]
fn deeply_nested_discovery() {
    let cmd = Command::new("a")
        .arg(arg!(--"long-a").global(true).action(ArgAction::SetTrue))
        .subcommand(
            Command::new("b")
                .arg(arg!(--"long-b").global(true).action(ArgAction::SetTrue))
                .subcommand(
                    Command::new("c")
                        .arg(arg!(--"long-c").global(true).action(ArgAction::SetTrue))
                        .subcommand(Command::new("d")),
                ),
        );

    let m = cmd
        .try_get_matches_from(["a", "b", "c", "d", "--long-a", "--long-b", "--long-c"])
        .unwrap();
    assert!(*m.get_one::<bool>("long-a").expect("defaulted by clap"));
    let m = m.subcommand_matches("b").unwrap();
    assert!(*m.get_one::<bool>("long-b").expect("defaulted by clap"));
    let m = m.subcommand_matches("c").unwrap();
    assert!(*m.get_one::<bool>("long-c").expect("defaulted by clap"));
}
<commit_msg>test(parser): Verify global/default interaction<commit_after>use clap::{arg, Arg, ArgAction, Command};

#[test]
fn issue_1076() {
    let mut cmd = Command::new("myprog")
        .arg(
            Arg::new("GLOBAL_ARG")
                .long("global-arg")
                .help("Specifies something needed by the subcommands")
                .global(true)
                .takes_value(true)
                .default_value("default_value"),
        )
        .arg(
            Arg::new("GLOBAL_FLAG")
                .long("global-flag")
                .help("Specifies something needed by the subcommands")
                .global(true)
                .takes_value(true),
        )
        .subcommand(Command::new("outer").subcommand(Command::new("inner")));
    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
}

#[test]
fn propagate_global_arg_in_subcommand_to_subsubcommand_1385() {
    let m1 = Command::new("foo")
        .subcommand(
            Command::new("sub1")
                .arg(Arg::new("arg1").long("arg1").takes_value(true).global(true))
                .subcommand(Command::new("sub1a")),
        )
        .try_get_matches_from(&["foo", "sub1", "--arg1", "v1", "sub1a"])
        .unwrap();
    assert_eq!(
        "v1",
        m1.subcommand_matches("sub1")
            .unwrap()
            .subcommand_matches("sub1a")
            .unwrap()
            .get_one::<String>("arg1")
            .map(|v| v.as_str())
            .unwrap()
    );
}

#[test]
fn propagate_global_arg_to_subcommand_in_subsubcommand_2053() {
    let m = Command::new("opts")
        .arg(arg!(--"global-flag").global(true))
        .arg(arg!(--"global-str" <str>).required(false).global(true))
        .subcommand(
            Command::new("test")
                .arg(arg!(--"sub-flag").global(true))
                .arg(arg!(--"sub-str" <str>).required(false).global(true))
                .subcommand(Command::new("test")),
        )
        .try_get_matches_from(&[
            "cmd",
            "test",
            "test",
            "--global-flag",
            "--global-str",
            "hello",
            "--sub-flag",
            "--sub-str",
            "world",
        ])
        .unwrap();
    assert_eq!(
        Some("world"),
        m.subcommand_matches("test")
            .unwrap()
            .get_one::<String>("sub-str")
            .map(|v| v.as_str())
    );
}

#[test]
fn global_arg_available_in_subcommand() {
    let m = Command::new("opt")
        .args(&[
            Arg::new("global")
                .global(true)
                .long("global")
                .action(ArgAction::SetTrue),
            Arg::new("not")
                .global(false)
                .long("not")
                .action(ArgAction::SetTrue),
        ])
        .subcommand(Command::new("ping"))
        .try_get_matches_from(&["opt", "ping", "--global"])
        .unwrap();

    assert!(*m.get_one::<bool>("global").expect("defaulted by clap"));
    assert!(*m
        .subcommand_matches("ping")
        .unwrap()
        .get_one::<bool>("global")
        .expect("defaulted by clap"));
}

#[test]
fn deeply_nested_discovery() {
    let cmd = Command::new("a")
        .arg(arg!(--"long-a").global(true).action(ArgAction::SetTrue))
        .subcommand(
            Command::new("b")
                .arg(arg!(--"long-b").global(true).action(ArgAction::SetTrue))
                .subcommand(
                    Command::new("c")
                        .arg(arg!(--"long-c").global(true).action(ArgAction::SetTrue))
                        .subcommand(Command::new("d")),
                ),
        );

    let m = cmd
        .try_get_matches_from(["a", "b", "c", "d", "--long-a", "--long-b", "--long-c"])
        .unwrap();
    assert!(*m.get_one::<bool>("long-a").expect("defaulted by clap"));
    let m = m.subcommand_matches("b").unwrap();
    assert!(*m.get_one::<bool>("long-b").expect("defaulted by clap"));
    let m = m.subcommand_matches("c").unwrap();
    assert!(*m.get_one::<bool>("long-c").expect("defaulted by clap"));
}

#[test]
fn global_overrides_default() {
    let cmd = Command::new("test")
        .arg(
            Arg::new("name")
                .long("name")
                .global(true)
                .takes_value(true)
                .default_value("from_default"),
        )
        .subcommand(Command::new("sub"));

    let m = cmd.clone().try_get_matches_from(["test"]).unwrap();
    assert_eq!(
        m.get_one::<String>("name").unwrap().as_str(),
        "from_default"
    );

    let m = cmd
        .clone()
        .try_get_matches_from(["test", "--name", "from_arg"])
        .unwrap();
    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");

    let m = cmd
        .clone()
        .try_get_matches_from(["test", "--name", "from_arg", "sub"])
        .unwrap();
    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");

    let m = cmd
        .clone()
        .try_get_matches_from(["test", "sub", "--name", "from_arg"])
        .unwrap();
    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");
}
<|endoftext|>


<commit_before>use proc_macro2::TokenStream;
use quote::quote;
use std::iter;
use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident};

use crate::accepts;
use crate::composites::Field;
use crate::enums::Variant;
use crate::overrides::Overrides;

pub fn expand_derive_tosql(input: DeriveInput) -> Result<TokenStream, Error> {
    let overrides = Overrides::extract(&input.attrs)?;

    let name = overrides.name.unwrap_or_else(|| input.ident.to_string());

    let (accepts_body, to_sql_body) = match input.data {
        Data::Enum(ref data) => {
            let variants = data
                .variants
                .iter()
                .map(Variant::parse)
                .collect::<Result<Vec<_>, _>>()?;
            (
                accepts::enum_body(&name, &variants),
                enum_body(&input.ident, &variants),
            )
        }
        Data::Struct(DataStruct {
            fields: Fields::Unnamed(ref fields),
            ..
        }) if fields.unnamed.len() == 1 => {
            let field = fields.unnamed.first().unwrap();
            (accepts::domain_body(&name, &field), domain_body())
        }
        Data::Struct(DataStruct {
            fields: Fields::Named(ref fields),
            ..
        }) => {
            let fields = fields
                .named
                .iter()
                .map(Field::parse)
                .collect::<Result<Vec<_>, _>>()?;
            (
                accepts::composite_body(&name, "ToSql", &fields),
                composite_body(&fields),
            )
        }
        _ => {
            return Err(Error::new_spanned(
                input,
                "#[derive(ToSql)] may only be applied to structs, single field tuple structs, and enums",
            ));
        }
    };

    let ident = &input.ident;
    let out = quote! {
        impl postgres_types::ToSql for #ident {
            fn to_sql(&self,
                      _type: &postgres_types::Type,
                      buf: &mut postgres_types::private::BytesMut)
                      -> std::result::Result<postgres_types::IsNull,
                                             std::boxed::Box<std::error::Error +
                                                             std::marker::Sync +
                                                             std::marker::Send>> {
                #to_sql_body
            }

            fn accepts(type_: &postgres_types::Type) -> bool {
                #accepts_body
            }

            postgres_types::to_sql_checked!();
        }
    };

    Ok(out)
}

fn enum_body(ident: &Ident, variants: &[Variant]) -> TokenStream {
    let idents = iter::repeat(ident);
    let variant_idents = variants.iter().map(|v| &v.ident);
    let variant_names = variants.iter().map(|v| &v.name);

    quote! {
        let s = match *self {
            #(
                #idents::#variant_idents => #variant_names,
            )*
        };

        buf.extend_from_slice(s.as_bytes());
        std::result::Result::Ok(postgres_types::IsNull::No)
    }
}

fn domain_body() -> TokenStream {
    quote! {
        let type_ = match *_type.kind() {
            postgres_types::Kind::Domain(ref type_) => type_,
            _ => unreachable!(),
        };

        postgres_types::ToSql::to_sql(&self.0, type_, buf)
    }
}

fn composite_body(fields: &[Field]) -> TokenStream {
    let field_names = fields.iter().map(|f| &f.name);
    let field_idents = fields.iter().map(|f| &f.ident);

    quote! {
        let fields = match *_type.kind() {
            postgres_types::Kind::Composite(ref fields) => fields,
            _ => unreachable!(),
        };

        buf.extend_from_slice(&(fields.len() as i32).to_be_bytes());

        for field in fields {
            buf.extend_from_slice(&field.type_().oid().to_be_bytes());

            let base = buf.len();
            buf.extend_from_slice(&[0; 4]);
            let r = match field.name() {
                #(
                    #field_names => postgres_types::ToSql::to_sql(&self.#field_idents, field.type_(), buf),
                )*
                _ => unreachable!(),
            };

            let count = match r? {
                postgres_types::IsNull::Yes => -1,
                postgres_types::IsNull::No => {
                    let len = buf.len() - base - 4;
                    if len > i32::max_value() as usize {
                        return std::result::Result::Err(
                            std::convert::Into::into("value too large to transmit"));
                    }
                    len as i32
                }
            };

            buf[base..base + 4].copy_from_slice(&count.to_be_bytes());
        }

        std::result::Result::Ok(postgres_types::IsNull::No)
    }
}
<commit_msg>fix clippy<commit_after>use proc_macro2::TokenStream;
use quote::quote;
use std::iter;
use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident};

use crate::accepts;
use crate::composites::Field;
use crate::enums::Variant;
use crate::overrides::Overrides;

pub fn expand_derive_tosql(input: DeriveInput) -> Result<TokenStream, Error> {
    let overrides = Overrides::extract(&input.attrs)?;

    let name = overrides.name.unwrap_or_else(|| input.ident.to_string());

    let (accepts_body, to_sql_body) = match input.data {
        Data::Enum(ref data) => {
            let variants = data
                .variants
                .iter()
                .map(Variant::parse)
                .collect::<Result<Vec<_>, _>>()?;
            (
                accepts::enum_body(&name, &variants),
                enum_body(&input.ident, &variants),
            )
        }
        Data::Struct(DataStruct {
            fields: Fields::Unnamed(ref fields),
            ..
        }) if fields.unnamed.len() == 1 => {
            let field = fields.unnamed.first().unwrap();
            (accepts::domain_body(&name, field), domain_body())
        }
        Data::Struct(DataStruct {
            fields: Fields::Named(ref fields),
            ..
        }) => {
            let fields = fields
                .named
                .iter()
                .map(Field::parse)
                .collect::<Result<Vec<_>, _>>()?;
            (
                accepts::composite_body(&name, "ToSql", &fields),
                composite_body(&fields),
            )
        }
        _ => {
            return Err(Error::new_spanned(
                input,
                "#[derive(ToSql)] may only be applied to structs, single field tuple structs, and enums",
            ));
        }
    };

    let ident = &input.ident;
    let out = quote! {
        impl postgres_types::ToSql for #ident {
            fn to_sql(&self,
                      _type: &postgres_types::Type,
                      buf: &mut postgres_types::private::BytesMut)
                      -> std::result::Result<postgres_types::IsNull,
                                             std::boxed::Box<std::error::Error +
                                                             std::marker::Sync +
                                                             std::marker::Send>> {
                #to_sql_body
            }

            fn accepts(type_: &postgres_types::Type) -> bool {
                #accepts_body
            }

            postgres_types::to_sql_checked!();
        }
    };

    Ok(out)
}

fn enum_body(ident: &Ident, variants: &[Variant]) -> TokenStream {
    let idents = iter::repeat(ident);
    let variant_idents = variants.iter().map(|v| &v.ident);
    let variant_names = variants.iter().map(|v| &v.name);

    quote! {
        let s = match *self {
            #(
                #idents::#variant_idents => #variant_names,
            )*
        };

        buf.extend_from_slice(s.as_bytes());
        std::result::Result::Ok(postgres_types::IsNull::No)
    }
}

fn domain_body() -> TokenStream {
    quote! {
        let type_ = match *_type.kind() {
            postgres_types::Kind::Domain(ref type_) => type_,
            _ => unreachable!(),
        };

        postgres_types::ToSql::to_sql(&self.0, type_, buf)
    }
}

fn composite_body(fields: &[Field]) -> TokenStream {
    let field_names = fields.iter().map(|f| &f.name);
    let field_idents = fields.iter().map(|f| &f.ident);

    quote! {
        let fields = match *_type.kind() {
            postgres_types::Kind::Composite(ref fields) => fields,
            _ => unreachable!(),
        };

        buf.extend_from_slice(&(fields.len() as i32).to_be_bytes());

        for field in fields {
            buf.extend_from_slice(&field.type_().oid().to_be_bytes());

            let base = buf.len();
            buf.extend_from_slice(&[0; 4]);
            let r = match field.name() {
                #(
                    #field_names => postgres_types::ToSql::to_sql(&self.#field_idents, field.type_(), buf),
                )*
                _ => unreachable!(),
            };

            let count = match r? {
                postgres_types::IsNull::Yes => -1,
                postgres_types::IsNull::No => {
                    let len = buf.len() - base - 4;
                    if len > i32::max_value() as usize {
                        return std::result::Result::Err(
                            std::convert::Into::into("value too large to transmit"));
                    }
                    len as i32
                }
            };

            buf[base..base + 4].copy_from_slice(&count.to_be_bytes());
        }

        std::result::Result::Ok(postgres_types::IsNull::No)
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::path::Path;
use std::path::PathBuf;

fn list_dir(p: &Path) -> Vec<PathBuf> {
    let mut children = fs::read_dir(p)
        .unwrap()
        .map(|r| r.map(|e| e.path()))
        .collect::<Result<Vec<_>, _>>()
        .unwrap();
    children.sort();
    children
}

fn assert_equal_recursively(a: &Path, b: &Path) {
    assert_eq!(a.is_dir(), b.is_dir(), "{} {}", a.display(), b.display());
    assert_eq!(a.is_file(), b.is_file(), "{} {}", a.display(), b.display());
    if a.is_dir() {
        let mut a_contents = list_dir(a).into_iter();
        let mut b_contents = list_dir(b).into_iter();
        loop {
            let a_child = a_contents.next();
            let b_child = b_contents.next();
            match (a_child, b_child) {
                (Some(a_child), Some(b_child)) => {
                    assert_eq!(a_child.file_name(), b_child.file_name());
                    assert_equal_recursively(&a_child, &b_child);
                }
                (None, None) => break,
                _ => panic!(
                    "mismatched directories: {} and {}",
                    a.display(),
                    b.display()
                ),
            }
        }
    } else {
        let a_contents = fs::read_to_string(a).unwrap();
        let b_contents = fs::read_to_string(b).unwrap();
        assert_eq!(a_contents, b_contents);
    }
}

#[test]
fn test_bundled_google_proto_files_consistent() {
    let source = "../protoc-bin-vendored/include/google";
    let our_copy = "src/proto/google";
    assert_equal_recursively(Path::new(source), Path::new(our_copy));
}

#[test]
fn test_bundled_rustproto_proto_consistent() {
    let source = "../proto/rustproto.proto";
    let our_copy = "src/proto/rustproto.proto";
    assert_equal_recursively(Path::new(source), Path::new(our_copy));
}
<commit_msg>Fix tests after removing protoc-bin-vendored<commit_after>use std::fs;
use std::path::Path;
use std::path::PathBuf;

fn list_dir(p: &Path) -> Vec<PathBuf> {
    let mut children = fs::read_dir(p)
        .unwrap()
        .map(|r| r.map(|e| e.path()))
        .collect::<Result<Vec<_>, _>>()
        .unwrap();
    children.sort();
    children
}

fn assert_equal_recursively(a: &Path, b: &Path) {
    assert_eq!(a.is_dir(), b.is_dir(), "{} {}", a.display(), b.display());
    assert_eq!(a.is_file(), b.is_file(), "{} {}", a.display(), b.display());
    if a.is_dir() {
        let mut a_contents = list_dir(a).into_iter();
        let mut b_contents = list_dir(b).into_iter();
        loop {
            let a_child = a_contents.next();
            let b_child = b_contents.next();
            match (a_child, b_child) {
                (Some(a_child), Some(b_child)) => {
                    assert_eq!(a_child.file_name(), b_child.file_name());
                    assert_equal_recursively(&a_child, &b_child);
                }
                (None, None) => break,
                _ => panic!(
                    "mismatched directories: {} and {}",
                    a.display(),
                    b.display()
                ),
            }
        }
    } else {
        let a_contents = fs::read_to_string(a).unwrap();
        let b_contents = fs::read_to_string(b).unwrap();
        assert_eq!(a_contents, b_contents);
    }
}

#[test]
fn test_bundled_google_proto_files_consistent() {
    let source = "../proto/google";
    let our_copy = "src/proto/google";
    assert_equal_recursively(Path::new(source), Path::new(our_copy));
}

#[test]
fn test_bundled_rustproto_proto_consistent() {
    let source = "../proto/rustproto.proto";
    let our_copy = "src/proto/rustproto.proto";
    assert_equal_recursively(Path::new(source), Path::new(our_copy));
}
<|endoftext|>