//! The structure use to reference a method invocation.

use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::hash::Hash;

use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;

use crate::dex_id::*;
use crate::DexString;
use crate::Result;

/// The structure use to reference a method invocation.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum MethodHandle {
    StaticPut(StaticPut),
    StaticGet(StaticGet),
    InstancePut(InstancePut),
    InstanceGet(InstanceGet),
    InvokeStatic(InvokeStatic),
    InvokeInstance(InvokeInstance),
    InvokeConstructor(InvokeConstructor),
    InvokeDirect(InvokeDirect),
    InvokeInterface(InvokeInterface),
}

#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct StaticPut(pub IdField);

#[pymethods]
impl StaticPut {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdField) -> Self {
        Self(val)
    }

    pub fn get_field(&self) -> IdField {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("StaticPut({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        HashSet::new()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        let mut fields = HashSet::new();
        fields.insert(self.0.clone());
        fields
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        HashSet::new()
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::StaticPut(self.clone()));
        methods
    }
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct StaticGet(pub IdField);

#[pymethods]
impl StaticGet {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdField) -> Self {
        Self(val)
    }

    pub fn get_field(&self) -> IdField {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("StaticGet({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        HashSet::new()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        let mut fields = HashSet::new();
        fields.insert(self.0.clone());
        fields
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        HashSet::new()
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::StaticGet(self.clone()));
        methods
    }
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct InstancePut(pub IdField);

#[pymethods]
impl InstancePut {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdField) -> Self {
        Self(val)
    }

    pub fn get_field(&self) -> IdField {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("InstancePut({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        HashSet::new()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        let mut fields = HashSet::new();
        fields.insert(self.0.clone());
        fields
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        HashSet::new()
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::InstancePut(self.clone()));
        methods
    }
}
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct InstanceGet(pub IdField);

#[pymethods]
impl InstanceGet {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdField) -> Self {
        Self(val)
    }

    pub fn get_field(&self) -> IdField {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("InstanceGet({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        HashSet::new()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        let mut fields = HashSet::new();
        fields.insert(self.0.clone());
        fields
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        HashSet::new()
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::InstanceGet(self.clone()));
        methods
    }
}

#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct InvokeStatic(pub IdMethod);

#[pymethods]
impl InvokeStatic {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdMethod) -> Self {
        Self(val)
    }

    pub fn get_method(&self) -> IdMethod {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("InvokeStatic({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        self.0.get_all_protos()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        HashSet::new()
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        let mut methods = HashSet::new();
        methods.insert(self.0.clone());
        methods
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::InvokeStatic(self.clone()));
        methods
    }
}

#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct InvokeInstance(pub IdMethod);

#[pymethods]
impl InvokeInstance {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdMethod) -> Self {
        Self(val)
    }

    pub fn get_method(&self) -> IdMethod {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("InvokeInstance({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        self.0.get_all_protos()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        HashSet::new()
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        let mut methods = HashSet::new();
        methods.insert(self.0.clone());
        methods
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::InvokeInstance(self.clone()));
        methods
    }
}

#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct InvokeConstructor(pub IdMethod);

#[pymethods]
impl InvokeConstructor {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdMethod) -> Self {
        Self(val)
    }

    pub fn get_method(&self) -> IdMethod {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("InvokeConstructor({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        self.0.get_all_protos()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        HashSet::new()
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        let mut methods = HashSet::new();
        methods.insert(self.0.clone());
        methods
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::InvokeConstructor(self.clone()));
        methods
    }
}

#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct InvokeDirect(pub IdMethod);

#[pymethods]
impl InvokeDirect {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdMethod) -> Self {
        Self(val)
    }

    pub fn get_method(&self) -> IdMethod {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("InvokeDirect({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        self.0.get_all_protos()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        HashSet::new()
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        let mut methods = HashSet::new();
        methods.insert(self.0.clone());
        methods
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::InvokeDirect(self.clone()));
        methods
    }
}

#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct InvokeInterface(pub IdMethod);

#[pymethods]
impl InvokeInterface {
    pub fn to_json(&self) -> Result<String> {
        Ok(serde_json::to_string(self)?)
    }

    #[staticmethod]
    pub fn from_json(json: &str) -> Result<Self> {
        Ok(serde_json::from_str(json)?)
    }

    #[new]
    pub fn new(val: IdMethod) -> Self {
        Self(val)
    }

    pub fn get_method(&self) -> IdMethod {
        self.0.clone()
    }

    pub fn __str__(&self) -> String {
        self.__repr__()
    }

    pub fn __repr__(&self) -> String {
        format!("InvokeInterface({})", self.0.__str__())
    }

    /// Return all strings referenced in the handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        self.0.get_all_strings()
    }

    /// Return all types referenced in the handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        self.0.get_all_types()
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        self.0.get_all_protos()
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        HashSet::new()
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        let mut methods = HashSet::new();
        methods.insert(self.0.clone());
        methods
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        let mut methods = HashSet::new();
        methods.insert(MethodHandle::InvokeInterface(self.clone()));
        methods
    }
}

impl<'source> FromPyObject<'source> for MethodHandle {
    fn extract(ob: &'source PyAny) -> PyResult<Self> {
        if let Ok(val) = StaticPut::extract(ob) {
            Ok(Self::StaticPut(val))
        } else if let Ok(val) = StaticGet::extract(ob) {
            Ok(Self::StaticGet(val))
        } else if let Ok(val) = InstancePut::extract(ob) {
            Ok(Self::InstancePut(val))
        } else if let Ok(val) = InstanceGet::extract(ob) {
            Ok(Self::InstanceGet(val))
        } else if let Ok(val) = InvokeStatic::extract(ob) {
            Ok(Self::InvokeStatic(val))
        } else if let Ok(val) = InvokeInstance::extract(ob) {
            Ok(Self::InvokeInstance(val))
        } else if let Ok(val) = InvokeConstructor::extract(ob) {
            Ok(Self::InvokeConstructor(val))
        } else if let Ok(val) = InvokeDirect::extract(ob) {
            Ok(Self::InvokeDirect(val))
        } else if let Ok(val) = InvokeInterface::extract(ob) {
            Ok(Self::InvokeInterface(val))
        } else {
            Err(PyErr::new::<PyTypeError, _>(format!(
                "{} is not a castable as a MethodHandle",
                ob.repr()?
            )))
        }
    }
}

impl IntoPy<PyObject> for MethodHandle {
    fn into_py(self, py: Python<'_>) -> PyObject {
        match self {
            Self::StaticPut(val) => val.into_py(py),
            Self::StaticGet(val) => val.into_py(py),
            Self::InstancePut(val) => val.into_py(py),
            Self::InstanceGet(val) => val.into_py(py),
            Self::InvokeStatic(val) => val.into_py(py),
            Self::InvokeInstance(val) => val.into_py(py),
            Self::InvokeConstructor(val) => val.into_py(py),
            Self::InvokeDirect(val) => val.into_py(py),
            Self::InvokeInterface(val) => val.into_py(py),
        }
    }
}

impl MethodHandle {
    // Not exposed to python, but meh, let's keep it coherent
    pub fn __str__(&self) -> String {
        match self {
            Self::StaticPut(val) => val.__str__(),
            Self::StaticGet(val) => val.__str__(),
            Self::InstancePut(val) => val.__str__(),
            Self::InstanceGet(val) => val.__str__(),
            Self::InvokeStatic(val) => val.__str__(),
            Self::InvokeInstance(val) => val.__str__(),
            Self::InvokeConstructor(val) => val.__str__(),
            Self::InvokeDirect(val) => val.__str__(),
            Self::InvokeInterface(val) => val.__str__(),
        }
    }

    // Not exposed to python, but meh, let's keep it coherent
    pub fn __repr__(&self) -> String {
        match self {
            Self::StaticPut(val) => val.__repr__(),
            Self::StaticGet(val) => val.__repr__(),
            Self::InstancePut(val) => val.__repr__(),
            Self::InstanceGet(val) => val.__repr__(),
            Self::InvokeStatic(val) => val.__repr__(),
            Self::InvokeInstance(val) => val.__repr__(),
            Self::InvokeConstructor(val) => val.__str__(),
            Self::InvokeDirect(val) => val.__repr__(),
            Self::InvokeInterface(val) => val.__repr__(),
        }
    }

    /// Return all strings referenced in the Handle.
    pub fn get_all_strings(&self) -> HashSet<DexString> {
        match self {
            Self::StaticPut(val) => val.get_all_strings(),
            Self::StaticGet(val) => val.get_all_strings(),
            Self::InstancePut(val) => val.get_all_strings(),
            Self::InstanceGet(val) => val.get_all_strings(),
            Self::InvokeStatic(val) => val.get_all_strings(),
            Self::InvokeInstance(val) => val.get_all_strings(),
            Self::InvokeConstructor(val) => val.get_all_strings(),
            Self::InvokeDirect(val) => val.get_all_strings(),
            Self::InvokeInterface(val) => val.get_all_strings(),
        }
    }

    /// Return all types referenced in the Handle.
    pub fn get_all_types(&self) -> HashSet<IdType> {
        match self {
            Self::StaticPut(val) => val.get_all_types(),
            Self::StaticGet(val) => val.get_all_types(),
            Self::InstancePut(val) => val.get_all_types(),
            Self::InstanceGet(val) => val.get_all_types(),
            Self::InvokeStatic(val) => val.get_all_types(),
            Self::InvokeInstance(val) => val.get_all_types(),
            Self::InvokeConstructor(val) => val.get_all_types(),
            Self::InvokeDirect(val) => val.get_all_types(),
            Self::InvokeInterface(val) => val.get_all_types(),
        }
    }

    /// Return all prototypes referenced in the handle.
    pub fn get_all_protos(&self) -> HashSet<IdMethodType> {
        match self {
            Self::StaticPut(val) => val.get_all_protos(),
            Self::StaticGet(val) => val.get_all_protos(),
            Self::InstancePut(val) => val.get_all_protos(),
            Self::InstanceGet(val) => val.get_all_protos(),
            Self::InvokeStatic(val) => val.get_all_protos(),
            Self::InvokeInstance(val) => val.get_all_protos(),
            Self::InvokeConstructor(val) => val.get_all_protos(),
            Self::InvokeDirect(val) => val.get_all_protos(),
            Self::InvokeInterface(val) => val.get_all_protos(),
        }
    }

    /// Return all field ids referenced in the handle.
    pub fn get_all_field_ids(&self) -> HashSet<IdField> {
        match self {
            Self::StaticPut(val) => val.get_all_field_ids(),
            Self::StaticGet(val) => val.get_all_field_ids(),
            Self::InstancePut(val) => val.get_all_field_ids(),
            Self::InstanceGet(val) => val.get_all_field_ids(),
            Self::InvokeStatic(val) => val.get_all_field_ids(),
            Self::InvokeInstance(val) => val.get_all_field_ids(),
            Self::InvokeConstructor(val) => val.get_all_field_ids(),
            Self::InvokeDirect(val) => val.get_all_field_ids(),
            Self::InvokeInterface(val) => val.get_all_field_ids(),
        }
    }

    /// Return all method ids referenced in the handle.
    pub fn get_all_method_ids(&self) -> HashSet<IdMethod> {
        match self {
            Self::StaticPut(val) => val.get_all_method_ids(),
            Self::StaticGet(val) => val.get_all_method_ids(),
            Self::InstancePut(val) => val.get_all_method_ids(),
            Self::InstanceGet(val) => val.get_all_method_ids(),
            Self::InvokeStatic(val) => val.get_all_method_ids(),
            Self::InvokeInstance(val) => val.get_all_method_ids(),
            Self::InvokeConstructor(val) => val.get_all_method_ids(),
            Self::InvokeDirect(val) => val.get_all_method_ids(),
            Self::InvokeInterface(val) => val.get_all_method_ids(),
        }
    }

    /// Return all method handles referenced in the handle.
    pub fn get_all_method_handles(&self) -> HashSet<MethodHandle> {
        match self {
            Self::StaticPut(val) => val.get_all_method_handles(),
            Self::StaticGet(val) => val.get_all_method_handles(),
            Self::InstancePut(val) => val.get_all_method_handles(),
            Self::InstanceGet(val) => val.get_all_method_handles(),
            Self::InvokeStatic(val) => val.get_all_method_handles(),
            Self::InvokeInstance(val) => val.get_all_method_handles(),
            Self::InvokeConstructor(val) => val.get_all_method_handles(),
            Self::InvokeDirect(val) => val.get_all_method_handles(),
            Self::InvokeInterface(val) => val.get_all_method_handles(),
        }
    }
}
