use crate::{data_structure, Elf64Word};

/// indicates the segment is executable.
pub const ELF_PROGRAM_HEADER_FLAG_EXECUTABLE: Elf64Word = 0b1;
/// indicates the segment is writable.
pub const ELF_PROGRAM_HEADER_FLAG_WRITABLE: Elf64Word = 0b10;
/// indicates the segment is readable.
pub const ELF_PROGRAM_HEADER_FLAG_READABLE: Elf64Word = 0b100;

/// the flag set of the program heder
pub type ProgramHeaderFlagSet = data_structure::FlagSet<Elf64Word>;

impl ProgramHeaderFlagSet {
    /// initializes a flag set that all flags stand.
    pub fn all() -> Self {
        Self {
            inner: ELF_PROGRAM_HEADER_FLAG_READABLE
                | ELF_PROGRAM_HEADER_FLAG_WRITABLE
                | ELF_PROGRAM_HEADER_FLAG_EXECUTABLE,
        }
    }
}

impl From<Elf64Word> for ProgramHeaderFlagSet {
    fn from(value: Elf64Word) -> Self {
        Self { inner: value }
    }
}

pub enum ProgramHeaderFlag {
    /// the segment is executable
    Executable,
    /// the segment is writable
    Writable,
    /// the segment is readable
    Readable,
    /// custom value
    Any(Elf64Word),
}

impl From<Elf64Word> for ProgramHeaderFlag {
    fn from(value: Elf64Word) -> Self {
        match value {
            ELF_PROGRAM_HEADER_FLAG_EXECUTABLE => Self::Executable,
            ELF_PROGRAM_HEADER_FLAG_WRITABLE => Self::Writable,
            ELF_PROGRAM_HEADER_FLAG_READABLE => Self::Readable,
            _ => Self::Any(value),
        }
    }
}

impl From<ProgramHeaderFlag> for Elf64Word {
    fn from(value: ProgramHeaderFlag) -> Self {
        match value {
            ProgramHeaderFlag::Executable => ELF_PROGRAM_HEADER_FLAG_EXECUTABLE,
            ProgramHeaderFlag::Writable => ELF_PROGRAM_HEADER_FLAG_WRITABLE,
            ProgramHeaderFlag::Readable => ELF_PROGRAM_HEADER_FLAG_READABLE,
            ProgramHeaderFlag::Any(value) => value,
        }
    }
}
