use auth::StAccess;
use auth::StTableType;
use sats::impl_serialize;
pub use spacetimedb_sats::buffer;
pub mod address;
pub mod data_key;
pub mod filter;
pub mod identity;
pub use spacetimedb_sats::de;
pub mod error;
pub mod hash;
#[cfg(feature = "serde")]
pub mod name;
pub mod operator;
pub mod primary_key;
pub use spacetimedb_sats::ser;
pub mod type_def {
    pub use spacetimedb_sats::{AlgebraicType, ProductType, ProductTypeElement, SumType};
}
pub mod type_value {
    pub use spacetimedb_sats::{AlgebraicValue, ProductValue};
}
pub mod auth;
#[cfg(feature = "serde")]
pub mod recovery;
pub mod relation;
pub mod table;
#[cfg(feature = "cli")]
pub mod util;
pub mod version;
pub use spacetimedb_sats::bsatn;
pub use address::Address;
pub use data_key::DataKey;
pub use hash::Hash;
pub use identity::Identity;
pub use primary_key::PrimaryKey;
pub use type_def::*;
pub use type_value::{AlgebraicValue, ProductValue};
pub use spacetimedb_sats as sats;
pub const MODULE_ABI_VERSION: VersionTuple = VersionTuple::new(3, 0);
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct VersionTuple {
    pub major: u16,
    pub minor: u16,
}
impl VersionTuple {
    pub const fn new(major: u16, minor: u16) -> Self {
        Self { major, minor }
    }
    #[inline]
    pub const fn eq(self, other: Self) -> bool {
        self.major == other.major && self.minor == other.minor
    }
    #[inline]
    pub const fn supports(self, module_version: VersionTuple) -> bool {
        self.major == module_version.major && self.minor >= module_version.minor
    }
    #[inline]
    pub const fn from_u32(v: u32) -> Self {
        let major = (v >> 16) as u16;
        let minor = (v & 0xFF) as u16;
        Self { major, minor }
    }
    #[inline]
    pub const fn to_u32(self) -> u32 {
        (self.major as u32) << 16 | self.minor as u32
    }
}
impl std::fmt::Display for VersionTuple {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self { major, minor } = *self;
        write!(f, "{major}.{minor}")
    }
}
extern crate self as spacetimedb_lib;
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, de::Deserialize, ser::Serialize)]
pub struct TableDef {
    pub name: String,
    pub data: sats::AlgebraicTypeRef,
    pub column_attrs: Vec<ColumnIndexAttribute>,
    pub indexes: Vec<IndexDef>,
    pub table_type: StTableType,
    pub table_access: StAccess,
}
#[derive(Debug, Clone, de::Deserialize, ser::Serialize)]
pub struct ReducerDef {
    pub name: String,
    pub args: Vec<ProductTypeElement>,
}
impl ReducerDef {
    pub fn encode(&self, writer: &mut impl buffer::BufWriter) {
        bsatn::to_writer(writer, self).unwrap()
    }
    pub fn serialize_args<'a>(ty: sats::WithTypespace<'a, Self>, value: &'a ProductValue) -> impl ser::Serialize + 'a {
        ReducerArgsWithSchema { value, ty }
    }
    pub fn deserialize(
        ty: sats::WithTypespace<'_, Self>,
    ) -> impl for<'de> de::DeserializeSeed<'de, Output = ProductValue> + '_ {
        ReducerDeserialize(ty)
    }
}
struct ReducerDeserialize<'a>(sats::WithTypespace<'a, ReducerDef>);
impl<'de> de::DeserializeSeed<'de> for ReducerDeserialize<'_> {
    type Output = ProductValue;
    fn deserialize<D: de::Deserializer<'de>>(self, deserializer: D) -> Result<Self::Output, D::Error> {
        deserializer.deserialize_product(self)
    }
}
impl<'de> de::ProductVisitor<'de> for ReducerDeserialize<'_> {
    type Output = ProductValue;
    fn product_name(&self) -> Option<&str> {
        Some(&self.0.ty().name)
    }
    fn product_len(&self) -> usize {
        self.0.ty().args.len()
    }
    fn product_kind(&self) -> de::ProductKind {
        de::ProductKind::ReducerArgs
    }
    fn visit_seq_product<A: de::SeqProductAccess<'de>>(self, tup: A) -> Result<Self::Output, A::Error> {
        de::visit_seq_product(self.0.map(|r| &*r.args), &self, tup)
    }
    fn visit_named_product<A: de::NamedProductAccess<'de>>(self, tup: A) -> Result<Self::Output, A::Error> {
        de::visit_named_product(self.0.map(|r| &*r.args), &self, tup)
    }
}
struct ReducerArgsWithSchema<'a> {
    value: &'a ProductValue,
    ty: sats::WithTypespace<'a, ReducerDef>,
}
impl_serialize!([] ReducerArgsWithSchema<'_>, (self, ser) => {
    use itertools::Itertools;
    use ser::SerializeSeqProduct;
    let mut seq = ser.serialize_seq_product(self.value.elements.len())?;
    for (value, elem) in self.value.elements.iter().zip_eq(&self.ty.ty().args) {
        seq.serialize_element(&self.ty.with(&elem.algebraic_type).with_value(value))?;
    }
    seq.end()
});
#[derive(Debug, Clone, Default, de::Deserialize, ser::Serialize)]
pub struct ModuleDef {
    pub typespace: sats::Typespace,
    pub tables: Vec<TableDef>,
    pub reducers: Vec<ReducerDef>,
    pub misc_exports: Vec<MiscModuleExport>,
}
#[derive(Debug, Clone, de::Deserialize, ser::Serialize)]
pub enum MiscModuleExport {
    TypeAlias(TypeAlias),
}
#[derive(Debug, Clone, de::Deserialize, ser::Serialize)]
pub struct TypeAlias {
    pub name: String,
    pub ty: sats::AlgebraicTypeRef,
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, de::Deserialize, ser::Serialize)]
pub struct IndexDef {
    pub name: String,
    pub ty: IndexType,
    pub col_ids: Vec<u8>,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, de::Deserialize, ser::Serialize)]
pub enum IndexType {
    BTree,
    Hash,
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, de::Deserialize, ser::Serialize)]
pub enum ColumnIndexAttribute {
    #[default]
    UnSet = 0,
    Identity = 1,
    Unique = 2,
    Indexed = 3,
    AutoInc = 4,
    PrimaryKey = 5,
    PrimaryKeyAuto = 6,
}
impl ColumnIndexAttribute {
    pub const fn is_unique(self) -> bool {
        matches!(
            self,
            Self::Identity | Self::Unique | Self::PrimaryKey | Self::PrimaryKeyAuto
        )
    }
    pub const fn is_autoinc(self) -> bool {
        matches!(self, Self::Identity | Self::AutoInc | Self::PrimaryKeyAuto)
    }
    pub const fn is_primary(self) -> bool {
        matches!(self, Self::PrimaryKey | Self::PrimaryKeyAuto)
    }
}
impl TryFrom<u8> for ColumnIndexAttribute {
    type Error = ();
    fn try_from(v: u8) -> Result<Self, Self::Error> {
        match v {
            0 => Ok(Self::UnSet),
            1 => Ok(Self::Identity),
            2 => Ok(Self::Unique),
            3 => Ok(Self::Indexed),
            4 => Ok(Self::AutoInc),
            5 => Ok(Self::PrimaryKey),
            6 => Ok(Self::PrimaryKeyAuto),
            _ => Err(()),
        }
    }
}