use std::{collections::BTreeMap, hash::Hasher};
pub use uniffi_checksum_derive::Checksum;
mod ffi_names;
pub use ffi_names::*;
mod group;
pub use group::{create_metadata_groups, fixup_external_type, group_metadata, MetadataGroup};
mod reader;
pub use reader::{read_metadata, read_metadata_type};
mod types;
pub use types::{AsType, ExternalKind, ObjectImpl, Type, TypeIterator};
mod metadata;
pub const UNIFFI_CONTRACT_VERSION: u32 = 24;
pub trait Checksum {
    fn checksum<H: Hasher>(&self, state: &mut H);
}
impl Checksum for bool {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        state.write_u8(*self as u8);
    }
}
impl Checksum for u64 {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        state.write(&self.to_le_bytes());
    }
}
impl Checksum for i64 {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        state.write(&self.to_le_bytes());
    }
}
impl<T: Checksum> Checksum for Box<T> {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        (**self).checksum(state)
    }
}
impl<T: Checksum> Checksum for [T] {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        state.write(&(self.len() as u64).to_le_bytes());
        for item in self {
            Checksum::checksum(item, state);
        }
    }
}
impl<T: Checksum> Checksum for Vec<T> {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        Checksum::checksum(&**self, state);
    }
}
impl<K: Checksum, V: Checksum> Checksum for BTreeMap<K, V> {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        state.write(&(self.len() as u64).to_le_bytes());
        for (key, value) in self {
            Checksum::checksum(key, state);
            Checksum::checksum(value, state);
        }
    }
}
impl<T: Checksum> Checksum for Option<T> {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        match self {
            None => state.write(&0u64.to_le_bytes()),
            Some(value) => {
                state.write(&1u64.to_le_bytes());
                Checksum::checksum(value, state)
            }
        }
    }
}
impl Checksum for str {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        state.write(self.as_bytes());
        state.write_u8(0xff);
    }
}
impl Checksum for String {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        (**self).checksum(state)
    }
}
impl Checksum for &str {
    fn checksum<H: Hasher>(&self, state: &mut H) {
        (**self).checksum(state)
    }
}
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct NamespaceMetadata {
    pub crate_name: String,
    pub name: String,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct UdlFile {
    pub module_path: String,
    pub namespace: String,
    pub file_stub: String,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FnMetadata {
    pub module_path: String,
    pub name: String,
    pub is_async: bool,
    pub inputs: Vec<FnParamMetadata>,
    pub return_type: Option<Type>,
    pub throws: Option<Type>,
    pub checksum: Option<u16>,
}
impl FnMetadata {
    pub fn ffi_symbol_name(&self) -> String {
        fn_symbol_name(&self.module_path, &self.name)
    }
    pub fn checksum_symbol_name(&self) -> String {
        fn_checksum_symbol_name(&self.module_path, &self.name)
    }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ConstructorMetadata {
    pub module_path: String,
    pub self_name: String,
    pub name: String,
    pub inputs: Vec<FnParamMetadata>,
    pub throws: Option<Type>,
    pub checksum: Option<u16>,
}
impl ConstructorMetadata {
    pub fn ffi_symbol_name(&self) -> String {
        constructor_symbol_name(&self.module_path, &self.self_name, &self.name)
    }
    pub fn checksum_symbol_name(&self) -> String {
        constructor_checksum_symbol_name(&self.module_path, &self.self_name, &self.name)
    }
    pub fn is_primary(&self) -> bool {
        self.name == "new"
    }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct MethodMetadata {
    pub module_path: String,
    pub self_name: String,
    pub name: String,
    pub is_async: bool,
    pub inputs: Vec<FnParamMetadata>,
    pub return_type: Option<Type>,
    pub throws: Option<Type>,
    pub takes_self_by_arc: bool, pub checksum: Option<u16>,
}
impl MethodMetadata {
    pub fn ffi_symbol_name(&self) -> String {
        method_symbol_name(&self.module_path, &self.self_name, &self.name)
    }
    pub fn checksum_symbol_name(&self) -> String {
        method_checksum_symbol_name(&self.module_path, &self.self_name, &self.name)
    }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct TraitMethodMetadata {
    pub module_path: String,
    pub trait_name: String,
    pub index: u32,
    pub name: String,
    pub is_async: bool,
    pub inputs: Vec<FnParamMetadata>,
    pub return_type: Option<Type>,
    pub throws: Option<Type>,
    pub takes_self_by_arc: bool, pub checksum: Option<u16>,
}
impl TraitMethodMetadata {
    pub fn ffi_symbol_name(&self) -> String {
        method_symbol_name(&self.module_path, &self.trait_name, &self.name)
    }
    pub fn checksum_symbol_name(&self) -> String {
        method_checksum_symbol_name(&self.module_path, &self.trait_name, &self.name)
    }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FnParamMetadata {
    pub name: String,
    pub ty: Type,
    pub by_ref: bool,
    pub optional: bool,
    pub default: Option<LiteralMetadata>,
}
impl FnParamMetadata {
    pub fn simple(name: &str, ty: Type) -> Self {
        Self {
            name: name.to_string(),
            ty,
            by_ref: false,
            optional: false,
            default: None,
        }
    }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Checksum)]
pub enum LiteralMetadata {
    Boolean(bool),
    String(String),
    UInt(u64, Radix, Type),
    Int(i64, Radix, Type),
    Float(String, Type),
    Enum(String, Type),
    EmptySequence,
    EmptyMap,
    Null,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Checksum)]
pub enum Radix {
    Decimal = 10,
    Octal = 8,
    Hexadecimal = 16,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct RecordMetadata {
    pub module_path: String,
    pub name: String,
    pub fields: Vec<FieldMetadata>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FieldMetadata {
    pub name: String,
    pub ty: Type,
    pub default: Option<LiteralMetadata>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct EnumMetadata {
    pub module_path: String,
    pub name: String,
    pub variants: Vec<VariantMetadata>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct VariantMetadata {
    pub name: String,
    pub fields: Vec<FieldMetadata>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ObjectMetadata {
    pub module_path: String,
    pub name: String,
    pub imp: types::ObjectImpl,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CallbackInterfaceMetadata {
    pub module_path: String,
    pub name: String,
}
impl ObjectMetadata {
    pub fn free_ffi_symbol_name(&self) -> String {
        free_fn_symbol_name(&self.module_path, &self.name)
    }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum UniffiTraitMetadata {
    Debug {
        fmt: MethodMetadata,
    },
    Display {
        fmt: MethodMetadata,
    },
    Eq {
        eq: MethodMetadata,
        ne: MethodMetadata,
    },
    Hash {
        hash: MethodMetadata,
    },
}
impl UniffiTraitMetadata {
    fn module_path(&self) -> &String {
        &match self {
            UniffiTraitMetadata::Debug { fmt } => fmt,
            UniffiTraitMetadata::Display { fmt } => fmt,
            UniffiTraitMetadata::Eq { eq, .. } => eq,
            UniffiTraitMetadata::Hash { hash } => hash,
        }
        .module_path
    }
    pub fn self_name(&self) -> &String {
        &match self {
            UniffiTraitMetadata::Debug { fmt } => fmt,
            UniffiTraitMetadata::Display { fmt } => fmt,
            UniffiTraitMetadata::Eq { eq, .. } => eq,
            UniffiTraitMetadata::Hash { hash } => hash,
        }
        .self_name
    }
}
#[repr(u8)]
pub enum UniffiTraitDiscriminants {
    Debug,
    Display,
    Eq,
    Hash,
}
impl UniffiTraitDiscriminants {
    pub fn from(v: u8) -> anyhow::Result<Self> {
        Ok(match v {
            0 => UniffiTraitDiscriminants::Debug,
            1 => UniffiTraitDiscriminants::Display,
            2 => UniffiTraitDiscriminants::Eq,
            3 => UniffiTraitDiscriminants::Hash,
            _ => anyhow::bail!("invalid trait discriminant {v}"),
        })
    }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ErrorMetadata {
    Enum { enum_: EnumMetadata, is_flat: bool },
}
impl ErrorMetadata {
    pub fn name(&self) -> &String {
        match self {
            Self::Enum { enum_, .. } => &enum_.name,
        }
    }
    pub fn module_path(&self) -> &String {
        match self {
            Self::Enum { enum_, .. } => &enum_.module_path,
        }
    }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CustomTypeMetadata {
    pub module_path: String,
    pub name: String,
    pub builtin: Type,
}
pub fn checksum<T: Checksum>(val: &T) -> u16 {
    let mut hasher = siphasher::sip::SipHasher13::new();
    val.checksum(&mut hasher);
    (hasher.finish() & 0x000000000000FFFF) as u16
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Metadata {
    Namespace(NamespaceMetadata),
    UdlFile(UdlFile),
    Func(FnMetadata),
    Object(ObjectMetadata),
    CallbackInterface(CallbackInterfaceMetadata),
    Record(RecordMetadata),
    Enum(EnumMetadata),
    Error(ErrorMetadata),
    Constructor(ConstructorMetadata),
    Method(MethodMetadata),
    TraitMethod(TraitMethodMetadata),
    CustomType(CustomTypeMetadata),
    UniffiTrait(UniffiTraitMetadata),
}
impl Metadata {
    pub fn read(data: &[u8]) -> anyhow::Result<Self> {
        read_metadata(data)
    }
    pub(crate) fn module_path(&self) -> &String {
        match self {
            Metadata::Namespace(meta) => &meta.crate_name,
            Metadata::UdlFile(meta) => &meta.module_path,
            Metadata::Func(meta) => &meta.module_path,
            Metadata::Constructor(meta) => &meta.module_path,
            Metadata::Method(meta) => &meta.module_path,
            Metadata::Record(meta) => &meta.module_path,
            Metadata::Enum(meta) => &meta.module_path,
            Metadata::Object(meta) => &meta.module_path,
            Metadata::CallbackInterface(meta) => &meta.module_path,
            Metadata::TraitMethod(meta) => &meta.module_path,
            Metadata::Error(meta) => meta.module_path(),
            Metadata::CustomType(meta) => &meta.module_path,
            Metadata::UniffiTrait(meta) => meta.module_path(),
        }
    }
}
impl From<NamespaceMetadata> for Metadata {
    fn from(value: NamespaceMetadata) -> Metadata {
        Self::Namespace(value)
    }
}
impl From<UdlFile> for Metadata {
    fn from(value: UdlFile) -> Metadata {
        Self::UdlFile(value)
    }
}
impl From<FnMetadata> for Metadata {
    fn from(value: FnMetadata) -> Metadata {
        Self::Func(value)
    }
}
impl From<ConstructorMetadata> for Metadata {
    fn from(c: ConstructorMetadata) -> Self {
        Self::Constructor(c)
    }
}
impl From<MethodMetadata> for Metadata {
    fn from(m: MethodMetadata) -> Self {
        Self::Method(m)
    }
}
impl From<RecordMetadata> for Metadata {
    fn from(r: RecordMetadata) -> Self {
        Self::Record(r)
    }
}
impl From<EnumMetadata> for Metadata {
    fn from(e: EnumMetadata) -> Self {
        Self::Enum(e)
    }
}
impl From<ErrorMetadata> for Metadata {
    fn from(e: ErrorMetadata) -> Self {
        Self::Error(e)
    }
}
impl From<ObjectMetadata> for Metadata {
    fn from(v: ObjectMetadata) -> Self {
        Self::Object(v)
    }
}
impl From<CallbackInterfaceMetadata> for Metadata {
    fn from(v: CallbackInterfaceMetadata) -> Self {
        Self::CallbackInterface(v)
    }
}
impl From<TraitMethodMetadata> for Metadata {
    fn from(v: TraitMethodMetadata) -> Self {
        Self::TraitMethod(v)
    }
}
impl From<CustomTypeMetadata> for Metadata {
    fn from(v: CustomTypeMetadata) -> Self {
        Self::CustomType(v)
    }
}
impl From<UniffiTraitMetadata> for Metadata {
    fn from(v: UniffiTraitMetadata) -> Self {
        Self::UniffiTrait(v)
    }
}