use crate::ffi::{ffi_arc_dyn_getter, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::static_data::{BattleItemCategory, Item, ItemCategory, ItemImpl}; use crate::StringKey; use anyhow::anyhow; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiates an item. #[no_mangle] unsafe extern "C" fn item_new( name: *const c_char, category: ItemCategory, battle_category: BattleItemCategory, price: i32, flags: *const *const c_char, flags_length: usize, ) -> NativeResult>> { let flags = std::slice::from_raw_parts(flags, flags_length); let name: StringKey = match CStr::from_ptr(name).to_str() { Ok(name) => name.into(), Err(_) => return NativeResult::err(anyhow!("Unable to convert name to string")), }; let mut flags_set: HashSet = HashSet::with_capacity(flags_length); for flag in flags { let flag = match CStr::from_ptr(*flag).to_str() { Ok(flag) => flag, Err(_) => return NativeResult::err(anyhow!("Unable to convert flag to string")), }; flags_set.insert(flag.into()); } let item: Arc = Arc::new(ItemImpl::new(&name, category, battle_category, price, flags_set)); NativeResult::ok(item.into()) } /// Drops a reference counted item. #[no_mangle] unsafe extern "C" fn item_drop(ptr: OwnedPtr>) { drop_in_place(ptr) } /// The name of the item. #[no_mangle] unsafe extern "C" fn item_name(ptr: ExternPointer>) -> NativeResult> { let name = ptr.as_ref().name(); match CString::new(name.str()) { Ok(name) => NativeResult::ok(name.into_raw()), Err(_) => NativeResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())), } } ffi_arc_dyn_getter!(Item, category, ItemCategory); ffi_arc_dyn_getter!(Item, battle_category, BattleItemCategory); ffi_arc_dyn_getter!(Item, price, i32); /// Checks whether the item has a specific flag. #[no_mangle] unsafe extern "C" fn item_has_flag(ptr: ExternPointer>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); u8::from(ptr.as_ref().has_flag(&flag)) }