// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

use crate::enum_utils::{
	to_cc_a, to_cc_ae, to_cc_b, to_cc_be, to_cc_e, to_cc_g, to_cc_ge, to_cc_l, to_cc_le, to_cc_ne, to_cc_np, to_cc_p, to_memory_size_options,
	to_register,
};
use crate::instruction::Instruction;
use crate::utils::to_value_error;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use static_assertions::const_assert_eq;

// GENERATOR-BEGIN: FormatterSyntax
// ⚠️This was generated by GENERATOR!🦹‍♂️
/// Formatter syntax (GNU Assembler, Intel XED, masm, nasm)
#[allow(dead_code)]
pub(crate) enum FormatterSyntax {
	/// GNU Assembler (AT&T)
	Gas = 0,
	/// Intel XED
	Intel = 1,
	/// masm
	Masm = 2,
	/// nasm
	Nasm = 3,
}
// GENERATOR-END: FormatterSyntax

/// x86 formatter that supports GNU Assembler, Intel XED, masm and nasm syntax
///
/// Args:
///     `syntax` (:class:`FormatterSyntax`): Formatter syntax
///
/// Examples:
///
/// .. testcode::
///
///     from iced_x86 import *
///
///     data = b"\x62\xF2\x4F\xDD\x72\x50\x01"
///     decoder = Decoder(64, data)
///     instr = decoder.decode()
///
///     formatter = Formatter(FormatterSyntax.MASM)
///     formatter.uppercase_mnemonics = True
///     disasm = formatter.format(instr)
///     assert disasm == "VCVTNE2PS2BF16 zmm2{k5}{z},zmm6,dword bcst [rax+4]"
#[pyclass(module = "_iced_x86_py")]
#[text_signature = "(syntax, /)"]
pub(crate) struct Formatter {
	fmt_output: String,
	formatter: Box<dyn iced_x86::Formatter>,
}

unsafe impl Send for Formatter {}

#[pymethods]
impl Formatter {
	#[new]
	fn new(syntax: u32) -> PyResult<Self> {
		let formatter: Box<dyn iced_x86::Formatter> = if syntax == FormatterSyntax::Gas as u32 {
			Box::new(iced_x86::GasFormatter::new())
		} else if syntax == FormatterSyntax::Intel as u32 {
			Box::new(iced_x86::IntelFormatter::new())
		} else if syntax == FormatterSyntax::Masm as u32 {
			Box::new(iced_x86::MasmFormatter::new())
		} else if syntax == FormatterSyntax::Nasm as u32 {
			Box::new(iced_x86::NasmFormatter::new())
		} else {
			return Err(PyValueError::new_err("Invalid formatter syntax"));
		};

		Ok(Formatter { fmt_output: String::new(), formatter })
	}

	/// Formats the whole instruction: prefixes, mnemonic, operands
	///
	/// Args:
	///     `instruction` (Instruction): Instruction to format
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, instruction, /)"]
	fn format(&mut self, instruction: &Instruction) -> &str {
		self.fmt_output.clear();
		self.formatter.format(&instruction.instr, &mut self.fmt_output);
		&self.fmt_output
	}

	/// Formats the mnemonic and any prefixes
	///
	/// Args:
	///     `instruction` (Instruction): Instruction to format
	///     `options` (:class:`FormatMnemonicOptions`): (default = :class:`FormatMnemonicOptions.NONE`) Options
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, instruction, options, /)"]
	#[args(options = 0)]
	fn format_mnemonic(&mut self, instruction: &Instruction, options: u32) -> &str {
		// #[args] line assumption
		const_assert_eq!(iced_x86::FormatMnemonicOptions::NONE, 0);

		self.fmt_output.clear();
		self.formatter.format_mnemonic_options(&instruction.instr, &mut self.fmt_output, options);
		&self.fmt_output
	}

	/// Gets the number of operands that will be formatted. A formatter can add and remove operands
	///
	/// Args:
	///     `instruction` (Instruction): Instruction
	///
	/// Returns:
	///     int: Operand count
	#[text_signature = "($self, instruction, /)"]
	fn operand_count(&mut self, instruction: &Instruction) -> u32 {
		self.formatter.operand_count(&instruction.instr)
	}

	/// Returns the operand access but only if it's an operand added by the formatter.
	///
	/// If it's an operand that is part of :class:`Instruction`, you should call eg. :class:`InstructionInfoFactory.info`.
	///
	/// Args:
	///     `instruction` (Instruction): Instruction
	///     `operand` (int): Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. See :class:`Formatter.operand_count`
	///
	/// Returns:
	///     :class:`OpAccess`, None: Operand access or ``None``
	///
	/// Raises:
	///     ValueError: If `operand` is invalid
	#[text_signature = "($self, instruction, operand, /)"]
	fn op_access(&mut self, instruction: &Instruction, operand: u32) -> PyResult<Option<u32>> {
		self.formatter
			.op_access(&instruction.instr, operand)
			.map_or_else(|_| Err(PyValueError::new_err("Invalid operand")), |res| Ok(res.map(|v| v as u32)))
	}

	/// Converts a formatter operand index to an instruction operand index.
	///
	/// Returns ``None`` if it's an operand added by the formatter
	///
	/// Args:
	///     `instruction` (Instruction): Instruction
	///     `operand` (int): Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. See :class:`Formatter.operand_count`
	///
	/// Returns:
	///     int, None: Instruction operand or ``None`` if it's an operand added by the formatter
	///
	/// Raises:
	///     ValueError: If `operand` is invalid
	#[text_signature = "($self, instruction, operand, /)"]
	fn get_instruction_operand(&mut self, instruction: &Instruction, operand: u32) -> PyResult<Option<u32>> {
		self.formatter.get_instruction_operand(&instruction.instr, operand).map_err(to_value_error)
	}

	/// Converts an instruction operand index to a formatter operand index.
	///
	/// Returns ``None`` if the instruction operand isn't used by the formatter
	///
	/// Args:
	///     `instruction` (Instruction): Instruction
	///     `instruction_operand` (int): Instruction operand
	///
	/// Returns:
	///     int, None: Instruction operand or ``None`` if the instruction operand isn't used by the formatter
	///
	/// Raises:
	///     ValueError: If `instruction_operand` is invalid
	#[text_signature = "($self, instruction, instruction_operand, /)"]
	fn get_formatter_operand(&mut self, instruction: &Instruction, instruction_operand: u32) -> PyResult<Option<u32>> {
		self.formatter.get_formatter_operand(&instruction.instr, instruction_operand).map_err(to_value_error)
	}

	/// Formats an operand.
	///
	/// Args:
	///     `instruction` (Instruction): Instruction
	///     `operand` (int): Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. See :class:`Formatter.operand_count`
	///
	/// Returns:
	///     str: The formatted string
	///
	/// Raises:
	///     ValueError: If `operand` is invalid
	#[text_signature = "($self, instruction, operand, /)"]
	fn format_operand(&mut self, instruction: &Instruction, operand: u32) -> PyResult<&str> {
		self.fmt_output.clear();
		self.formatter.format_operand(&instruction.instr, &mut self.fmt_output, operand).map_err(to_value_error)?;
		Ok(&self.fmt_output)
	}

	/// Formats an operand separator
	///
	/// Args:
	///     `instruction` (Instruction): Instruction
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, instruction, /)"]
	fn format_operand_separator(&mut self, instruction: &Instruction) -> &str {
		self.fmt_output.clear();
		self.formatter.format_operand_separator(&instruction.instr, &mut self.fmt_output);
		&self.fmt_output
	}

	/// Formats all operands
	///
	/// Args:
	///     `instruction` (Instruction): Instruction to format
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, instruction, /)"]
	fn format_all_operands(&mut self, instruction: &Instruction) -> &str {
		self.fmt_output.clear();
		self.formatter.format_all_operands(&instruction.instr, &mut self.fmt_output);
		&self.fmt_output
	}

	/// Formats a register
	///
	/// Args:
	///     `register` (:class:`Register`): Register
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, register, /)"]
	fn format_register(&mut self, register: u32) -> PyResult<&str> {
		Ok(self.formatter.format_register(to_register(register)?))
	}

	/// Formats a ``i8``
	///
	/// Args:
	///     `value` (int): (``i8``) Value
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, value, /)"]
	fn format_i8(&mut self, value: i8) -> &str {
		self.formatter.format_i8(value)
	}

	/// Formats a ``i16``
	///
	/// Args:
	///     `value` (int): (``i16``) Value
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, value, /)"]
	fn format_i16(&mut self, value: i16) -> &str {
		self.formatter.format_i16(value)
	}

	/// Formats a ``i32``
	///
	/// Args:
	///     `value` (int): (``i32``) Value
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, value, /)"]
	fn format_i32(&mut self, value: i32) -> &str {
		self.formatter.format_i32(value)
	}

	/// Formats a ``i64``
	///
	/// Args:
	///     `value` (int): (``i64``) Value
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, value, /)"]
	fn format_i64(&mut self, value: i64) -> &str {
		self.formatter.format_i64(value)
	}

	/// Formats a ``u8``
	///
	/// Args:
	///     `value` (int): (``u8``) Value
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, value, /)"]
	fn format_u8(&mut self, value: u8) -> &str {
		self.formatter.format_u8(value)
	}

	/// Formats a ``u16``
	///
	/// Args:
	///     `value` (int): (``u16``) Value
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, value, /)"]
	fn format_u16(&mut self, value: u16) -> &str {
		self.formatter.format_u16(value)
	}

	/// Formats a ``u32``
	///
	/// Args:
	///     `value` (int): (``u32``) Value
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, value, /)"]
	fn format_u32(&mut self, value: u32) -> &str {
		self.formatter.format_u32(value)
	}

	/// Formats a ``u64``
	///
	/// Args:
	///     `value` (int): (``u64``) Value
	///
	/// Returns:
	///     str: The formatted string
	#[text_signature = "($self, value, /)"]
	fn format_u64(&mut self, value: u64) -> &str {
		self.formatter.format_u64(value)
	}

	/// bool: Prefixes are uppercased
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``REP stosd``
	/// ✔️          ``False``   ``rep stosd``
	/// =========== ========== ================================================
	#[getter]
	fn uppercase_prefixes(&self) -> bool {
		self.formatter.options().uppercase_prefixes()
	}

	#[setter]
	fn set_uppercase_prefixes(&mut self, new_value: bool) {
		self.formatter.options_mut().set_uppercase_prefixes(new_value);
	}

	/// bool: Mnemonics are uppercased
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``MOV rcx,rax``
	/// ✔️          ``False``   ``mov rcx,rax``
	/// =========== ========== ================================================
	#[getter]
	fn uppercase_mnemonics(&self) -> bool {
		self.formatter.options().uppercase_mnemonics()
	}

	#[setter]
	fn set_uppercase_mnemonics(&mut self, new_value: bool) {
		self.formatter.options_mut().set_uppercase_mnemonics(new_value);
	}

	/// bool: Registers are uppercased
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov RCX,[RAX+RDX*8]``
	/// ✔️          ``False``   ``mov rcx,[rax+rdx*8]``
	/// =========== ========== ================================================
	#[getter]
	fn uppercase_registers(&self) -> bool {
		self.formatter.options().uppercase_registers()
	}

	#[setter]
	fn set_uppercase_registers(&mut self, new_value: bool) {
		self.formatter.options_mut().set_uppercase_registers(new_value);
	}

	/// bool: Keywords are uppercased (eg. ``BYTE PTR``, ``SHORT``)
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov BYTE PTR [rcx],12h``
	/// ✔️          ``False``   ``mov byte ptr [rcx],12h``
	/// =========== ========== ================================================
	#[getter]
	fn uppercase_keywords(&self) -> bool {
		self.formatter.options().uppercase_keywords()
	}

	#[setter]
	fn set_uppercase_keywords(&mut self, new_value: bool) {
		self.formatter.options_mut().set_uppercase_keywords(new_value);
	}

	/// bool: Uppercase decorators, eg. ``{z}``, ``{sae}``, ``{rd-sae}`` (but not opmask registers: ``{k1}``)
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``vunpcklps xmm2{k5}{Z},xmm6,dword bcst [rax+4]``
	/// ✔️          ``False``   ``vunpcklps xmm2{k5}{z},xmm6,dword bcst [rax+4]``
	/// =========== ========== ================================================
	#[getter]
	fn uppercase_decorators(&self) -> bool {
		self.formatter.options().uppercase_decorators()
	}

	#[setter]
	fn set_uppercase_decorators(&mut self, new_value: bool) {
		self.formatter.options_mut().set_uppercase_decorators(new_value);
	}

	/// bool: Everything is uppercased, except numbers and their prefixes/suffixes
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``MOV EAX,GS:[RCX*4+0ffh]``
	/// ✔️          ``False``   ``mov eax,gs:[rcx*4+0ffh]``
	/// =========== ========== ================================================
	#[getter]
	fn uppercase_all(&self) -> bool {
		self.formatter.options().uppercase_all()
	}

	#[setter]
	fn set_uppercase_all(&mut self, new_value: bool) {
		self.formatter.options_mut().set_uppercase_all(new_value);
	}

	/// int: (``u32``) Character index (0-based) where the first operand is formatted. Can be set to 0 to format it immediately after the mnemonic.
	/// At least one space or tab is always added between the mnemonic and the first operand.
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``0``      ``mov•rcx,rbp``
	/// \           ``8``      ``mov•••••rcx,rbp``
	/// =========== ========== ================================================
	#[getter]
	fn first_operand_char_index(&self) -> u32 {
		self.formatter.options().first_operand_char_index()
	}

	#[setter]
	fn set_first_operand_char_index(&mut self, new_value: u32) {
		self.formatter.options_mut().set_first_operand_char_index(new_value);
	}

	/// int: (``u32``) Size of a tab character or 0 to use spaces
	///
	/// Default: ``0``
	#[getter]
	fn tab_size(&self) -> u32 {
		self.formatter.options().tab_size()
	}

	#[setter]
	fn set_tab_size(&mut self, new_value: u32) {
		self.formatter.options_mut().set_tab_size(new_value);
	}

	/// bool: Add a space after the operand separator
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov rax, rcx``
	/// ✔️          ``False``   ``mov rax,rcx``
	/// =========== ========== ================================================
	#[getter]
	fn space_after_operand_separator(&self) -> bool {
		self.formatter.options().space_after_operand_separator()
	}

	#[setter]
	fn set_space_after_operand_separator(&mut self, new_value: bool) {
		self.formatter.options_mut().set_space_after_operand_separator(new_value);
	}

	/// bool: Add a space between the memory expression and the brackets
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,[ rcx+rdx ]``
	/// ✔️          ``False``   ``mov eax,[rcx+rdx]``
	/// =========== ========== ================================================
	#[getter]
	fn space_after_memory_bracket(&self) -> bool {
		self.formatter.options().space_after_memory_bracket()
	}

	#[setter]
	fn set_space_after_memory_bracket(&mut self, new_value: bool) {
		self.formatter.options_mut().set_space_after_memory_bracket(new_value);
	}

	/// bool: Add spaces between memory operand ``+`` and ``-`` operators
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,[rcx + rdx*8 - 80h]``
	/// ✔️          ``False``   ``mov eax,[rcx+rdx*8-80h]``
	/// =========== ========== ================================================
	#[getter]
	fn space_between_memory_add_operators(&self) -> bool {
		self.formatter.options().space_between_memory_add_operators()
	}

	#[setter]
	fn set_space_between_memory_add_operators(&mut self, new_value: bool) {
		self.formatter.options_mut().set_space_between_memory_add_operators(new_value);
	}

	/// bool: Add spaces between memory operand ``*`` operator
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,[rcx+rdx * 8-80h]``
	/// ✔️          ``False``   ``mov eax,[rcx+rdx*8-80h]``
	/// =========== ========== ================================================
	#[getter]
	fn space_between_memory_mul_operators(&self) -> bool {
		self.formatter.options().space_between_memory_mul_operators()
	}

	#[setter]
	fn set_space_between_memory_mul_operators(&mut self, new_value: bool) {
		self.formatter.options_mut().set_space_between_memory_mul_operators(new_value);
	}

	/// bool: Show memory operand scale value before the index register
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,[8*rdx]``
	/// ✔️          ``False``   ``mov eax,[rdx*8]``
	/// =========== ========== ================================================
	#[getter]
	fn scale_before_index(&self) -> bool {
		self.formatter.options().scale_before_index()
	}

	#[setter]
	fn set_scale_before_index(&mut self, new_value: bool) {
		self.formatter.options_mut().set_scale_before_index(new_value);
	}

	/// bool: Always show the scale value even if it's ``*1``
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,[rbx+rcx*1]``
	/// ✔️          ``False``   ``mov eax,[rbx+rcx]``
	/// =========== ========== ================================================
	#[getter]
	fn always_show_scale(&self) -> bool {
		self.formatter.options().always_show_scale()
	}

	#[setter]
	fn set_always_show_scale(&mut self, new_value: bool) {
		self.formatter.options_mut().set_always_show_scale(new_value);
	}

	/// bool: Always show the effective segment register.
	///
	/// If the option is ``False``, only show the segment register if there's a segment override prefix.
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,ds:[ecx]``
	/// ✔️          ``False``   ``mov eax,[ecx]``
	/// =========== ========== ================================================
	#[getter]
	fn always_show_segment_register(&self) -> bool {
		self.formatter.options().always_show_segment_register()
	}

	#[setter]
	fn set_always_show_segment_register(&mut self, new_value: bool) {
		self.formatter.options_mut().set_always_show_segment_register(new_value);
	}

	/// bool: Show zero displacements
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,[rcx*2+0]``
	/// ✔️          ``False``   ``mov eax,[rcx*2]``
	/// =========== ========== ================================================
	#[getter]
	fn show_zero_displacements(&self) -> bool {
		self.formatter.options().show_zero_displacements()
	}

	#[setter]
	fn set_show_zero_displacements(&mut self, new_value: bool) {
		self.formatter.options_mut().set_show_zero_displacements(new_value);
	}

	/// str: Hex number prefix or an empty string, eg. ``"0x"``
	///
	/// Default: ``""`` (masm/nasm/intel), ``"0x"`` (gas)
	#[getter]
	fn hex_prefix(&self) -> &str {
		self.formatter.options().hex_prefix()
	}

	#[setter]
	fn set_hex_prefix(&mut self, new_value: String) {
		self.formatter.options_mut().set_hex_prefix_string(new_value);
	}

	/// str: Hex number suffix or an empty string, eg. ``"h"``
	///
	/// Default: ``"h"`` (masm/nasm/intel), ``""`` (gas)
	#[getter]
	fn hex_suffix(&self) -> &str {
		self.formatter.options().hex_suffix()
	}

	#[setter]
	fn set_hex_suffix(&mut self, new_value: String) {
		self.formatter.options_mut().set_hex_suffix_string(new_value);
	}

	/// int: (``u8``) Size of a digit group, see also :class:`Formatter.digit_separator`
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``0``      ``0x12345678``
	/// ✔️          ``4``      ``0x1234_5678``
	/// =========== ========== ================================================
	#[getter]
	fn hex_digit_group_size(&self) -> u32 {
		self.formatter.options().hex_digit_group_size()
	}

	#[setter]
	fn set_hex_digit_group_size(&mut self, new_value: u32) {
		self.formatter.options_mut().set_hex_digit_group_size(new_value);
	}

	/// str: Decimal number prefix or an empty string
	///
	/// Default: ``""``
	#[getter]
	fn decimal_prefix(&self) -> &str {
		self.formatter.options().decimal_prefix()
	}

	#[setter]
	fn set_decimal_prefix(&mut self, new_value: String) {
		self.formatter.options_mut().set_decimal_prefix_string(new_value);
	}

	/// str: Decimal number suffix or an empty string
	///
	/// Default: ``""``
	#[getter]
	fn decimal_suffix(&self) -> &str {
		self.formatter.options().decimal_suffix()
	}

	#[setter]
	fn set_decimal_suffix(&mut self, new_value: String) {
		self.formatter.options_mut().set_decimal_suffix_string(new_value);
	}

	/// int: (``u8``) Size of a digit group, see also :class:`Formatter.digit_separator`
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``0``      ``12345678``
	/// ✔️          ``3``      ``12_345_678``
	/// =========== ========== ================================================
	#[getter]
	fn decimal_digit_group_size(&self) -> u32 {
		self.formatter.options().decimal_digit_group_size()
	}

	#[setter]
	fn set_decimal_digit_group_size(&mut self, new_value: u32) {
		self.formatter.options_mut().set_decimal_digit_group_size(new_value);
	}

	/// str: Octal number prefix or an empty string
	///
	/// Default: ``""`` (masm/nasm/intel), ``"0"`` (gas)
	#[getter]
	fn octal_prefix(&self) -> &str {
		self.formatter.options().octal_prefix()
	}

	#[setter]
	fn set_octal_prefix(&mut self, new_value: String) {
		self.formatter.options_mut().set_octal_prefix_string(new_value);
	}

	/// str: Octal number suffix or an empty string
	///
	/// Default: ``"o"`` (masm/nasm/intel), ``""`` (gas)
	#[getter]
	fn octal_suffix(&self) -> &str {
		self.formatter.options().octal_suffix()
	}

	#[setter]
	fn set_octal_suffix(&mut self, new_value: String) {
		self.formatter.options_mut().set_octal_suffix_string(new_value);
	}

	/// int: (``u8``) Size of a digit group, see also :class:`Formatter.digit_separator`
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``0``      ``12345670``
	/// ✔️          ``4``      ``1234_5670``
	/// =========== ========== ================================================
	#[getter]
	fn octal_digit_group_size(&self) -> u32 {
		self.formatter.options().octal_digit_group_size()
	}

	#[setter]
	fn set_octal_digit_group_size(&mut self, new_value: u32) {
		self.formatter.options_mut().set_octal_digit_group_size(new_value);
	}

	/// str: Binary number prefix or an empty string
	///
	/// Default: ``""`` (masm/nasm/intel), ``"0b"`` (gas)
	#[getter]
	fn binary_prefix(&self) -> &str {
		self.formatter.options().binary_prefix()
	}

	#[setter]
	fn set_binary_prefix(&mut self, new_value: String) {
		self.formatter.options_mut().set_binary_prefix_string(new_value);
	}

	/// str: Binary number suffix or an empty string
	///
	/// Default: ``"b"`` (masm/nasm/intel), ``""`` (gas)
	#[getter]
	fn binary_suffix(&self) -> &str {
		self.formatter.options().binary_suffix()
	}

	#[setter]
	fn set_binary_suffix(&mut self, new_value: String) {
		self.formatter.options_mut().set_binary_suffix_string(new_value);
	}

	/// int: (``u8``) Size of a digit group, see also :class:`Formatter.digit_separator`
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``0``      ``11010111``
	/// ✔️          ``4``      ``1101_0111``
	/// =========== ========== ================================================
	#[getter]
	fn binary_digit_group_size(&self) -> u32 {
		self.formatter.options().binary_digit_group_size()
	}

	#[setter]
	fn set_binary_digit_group_size(&mut self, new_value: u32) {
		self.formatter.options_mut().set_binary_digit_group_size(new_value);
	}

	/// str: Digit separator or an empty string. See also eg. :class:`Formatter.hex_digit_group_size`
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``""``     ``0x12345678``
	/// \           ``"_"``    ``0x1234_5678``
	/// =========== ========== ================================================
	#[getter]
	fn digit_separator(&self) -> &str {
		self.formatter.options().digit_separator()
	}

	#[setter]
	fn set_digit_separator(&mut self, new_value: String) {
		self.formatter.options_mut().set_digit_separator_string(new_value);
	}

	/// bool: Add leading zeroes to hexadecimal/octal/binary numbers.
	///
	/// This option has no effect on branch targets and displacements, use :class:`Formatter.branch_leading_zeroes`
	/// and :class:`Formatter.displacement_leading_zeroes`.
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``0x0000000A``/``0000000Ah``
	/// ✔️          ``False``   ``0xA``/``0Ah``
	/// =========== ========== ================================================
	#[getter]
	fn leading_zeroes(&self) -> bool {
		self.formatter.options().leading_zeroes()
	}

	#[setter]
	fn set_leading_zeroes(&mut self, new_value: bool) {
		self.formatter.options_mut().set_leading_zeroes(new_value);
	}

	/// bool: Use uppercase hex digits
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``0xFF``
	/// \           ``False``   ``0xff``
	/// =========== ========== ================================================
	#[getter]
	fn uppercase_hex(&self) -> bool {
		self.formatter.options().uppercase_hex()
	}

	#[setter]
	fn set_uppercase_hex(&mut self, new_value: bool) {
		self.formatter.options_mut().set_uppercase_hex(new_value);
	}

	/// bool: Small hex numbers (-9 .. 9) are shown in decimal
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``9``
	/// \           ``False``   ``0x9``
	/// =========== ========== ================================================
	#[getter]
	fn small_hex_numbers_in_decimal(&self) -> bool {
		self.formatter.options().small_hex_numbers_in_decimal()
	}

	#[setter]
	fn set_small_hex_numbers_in_decimal(&mut self, new_value: bool) {
		self.formatter.options_mut().set_small_hex_numbers_in_decimal(new_value);
	}

	/// bool: Add a leading zero to hex numbers if there's no prefix and the number starts with hex digits ``A-F``
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``0FFh``
	/// \           ``False``   ``FFh``
	/// =========== ========== ================================================
	#[getter]
	fn add_leading_zero_to_hex_numbers(&self) -> bool {
		self.formatter.options().add_leading_zero_to_hex_numbers()
	}

	#[setter]
	fn set_add_leading_zero_to_hex_numbers(&mut self, new_value: bool) {
		self.formatter.options_mut().set_add_leading_zero_to_hex_numbers(new_value);
	}

	/// int: Number base (``2``, ``8``, ``10``, ``16``)
	///
	/// Raises:
	///     ValueError: If it's an invalid number base
	///
	/// Default: ``16``
	#[getter]
	fn number_base(&self) -> u32 {
		match self.formatter.options().number_base() {
			iced_x86::NumberBase::Binary => 2,
			iced_x86::NumberBase::Octal => 8,
			iced_x86::NumberBase::Decimal => 10,
			iced_x86::NumberBase::Hexadecimal => 16,
		}
	}

	#[setter]
	fn set_number_base(&mut self, new_value: u32) -> PyResult<()> {
		let base = match new_value {
			2 => iced_x86::NumberBase::Binary,
			8 => iced_x86::NumberBase::Octal,
			10 => iced_x86::NumberBase::Decimal,
			16 => iced_x86::NumberBase::Hexadecimal,
			_ => return Err(PyValueError::new_err("Invalid number base")),
		};
		self.formatter.options_mut().set_number_base(base);
		Ok(())
	}

	/// bool: Add leading zeroes to branch offsets. Used by ``CALL NEAR``, ``CALL FAR``, ``JMP NEAR``, ``JMP FAR``, ``Jcc``, ``LOOP``, ``LOOPcc``, ``XBEGIN``
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``je 00000123h``
	/// \           ``False``   ``je 123h``
	/// =========== ========== ================================================
	#[getter]
	fn branch_leading_zeroes(&self) -> bool {
		self.formatter.options().branch_leading_zeroes()
	}

	#[setter]
	fn set_branch_leading_zeroes(&mut self, new_value: bool) {
		self.formatter.options_mut().set_branch_leading_zeroes(new_value);
	}

	/// bool: Show immediate operands as signed numbers
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,-1``
	/// ✔️          ``False``   ``mov eax,FFFFFFFF``
	/// =========== ========== ================================================
	#[getter]
	fn signed_immediate_operands(&self) -> bool {
		self.formatter.options().signed_immediate_operands()
	}

	#[setter]
	fn set_signed_immediate_operands(&mut self, new_value: bool) {
		self.formatter.options_mut().set_signed_immediate_operands(new_value);
	}

	/// bool: Displacements are signed numbers
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``mov al,[eax-2000h]``
	/// \           ``False``   ``mov al,[eax+0FFFFE000h]``
	/// =========== ========== ================================================
	#[getter]
	fn signed_memory_displacements(&self) -> bool {
		self.formatter.options().signed_memory_displacements()
	}

	#[setter]
	fn set_signed_memory_displacements(&mut self, new_value: bool) {
		self.formatter.options_mut().set_signed_memory_displacements(new_value);
	}

	/// bool: Add leading zeroes to displacements
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov al,[eax+00000012h]``
	/// ✔️          ``False``   ``mov al,[eax+12h]``
	/// =========== ========== ================================================
	#[getter]
	fn displacement_leading_zeroes(&self) -> bool {
		self.formatter.options().displacement_leading_zeroes()
	}

	#[setter]
	fn set_displacement_leading_zeroes(&mut self, new_value: bool) {
		self.formatter.options_mut().set_displacement_leading_zeroes(new_value);
	}

	/// :class:`MemorySizeOptions`: Options that control if the memory size (eg. ``DWORD PTR``) is shown or not.
	///
	/// This is ignored by the gas (AT&T) formatter.
	///
	/// Default: :class:`MemorySizeOptions.DEFAULT`
	#[getter]
	fn memory_size_options(&self) -> u32 {
		self.formatter.options().memory_size_options() as u32
	}

	#[setter]
	fn set_memory_size_options(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_memory_size_options(to_memory_size_options(new_value)?);
		Ok(())
	}

	/// bool: Show ``RIP+displ`` or the virtual address
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,[rip+12345678h]``
	/// ✔️          ``False``   ``mov eax,[1029384756AFBECDh]``
	/// =========== ========== ================================================
	#[getter]
	fn rip_relative_addresses(&self) -> bool {
		self.formatter.options().rip_relative_addresses()
	}

	#[setter]
	fn set_rip_relative_addresses(&mut self, new_value: bool) {
		self.formatter.options_mut().set_rip_relative_addresses(new_value);
	}

	/// bool: Show ``NEAR``, ``SHORT``, etc if it's a branch instruction
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``je short 1234h``
	/// \           ``False``   ``je 1234h``
	/// =========== ========== ================================================
	#[getter]
	fn show_branch_size(&self) -> bool {
		self.formatter.options().show_branch_size()
	}

	#[setter]
	fn set_show_branch_size(&mut self, new_value: bool) {
		self.formatter.options_mut().set_show_branch_size(new_value);
	}

	/// bool: Use pseudo instructions
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``vcmpnltsd xmm2,xmm6,xmm3``
	/// \           ``False``   ``vcmpsd xmm2,xmm6,xmm3,5``
	/// =========== ========== ================================================
	#[getter]
	fn use_pseudo_ops(&self) -> bool {
		self.formatter.options().use_pseudo_ops()
	}

	#[setter]
	fn set_use_pseudo_ops(&mut self, new_value: bool) {
		self.formatter.options_mut().set_use_pseudo_ops(new_value);
	}

	/// bool: Show the original value after the symbol name
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,[myfield (12345678)]``
	/// ✔️          ``False``   ``mov eax,[myfield]``
	/// =========== ========== ================================================
	#[getter]
	fn show_symbol_address(&self) -> bool {
		self.formatter.options().show_symbol_address()
	}

	#[setter]
	fn set_show_symbol_address(&mut self, new_value: bool) {
		self.formatter.options_mut().set_show_symbol_address(new_value);
	}

	/// bool: (gas only): If ``True``, the formatter doesn't add ``%`` to registers
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``mov eax,ecx``
	/// ✔️          ``False``   ``mov %eax,%ecx``
	/// =========== ========== ================================================
	#[getter]
	fn gas_naked_registers(&self) -> bool {
		self.formatter.options().gas_naked_registers()
	}

	#[setter]
	fn set_gas_naked_registers(&mut self, new_value: bool) {
		self.formatter.options_mut().set_gas_naked_registers(new_value);
	}

	/// bool: (gas only): Shows the mnemonic size suffix even when not needed
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``movl %eax,%ecx``
	/// ✔️          ``False``   ``mov %eax,%ecx``
	/// =========== ========== ================================================
	#[getter]
	fn gas_show_mnemonic_size_suffix(&self) -> bool {
		self.formatter.options().gas_show_mnemonic_size_suffix()
	}

	#[setter]
	fn set_gas_show_mnemonic_size_suffix(&mut self, new_value: bool) {
		self.formatter.options_mut().set_gas_show_mnemonic_size_suffix(new_value);
	}

	/// bool: (gas only): Add a space after the comma if it's a memory operand
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``(%eax, %ecx, 2)``
	/// ✔️          ``False``   ``(%eax,%ecx,2)``
	/// =========== ========== ================================================
	#[getter]
	fn gas_space_after_memory_operand_comma(&self) -> bool {
		self.formatter.options().gas_space_after_memory_operand_comma()
	}

	#[setter]
	fn set_gas_space_after_memory_operand_comma(&mut self, new_value: bool) {
		self.formatter.options_mut().set_gas_space_after_memory_operand_comma(new_value);
	}

	/// bool: (masm only): Add a ``DS`` segment override even if it's not present. Used if it's 16/32-bit code and mem op is a displ
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``mov eax,ds:[12345678]``
	/// \           ``False``   ``mov eax,[12345678]``
	/// =========== ========== ================================================
	#[getter]
	fn masm_add_ds_prefix32(&self) -> bool {
		self.formatter.options().masm_add_ds_prefix32()
	}

	#[setter]
	fn set_masm_add_ds_prefix32(&mut self, new_value: bool) {
		self.formatter.options_mut().set_masm_add_ds_prefix32(new_value);
	}

	/// bool: (masm only): Show symbols in brackets
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``[ecx+symbol]`` / ``[symbol]``
	/// \           ``False``   ``symbol[ecx]`` / ``symbol``
	/// =========== ========== ================================================
	#[getter]
	fn masm_symbol_displ_in_brackets(&self) -> bool {
		self.formatter.options().masm_symbol_displ_in_brackets()
	}

	#[setter]
	fn set_masm_symbol_displ_in_brackets(&mut self, new_value: bool) {
		self.formatter.options_mut().set_masm_symbol_displ_in_brackets(new_value);
	}

	/// bool: (masm only): Show displacements in brackets
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// ✔️          ``True``   ``[ecx+1234h]``
	/// \           ``False``   ``1234h[ecx]``
	/// =========== ========== ================================================
	#[getter]
	fn masm_displ_in_brackets(&self) -> bool {
		self.formatter.options().masm_displ_in_brackets()
	}

	#[setter]
	fn set_masm_displ_in_brackets(&mut self, new_value: bool) {
		self.formatter.options_mut().set_masm_displ_in_brackets(new_value);
	}

	/// bool: (nasm only): Shows ``BYTE``, ``WORD``, ``DWORD`` or ``QWORD`` if it's a sign extended immediate operand value
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``or rcx,byte -1``
	/// ✔️          ``False``   ``or rcx,-1``
	/// =========== ========== ================================================
	#[getter]
	fn nasm_show_sign_extended_immediate_size(&self) -> bool {
		self.formatter.options().nasm_show_sign_extended_immediate_size()
	}

	#[setter]
	fn set_nasm_show_sign_extended_immediate_size(&mut self, new_value: bool) {
		self.formatter.options_mut().set_nasm_show_sign_extended_immediate_size(new_value);
	}

	/// bool: Use ``st(0)`` instead of ``st`` if ``st`` can be used. Ignored by the nasm formatter.
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``fadd st(0),st(3)``
	/// ✔️          ``False``   ``fadd st,st(3)``
	/// =========== ========== ================================================
	#[getter]
	fn prefer_st0(&self) -> bool {
		self.formatter.options().prefer_st0()
	}

	#[setter]
	fn set_prefer_st0(&mut self, new_value: bool) {
		self.formatter.options_mut().set_prefer_st0(new_value);
	}

	/// bool: Show useless prefixes. If it has useless prefixes, it could be data and not code.
	///
	/// =========== ========== ================================================
	/// Default     Value      Example
	/// =========== ========== ================================================
	/// \           ``True``   ``es rep add eax,ecx``
	/// ✔️          ``False``   ``add eax,ecx``
	/// =========== ========== ================================================
	#[getter]
	fn show_useless_prefixes(&self) -> bool {
		self.formatter.options().show_useless_prefixes()
	}

	#[setter]
	fn set_show_useless_prefixes(&mut self, new_value: bool) {
		self.formatter.options_mut().set_show_useless_prefixes(new_value)
	}

	/// :class:`CC_b`: Mnemonic condition code selector (eg. ``JB`` / ``JC`` / ``JNAE``)
	///
	/// Default: ``JB``, ``CMOVB``, ``SETB``
	#[getter]
	fn cc_b(&self) -> u32 {
		self.formatter.options().cc_b() as u32
	}

	#[setter]
	fn set_cc_b(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_b(to_cc_b(new_value)?);
		Ok(())
	}

	/// :class:`CC_ae`: Mnemonic condition code selector (eg. ``JAE`` / ``JNB`` / ``JNC``)
	///
	/// Default: ``JAE``, ``CMOVAE``, ``SETAE``
	#[getter]
	fn cc_ae(&self) -> u32 {
		self.formatter.options().cc_ae() as u32
	}

	#[setter]
	fn set_cc_ae(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_ae(to_cc_ae(new_value)?);
		Ok(())
	}

	/// :class:`CC_e`: Mnemonic condition code selector (eg. ``JE`` / ``JZ``)
	///
	/// Default: ``JE``, ``CMOVE``, ``SETE``, ``LOOPE``, ``REPE``
	#[getter]
	fn cc_e(&self) -> u32 {
		self.formatter.options().cc_e() as u32
	}

	#[setter]
	fn set_cc_e(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_e(to_cc_e(new_value)?);
		Ok(())
	}

	/// :class:`CC_ne`: Mnemonic condition code selector (eg. ``JNE`` / ``JNZ``)
	///
	/// Default: ``JNE``, ``CMOVNE``, ``SETNE``, ``LOOPNE``, ``REPNE``
	#[getter]
	fn cc_ne(&self) -> u32 {
		self.formatter.options().cc_ne() as u32
	}

	#[setter]
	fn set_cc_ne(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_ne(to_cc_ne(new_value)?);
		Ok(())
	}

	/// :class:`CC_be`: Mnemonic condition code selector (eg. ``JBE`` / ``JNA``)
	///
	/// Default: ``JBE``, ``CMOVBE``, ``SETBE``
	#[getter]
	fn cc_be(&self) -> u32 {
		self.formatter.options().cc_be() as u32
	}

	#[setter]
	fn set_cc_be(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_be(to_cc_be(new_value)?);
		Ok(())
	}

	/// :class:`CC_a`: Mnemonic condition code selector (eg. ``JA`` / ``JNBE``)
	///
	/// Default: ``JA``, ``CMOVA``, ``SETA``
	#[getter]
	fn cc_a(&self) -> u32 {
		self.formatter.options().cc_a() as u32
	}

	#[setter]
	fn set_cc_a(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_a(to_cc_a(new_value)?);
		Ok(())
	}

	/// :class:`CC_p`: Mnemonic condition code selector (eg. ``JP`` / ``JPE``)
	///
	/// Default: ``JP``, ``CMOVP``, ``SETP``
	#[getter]
	fn cc_p(&self) -> u32 {
		self.formatter.options().cc_p() as u32
	}

	#[setter]
	fn set_cc_p(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_p(to_cc_p(new_value)?);
		Ok(())
	}

	/// :class:`CC_np`: Mnemonic condition code selector (eg. ``JNP`` / ``JPO``)
	///
	/// Default: ``JNP``, ``CMOVNP``, ``SETNP``
	#[getter]
	fn cc_np(&self) -> u32 {
		self.formatter.options().cc_np() as u32
	}

	#[setter]
	fn set_cc_np(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_np(to_cc_np(new_value)?);
		Ok(())
	}

	/// :class:`CC_l`: Mnemonic condition code selector (eg. ``JL`` / ``JNGE``)
	///
	/// Default: ``JL``, ``CMOVL``, ``SETL``
	#[getter]
	fn cc_l(&self) -> u32 {
		self.formatter.options().cc_l() as u32
	}

	#[setter]
	fn set_cc_l(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_l(to_cc_l(new_value)?);
		Ok(())
	}

	/// :class:`CC_ge`: Mnemonic condition code selector (eg. ``JGE`` / ``JNL``)
	///
	/// Default: ``JGE``, ``CMOVGE``, ``SETGE``
	#[getter]
	fn cc_ge(&self) -> u32 {
		self.formatter.options().cc_ge() as u32
	}

	#[setter]
	fn set_cc_ge(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_ge(to_cc_ge(new_value)?);
		Ok(())
	}

	/// :class:`CC_le`: Mnemonic condition code selector (eg. ``JLE`` / ``JNG``)
	///
	/// Default: ``JLE``, ``CMOVLE``, ``SETLE``
	#[getter]
	fn cc_le(&self) -> u32 {
		self.formatter.options().cc_le() as u32
	}

	#[setter]
	fn set_cc_le(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_le(to_cc_le(new_value)?);
		Ok(())
	}

	/// :class:`CC_g`: Mnemonic condition code selector (eg. ``JG`` / ``JNLE``)
	///
	/// Default: ``JG``, ``CMOVG``, ``SETG``
	#[getter]
	fn cc_g(&self) -> u32 {
		self.formatter.options().cc_g() as u32
	}

	#[setter]
	fn set_cc_g(&mut self, new_value: u32) -> PyResult<()> {
		self.formatter.options_mut().set_cc_g(to_cc_g(new_value)?);
		Ok(())
	}
}
