//! Constants definition

use crate as androscalpel_serializer;
use crate::core::Serializable;

/// [dex-file-magic](https://source.android.com/docs/core/runtime/dex-format#dex-file-magic)
/// `version` is the Dex version of this file (encoded decimal digit).
#[derive(Serializable, PartialEq, Eq, Debug, Clone)]
pub struct DexFileMagic {
    #[prefix([0x64, 0x65, 0x78, 0x0a])]
    #[suffix([0x00])]
    pub version: [u8; 3],
}

/// [endian-constant](https://source.android.com/docs/core/runtime/dex-format#endian-constant)
///
/// The only supported value as of 2023 is [`EndianConstant`]
/// ([because](https://cs.android.com/android/platform/superproject/main/+/main:art/libdexfile/dex/dex_file_verifier.cc;l=597;drc=397dd78fcdcfed36ee62302e2b90712e2d784364))
#[derive(Serializable, PartialEq, Eq, Debug, Clone)]
#[prefix_type(u32)]
pub enum EndianConstant {
    #[prefix(0x12345678)]
    EndianConstant,
    #[prefix(0x78563412)]
    ReverseEndianConstant,
    #[default_variant]
    Unknown(u32),
}

/// [no-index](https://source.android.com/docs/core/runtime/dex-format#no-index)
pub const NO_INDEX: crate::Uleb128p1 = crate::Uleb128p1(0xFFFFFFFF);

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// public: visible everywhere
///
/// # For Fields
///
/// public: visible everywhere
///
/// # For Methods
///
/// public: visible everywhere
pub const ACC_PUBLIC: u32 = 0x1;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// private: only visible to defining class
///
/// Only allowed on for `InnerClass` annotations, and must not ever be on in a `class_def_item`
///
/// # For Fields
///
/// private: only visible to defining class
///
/// # For Methods
///
/// private: only visible to defining class
pub const ACC_PRIVATE: u32 = 0x2;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// protected: visible to package and subclasses
///
/// Only allowed on for `InnerClass` annotations, and must not ever be on in a `class_def_item`
///
/// # For Fields
///
/// protected: visible to package and subclasses
///
/// # For Methods
///
/// protected: visible to package and subclasses
pub const ACC_PROTECTED: u32 = 0x4;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// static: is not constructed with an outer this reference
///
/// Only allowed on for `InnerClass` annotations, and must not ever be on in a `class_def_item`
///
/// # For Fields
///
/// static: global to defining class
///
/// # For Methods
///
/// static: does not take a this argument
pub const ACC_STATIC: u32 = 0x8;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// final: not subclassable
///
/// # For Fields
///
/// final: immutable after construction
///
/// # For Methods
///
/// final: not overridable
pub const ACC_FINAL: u32 = 0x10;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Methods
///
/// synchronized: associated lock automatically acquired around call to this method.
///
/// Note: This is only valid to set when ACC_NATIVE is also set.
pub const ACC_SYNCHRONIZED: u32 = 0x20;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Fields
///
/// volatile: special access rules to help with thread safety
pub const ACC_VOLATILE: u32 = 0x40;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Methods
///
/// bridge method, added automatically by compiler as a type-safe bridge
pub const ACC_BRIDGE: u32 = 0x40;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Fields
///
/// transient: not to be saved by default serialization
pub const ACC_TRANSIENT: u32 = 0x80;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Methods
///
/// last argument should be treated as a "rest" argument by compiler
pub const ACC_VARARGS: u32 = 0x80;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Methods
///
/// native: implemented in native code
pub const ACC_NATIVE: u32 = 0x100;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// interface: multiply-implementable abstract class
pub const ACC_INTERFACE: u32 = 0x200;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// abstract: not directly instantiable
///
/// # For Methods
///
/// abstract: unimplemented by this class
pub const ACC_ABSTRACT: u32 = 0x400;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Methods
///
/// strictfp: strict rules for floating-point arithmetic
pub const ACC_STRICT: u32 = 0x800;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// not directly defined in source code
///
/// # For Fields
///
/// not directly defined in source code
///
/// # For Methods
///
/// not directly defined in source code
pub const ACC_SYNTHETIC: u32 = 0x1000;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// declared as an annotation class
pub const ACC_ANNOTATION: u32 = 0x2000;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Classes / InnerClass annotation
///
/// declared as an enumerated type
///
/// # For Fields
///
/// declared as an enumerated value
pub const ACC_ENUM: u32 = 0x4000;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Methods
///
/// constructor method (class or instance initializer)
pub const ACC_CONSTRUCTOR: u32 = 0x10000;

/// [access-flags](https://source.android.com/docs/core/runtime/dex-format#access-flags)
///
/// # For Methods
///
/// declared synchronized.
///
/// Note: This has no effect on execution (other than in reflection of this flag, per se).
pub const ACC_DECLARED_SYNCHRONIZED: u32 = 0x20000;

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

    #[test]
    fn test_dexfilemagic() {
        assert_eq!(
            DexFileMagic {
                version: [b'0', b'3', b'9']
            }
            .serialize_to_vec()
            .unwrap(),
            vec![0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x39, 0x00]
        );
        assert_eq!(
            DexFileMagic::deserialize_from_slice(&[0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x39, 0x00])
                .unwrap(),
            DexFileMagic {
                version: [b'0', b'3', b'9']
            }
        );
    }

    #[test]
    fn test_endianconstant() {
        assert_eq!(
            EndianConstant::EndianConstant.serialize_to_vec().unwrap(),
            vec![0x78, 0x56, 0x34, 0x12]
        );
        assert_eq!(
            EndianConstant::deserialize_from_slice(&[0x78, 0x56, 0x34, 0x12]).unwrap(),
            EndianConstant::EndianConstant
        );
    }
}
