use crate::{
    encode_section, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType,
    CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EntityType {
    Function(u32),
    Table(TableType),
    Memory(MemoryType),
    Global(GlobalType),
    Tag(TagType),
}
impl Encode for EntityType {
    fn encode(&self, sink: &mut Vec<u8>) {
        match self {
            Self::Function(i) => {
                sink.push(CORE_FUNCTION_SORT);
                i.encode(sink);
            }
            Self::Table(t) => {
                sink.push(CORE_TABLE_SORT);
                t.encode(sink);
            }
            Self::Memory(t) => {
                sink.push(CORE_MEMORY_SORT);
                t.encode(sink);
            }
            Self::Global(t) => {
                sink.push(CORE_GLOBAL_SORT);
                t.encode(sink);
            }
            Self::Tag(t) => {
                sink.push(CORE_TAG_SORT);
                t.encode(sink);
            }
        }
    }
}
impl From<TableType> for EntityType {
    fn from(t: TableType) -> Self {
        Self::Table(t)
    }
}
impl From<MemoryType> for EntityType {
    fn from(t: MemoryType) -> Self {
        Self::Memory(t)
    }
}
impl From<GlobalType> for EntityType {
    fn from(t: GlobalType) -> Self {
        Self::Global(t)
    }
}
impl From<TagType> for EntityType {
    fn from(t: TagType) -> Self {
        Self::Tag(t)
    }
}
#[cfg(feature = "wasmparser")]
impl From<wasmparser::TypeRef> for EntityType {
    fn from(type_ref: wasmparser::TypeRef) -> Self {
        match type_ref {
            wasmparser::TypeRef::Func(i) => EntityType::Function(i),
            wasmparser::TypeRef::Table(t) => EntityType::Table(t.into()),
            wasmparser::TypeRef::Memory(m) => EntityType::Memory(m.into()),
            wasmparser::TypeRef::Global(g) => EntityType::Global(g.into()),
            wasmparser::TypeRef::Tag(t) => EntityType::Tag(t.into()),
        }
    }
}
#[derive(Clone, Debug, Default)]
pub struct ImportSection {
    bytes: Vec<u8>,
    num_added: u32,
}
impl ImportSection {
    pub fn new() -> Self {
        Self::default()
    }
    pub fn len(&self) -> u32 {
        self.num_added
    }
    pub fn is_empty(&self) -> bool {
        self.num_added == 0
    }
    pub fn import(&mut self, module: &str, field: &str, ty: impl Into<EntityType>) -> &mut Self {
        module.encode(&mut self.bytes);
        field.encode(&mut self.bytes);
        ty.into().encode(&mut self.bytes);
        self.num_added += 1;
        self
    }
}
impl Encode for ImportSection {
    fn encode(&self, sink: &mut Vec<u8>) {
        encode_section(sink, self.num_added, &self.bytes);
    }
}
impl Section for ImportSection {
    fn id(&self) -> u8 {
        SectionId::Import.into()
    }
}