use core::ffi::c_void;
use std::fmt;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
use serde::Serialize;
use crate::download::{ContentRequest, Download};
use crate::ffi;
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct AssetPackSnapshot {
pub id: String,
pub download_size: i64,
pub version: i64,
pub description: String,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
#[serde(transparent)]
pub struct AssetPackStatus(u64);
impl AssetPackStatus {
pub const DOWNLOAD_AVAILABLE: Self = Self(1 << 0);
pub const UPDATE_AVAILABLE: Self = Self(1 << 1);
pub const UP_TO_DATE: Self = Self(1 << 2);
pub const OUT_OF_DATE: Self = Self(1 << 3);
pub const OBSOLETE: Self = Self(1 << 4);
pub const DOWNLOADING: Self = Self(1 << 5);
pub const DOWNLOADED: Self = Self(1 << 6);
pub const fn new(bits: u64) -> Self {
Self(bits)
}
pub const fn bits(self) -> u64 {
self.0
}
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
pub const fn is_empty(self) -> bool {
self.0 == 0
}
}
impl BitOr for AssetPackStatus {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl BitOrAssign for AssetPackStatus {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl BitAnd for AssetPackStatus {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl BitAndAssign for AssetPackStatus {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
pub struct AssetPack {
pub(crate) ptr: *mut c_void,
}
impl AssetPack {
pub(crate) fn from_raw(ptr: *mut c_void) -> Option<Self> {
(!ptr.is_null()).then_some(Self { ptr })
}
#[cfg(feature = "async")]
pub(crate) const fn raw_ptr(&self) -> *mut c_void {
self.ptr
}
pub fn id(&self) -> String {
unsafe { ffi::owned_string(ffi::ba_asset_pack_identifier(self.ptr)) }
}
pub fn download_size(&self) -> i64 {
unsafe { ffi::ba_asset_pack_download_size(self.ptr) as i64 }
}
pub fn version(&self) -> i64 {
unsafe { ffi::ba_asset_pack_version(self.ptr) as i64 }
}
pub fn description(&self) -> String {
unsafe { ffi::owned_string(ffi::ba_asset_pack_description(self.ptr)) }
}
pub fn user_info(&self) -> Option<Vec<u8>> {
let mut length = 0isize;
let ptr = unsafe { ffi::ba_asset_pack_user_info_copy(self.ptr, &mut length) };
(!ptr.is_null()).then(|| unsafe { ffi::owned_bytes(ptr, length) })
}
pub fn snapshot(&self) -> AssetPackSnapshot {
AssetPackSnapshot {
id: self.id(),
download_size: self.download_size(),
version: self.version(),
description: self.description(),
}
}
pub fn download(&self) -> Option<Download> {
Download::from_raw(unsafe { ffi::ba_asset_pack_download(self.ptr) })
}
pub fn download_for_request(&self, request: ContentRequest) -> Option<Download> {
Download::from_raw(unsafe {
ffi::ba_asset_pack_download_for_request(self.ptr, request.as_raw())
})
}
}
impl Clone for AssetPack {
fn clone(&self) -> Self {
Self {
ptr: ffi::retained(self.ptr),
}
}
}
impl Drop for AssetPack {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { ffi::ba_object_release(self.ptr) };
}
}
}
impl fmt::Debug for AssetPack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AssetPack")
.field("snapshot", &self.snapshot())
.finish()
}
}
unsafe impl Send for AssetPack {}
unsafe impl Sync for AssetPack {}
pub(crate) fn collect_asset_packs(array_ptr: *mut c_void) -> Vec<AssetPack> {
if array_ptr.is_null() {
return Vec::new();
}
let length =
usize::try_from(unsafe { ffi::ba_asset_pack_array_len(array_ptr) }).unwrap_or_default();
let mut asset_packs = Vec::with_capacity(length);
for index in 0..length {
let index = isize::try_from(index).expect("asset-pack array length originates from isize");
let item_ptr = unsafe { ffi::ba_asset_pack_array_get(array_ptr, index) };
if let Some(asset_pack) = AssetPack::from_raw(item_ptr) {
asset_packs.push(asset_pack);
}
}
unsafe { ffi::ba_object_release(array_ptr) };
asset_packs
}