//! Generate the internal `bitflags`-facing flags type.
//!
//! The code generated here is owned by `bitflags`, but still part of its public API.
//! Changes to the types generated here need to be considered like any other public API change.

/// Declare the `bitflags`-facing bitflags struct.
///
/// This type is part of the `bitflags` crate's public API, but not part of the user's.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __declare_internal_bitflags {
    (
        $vis:vis struct $InternalBitFlags:ident: $T:ty;
        $iter_vis:vis struct $Iter:ident;
        $iter_names_vis:vis struct $IterNames:ident;
    ) => {
        // NOTE: The ABI of this type is _guaranteed_ to be the same as `T`
        // This is relied on by some external libraries like `bytemuck` to make
        // its `unsafe` trait impls sound.
        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
        #[repr(transparent)]
        $vis struct $InternalBitFlags {
            bits: $T,
        }

        $iter_vis struct $Iter {
            inner: $IterNames,
            done: bool,
        }

        $iter_names_vis struct $IterNames {
            idx: usize,
            source: $InternalBitFlags,
            state: $InternalBitFlags,
        }
    };
}

/// Implement functions on the private (bitflags-facing) bitflags type.
///
/// Methods and trait implementations can be freely added here without breaking end-users.
/// If we want to expose new functionality to `#[derive]`, this is the place to do it.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __impl_internal_bitflags {
    (
        $InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterNames:ident {
            $(
                $(#[$attr:ident $($args:tt)*])*
                $Flag:ident;
            )*
        }
    ) => {
        impl $crate::__private::PublicFlags for $BitFlags {
            type Internal = $InternalBitFlags;
        }

        impl $crate::__private::core::default::Default for $InternalBitFlags {
            #[inline]
            fn default() -> Self {
                $InternalBitFlags::empty()
            }
        }

        impl $crate::__private::core::fmt::Debug for $InternalBitFlags {
            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter<'_>) -> $crate::__private::core::fmt::Result {
                if self.is_empty() {
                    // If no flags are set then write an empty hex flag to avoid
                    // writing an empty string. In some contexts, like serialization,
                    // an empty string is preferrable, but it may be unexpected in
                    // others for a format not to produce any output.
                    //
                    // We can remove this `0x0` and remain compatible with `FromStr`,
                    // because an empty string will still parse to an empty set of flags,
                    // just like `0x0` does.
                    $crate::__private::core::write!(f, "{:#x}", <$T as $crate::__private::Bits>::EMPTY)
                } else {
                    $crate::__private::core::fmt::Display::fmt(self, f)
                }
            }
        }

        impl $crate::__private::core::fmt::Display for $InternalBitFlags {
            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter<'_>) -> $crate::__private::core::fmt::Result {
                // A formatter for bitflags that produces text output like:
                //
                // A | B | 0xf6
                //
                // The names of set flags are written in a bar-separated-format,
                // followed by a hex number of any remaining bits that are set
                // but don't correspond to any flags.

                // Iterate over the valid flags
                let mut first = true;
                let mut iter = self.iter_names();
                for (name, _) in &mut iter {
                    if !first {
                        f.write_str(" | ")?;
                    }

                    first = false;
                    f.write_str(name)?;
                }

                // Append any extra bits that correspond to flags to the end of the format
                let extra_bits = iter.state.bits();
                if extra_bits != <$T as $crate::__private::Bits>::EMPTY {
                    if !first {
                        f.write_str(" | ")?;
                    }

                    $crate::__private::core::write!(f, "{:#x}", extra_bits)?;
                }

                $crate::__private::core::fmt::Result::Ok(())
            }
        }

        // The impl for `FromStr` should parse anything produced by `Display`
        impl $crate::__private::core::str::FromStr for $InternalBitFlags {
            type Err = $crate::parser::ParseError;

            fn from_str(s: &str) -> $crate::__private::core::result::Result<Self, Self::Err> {
                let s = s.trim();

                let mut parsed_flags = Self::empty();

                // If the input is empty then return an empty set of flags
                if s.is_empty() {
                    return $crate::__private::core::result::Result::Ok(parsed_flags);
                }

                for flag in s.split('|') {
                    let flag = flag.trim();

                    // If the flag is empty then we've got missing input
                    if flag.is_empty() {
                        return $crate::__private::core::result::Result::Err($crate::parser::ParseError::empty_flag());
                    }

                    // If the flag starts with `0x` then it's a hex number
                    // Parse it directly to the underlying bits type
                    let parsed_flag = if let $crate::__private::core::option::Option::Some(flag) = flag.strip_prefix("0x") {
                        let bits = <$T>::from_str_radix(flag, 16).map_err(|_| $crate::parser::ParseError::invalid_hex_flag(flag))?;

                        Self::from_bits_retain(bits)
                    }
                    // Otherwise the flag is a name
                    // The generated flags type will determine whether
                    // or not it's a valid identifier
                    else {
                        Self::from_name(flag).ok_or_else(|| $crate::parser::ParseError::invalid_named_flag(flag))?
                    };

                    parsed_flags.insert(parsed_flag);
                }

                $crate::__private::core::result::Result::Ok(parsed_flags)
            }
        }

        impl $crate::__private::core::fmt::Binary for $InternalBitFlags {
            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
                $crate::__private::core::fmt::Binary::fmt(&self.bits(), f)
            }
        }

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

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

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

        impl $InternalBitFlags {
            #[inline]
            pub const fn empty() -> Self {
                Self { bits: <$T as $crate::__private::Bits>::EMPTY }
            }

            #[inline]
            pub const fn all() -> Self {
                Self::from_bits_truncate(<$T as $crate::__private::Bits>::ALL)
            }

            #[inline]
            pub const fn bits(&self) -> $T {
                self.bits
            }

            #[inline]
            pub fn bits_mut(&mut self) -> &mut $T {
                &mut self.bits
            }

            #[inline]
            pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option<Self> {
                let truncated = Self::from_bits_truncate(bits).bits;

                if truncated == bits {
                    $crate::__private::core::option::Option::Some(Self { bits })
                } else {
                    $crate::__private::core::option::Option::None
                }
            }

            #[inline]
            pub const fn from_bits_truncate(bits: $T) -> Self {
                if bits == <$T as $crate::__private::Bits>::EMPTY {
                    return Self { bits }
                }

                let mut truncated = <$T as $crate::__private::Bits>::EMPTY;

                $(
                    __expr_safe_flags!(
                        $(#[$attr $($args)*])*
                        {
                            if bits & $BitFlags::$Flag.bits() == $BitFlags::$Flag.bits() {
                                truncated |= $BitFlags::$Flag.bits()
                            }
                        }
                    );
                )*

                Self { bits: truncated }
            }

            #[inline]
            pub const fn from_bits_retain(bits: $T) -> Self {
                Self { bits }
            }

            #[inline]
            pub fn from_name(name: &str) -> $crate::__private::core::option::Option<Self> {
                $(
                    __expr_safe_flags!(
                        $(#[$attr $($args)*])*
                        {
                            if name == $crate::__private::core::stringify!($Flag) {
                                return $crate::__private::core::option::Option::Some(Self { bits: $BitFlags::$Flag.bits() });
                            }
                        }
                    );
                )*

                let _ = name;
                $crate::__private::core::option::Option::None
            }

            #[inline]
            pub const fn iter(&self) -> $Iter {
                $Iter {
                    inner: self.iter_names(),
                    done: false,
                }
            }

            #[inline]
            pub const fn iter_names(&self) -> $IterNames {
                $IterNames {
                    idx: 0,
                    source: *self,
                    state: *self,
                }
            }

            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.bits == Self::empty().bits
            }

            #[inline]
            pub const fn is_all(&self) -> bool {
                Self::all().bits | self.bits == self.bits
            }

            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                !(Self { bits: self.bits & other.bits}).is_empty()
            }

            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                (self.bits & other.bits) == other.bits
            }

            #[inline]
            pub fn insert(&mut self, other: Self) {
                self.bits |= other.bits;
            }

            #[inline]
            pub fn remove(&mut self, other: Self) {
                self.bits &= !other.bits;
            }

            #[inline]
            pub fn toggle(&mut self, other: Self) {
                self.bits ^= other.bits;
            }

            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                if value {
                    self.insert(other);
                } else {
                    self.remove(other);
                }
            }

            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self { bits: self.bits & other.bits }
            }

            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self { bits: self.bits | other.bits }
            }

            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self { bits: self.bits & !other.bits }
            }

            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self { bits: self.bits ^ other.bits }
            }

            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self::from_bits_truncate(!self.bits)
            }
        }

        impl $crate::__private::core::convert::AsRef<$T> for $InternalBitFlags {
            fn as_ref(&self) -> &$T {
                &self.bits
            }
        }

        impl $crate::__private::core::convert::From<$T> for $InternalBitFlags {
            fn from(bits: $T) -> Self {
                Self::from_bits_retain(bits)
            }
        }

        impl $crate::__private::core::iter::Iterator for $Iter {
            type Item = $BitFlags;

            fn next(&mut self) -> $crate::__private::core::option::Option<Self::Item> {
                match self.inner.next().map(|(_, value)| value) {
                    $crate::__private::core::option::Option::Some(value) => $crate::__private::core::option::Option::Some(value),
                    $crate::__private::core::option::Option::None if !self.done => {
                        self.done = true;

                        // After iterating through valid names, if there are any bits left over
                        // then return one final value that includes them. This makes `into_iter`
                        // and `from_iter` roundtrip
                        if self.inner.state != $InternalBitFlags::empty() {
                            $crate::__private::core::option::Option::Some($BitFlags::from_bits_retain(self.inner.state.bits()))
                        } else {
                            $crate::__private::core::option::Option::None
                        }
                    },
                    _ => $crate::__private::core::option::Option::None,
                }
            }
        }

        impl $crate::__private::core::iter::Iterator for $IterNames {
            type Item = (&'static str, $BitFlags);

            fn next(&mut self) -> $crate::__private::core::option::Option<Self::Item> {
                const NUM_FLAGS: usize = {
                    let mut num_flags = 0;

                    $(
                        __expr_safe_flags!(
                            $(#[$attr $($args)*])*
                            {
                                { num_flags += 1; }
                            }
                        );
                    )*

                    num_flags
                };

                const OPTIONS: [$T; NUM_FLAGS] = [
                    $(
                        __expr_safe_flags!(
                            $(#[$attr $($args)*])*
                            {
                                $BitFlags::$Flag.bits()
                            }
                        ),
                    )*
                ];

                const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [
                    $(
                        __expr_safe_flags!(
                            $(#[$attr $($args)*])*
                            {
                                $crate::__private::core::stringify!($Flag)
                            }
                        ),
                    )*
                ];

                if self.state.is_empty() || NUM_FLAGS == 0 {
                    $crate::__private::core::option::Option::None
                } else {
                    #[allow(clippy::indexing_slicing)]
                    for (flag, flag_name) in OPTIONS[self.idx..NUM_FLAGS].iter().copied()
                        .zip(OPTIONS_NAMES[self.idx..NUM_FLAGS].iter().copied())
                    {
                        self.idx += 1;

                        // NOTE: We check whether the flag exists in self, but remove it from
                        // a different value. This ensure that overlapping flags are handled
                        // properly. Take the following example:
                        //
                        // const A: 0b00000001;
                        // const B: 0b00000101;
                        //
                        // Given the bits 0b00000101, both A and B are set. But if we removed A
                        // as we encountered it we'd be left with 0b00000100, which doesn't
                        // correspond to a valid flag on its own.
                        if self.source.contains($InternalBitFlags { bits: flag }) {
                            self.state.remove($InternalBitFlags { bits: flag });

                            return $crate::__private::core::option::Option::Some((flag_name, $BitFlags::from_bits_retain(flag)))
                        }
                    }

                    $crate::__private::core::option::Option::None
                }
            }
        }
    };
}

/// A macro that processed the input to `bitflags!` and shuffles attributes around
/// based on whether or not they're "expression-safe".
///
/// This macro is a token-tree muncher that works on 2 levels:
///
/// For each attribute, we explicitly match on its identifier, like `cfg` to determine
/// whether or not it should be considered expression-safe.
///
/// If you find yourself with an attribute that should be considered expression-safe
/// and isn't, it can be added here.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __expr_safe_flags {
    // Entrypoint: Move all flags and all attributes into `unprocessed` lists
    // where they'll be munched one-at-a-time
    (
        $(#[$inner:ident $($args:tt)*])*
        { $e:expr }
    ) => {
        __expr_safe_flags! {
            expr: { $e },
            attrs: {
                // All attributes start here
                unprocessed: [$(#[$inner $($args)*])*],
                processed: {
                    // Attributes that are safe on expressions go here
                    expr: [],
                },
            },
        }
    };
    // Process the next attribute on the current flag
    // `cfg`: The next flag should be propagated to expressions
    // NOTE: You can copy this rules block and replace `cfg` with
    // your attribute name that should be considered expression-safe
    (
        expr: { $e:expr },
            attrs: {
            unprocessed: [
                // cfg matched here
                #[cfg $($args:tt)*]
                $($attrs_rest:tt)*
            ],
            processed: {
                expr: [$($expr:tt)*],
            },
        },
    ) => {
        __expr_safe_flags! {
            expr: { $e },
            attrs: {
                unprocessed: [
                    $($attrs_rest)*
                ],
                processed: {
                    expr: [
                        $($expr)*
                        // cfg added here
                        #[cfg $($args)*]
                    ],
                },
            },
        }
    };
    // Process the next attribute on the current flag
    // `$other`: The next flag should not be propagated to expressions
    (
        expr: { $e:expr },
            attrs: {
            unprocessed: [
                // $other matched here
                #[$other:ident $($args:tt)*]
                $($attrs_rest:tt)*
            ],
            processed: {
                expr: [$($expr:tt)*],
            },
        },
    ) => {
        __expr_safe_flags! {
            expr: { $e },
                attrs: {
                unprocessed: [
                    $($attrs_rest)*
                ],
                processed: {
                    expr: [
                        // $other not added here
                        $($expr)*
                    ],
                },
            },
        }
    };
    // Once all attributes on all flags are processed, generate the actual code
    (
        expr: { $e:expr },
        attrs: {
            unprocessed: [],
            processed: {
                expr: [$(#[$expr:ident $($exprargs:tt)*])*],
            },
        },
    ) => {
        $(#[$expr $($exprargs)*])*
        { $e }
    }
}
