From a6ee303123b4c2b2152704e639b451771737d69f Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 22 Jul 2019 13:01:19 +0000 Subject: [PATCH 1/5] imservice: Handle content type in Rust This adds `bitflags.rs` from the bitflags crate. Due to not wanting to introduce Cargo as the dependency manager yet, it's slightly modified to compile as a naked module. --- src/bitflags.rs | 1354 ++++++++++++++++++++++++++++++++++++++++++++++ src/imservice.c | 8 - src/imservice.h | 1 + src/imservice.rs | 124 ++++- 4 files changed, 1476 insertions(+), 11 deletions(-) create mode 100644 src/bitflags.rs diff --git a/src/bitflags.rs b/src/bitflags.rs new file mode 100644 index 00000000..329cbf84 --- /dev/null +++ b/src/bitflags.rs @@ -0,0 +1,1354 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Adapted from the bitflags crate revision 4e762d0 + +//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. +//! It can be used for creating typesafe wrappers around C APIs. +//! +//! The `bitflags!` macro generates a `struct` that manages a set of flags. The +//! flags should only be defined for integer types, otherwise unexpected type +//! errors may occur at compile time. +//! +//! # Example +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +//! } +//! } +//! +//! fn main() { +//! let e1 = Flags::A | Flags::C; +//! let e2 = Flags::B | Flags::C; +//! assert_eq!((e1 | e2), Flags::ABC); // union +//! assert_eq!((e1 & e2), Flags::C); // intersection +//! assert_eq!((e1 - e2), Flags::A); // set difference +//! assert_eq!(!e2, Flags::A); // set complement +//! } +//! ``` +//! +//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code +//! generated by the above `bitflags!` expansion. +//! +//! The generated `struct`s can also be extended with type and trait +//! implementations: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! use std::fmt; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! } +//! } +//! +//! impl Flags { +//! pub fn clear(&mut self) { +//! self.bits = 0; // The `bits` field can be accessed from within the +//! // same module where the `bitflags!` macro was invoked. +//! } +//! } +//! +//! impl fmt::Display for Flags { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! write!(f, "hi!") +//! } +//! } +//! +//! fn main() { +//! let mut flags = Flags::A | Flags::B; +//! flags.clear(); +//! assert!(flags.is_empty()); +//! assert_eq!(format!("{}", flags), "hi!"); +//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +//! assert_eq!(format!("{:?}", Flags::B), "B"); +//! } +//! ``` +//! +//! # Visibility +//! +//! The generated struct and its associated flag constants are not exported +//! out of the current module by default. A definition can be exported out of +//! the current module by adding `pub` before `flags`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! mod example { +//! bitflags! { +//! pub struct Flags1: u32 { +//! const A = 0b00000001; +//! } +//! } +//! bitflags! { +//! # pub +//! struct Flags2: u32 { +//! const B = 0b00000010; +//! } +//! } +//! } +//! +//! fn main() { +//! let flag1 = example::Flags1::A; +//! let flag2 = example::Flags2::B; // error: const `B` is private +//! } +//! ``` +//! +//! # Attributes +//! +//! Attributes can be attached to the generated `struct` by placing them +//! before the `flags` keyword. +//! +//! # Trait implementations +//! +//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` +//! traits automatically derived for the `struct` using the `derive` attribute. +//! Additional traits can be derived by providing an explicit `derive` +//! attribute on `flags`. +//! +//! The `Extend` and `FromIterator` traits are implemented for the `struct`, +//! too: `Extend` adds the union of the instances of the `struct` iterated over, +//! while `FromIterator` calculates the union. +//! +//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` trait is also +//! implemented by displaying the bits value of the internal struct. +//! +//! ## Operators +//! +//! The following operator traits are implemented for the generated `struct`: +//! +//! - `BitOr` and `BitOrAssign`: union +//! - `BitAnd` and `BitAndAssign`: intersection +//! - `BitXor` and `BitXorAssign`: toggle +//! - `Sub` and `SubAssign`: set difference +//! - `Not`: set complement +//! +//! # Methods +//! +//! The following methods are defined for the generated `struct`: +//! +//! - `empty`: an empty set of flags +//! - `all`: the set of all flags +//! - `bits`: the raw value of the flags currently stored +//! - `from_bits`: convert from underlying bit representation, unless that +//! representation contains bits that do not correspond to a flag +//! - `from_bits_truncate`: convert from underlying bit representation, dropping +//! any bits that do not correspond to flags +//! - `is_empty`: `true` if no flags are currently stored +//! - `is_all`: `true` if all flags are currently set +//! - `intersects`: `true` if there are flags common to both `self` and `other` +//! - `contains`: `true` all of the flags in `other` are contained within `self` +//! - `insert`: inserts the specified flags in-place +//! - `remove`: removes the specified flags in-place +//! - `toggle`: the specified flags will be inserted if not present, and removed +//! if they are. +//! - `set`: inserts or removes the specified flags depending on the passed value +//! +//! ## Default +//! +//! The `Default` trait is not automatically implemented for the generated struct. +//! +//! If your default value is equal to `0` (which is the same value as calling `empty()` +//! on the generated struct), you can simply derive `Default`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! // Results in default value with bits: 0 +//! #[derive(Default)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! fn main() { +//! let derived_default: Flags = Default::default(); +//! assert_eq!(derived_default.bits(), 0); +//! } +//! ``` +//! +//! If your default value is not equal to `0` you need to implement `Default` yourself: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! // explicit `Default` implementation +//! impl Default for Flags { +//! fn default() -> Flags { +//! Flags::A | Flags::C +//! } +//! } +//! +//! fn main() { +//! let implemented_default: Flags = Default::default(); +//! assert_eq!(implemented_default, (Flags::A | Flags::C)); +//! } +//! ``` +//! +//! # Zero Flags +//! +//! Flags with a value equal to zero will have some strange behavior that one should be aware of. +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const NONE = 0b00000000; +//! const SOME = 0b00000001; +//! } +//! } +//! +//! fn main() { +//! let empty = Flags::empty(); +//! let none = Flags::NONE; +//! let some = Flags::SOME; +//! +//! // Zero flags are treated as always present +//! assert!(empty.contains(Flags::NONE)); +//! assert!(none.contains(Flags::NONE)); +//! assert!(some.contains(Flags::NONE)); +//! +//! // Zero flags will be ignored when testing for emptiness +//! assert!(none.is_empty()); +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/bitflags/1.1.0")] + +#[cfg(test)] +#[macro_use] +extern crate std; + +// Re-export libcore using an alias so that the macros can work without +// requiring `extern crate core` downstream. +#[doc(hidden)] +pub extern crate core as _core; + +/// The macro used to generate the flag structure. +/// +/// See the [crate level docs](../bitflags/index.html) for complete documentation. +/// +/// # Example +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// const C = 0b00000100; +/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +/// } +/// } +/// +/// fn main() { +/// let e1 = Flags::A | Flags::C; +/// let e2 = Flags::B | Flags::C; +/// assert_eq!((e1 | e2), Flags::ABC); // union +/// assert_eq!((e1 & e2), Flags::C); // intersection +/// assert_eq!((e1 - e2), Flags::A); // set difference +/// assert_eq!(!e2, Flags::A); // set complement +/// } +/// ``` +/// +/// The generated `struct`s can also be extended with type and trait +/// implementations: +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// use std::fmt; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// } +/// } +/// +/// impl Flags { +/// pub fn clear(&mut self) { +/// self.bits = 0; // The `bits` field can be accessed from within the +/// // same module where the `bitflags!` macro was invoked. +/// } +/// } +/// +/// impl fmt::Display for Flags { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "hi!") +/// } +/// } +/// +/// fn main() { +/// let mut flags = Flags::A | Flags::B; +/// flags.clear(); +/// assert!(flags.is_empty()); +/// assert_eq!(format!("{}", flags), "hi!"); +/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +/// assert_eq!(format!("{:?}", Flags::B), "B"); +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitflags { + ( + $(#[$outer:meta])* + pub struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + (pub) $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; + ( + $(#[$outer:meta])* + struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + () $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; + ( + $(#[$outer:meta])* + pub ($($vis:tt)+) struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + (pub ($($vis)+)) $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __bitflags { + ( + $(#[$outer:meta])* + ($($vis:tt)*) $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + $(#[$outer])* + #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] + $($vis)* struct $BitFlags { + bits: $T, + } + + __impl_bitflags! { + $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(bitflags_const_fn)] +macro_rules! __fn_bitflags { + ( + $(# $attr_args:tt)* + const fn $($item:tt)* + ) => { + $(# $attr_args)* + const fn $($item)* + }; + ( + $(# $attr_args:tt)* + pub const fn $($item:tt)* + ) => { + $(# $attr_args)* + pub const fn $($item)* + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(not(bitflags_const_fn))] +macro_rules! __fn_bitflags { + ( + $(# $attr_args:tt)* + const fn $($item:tt)* + ) => { + $(# $attr_args)* + fn $($item)* + }; + ( + $(# $attr_args:tt)* + pub const fn $($item:tt)* + ) => { + $(# $attr_args)* + pub fn $($item)* + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_bitflags { + ( + $BitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + impl bitflags::_core::fmt::Debug for $BitFlags { + fn fmt(&self, f: &mut bitflags::_core::fmt::Formatter) -> bitflags::_core::fmt::Result { + // This convoluted approach is to handle #[cfg]-based flag + // omission correctly. For example it needs to support: + // + // #[cfg(unix)] const A: Flag = /* ... */; + // #[cfg(windows)] const B: Flag = /* ... */; + + // Unconditionally define a check for every flag, even disabled + // ones. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + fn $Flag(&self) -> bool { false } + )+ + } + + // Conditionally override the check for just those flags that + // are not #[cfg]ed away. + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + fn $Flag(&self) -> bool { + if Self::$Flag.bits == 0 && self.bits != 0 { + false + } else { + self.bits & Self::$Flag.bits == Self::$Flag.bits + } + } + } + )+ + } + + let mut first = true; + $( + if <$BitFlags as __BitFlags>::$Flag(self) { + if !first { + f.write_str(" | ")?; + } + first = false; + f.write_str(__bitflags_stringify!($Flag))?; + } + )+ + if first { + f.write_str("(empty)")?; + } + Ok(()) + } + } + impl bitflags::_core::fmt::Binary for $BitFlags { + fn fmt(&self, f: &mut bitflags::_core::fmt::Formatter) -> bitflags::_core::fmt::Result { + bitflags::_core::fmt::Binary::fmt(&self.bits, f) + } + } + impl bitflags::_core::fmt::Octal for $BitFlags { + fn fmt(&self, f: &mut bitflags::_core::fmt::Formatter) -> bitflags::_core::fmt::Result { + bitflags::_core::fmt::Octal::fmt(&self.bits, f) + } + } + impl bitflags::_core::fmt::LowerHex for $BitFlags { + fn fmt(&self, f: &mut bitflags::_core::fmt::Formatter) -> bitflags::_core::fmt::Result { + bitflags::_core::fmt::LowerHex::fmt(&self.bits, f) + } + } + impl bitflags::_core::fmt::UpperHex for $BitFlags { + fn fmt(&self, f: &mut bitflags::_core::fmt::Formatter) -> bitflags::_core::fmt::Result { + bitflags::_core::fmt::UpperHex::fmt(&self.bits, f) + } + } + + #[allow(dead_code)] + impl $BitFlags { + $( + $(#[$attr $($args)*])* + pub const $Flag: $BitFlags = $BitFlags { bits: $value }; + )+ + + __fn_bitflags! { + /// Returns an empty set of flags + #[inline] + pub const fn empty() -> $BitFlags { + $BitFlags { bits: 0 } + } + } + + __fn_bitflags! { + /// Returns the set containing all flags. + #[inline] + pub const fn all() -> $BitFlags { + // See `Debug::fmt` for why this approach is taken. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + const $Flag: $T = 0; + )+ + } + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + const $Flag: $T = Self::$Flag.bits; + } + )+ + } + $BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag)|+ } + } + } + + __fn_bitflags! { + /// Returns the raw value of the flags currently stored. + #[inline] + pub const fn bits(&self) -> $T { + self.bits + } + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub fn from_bits(bits: $T) -> bitflags::_core::option::Option<$BitFlags> { + if (bits & !$BitFlags::all().bits()) == 0 { + bitflags::_core::option::Option::Some($BitFlags { bits }) + } else { + bitflags::_core::option::Option::None + } + } + + __fn_bitflags! { + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub const fn from_bits_truncate(bits: $T) -> $BitFlags { + $BitFlags { bits: bits & $BitFlags::all().bits } + } + } + + __fn_bitflags! { + /// Returns `true` if no flags are currently stored. + #[inline] + pub const fn is_empty(&self) -> bool { + self.bits() == $BitFlags::empty().bits() + } + } + + __fn_bitflags! { + /// Returns `true` if all flags are currently set. + #[inline] + pub const fn is_all(&self) -> bool { + self.bits == $BitFlags::all().bits + } + } + + __fn_bitflags! { + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub const fn intersects(&self, other: $BitFlags) -> bool { + !$BitFlags{ bits: self.bits & other.bits}.is_empty() + } + } + + __fn_bitflags! { + /// Returns `true` all of the flags in `other` are contained within `self`. + #[inline] + pub const fn contains(&self, other: $BitFlags) -> bool { + (self.bits & other.bits) == other.bits + } + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + + /// Inserts or removes the specified flags depending on the passed value. + #[inline] + pub fn set(&mut self, other: $BitFlags, value: bool) { + if value { + self.insert(other); + } else { + self.remove(other); + } + } + } + + impl bitflags::_core::ops::BitOr for $BitFlags { + type Output = $BitFlags; + + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits | other.bits } + } + } + + impl bitflags::_core::ops::BitOrAssign for $BitFlags { + + /// Adds the set of flags. + #[inline] + fn bitor_assign(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + } + + impl bitflags::_core::ops::BitXor for $BitFlags { + type Output = $BitFlags; + + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits ^ other.bits } + } + } + + impl bitflags::_core::ops::BitXorAssign for $BitFlags { + + /// Toggles the set of flags. + #[inline] + fn bitxor_assign(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + } + + impl bitflags::_core::ops::BitAnd for $BitFlags { + type Output = $BitFlags; + + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & other.bits } + } + } + + impl bitflags::_core::ops::BitAndAssign for $BitFlags { + + /// Disables all flags disabled in the set. + #[inline] + fn bitand_assign(&mut self, other: $BitFlags) { + self.bits &= other.bits; + } + } + + impl bitflags::_core::ops::Sub for $BitFlags { + type Output = $BitFlags; + + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & !other.bits } + } + } + + impl bitflags::_core::ops::SubAssign for $BitFlags { + + /// Disables all flags enabled in the set. + #[inline] + fn sub_assign(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + } + + impl bitflags::_core::ops::Not for $BitFlags { + type Output = $BitFlags; + + /// Returns the complement of this set of flags. + #[inline] + fn not(self) -> $BitFlags { + $BitFlags { bits: !self.bits } & $BitFlags::all() + } + } + + impl bitflags::_core::iter::Extend<$BitFlags> for $BitFlags { + fn extend>(&mut self, iterator: T) { + for item in iterator { + self.insert(item) + } + } + } + + impl bitflags::_core::iter::FromIterator<$BitFlags> for $BitFlags { + fn from_iter>(iterator: T) -> $BitFlags { + let mut result = Self::empty(); + result.extend(iterator); + result + } + } + }; + + // Every attribute that the user writes on a const is applied to the + // corresponding const that we generate, but within the implementation of + // Debug and all() we want to ignore everything but #[cfg] attributes. In + // particular, including a #[deprecated] attribute on those items would fail + // to compile. + // https://github.com/bitflags/bitflags/issues/109 + // + // Input: + // + // ? #[cfg(feature = "advanced")] + // ? #[deprecated(note = "Use somthing else.")] + // ? #[doc = r"High quality documentation."] + // fn f() -> i32 { /* ... */ } + // + // Output: + // + // #[cfg(feature = "advanced")] + // fn f() -> i32 { /* ... */ } + ( + $(#[$filtered:meta])* + ? #[cfg $($cfgargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + #[cfg $($cfgargs)*] + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + // $next != `cfg` + ? #[$next:ident $($nextargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + // $next filtered out + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + fn $($item:tt)* + ) => { + $(#[$filtered])* + fn $($item)* + }; + + // Every attribute that the user writes on a const is applied to the + // corresponding const that we generate, but within the implementation of + // Debug and all() we want to ignore everything but #[cfg] attributes. In + // particular, including a #[deprecated] attribute on those items would fail + // to compile. + // https://github.com/bitflags/bitflags/issues/109 + // + // const version + // + // Input: + // + // ? #[cfg(feature = "advanced")] + // ? #[deprecated(note = "Use somthing else.")] + // ? #[doc = r"High quality documentation."] + // const f: i32 { /* ... */ } + // + // Output: + // + // #[cfg(feature = "advanced")] + // const f: i32 { /* ... */ } + ( + $(#[$filtered:meta])* + ? #[cfg $($cfgargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + const $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + #[cfg $($cfgargs)*] + $(? #[$rest $($restargs)*])* + const $($item)* + } + }; + ( + $(#[$filtered:meta])* + // $next != `cfg` + ? #[$next:ident $($nextargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + const $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + // $next filtered out + $(? #[$rest $($restargs)*])* + const $($item)* + } + }; + ( + $(#[$filtered:meta])* + const $($item:tt)* + ) => { + $(#[$filtered])* + const $($item)* + }; +} + +// Same as std::stringify but callable from __impl_bitflags, which needs to use +// local_inner_macros so can only directly call macros from this crate. +#[macro_export] +#[doc(hidden)] +macro_rules! __bitflags_stringify { + ($s:ident) => { + stringify!($s) + }; +} + +#[cfg(feature = "example_generated")] +pub mod example_generated; + +#[cfg(test)] +mod tests { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + bitflags! { + #[doc = "> The first principle is that you must not fool yourself — and"] + #[doc = "> you are the easiest person to fool."] + #[doc = "> "] + #[doc = "> - Richard Feynman"] + struct Flags: u32 { + const A = 0b00000001; + #[doc = " macros are way better at generating code than trans is"] + const B = 0b00000010; + const C = 0b00000100; + #[doc = "* cmr bed"] + #[doc = "* strcat table"] + #[doc = " wait what?"] + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } + } + + bitflags! { + struct _CfgFlags: u32 { + #[cfg(unix)] + const _CFG_A = 0b01; + #[cfg(windows)] + const _CFG_B = 0b01; + #[cfg(unix)] + const _CFG_C = Self::_CFG_A.bits | 0b10; + } + } + + bitflags! { + struct AnotherSetOfFlags: i8 { + const ANOTHER_FLAG = -1_i8; + } + } + + bitflags! { + struct LongFlags: u32 { + const LONG_A = 0b1111111111111111; + } + } + + #[test] + fn test_bits() { + assert_eq!(Flags::empty().bits(), 0b00000000); + assert_eq!(Flags::A.bits(), 0b00000001); + assert_eq!(Flags::ABC.bits(), 0b00000111); + + assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); + assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8); + } + + #[test] + fn test_from_bits() { + assert_eq!(Flags::from_bits(0), Some(Flags::empty())); + assert_eq!(Flags::from_bits(0b1), Some(Flags::A)); + assert_eq!(Flags::from_bits(0b10), Some(Flags::B)); + assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B)); + assert_eq!(Flags::from_bits(0b1000), None); + + assert_eq!( + AnotherSetOfFlags::from_bits(!0_i8), + Some(AnotherSetOfFlags::ANOTHER_FLAG) + ); + } + + #[test] + fn test_from_bits_truncate() { + assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1), Flags::A); + assert_eq!(Flags::from_bits_truncate(0b10), Flags::B); + assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B)); + assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A); + + assert_eq!( + AnotherSetOfFlags::from_bits_truncate(0_i8), + AnotherSetOfFlags::empty() + ); + } + + #[test] + fn test_is_empty() { + assert!(Flags::empty().is_empty()); + assert!(!Flags::A.is_empty()); + assert!(!Flags::ABC.is_empty()); + + assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty()); + } + + #[test] + fn test_is_all() { + assert!(Flags::all().is_all()); + assert!(!Flags::A.is_all()); + assert!(Flags::ABC.is_all()); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all()); + } + + #[test] + fn test_two_empties_do_not_intersect() { + let e1 = Flags::empty(); + let e2 = Flags::empty(); + assert!(!e1.intersects(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_empty_does_not_intersect_with_full() { + let e1 = Flags::empty(); + let e2 = Flags::ABC; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_disjoint_intersects() { + let e1 = Flags::A; + let e2 = Flags::B; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_overlapping_intersects() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(e1.intersects(e2)); + } + + #[test] + fn test_contains() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(!e1.contains(e2)); + assert!(e2.contains(e1)); + assert!(Flags::ABC.contains(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_insert() { + let mut e1 = Flags::A; + let e2 = Flags::A | Flags::B; + e1.insert(e2); + assert_eq!(e1, e2); + + let mut e3 = AnotherSetOfFlags::empty(); + e3.insert(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG); + } + + #[test] + fn test_remove() { + let mut e1 = Flags::A | Flags::B; + let e2 = Flags::A | Flags::C; + e1.remove(e2); + assert_eq!(e1, Flags::B); + + let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG; + e3.remove(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_operators() { + let e1 = Flags::A | Flags::C; + let e2 = Flags::B | Flags::C; + assert_eq!((e1 | e2), Flags::ABC); // union + assert_eq!((e1 & e2), Flags::C); // intersection + assert_eq!((e1 - e2), Flags::A); // set difference + assert_eq!(!e2, Flags::A); // set complement + assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle + let mut e3 = e1; + e3.toggle(e2); + assert_eq!(e3, Flags::A | Flags::B); + + let mut m4 = AnotherSetOfFlags::empty(); + m4.toggle(AnotherSetOfFlags::empty()); + assert_eq!(m4, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_set() { + let mut e1 = Flags::A | Flags::C; + e1.set(Flags::B, true); + e1.set(Flags::C, false); + + assert_eq!(e1, Flags::A | Flags::B); + } + + #[test] + fn test_assignment_operators() { + let mut m1 = Flags::empty(); + let e1 = Flags::A | Flags::C; + // union + m1 |= Flags::A; + assert_eq!(m1, Flags::A); + // intersection + m1 &= e1; + assert_eq!(m1, Flags::A); + // set difference + m1 -= m1; + assert_eq!(m1, Flags::empty()); + // toggle + m1 ^= e1; + assert_eq!(m1, e1); + } + + + #[cfg(bitflags_const_fn)] + #[test] + fn test_const_fn() { + const _M1: Flags = Flags::empty(); + + const M2: Flags = Flags::A; + assert_eq!(M2, Flags::A); + + const M3: Flags = Flags::C; + assert_eq!(M3, Flags::C); + } + + #[test] + fn test_extend() { + let mut flags; + + flags = Flags::empty(); + flags.extend([].iter().cloned()); + assert_eq!(flags, Flags::empty()); + + flags = Flags::empty(); + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::A; + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::B; + flags.extend([Flags::A, Flags::ABC].iter().cloned()); + assert_eq!(flags, Flags::ABC); + } + + #[test] + fn test_from_iterator() { + assert_eq!([].iter().cloned().collect::(), Flags::empty()); + assert_eq!( + [Flags::A, Flags::B].iter().cloned().collect::(), + Flags::A | Flags::B + ); + assert_eq!( + [Flags::A, Flags::ABC].iter().cloned().collect::(), + Flags::ABC + ); + } + + #[test] + fn test_lt() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(!(a < b) && !(b < a)); + b = Flags::B; + assert!(a < b); + a = Flags::C; + assert!(!(a < b) && b < a); + b = Flags::C | Flags::B; + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(a <= b && a >= b); + a = Flags::A; + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b = Flags::B; + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + fn hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + #[test] + fn test_hash() { + let mut x = Flags::empty(); + let mut y = Flags::empty(); + assert_eq!(hash(&x), hash(&y)); + x = Flags::all(); + y = Flags::ABC; + assert_eq!(hash(&x), hash(&y)); + } + + #[test] + fn test_debug() { + assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); + assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); + assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); + } + + #[test] + fn test_binary() { + assert_eq!(format!("{:b}", Flags::ABC), "111"); + assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); + } + + #[test] + fn test_octal() { + assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); + assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); + } + + #[test] + fn test_lowerhex() { + assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); + assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); + } + + #[test] + fn test_upperhex() { + assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); + assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); + } + + mod submodule { + bitflags! { + pub struct PublicFlags: i8 { + const X = 0; + } + } + bitflags! { + struct PrivateFlags: i8 { + const Y = 0; + } + } + + #[test] + fn test_private() { + let _ = PrivateFlags::Y; + } + } + + #[test] + fn test_public() { + let _ = submodule::PublicFlags::X; + } + + mod t1 { + mod foo { + pub type Bar = i32; + } + + bitflags! { + /// baz + struct Flags: foo::Bar { + const A = 0b00000001; + #[cfg(foo)] + const B = 0b00000010; + #[cfg(foo)] + const C = 0b00000010; + } + } + } + + #[test] + fn test_in_function() { + bitflags! { + struct Flags: u8 { + const A = 1; + #[cfg(any())] // false + const B = 2; + } + } + assert_eq!(Flags::all(), Flags::A); + assert_eq!(format!("{:?}", Flags::A), "A"); + } + + #[test] + fn test_deprecated() { + bitflags! { + pub struct TestFlags: u32 { + #[deprecated(note = "Use something else.")] + const ONE = 1; + } + } + } + + #[test] + fn test_pub_crate() { + mod module { + bitflags! { + pub (crate) struct Test: u8 { + const FOO = 1; + } + } + } + + assert_eq!(module::Test::FOO.bits(), 1); + } + + #[test] + fn test_pub_in_module() { + mod module { + mod submodule { + bitflags! { + // `pub (in super)` means only the module `module` will + // be able to access this. + pub (in super) struct Test: u8 { + const FOO = 1; + } + } + } + + mod test { + // Note: due to `pub (in super)`, + // this cannot be accessed directly by the testing code. + pub(super) fn value() -> u8 { + super::submodule::Test::FOO.bits() + } + } + + pub fn value() -> u8 { + test::value() + } + } + + assert_eq!(module::value(), 1) + } + + #[test] + fn test_zero_value_flags() { + bitflags! { + struct Flags: u32 { + const NONE = 0b0; + const SOME = 0b1; + } + } + + assert!(Flags::empty().contains(Flags::NONE)); + assert!(Flags::SOME.contains(Flags::NONE)); + assert!(Flags::NONE.is_empty()); + + assert_eq!(format!("{:?}", Flags::empty()), "NONE"); + assert_eq!(format!("{:?}", Flags::SOME), "SOME"); + } +} diff --git a/src/imservice.c b/src/imservice.c index 9c565040..1a743e28 100644 --- a/src/imservice.c +++ b/src/imservice.c @@ -7,14 +7,6 @@ void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method, uint32_t cause) {} -void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method, uint32_t hint, uint32_t purpose) -{ - struct imservice *ims = (struct imservice*)data; - EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(ims->ui_manager); - - eekboard_context_service_set_hint_purpose(context, hint, purpose); -} - void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method) {} diff --git a/src/imservice.h b/src/imservice.h index 271f863f..46933916 100644 --- a/src/imservice.h +++ b/src/imservice.h @@ -22,5 +22,6 @@ void imservice_handle_input_method_deactivate(void *data, struct zwp_input_metho void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *input_method, const char *text, uint32_t cursor, uint32_t anchor); void imservice_handle_commit_state(void *data, struct zwp_input_method_v2 *input_method); +void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method, uint32_t hint, uint32_t purpose); #endif diff --git a/src/imservice.rs b/src/imservice.rs index 8de61063..1ef197ea 100644 --- a/src/imservice.rs +++ b/src/imservice.rs @@ -1,9 +1,11 @@ +#[macro_use] +mod bitflags; + use std::boxed::Box; use std::ffi::CString; use std::num::Wrapping; use std::string::String; - /// Gathers stuff defined in C or called by C pub mod c { use super::*; @@ -18,7 +20,7 @@ pub mod c { } // The following defined in C - + /// struct zwp_input_method_v2* #[repr(transparent)] pub struct InputMethod(*const c_void); @@ -31,6 +33,7 @@ pub mod c { extern "C" { fn imservice_make_visible(imservice: *const UIManager); fn imservice_try_hide(imservice: *const UIManager); + fn eekboard_context_service_set_hint_purpose(imservice: *const UIManager, hint: u32, purpose: u32); } // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers @@ -86,7 +89,31 @@ pub mod c { imservice.pending = IMProtocolState { surrounding_text: into_cstring(text).expect("Received invalid string"), surrounding_cursor: cursor, - ..imservice.pending + ..imservice.pending.clone() + }; + } + + #[no_mangle] + pub unsafe extern "C" + fn imservice_handle_content_type(imservice: *mut IMService, + _im: *const InputMethod, + hint: u32, purpose: u32) + { + let imservice = &mut *imservice; + imservice.pending = IMProtocolState { + content_hint: { + ContentHint::from_bits(hint).unwrap_or_else(|| { + eprintln!("Warning: received invalid hint flags"); + ContentHint::default() + }) + }, + content_purpose: { + ContentPurpose::from_num(purpose).unwrap_or_else(|| { + eprintln!("Warning: Received invalid purpose flags"); + ContentPurpose::Normal + }) + }, + ..imservice.pending.clone() }; } @@ -107,6 +134,10 @@ pub mod c { if active_changed { if imservice.current.active { imservice_make_visible(imservice.ui_manager); + eekboard_context_service_set_hint_purpose( + imservice.ui_manager, + imservice.current.content_hint.bits(), + imservice.current.content_purpose.as_num()); } else { imservice_try_hide(imservice.ui_manager); } @@ -116,11 +147,98 @@ pub mod c { // FIXME: destroy and deallocate } + +bitflags!{ + /// Map to `text_input_unstable_v3.content_hint` values + #[derive(Default)] + pub struct ContentHint: u32 { + const COMPLETION = 0x1; + const SPELLCHECK = 0x2; + const AUTO_CAPITALIZATION = 0x4; + const LOWERCASE = 0x8; + const UPPERCASE = 0x10; + const TITLECASE = 0x20; + const HIDDEN_TEXT = 0x40; + const SENSITIVE_DATA = 0x80; + const LATIN = 0x100; + const MULTILINE = 0x200; + } +} + +/// Map to `text_input_unstable_v3.content_purpose` values +#[derive(Debug, Clone)] +pub enum ContentPurpose { + Normal, + Alpha, + Digits, + Number, + Phone, + Url, + Email, + Name, + Password, + Pin, + Date, + Time, + Datetime, + Terminal, +} + +impl Default for ContentPurpose { + fn default() -> ContentPurpose { + ContentPurpose::Normal + } +} + +impl ContentPurpose { + fn from_num(num: u32) -> Option { + use ContentPurpose::*; + match num { + 0 => Some(Normal), + 1 => Some(Alpha), + 2 => Some(Digits), + 3 => Some(Number), + 4 => Some(Phone), + 5 => Some(Url), + 6 => Some(Email), + 7 => Some(Name), + 8 => Some(Password), + 9 => Some(Pin), + 10 => Some(Date), + 11 => Some(Time), + 12 => Some(Datetime), + 13 => Some(Terminal), + _ => None, + } + } + fn as_num(self: &ContentPurpose) -> u32 { + use ContentPurpose::*; + match self { + Normal => 0, + Alpha => 1, + Digits => 2, + Number => 3, + Phone => 4, + Url => 5, + Email => 6, + Name => 7, + Password => 8, + Pin => 9, + Date => 10, + Time => 11, + Datetime => 12, + Terminal => 13, + } + } +} + /// Describes the desired state of the input method as requested by the server #[derive(Default, Clone)] struct IMProtocolState { surrounding_text: CString, surrounding_cursor: u32, + content_purpose: ContentPurpose, + content_hint: ContentHint, active: bool, } From fad06348a7c22599d9367c7bd6bd3eb2321f9a99 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 22 Jul 2019 13:07:39 +0000 Subject: [PATCH 2/5] imservice: Make imservice opaque The structure is defined in Rust, with the intention of evaluating using Rust in this area. It's specifically not defined as repr(C), in order to encourage that. Without the repr, it was unsafe to have its members exposed in C. --- src/imservice.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/imservice.h b/src/imservice.h index 46933916..fab7c106 100644 --- a/src/imservice.h +++ b/src/imservice.h @@ -4,11 +4,7 @@ #include "input-method-unstable-v2-client-protocol.h" #include "eek/eek-types.h" -struct imservice -{ - struct zwp_input_method_v2 *im; - EekboardContextService *ui_manager; -}; +struct imservice; struct imservice* get_imservice(EekboardContextService *context, struct zwp_input_method_manager_v2 *manager, From 622ba6e38a9a7de9815a4f013a3e8392902bc6a5 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 22 Jul 2019 13:24:12 +0000 Subject: [PATCH 3/5] imservice: Handle text change cause Nothing is being done with this information yet --- src/imservice.c | 2 -- src/imservice.h | 1 + src/imservice.rs | 67 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/imservice.c b/src/imservice.c index 1a743e28..0eaa9db7 100644 --- a/src/imservice.c +++ b/src/imservice.c @@ -5,8 +5,6 @@ #include "eekboard/eekboard-context-service.h" -void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method, uint32_t cause) {} - void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method) {} diff --git a/src/imservice.h b/src/imservice.h index fab7c106..6f41bdbe 100644 --- a/src/imservice.h +++ b/src/imservice.h @@ -19,5 +19,6 @@ void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *i const char *text, uint32_t cursor, uint32_t anchor); void imservice_handle_commit_state(void *data, struct zwp_input_method_v2 *input_method); void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method, uint32_t hint, uint32_t purpose); +void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method, uint32_t cause); #endif diff --git a/src/imservice.rs b/src/imservice.rs index 1ef197ea..b0daea89 100644 --- a/src/imservice.rs +++ b/src/imservice.rs @@ -104,7 +104,7 @@ pub mod c { content_hint: { ContentHint::from_bits(hint).unwrap_or_else(|| { eprintln!("Warning: received invalid hint flags"); - ContentHint::default() + ContentHint::NONE }) }, content_purpose: { @@ -117,6 +117,24 @@ pub mod c { }; } + #[no_mangle] + pub unsafe extern "C" + fn imservice_handle_text_change_cause(imservice: *mut IMService, + _im: *const InputMethod, + cause: u32) + { + let imservice = &mut *imservice; + imservice.pending = IMProtocolState { + text_change_cause: { + ChangeCause::from_num(cause).unwrap_or_else(|| { + eprintln!("Warning: received invalid cause flags"); + ChangeCause::InputMethod + }) + }, + ..imservice.pending.clone() + }; + } + #[no_mangle] pub unsafe extern "C" fn imservice_handle_commit_state(imservice: *mut IMService, @@ -150,8 +168,8 @@ pub mod c { bitflags!{ /// Map to `text_input_unstable_v3.content_hint` values - #[derive(Default)] pub struct ContentHint: u32 { + const NONE = 0x0; const COMPLETION = 0x1; const SPELLCHECK = 0x2; const AUTO_CAPITALIZATION = 0x4; @@ -184,12 +202,6 @@ pub enum ContentPurpose { Terminal, } -impl Default for ContentPurpose { - fn default() -> ContentPurpose { - ContentPurpose::Normal - } -} - impl ContentPurpose { fn from_num(num: u32) -> Option { use ContentPurpose::*; @@ -232,16 +244,53 @@ impl ContentPurpose { } } +/// Map to `text_input_unstable_v3.change_cause` values +#[derive(Debug, Clone)] +pub enum ChangeCause { + InputMethod, + Other, +} + +impl ChangeCause { + pub fn from_num(num: u32) -> Option { + match num { + 0 => Some(ChangeCause::InputMethod), + 1 => Some(ChangeCause::Other), + _ => None + } + } + pub fn as_num(&self) -> u32 { + match &self { + ChangeCause::InputMethod => 0, + ChangeCause::Other => 1, + } + } +} + /// Describes the desired state of the input method as requested by the server -#[derive(Default, Clone)] +#[derive(Clone)] struct IMProtocolState { surrounding_text: CString, surrounding_cursor: u32, content_purpose: ContentPurpose, content_hint: ContentHint, + text_change_cause: ChangeCause, active: bool, } +impl Default for IMProtocolState { + fn default() -> IMProtocolState { + IMProtocolState { + surrounding_text: CString::default(), + surrounding_cursor: 0, // TODO: mark that there's no cursor + content_hint: ContentHint::NONE, + content_purpose: ContentPurpose::Normal, + text_change_cause: ChangeCause::InputMethod, + active: false, + } + } +} + pub struct IMService { /// Owned reference (still created and destroyed in C) im: *const c::InputMethod, From c5d2d76ab18d8f4e107af24a992c6eaeae6f9ac6 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 22 Jul 2019 15:56:38 +0000 Subject: [PATCH 4/5] imservice: Handle unavailable message --- src/imservice.c | 9 ++++++--- src/imservice.h | 1 + src/imservice.rs | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/imservice.c b/src/imservice.c index 0eaa9db7..df245072 100644 --- a/src/imservice.c +++ b/src/imservice.c @@ -5,9 +5,6 @@ #include "eekboard/eekboard-context-service.h" -void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method) {} - - static const struct zwp_input_method_v2_listener input_method_listener = { .activate = imservice_handle_input_method_activate, .deactivate = imservice_handle_input_method_deactivate, @@ -42,3 +39,9 @@ void imservice_try_hide(EekboardContextService *context, (void)im; eekboard_context_service_hide_keyboard (context); } + +/// Declared explicitly because _destroy is inline, +/// making it unavailable in Rust +void imservice_destroy_im(struct zwp_input_method_v2 *im) { + zwp_input_method_v2_destroy(im); +} diff --git a/src/imservice.h b/src/imservice.h index 6f41bdbe..71c59275 100644 --- a/src/imservice.h +++ b/src/imservice.h @@ -20,5 +20,6 @@ void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *i void imservice_handle_commit_state(void *data, struct zwp_input_method_v2 *input_method); void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method, uint32_t hint, uint32_t purpose); void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method, uint32_t cause); +void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method); #endif diff --git a/src/imservice.rs b/src/imservice.rs index b0daea89..73f9d7ee 100644 --- a/src/imservice.rs +++ b/src/imservice.rs @@ -33,6 +33,7 @@ pub mod c { extern "C" { fn imservice_make_visible(imservice: *const UIManager); fn imservice_try_hide(imservice: *const UIManager); + fn imservice_destroy_im(im: *mut c::InputMethod); fn eekboard_context_service_set_hint_purpose(imservice: *const UIManager, hint: u32, purpose: u32); } @@ -162,6 +163,22 @@ pub mod c { } } + #[no_mangle] + pub unsafe extern "C" + fn imservice_handle_unavailable(imservice: *mut IMService, + im: *mut InputMethod) + { + imservice_destroy_im(im); + + let imservice = &mut *imservice; + + // no need to care about proper double-buffering, + // the keyboard is already decommissioned + imservice.current.active = false; + + imservice_try_hide(imservice.ui_manager); + } + // FIXME: destroy and deallocate } From 7e939c36cc4848879c3a97a40a607fdac5db2a47 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 22 Jul 2019 16:00:59 +0000 Subject: [PATCH 5/5] imservice: Call show/hide directly --- src/imservice.c | 8 ++------ src/imservice.rs | 10 +++++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/imservice.c b/src/imservice.c index df245072..efa6208a 100644 --- a/src/imservice.c +++ b/src/imservice.c @@ -28,15 +28,11 @@ struct imservice* get_imservice(EekboardContextService *context, return imservice; } -void imservice_make_visible(EekboardContextService *context, - struct zwp_input_method_v2 *im) { - (void)im; +void imservice_make_visible(EekboardContextService *context) { eekboard_context_service_show_keyboard (context); } -void imservice_try_hide(EekboardContextService *context, - struct zwp_input_method_v2 *im) { - (void)im; +void imservice_try_hide(EekboardContextService *context) { eekboard_context_service_hide_keyboard (context); } diff --git a/src/imservice.rs b/src/imservice.rs index 73f9d7ee..b59dad66 100644 --- a/src/imservice.rs +++ b/src/imservice.rs @@ -31,10 +31,10 @@ pub mod c { #[no_mangle] extern "C" { - fn imservice_make_visible(imservice: *const UIManager); - fn imservice_try_hide(imservice: *const UIManager); fn imservice_destroy_im(im: *mut c::InputMethod); fn eekboard_context_service_set_hint_purpose(imservice: *const UIManager, hint: u32, purpose: u32); + fn eekboard_context_service_show_keyboard(imservice: *const UIManager); + fn eekboard_context_service_hide_keyboard(imservice: *const UIManager); } // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers @@ -152,13 +152,13 @@ pub mod c { }; if active_changed { if imservice.current.active { - imservice_make_visible(imservice.ui_manager); + eekboard_context_service_show_keyboard(imservice.ui_manager); eekboard_context_service_set_hint_purpose( imservice.ui_manager, imservice.current.content_hint.bits(), imservice.current.content_purpose.as_num()); } else { - imservice_try_hide(imservice.ui_manager); + eekboard_context_service_hide_keyboard(imservice.ui_manager); } } } @@ -176,7 +176,7 @@ pub mod c { // the keyboard is already decommissioned imservice.current.active = false; - imservice_try_hide(imservice.ui_manager); + eekboard_context_service_hide_keyboard(imservice.ui_manager); } // FIXME: destroy and deallocate