//! Generate the user-facing flags type.
//!
//! The code here belongs to the end-user, so new trait implementations and methods can't be
//! added without potentially breaking users.

/// Declare the user-facing bitflags struct.
///
/// This type is guaranteed to be a newtype with a `bitflags`-facing type as its single field.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __declare_public_bitflags {
    (
        $(#[$outer:meta])*
        $vis:vis struct $BitFlags:ident;
    ) => {
        $(#[$outer])*
        $vis struct $BitFlags(<$BitFlags as $crate::__private::PublicFlags>::Internal);
    };
}

/// Implement functions on the public (user-facing) bitflags type.
///
/// We need to be careful about adding new methods and trait implementations here because they
/// could conflict with items added by the end-user.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __impl_public_bitflags {
    (
        $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident, $Iter:ident, $IterNames:ident;
    ) => {
        impl $crate::__private::core::fmt::Binary for $PublicBitFlags {
            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
                $crate::__private::core::fmt::Binary::fmt(&self.0, f)
            }
        }

        impl $crate::__private::core::fmt::Octal for $PublicBitFlags {
            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
                $crate::__private::core::fmt::Octal::fmt(&self.0, f)
            }
        }

        impl $crate::__private::core::fmt::LowerHex for $PublicBitFlags {
            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
                $crate::__private::core::fmt::LowerHex::fmt(&self.0, f)
            }
        }

        impl $crate::__private::core::fmt::UpperHex for $PublicBitFlags {
            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
                $crate::__private::core::fmt::UpperHex::fmt(&self.0, f)
            }
        }

        impl $PublicBitFlags {
            /// Returns an empty set of flags.
            #[inline]
            pub const fn empty() -> Self {
                Self($InternalBitFlags::empty())
            }

            /// Returns the set containing all flags.
            #[inline]
            pub const fn all() -> Self {
                Self($InternalBitFlags::all())
            }

            /// Returns the raw value of the flags currently stored.
            #[inline]
            pub const fn bits(&self) -> $T {
                self.0.bits()
            }

            /// Convert from underlying bit representation, unless that
            /// representation contains bits that do not correspond to a flag.
            #[inline]
            pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option<Self> {
                match $InternalBitFlags::from_bits(bits) {
                    $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)),
                    $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None,
                }
            }

            /// Convert from underlying bit representation, dropping any bits
            /// that do not correspond to flags.
            #[inline]
            pub const fn from_bits_truncate(bits: $T) -> Self {
                Self($InternalBitFlags::from_bits_truncate(bits))
            }

            /// Convert from underlying bit representation, preserving all
            /// bits (even those not corresponding to a defined flag).
            #[inline]
            pub const fn from_bits_retain(bits: $T) -> Self {
                Self($InternalBitFlags::from_bits_retain(bits))
            }

            /// Get the value for a flag from its stringified name.
            ///
            /// Names are _case-sensitive_, so must correspond exactly to
            /// the identifier given to the flag.
            #[inline]
            pub fn from_name(name: &str) -> $crate::__private::core::option::Option<Self> {
                match $InternalBitFlags::from_name(name) {
                    $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)),
                    $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None,
                }
            }

            /// Iterate over enabled flag values.
            #[inline]
            pub const fn iter(&self) -> $Iter {
                self.0.iter()
            }

            /// Iterate over enabled flag values with their stringified names.
            #[inline]
            pub const fn iter_names(&self) -> $IterNames {
                self.0.iter_names()
            }

            /// Returns `true` if no flags are currently stored.
            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.0.is_empty()
            }

            /// Returns `true` if all flags are currently set.
            #[inline]
            pub const fn is_all(&self) -> bool {
                self.0.is_all()
            }

            /// Returns `true` if there are flags common to both `self` and `other`.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0.intersects(other.0)
            }

            /// Returns `true` if all of the flags in `other` are contained within `self`.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0.contains(other.0)
            }

            /// Inserts the specified flags in-place.
            #[inline]
            pub fn insert(&mut self, other: Self) {
                self.0.insert(other.0)
            }

            /// Removes the specified flags in-place.
            #[inline]
            pub fn remove(&mut self, other: Self) {
                self.0.remove(other.0)
            }

            /// Toggles the specified flags in-place.
            #[inline]
            pub fn toggle(&mut self, other: Self) {
                self.0.toggle(other.0)
            }

            /// Inserts or removes the specified flags depending on the passed value.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                self.0.set(other.0, value)
            }

            /// Returns the intersection between the flags in `self` and
            /// `other`.
            ///
            /// Specifically, the returned set contains only the flags which are
            /// present in *both* `self` *and* `other`.
            ///
            /// This is equivalent to using the `&` operator (e.g.
            /// [`ops::BitAnd`]), as in `flags & other`.
            ///
            /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0.intersection(other.0))
            }

            /// Returns the union of between the flags in `self` and `other`.
            ///
            /// Specifically, the returned set contains all flags which are
            /// present in *either* `self` *or* `other`, including any which are
            /// present in both (see [`Self::symmetric_difference`] if that
            /// is undesirable).
            ///
            /// This is equivalent to using the `|` operator (e.g.
            /// [`ops::BitOr`]), as in `flags | other`.
            ///
            /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0.union(other.0))
            }

            /// Returns the difference between the flags in `self` and `other`.
            ///
            /// Specifically, the returned set contains all flags present in
            /// `self`, except for the ones present in `other`.
            ///
            /// It is also conceptually equivalent to the "bit-clear" operation:
            /// `flags & !other` (and this syntax is also supported).
            ///
            /// This is equivalent to using the `-` operator (e.g.
            /// [`ops::Sub`]), as in `flags - other`.
            ///
            /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0.difference(other.0))
            }

            /// Returns the [symmetric difference][sym-diff] between the flags
            /// in `self` and `other`.
            ///
            /// Specifically, the returned set contains the flags present which
            /// are present in `self` or `other`, but that are not present in
            /// both. Equivalently, it contains the flags present in *exactly
            /// one* of the sets `self` and `other`.
            ///
            /// This is equivalent to using the `^` operator (e.g.
            /// [`ops::BitXor`]), as in `flags ^ other`.
            ///
            /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference
            /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0.symmetric_difference(other.0))
            }

            /// Returns the complement of this set of flags.
            ///
            /// Specifically, the returned set contains all the flags which are
            /// not set in `self`, but which are allowed for this type.
            ///
            /// Alternatively, it can be thought of as the set difference
            /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`)
            ///
            /// This is equivalent to using the `!` operator (e.g.
            /// [`ops::Not`]), as in `!flags`.
            ///
            /// [`Self::all()`]: Self::all
            /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self(self.0.complement())
            }
        }

        impl $crate::__private::core::ops::BitOr for $PublicBitFlags {
            type Output = Self;

            /// Returns the union of the two sets of flags.
            #[inline]
            fn bitor(self, other: $PublicBitFlags) -> Self {
                self.union(other)
            }
        }

        impl $crate::__private::core::ops::BitOrAssign for $PublicBitFlags {
            /// Adds the set of flags.
            #[inline]
            fn bitor_assign(&mut self, other: Self) {
                self.0 = self.0.union(other.0);
            }
        }

        impl $crate::__private::core::ops::BitXor for $PublicBitFlags {
            type Output = Self;

            /// Returns the left flags, but with all the right flags toggled.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }

        impl $crate::__private::core::ops::BitXorAssign for $PublicBitFlags {
            /// Toggles the set of flags.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) {
                self.0 = self.0.symmetric_difference(other.0);
            }
        }

        impl $crate::__private::core::ops::BitAnd for $PublicBitFlags {
            type Output = Self;

            /// Returns the intersection between the two sets of flags.
            #[inline]
            fn bitand(self, other: Self) -> Self {
                self.intersection(other)
            }
        }

        impl $crate::__private::core::ops::BitAndAssign for $PublicBitFlags {
            /// Disables all flags disabled in the set.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                self.0 = self.0.intersection(other.0);
            }
        }

        impl $crate::__private::core::ops::Sub for $PublicBitFlags {
            type Output = Self;

            /// Returns the set difference of the two sets of flags.
            #[inline]
            fn sub(self, other: Self) -> Self {
                self.difference(other)
            }
        }

        impl $crate::__private::core::ops::SubAssign for $PublicBitFlags {
            /// Disables all flags enabled in the set.
            #[inline]
            fn sub_assign(&mut self, other: Self) {
                self.0 = self.0.difference(other.0);
            }
        }

        impl $crate::__private::core::ops::Not for $PublicBitFlags {
            type Output = Self;

            /// Returns the complement of this set of flags.
            #[inline]
            fn not(self) -> Self {
                self.complement()
            }
        }

        impl $crate::__private::core::iter::Extend<$PublicBitFlags> for $PublicBitFlags {
            fn extend<T: $crate::__private::core::iter::IntoIterator<Item=Self>>(&mut self, iterator: T) {
                for item in iterator {
                    self.insert(item)
                }
            }
        }

        impl $crate::__private::core::iter::FromIterator<$PublicBitFlags> for $PublicBitFlags {
            fn from_iter<T: $crate::__private::core::iter::IntoIterator<Item=Self>>(iterator: T) -> Self {
                use $crate::__private::core::iter::Extend;

                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }

        impl $crate::__private::core::iter::IntoIterator for $PublicBitFlags {
            type Item = Self;
            type IntoIter = $Iter;

            fn into_iter(self) -> Self::IntoIter {
                self.0.iter()
            }
        }

        impl $crate::BitFlags for $PublicBitFlags {
            type Bits = $T;

            type Iter = $Iter;
            type IterNames = $IterNames;

            fn empty() -> Self {
                $PublicBitFlags::empty()
            }

            fn all() -> Self {
                $PublicBitFlags::all()
            }

            fn bits(&self) -> $T {
                $PublicBitFlags::bits(self)
            }

            fn from_bits(bits: $T) -> $crate::__private::core::option::Option<$PublicBitFlags> {
                $PublicBitFlags::from_bits(bits)
            }

            fn from_bits_truncate(bits: $T) -> $PublicBitFlags {
                $PublicBitFlags::from_bits_truncate(bits)
            }

            fn from_bits_retain(bits: $T) -> $PublicBitFlags {
                $PublicBitFlags::from_bits_retain(bits)
            }

            fn from_name(name: &str) -> $crate::__private::core::option::Option<$PublicBitFlags> {
                $PublicBitFlags::from_name(name)
            }

            fn iter(&self) -> Self::Iter {
                $PublicBitFlags::iter(self)
            }

            fn iter_names(&self) -> Self::IterNames {
                $PublicBitFlags::iter_names(self)
            }

            fn is_empty(&self) -> bool {
                $PublicBitFlags::is_empty(self)
            }

            fn is_all(&self) -> bool {
                $PublicBitFlags::is_all(self)
            }

            fn intersects(&self, other: $PublicBitFlags) -> bool {
                $PublicBitFlags::intersects(self, other)
            }

            fn contains(&self, other: $PublicBitFlags) -> bool {
                $PublicBitFlags::contains(self, other)
            }

            fn insert(&mut self, other: $PublicBitFlags) {
                $PublicBitFlags::insert(self, other)
            }

            fn remove(&mut self, other: $PublicBitFlags) {
                $PublicBitFlags::remove(self, other)
            }

            fn toggle(&mut self, other: $PublicBitFlags) {
                $PublicBitFlags::toggle(self, other)
            }

            fn set(&mut self, other: $PublicBitFlags, value: bool) {
                $PublicBitFlags::set(self, other, value)
            }
        }

        impl $crate::__private::ImplementedByBitFlagsMacro for $PublicBitFlags {}
    };
}

/// Implement constants on the public (user-facing) bitflags type.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __impl_public_bitflags_consts {
    (
        $PublicBitFlags:ident {
            $(
                $(#[$attr:ident $($args:tt)*])*
                $Flag:ident = $value:expr;
            )*
        }
    ) => {
        impl $PublicBitFlags {
            $(
                $(#[$attr $($args)*])*
                pub const $Flag: Self = Self::from_bits_retain($value);
            )*
        }
    };
}
