Complete refactor of the FFI to use handles instead of pointers.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-06-24 14:44:23 +02:00
parent 4c222cb753
commit 78bb91093b
76 changed files with 1510 additions and 1952 deletions

View File

@@ -1,105 +1,102 @@
use crate::dynamic_data::{FleeChoice, LearnedMove, MoveChoice, PassChoice, Pokemon, TurnChoice};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use anyhow::anyhow;
use std::ptr::drop_in_place;
use std::ops::Deref;
use std::sync::Arc;
/// Disposes a turn choice.
#[no_mangle]
extern "C" fn turn_choice_drop(choice: OwnedPtr<TurnChoice>) {
unsafe { drop_in_place(choice) }
}
/// Get the user of the given choice.
#[no_mangle]
extern "C" fn turn_choice_user(choice: ExternPointer<TurnChoice>) -> IdentifiablePointer<Pokemon> {
choice.as_ref().user().clone().into()
extern "C" fn turn_choice_user(choice: FFIHandle<Arc<TurnChoice>>) -> FFIHandle<Pokemon> {
FFIHandle::get_handle(choice.from_ffi_handle().user().clone().into())
}
/// Get the speed of the user for the choice. Note that this speed is the speed of the Pokemon
/// at the start of the turn!
#[no_mangle]
extern "C" fn turn_choice_speed(choice: ExternPointer<TurnChoice>) -> u32 {
choice.as_ref().speed()
extern "C" fn turn_choice_speed(choice: FFIHandle<Arc<TurnChoice>>) -> u32 {
choice.from_ffi_handle().speed()
}
/// Gets whether or not the choice has failed. If we notice this when we execute the choice, we
/// will not execute it.
#[no_mangle]
extern "C" fn turn_choice_has_failed(choice: ExternPointer<TurnChoice>) -> u8 {
u8::from(choice.as_ref().has_failed())
extern "C" fn turn_choice_has_failed(choice: FFIHandle<Arc<TurnChoice>>) -> u8 {
u8::from(choice.from_ffi_handle().has_failed())
}
/// Fails the choice. This will prevent it from executing and run a specific fail handling during
/// execution. Note that this can not be undone.
#[no_mangle]
extern "C" fn turn_choice_fail(choice: ExternPointer<TurnChoice>) {
choice.as_ref().fail()
extern "C" fn turn_choice_fail(choice: FFIHandle<Arc<TurnChoice>>) {
choice.from_ffi_handle().fail()
}
/// Creates a new Turn Choice with a move to use.
#[no_mangle]
extern "C" fn turn_choice_move_new(
user: ExternPointer<Pokemon>,
learned_move: ExternPointer<Arc<LearnedMove>>,
user: FFIHandle<Pokemon>,
learned_move: FFIHandle<Arc<LearnedMove>>,
target_side: u8,
target_index: u8,
) -> IdentifiablePointer<TurnChoice> {
Box::new(TurnChoice::Move(MoveChoice::new(
user.as_ref().clone(),
learned_move.as_ref().clone(),
target_side,
target_index,
)))
.into()
) -> FFIHandle<Arc<TurnChoice>> {
FFIHandle::get_handle(
Arc::new(TurnChoice::Move(MoveChoice::new(
user.from_ffi_handle(),
learned_move.from_ffi_handle(),
target_side,
target_index,
)))
.into(),
)
}
/// The actual learned move on the Pokemon we use for this choice.
#[no_mangle]
extern "C" fn turn_choice_move_learned_move(
choice: ExternPointer<TurnChoice>,
) -> NativeResult<IdentifiablePointer<Arc<LearnedMove>>> {
if let TurnChoice::Move(c) = choice.as_ref() {
return NativeResult::ok(c.used_move().clone().into());
choice: FFIHandle<Arc<TurnChoice>>,
) -> FFIResult<FFIHandle<Arc<LearnedMove>>> {
if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() {
return FFIResult::ok(FFIHandle::get_handle(c.used_move().clone().into()));
}
NativeResult::err(anyhow!("Turn choice was not a learned move"))
FFIResult::err(anyhow!("Turn choice was not a learned move"))
}
/// The target side the move is aimed at.
#[no_mangle]
extern "C" fn turn_choice_move_target_side(choice: ExternPointer<TurnChoice>) -> NativeResult<u8> {
if let TurnChoice::Move(c) = choice.as_ref() {
return NativeResult::ok(c.target_side());
extern "C" fn turn_choice_move_target_side(choice: FFIHandle<Arc<TurnChoice>>) -> FFIResult<u8> {
if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() {
return FFIResult::ok(c.target_side());
}
NativeResult::err(anyhow!("Turn choice was not a learned move"))
FFIResult::err(anyhow!("Turn choice was not a learned move"))
}
/// The Pokemon index on the side we're aiming at.
#[no_mangle]
extern "C" fn turn_choice_move_target_index(choice: ExternPointer<TurnChoice>) -> NativeResult<u8> {
if let TurnChoice::Move(c) = choice.as_ref() {
return NativeResult::ok(c.target_index());
extern "C" fn turn_choice_move_target_index(choice: FFIHandle<Arc<TurnChoice>>) -> FFIResult<u8> {
if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() {
return FFIResult::ok(c.target_index());
}
NativeResult::err(anyhow!("Turn choice was not a learned move"))
FFIResult::err(anyhow!("Turn choice was not a learned move"))
}
/// The priority of the move choice at the beginning of the turn.
#[no_mangle]
extern "C" fn turn_choice_move_priority(choice: ExternPointer<TurnChoice>) -> NativeResult<i8> {
if let TurnChoice::Move(c) = choice.as_ref() {
return NativeResult::ok(c.priority());
extern "C" fn turn_choice_move_priority(choice: FFIHandle<Arc<TurnChoice>>) -> FFIResult<i8> {
if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() {
return FFIResult::ok(c.priority());
}
NativeResult::err(anyhow!("Turn choice was not a learned move"))
FFIResult::err(anyhow!("Turn choice was not a learned move"))
}
/// Creates a new Turn Choice for the user to flee.
#[no_mangle]
extern "C" fn turn_choice_flee_new(user: ExternPointer<Pokemon>) -> IdentifiablePointer<TurnChoice> {
Box::new(TurnChoice::Flee(FleeChoice::new(user.as_ref().clone()))).into()
extern "C" fn turn_choice_flee_new(user: FFIHandle<Pokemon>) -> FFIHandle<Arc<TurnChoice>> {
FFIHandle::get_handle(Arc::new(TurnChoice::Flee(FleeChoice::new(user.from_ffi_handle()))).into())
}
/// Creates a new Turn Choice for the user to pass the turn.
#[no_mangle]
extern "C" fn turn_choice_pass_new(user: ExternPointer<Pokemon>) -> IdentifiablePointer<TurnChoice> {
Box::new(TurnChoice::Pass(PassChoice::new(user.as_ref().clone()))).into()
extern "C" fn turn_choice_pass_new(user: FFIHandle<Pokemon>) -> FFIHandle<Arc<TurnChoice>> {
FFIHandle::get_handle(Arc::new(TurnChoice::Pass(PassChoice::new(user.from_ffi_handle()))).into())
}

View File

@@ -1,63 +1,61 @@
use crate::dynamic_data::{BattleStatCalculator, Gen7BattleStatCalculator, Pokemon};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{ExternPointer, FFIResult};
use crate::static_data::{Statistic, StatisticSet};
use std::ptr::drop_in_place;
use std::ops::Deref;
use std::sync::Arc;
/// Creates a new Gen 7 battle stat calculator
#[no_mangle]
extern "C" fn gen_7_battle_stat_calculator_new() -> IdentifiablePointer<Box<dyn BattleStatCalculator>> {
let v: Box<dyn BattleStatCalculator> = Box::new(Gen7BattleStatCalculator::new());
let id = v.value_identifier();
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
}
/// Drops a battle stat calculator.
#[no_mangle]
extern "C" fn battle_stat_calculator_drop(ptr: OwnedPtr<Box<dyn BattleStatCalculator>>) {
unsafe { drop_in_place(ptr) };
extern "C" fn gen_7_battle_stat_calculator_new() -> FFIHandle<Arc<dyn BattleStatCalculator>> {
let v: Arc<dyn BattleStatCalculator> = Arc::new(Gen7BattleStatCalculator::new());
FFIHandle::get_handle(v.into())
}
/// Calculate all the flat stats of a Pokemon, disregarding stat boosts.
#[no_mangle]
extern "C" fn battle_stat_calculator_calculate_flat_stats(
ptr: ExternPointer<Box<dyn BattleStatCalculator>>,
ptr: FFIHandle<Arc<dyn BattleStatCalculator>>,
pokemon: ExternPointer<Pokemon>,
mut stats: ExternPointer<Box<StatisticSet<u32>>>,
) -> NativeResult<()> {
ptr.as_ref()
.calculate_flat_stats(pokemon.as_ref(), stats.as_mut())
stats: FFIHandle<Arc<StatisticSet<u32>>>,
) -> FFIResult<()> {
ptr.from_ffi_handle()
.calculate_flat_stats(pokemon.as_ref(), stats.from_ffi_handle().deref())
.into()
}
/// Calculate a single flat stat of a Pokemon, disregarding stat boost
#[no_mangle]
extern "C" fn battle_stat_calculator_calculate_flat_stat(
ptr: ExternPointer<Box<dyn BattleStatCalculator>>,
pokemon: ExternPointer<Pokemon>,
ptr: FFIHandle<Arc<dyn BattleStatCalculator>>,
pokemon: FFIHandle<Pokemon>,
stat: Statistic,
) -> NativeResult<u32> {
ptr.as_ref().calculate_flat_stat(pokemon.as_ref(), stat).into()
) -> FFIResult<u32> {
ptr.from_ffi_handle()
.calculate_flat_stat(&pokemon.from_ffi_handle(), stat)
.into()
}
/// Calculate all the boosted stats of a Pokemon, including stat boosts.
#[no_mangle]
extern "C" fn battle_stat_calculator_calculate_boosted_stats(
ptr: ExternPointer<Box<dyn BattleStatCalculator>>,
pokemon: ExternPointer<Pokemon>,
mut stats: ExternPointer<Box<StatisticSet<u32>>>,
) -> NativeResult<()> {
ptr.as_ref()
.calculate_boosted_stats(pokemon.as_ref(), stats.as_mut())
ptr: FFIHandle<Arc<dyn BattleStatCalculator>>,
pokemon: FFIHandle<Pokemon>,
stats: FFIHandle<Arc<StatisticSet<u32>>>,
) -> FFIResult<()> {
ptr.from_ffi_handle()
.calculate_boosted_stats(&pokemon.from_ffi_handle(), stats.from_ffi_handle().deref())
.into()
}
/// Calculate a single boosted stat of a Pokemon, including stat boosts.
#[no_mangle]
extern "C" fn battle_stat_calculator_calculate_boosted_stat(
ptr: ExternPointer<Box<dyn BattleStatCalculator>>,
pokemon: ExternPointer<Pokemon>,
ptr: FFIHandle<Arc<dyn BattleStatCalculator>>,
pokemon: FFIHandle<Pokemon>,
stat: Statistic,
) -> NativeResult<u32> {
ptr.as_ref().calculate_boosted_stat(pokemon.as_ref(), stat).into()
) -> FFIResult<u32> {
ptr.from_ffi_handle()
.calculate_boosted_stat(&pokemon.from_ffi_handle(), stat)
.into()
}

View File

@@ -1,19 +1,11 @@
use crate::dynamic_data::{DamageLibrary, Gen7DamageLibrary};
use crate::ffi::{IdentifiablePointer, OwnedPtr};
use std::ptr::drop_in_place;
use crate::ffi::ffi_handle::FFIHandle;
use std::sync::Arc;
/// Creates a new generation 7 damage library. `has_randomness` defines whether a random damage
/// modifier (0.85x - 1.00x) is applied to the calculated damage.
#[no_mangle]
extern "C" fn gen_7_damage_library_new(has_randomness: u8) -> IdentifiablePointer<Box<dyn DamageLibrary>> {
let v: Box<dyn DamageLibrary> = Box::new(Gen7DamageLibrary::new(has_randomness == 1));
let id = v.value_identifier();
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
}
/// Drops a DamageLibrary.
#[no_mangle]
extern "C" fn damage_library_drop(ptr: OwnedPtr<Box<dyn DamageLibrary>>) {
unsafe { drop_in_place(ptr) };
extern "C" fn gen_7_damage_library_new(has_randomness: u8) -> FFIHandle<Arc<dyn DamageLibrary>> {
let v: Arc<dyn DamageLibrary> = Arc::new(Gen7DamageLibrary::new(has_randomness == 1));
FFIHandle::get_handle(v.into())
}

View File

@@ -1,68 +1,59 @@
use crate::dynamic_data::{
BattleStatCalculator, DamageLibrary, DynamicLibrary, DynamicLibraryImpl, MiscLibrary, ScriptResolver,
};
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::static_data::StaticData;
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Instantiates a new DynamicLibrary with given parameters.
#[no_mangle]
extern "C" fn dynamic_library_new(
static_data: OwnedPtr<Arc<dyn StaticData>>,
stat_calculator: OwnedPtr<Arc<dyn BattleStatCalculator>>,
damage_library: OwnedPtr<Arc<dyn DamageLibrary>>,
misc_library: OwnedPtr<Arc<dyn MiscLibrary>>,
script_resolver: OwnedPtr<Box<dyn ScriptResolver>>,
) -> IdentifiablePointer<Arc<dyn DynamicLibrary>> {
unsafe {
let a: Arc<dyn DynamicLibrary> = Arc::new(DynamicLibraryImpl::new(
static_data.read(),
stat_calculator.read(),
damage_library.read(),
misc_library.read(),
*Box::from_raw(script_resolver),
));
a.into()
}
}
/// Drops a dynamic library.
#[no_mangle]
extern "C" fn dynamic_library_drop(ptr: OwnedPtr<Arc<dyn DynamicLibrary>>) {
unsafe { drop_in_place(ptr) };
static_data: FFIHandle<Arc<dyn StaticData>>,
stat_calculator: FFIHandle<Arc<dyn BattleStatCalculator>>,
damage_library: FFIHandle<Arc<dyn DamageLibrary>>,
misc_library: FFIHandle<Arc<dyn MiscLibrary>>,
script_resolver: FFIHandle<Arc<dyn ScriptResolver>>,
) -> FFIHandle<Arc<dyn DynamicLibrary>> {
let a: Arc<dyn DynamicLibrary> = Arc::new(DynamicLibraryImpl::new(
static_data.from_ffi_handle(),
stat_calculator.from_ffi_handle(),
damage_library.from_ffi_handle(),
misc_library.from_ffi_handle(),
script_resolver.from_ffi_handle(),
));
FFIHandle::get_handle(a.into())
}
/// The static data is the immutable storage data for this library.
#[no_mangle]
extern "C" fn dynamic_library_get_static_data(
ptr: ExternPointer<Arc<dyn DynamicLibrary>>,
) -> IdentifiablePointer<Arc<dyn StaticData>> {
ptr.as_ref().static_data().clone().into()
ptr: FFIHandle<Arc<dyn DynamicLibrary>>,
) -> FFIHandle<Arc<dyn StaticData>> {
FFIHandle::get_handle(ptr.from_ffi_handle().static_data().clone().into())
}
/// The stat calculator deals with the calculation of flat and boosted stats, based on the
/// Pokemons attributes.
#[no_mangle]
extern "C" fn dynamic_library_get_stat_calculator(
ptr: ExternPointer<Arc<dyn DynamicLibrary>>,
) -> IdentifiablePointer<Arc<dyn BattleStatCalculator>> {
ptr.as_ref().stat_calculator().clone().into()
ptr: FFIHandle<Arc<dyn DynamicLibrary>>,
) -> FFIHandle<Arc<dyn BattleStatCalculator>> {
FFIHandle::get_handle(ptr.from_ffi_handle().stat_calculator().clone().into())
}
/// The damage calculator deals with the calculation of things relating to damage.
#[no_mangle]
extern "C" fn dynamic_library_get_damage_calculator(
ptr: ExternPointer<Arc<dyn DynamicLibrary>>,
) -> IdentifiablePointer<Arc<dyn DamageLibrary>> {
ptr.as_ref().damage_calculator().clone().into()
ptr: FFIHandle<Arc<dyn DynamicLibrary>>,
) -> FFIHandle<Arc<dyn DamageLibrary>> {
FFIHandle::get_handle(ptr.from_ffi_handle().damage_calculator().clone().into())
}
/// The Misc Library holds minor functions that do not fall in any of the other libraries and
/// calculators.
#[no_mangle]
extern "C" fn dynamic_library_get_misc_library(
ptr: ExternPointer<Arc<dyn DynamicLibrary>>,
) -> IdentifiablePointer<Arc<dyn MiscLibrary>> {
ptr.as_ref().misc_library().clone().into()
ptr: FFIHandle<Arc<dyn DynamicLibrary>>,
) -> FFIHandle<Arc<dyn MiscLibrary>> {
FFIHandle::get_handle(ptr.from_ffi_handle().misc_library().clone().into())
}

View File

@@ -1,18 +1,10 @@
use crate::dynamic_data::{Gen7MiscLibrary, MiscLibrary};
use crate::ffi::{IdentifiablePointer, OwnedPtr};
use std::ptr::drop_in_place;
use crate::ffi::ffi_handle::FFIHandle;
use std::sync::Arc;
/// Instantiates a new MiscLibrary.
#[no_mangle]
extern "C" fn gen_7_misc_library_new() -> IdentifiablePointer<Box<dyn MiscLibrary>> {
let v: Box<dyn MiscLibrary> = Box::new(Gen7MiscLibrary::new());
let id = v.value_identifier();
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
}
/// Drops a MiscLibrary.
#[no_mangle]
extern "C" fn misc_library_drop(ptr: OwnedPtr<Box<dyn MiscLibrary>>) {
unsafe { drop_in_place(ptr) };
extern "C" fn gen_7_misc_library_new() -> FFIHandle<Arc<dyn MiscLibrary>> {
let v: Arc<dyn MiscLibrary> = Arc::new(Gen7MiscLibrary::new());
FFIHandle::get_handle(v.into())
}

View File

@@ -1,49 +1,45 @@
use crate::dynamic_data::{EmptyScriptResolver, ScriptResolver};
use crate::ffi::{IdentifiablePointer, OwnedPtr};
use std::ptr::drop_in_place;
use crate::ffi::ffi_handle::FFIHandle;
use std::sync::Arc;
/// Instantiates a basic empty script resolver, that always returns None.
#[no_mangle]
extern "C" fn empty_script_resolver_new() -> IdentifiablePointer<Box<dyn ScriptResolver>> {
let v: Box<dyn ScriptResolver> = Box::new(EmptyScriptResolver {
identifier: Default::default(),
});
let id = v.value_identifier();
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
}
/// Drops a script resolver.
#[no_mangle]
extern "C" fn script_resolver_drop(ptr: OwnedPtr<Box<dyn ScriptResolver>>) {
unsafe { drop_in_place(ptr) };
extern "C" fn empty_script_resolver_new() -> FFIHandle<Arc<dyn ScriptResolver>> {
let v: Arc<dyn ScriptResolver> = Arc::new(EmptyScriptResolver {});
FFIHandle::get_handle(v.into())
}
/// Foreign function interfaces for the Webassembly script resolver.
#[cfg(feature = "wasm")]
mod web_assembly_script_resolver {
use crate::dynamic_data::ScriptResolver;
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver;
use std::sync::Arc;
/// Instantiates a new WebAssemblyScriptResolver.
#[no_mangle]
extern "C" fn webassembly_script_resolver_new() -> IdentifiablePointer<Box<dyn ScriptResolver>> {
let v: Box<dyn ScriptResolver> = WebAssemblyScriptResolver::new();
let id = v.value_identifier();
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
extern "C" fn webassembly_script_resolver_new() -> FFIHandle<Arc<dyn ScriptResolver>> {
let v: Arc<dyn ScriptResolver> = WebAssemblyScriptResolver::new();
FFIHandle::get_handle(v.into())
}
/// Load a compiled WASM module.
#[no_mangle]
extern "C" fn webassembly_script_resolver_load_wasm_from_bytes(
mut ptr: ExternPointer<Box<WebAssemblyScriptResolver>>,
ptr: FFIHandle<Arc<dyn ScriptResolver>>,
arr: *const u8,
len: usize,
) -> NativeResult<()> {
) -> FFIResult<()> {
#[allow(clippy::unwrap_used)] // Unwrap used, but we know it cannot fail.
unsafe {
ptr.as_mut()
let script_resolver = ptr.from_ffi_handle();
let wasm_script_resolver = script_resolver
.as_any()
.downcast_ref::<WebAssemblyScriptResolver>()
.unwrap();
wasm_script_resolver
.load_wasm_from_bytes(std::slice::from_raw_parts(arr, len))
.into()
}
@@ -51,9 +47,13 @@ mod web_assembly_script_resolver {
/// Tells the script resolver we're done loading wasm modules, and to finalize the resolver.
#[no_mangle]
extern "C" fn webassembly_script_resolver_finalize(
mut ptr: ExternPointer<Box<WebAssemblyScriptResolver>>,
) -> NativeResult<()> {
ptr.as_mut().finalize().into()
#[allow(clippy::unwrap_used)] // Unwrap used, but we know it cannot fail.
extern "C" fn webassembly_script_resolver_finalize(ptr: FFIHandle<Arc<dyn ScriptResolver>>) -> FFIResult<()> {
let script_resolver = ptr.from_ffi_handle();
let wasm_script_resolver = script_resolver
.as_any()
.downcast_ref::<WebAssemblyScriptResolver>()
.unwrap();
wasm_script_resolver.finalize().into()
}
}

View File

@@ -2,16 +2,18 @@ use crate::dynamic_data::{
Battle, BattleParty, BattleRandom, BattleResult, BattleSide, DynamicLibrary, Pokemon, TurnChoice,
};
use crate::ffi::dynamic_data::models::native_event_hook::NativeEventHook;
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::ops::Deref;
use std::sync::Arc;
/// Initializes a new battle.
#[no_mangle]
extern "C" fn battle_new(
library: ExternPointer<Arc<dyn DynamicLibrary>>,
parties: *const OwnedPtr<Arc<BattleParty>>,
library: FFIHandle<Arc<dyn DynamicLibrary>>,
parties: *const FFIHandle<Arc<BattleParty>>,
parties_length: usize,
can_flee: u8,
number_of_sides: u8,
@@ -19,11 +21,11 @@ extern "C" fn battle_new(
// NOTE: Split into two due to u128 not being ABI safe: https://github.com/rust-lang/rust/issues/54341
random_seed_1: u64,
random_seed_2: u64,
) -> IdentifiablePointer<Battle> {
) -> FFIHandle<Battle> {
let parties = unsafe {
std::slice::from_raw_parts(parties, parties_length)
.iter()
.map(|x| *Box::from_raw(*x))
.map(|x| x.from_ffi_handle())
.collect()
};
@@ -34,99 +36,98 @@ extern "C" fn battle_new(
};
let random_seed = if random_seed == 0 { None } else { Some(random_seed) };
Battle::new(
library.as_ref().clone(),
parties,
can_flee == 1,
number_of_sides,
pokemon_per_side,
random_seed,
FFIHandle::get_handle(
Battle::new(
library.from_ffi_handle(),
parties,
can_flee == 1,
number_of_sides,
pokemon_per_side,
random_seed,
)
.into(),
)
.into()
}
/// The library the battle uses for handling.
#[no_mangle]
extern "C" fn battle_library(ptr: ExternPointer<Arc<Battle>>) -> IdentifiablePointer<Arc<dyn DynamicLibrary>> {
ptr.as_ref().library().clone().into()
extern "C" fn battle_library(ptr: FFIHandle<Battle>) -> FFIHandle<Arc<dyn DynamicLibrary>> {
FFIHandle::get_handle(ptr.from_ffi_handle().library().clone().into())
}
/// The length of the list of all different parties in the battle.
#[no_mangle]
extern "C" fn battle_parties_length(ptr: ExternPointer<Arc<Battle>>) -> usize {
ptr.as_ref().parties().len()
extern "C" fn battle_parties_length(ptr: FFIHandle<Battle>) -> usize {
ptr.from_ffi_handle().parties().len()
}
/// Get a party in the battle.
#[no_mangle]
extern "C" fn battle_parties_get(
ptr: ExternPointer<Arc<Battle>>,
index: usize,
) -> IdentifiablePointer<Arc<BattleParty>> {
if let Some(v) = ptr.as_ref().parties().get(index) {
v.clone().into()
extern "C" fn battle_parties_get(ptr: FFIHandle<Battle>, index: usize) -> FFIHandle<Arc<BattleParty>> {
if let Some(v) = ptr.from_ffi_handle().parties().get(index) {
FFIHandle::get_handle(v.clone().into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Whether or not Pokemon can flee from the battle.
#[no_mangle]
extern "C" fn battle_can_flee(ptr: ExternPointer<Arc<Battle>>) -> u8 {
u8::from(ptr.as_ref().can_flee())
extern "C" fn battle_can_flee(ptr: FFIHandle<Battle>) -> u8 {
u8::from(ptr.from_ffi_handle().can_flee())
}
/// The number of sides in the battle. Typically 2.
#[no_mangle]
extern "C" fn battle_number_of_sides(ptr: ExternPointer<Arc<Battle>>) -> u8 {
ptr.as_ref().number_of_sides()
extern "C" fn battle_number_of_sides(ptr: FFIHandle<Battle>) -> u8 {
ptr.from_ffi_handle().number_of_sides()
}
/// The number of Pokemon that can be on each side.
#[no_mangle]
extern "C" fn battle_pokemon_per_side(ptr: ExternPointer<Arc<Battle>>) -> u8 {
ptr.as_ref().pokemon_per_side()
extern "C" fn battle_pokemon_per_side(ptr: FFIHandle<Battle>) -> u8 {
ptr.from_ffi_handle().pokemon_per_side()
}
/// The length of the list of all different sides in the battle.
#[no_mangle]
extern "C" fn battle_sides_length(ptr: ExternPointer<Arc<Battle>>) -> usize {
ptr.as_ref().sides().len()
extern "C" fn battle_sides_length(ptr: FFIHandle<Battle>) -> usize {
ptr.from_ffi_handle().sides().len()
}
/// Get a side in the battle.
#[no_mangle]
extern "C" fn battle_sides_get(ptr: ExternPointer<Arc<Battle>>, index: usize) -> IdentifiablePointer<BattleSide> {
if let Some(v) = ptr.as_ref().sides().get(index) {
(v as *const BattleSide).into()
extern "C" fn battle_sides_get(ptr: FFIHandle<Battle>, index: usize) -> FFIHandle<BattleSide> {
if let Some(v) = ptr.from_ffi_handle().sides().get(index) {
FFIHandle::get_handle(v.clone().into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// The RNG used for the battle.
#[no_mangle]
extern "C" fn battle_random(ptr: ExternPointer<Arc<Battle>>) -> IdentifiablePointer<Arc<BattleRandom>> {
ptr.as_ref().random().clone().into()
extern "C" fn battle_random(ptr: FFIHandle<Battle>) -> FFIHandle<Arc<BattleRandom>> {
FFIHandle::get_handle(ptr.from_ffi_handle().random().clone().into())
}
/// Whether or not the battle has ended.
#[no_mangle]
extern "C" fn battle_has_ended(ptr: ExternPointer<Arc<Battle>>) -> u8 {
u8::from(ptr.as_ref().has_ended())
extern "C" fn battle_has_ended(ptr: FFIHandle<Battle>) -> u8 {
u8::from(ptr.from_ffi_handle().has_ended())
}
/// Whether or not we have a conclusive winner
#[no_mangle]
extern "C" fn battle_has_conclusive_result(ptr: ExternPointer<Arc<Battle>>) -> u8 {
u8::from(ptr.as_ref().result() != BattleResult::Inconclusive)
extern "C" fn battle_has_conclusive_result(ptr: FFIHandle<Battle>) -> u8 {
u8::from(ptr.from_ffi_handle().result() != BattleResult::Inconclusive)
}
/// If we have a conclusive winner, the side that has won. If we don't have a conclusive winner, this
/// always returns 0.
#[no_mangle]
extern "C" fn battle_winning_side(ptr: ExternPointer<Arc<Battle>>) -> u8 {
if let BattleResult::Conclusive(winner) = ptr.as_ref().result() {
extern "C" fn battle_winning_side(ptr: FFIHandle<Battle>) -> u8 {
if let BattleResult::Conclusive(winner) = ptr.from_ffi_handle().result() {
winner
} else {
0
@@ -135,29 +136,29 @@ extern "C" fn battle_winning_side(ptr: ExternPointer<Arc<Battle>>) -> u8 {
/// Register a function to be triggered when an event in a battle occurs.
#[no_mangle]
extern "C" fn battle_register_event_hook(ptr: ExternPointer<Arc<Battle>>, f: NativeEventHook) {
ptr.as_ref().event_hook().register_listener(Box::new(f))
extern "C" fn battle_register_event_hook(ptr: FFIHandle<Battle>, f: NativeEventHook) {
ptr.from_ffi_handle().event_hook().register_listener(Box::new(f))
}
/// The index of the current turn. 0 until all choices
#[no_mangle]
extern "C" fn battle_current_turn(ptr: ExternPointer<Arc<Battle>>) -> u32 {
ptr.as_ref().current_turn()
extern "C" fn battle_current_turn(ptr: FFIHandle<Battle>) -> u32 {
ptr.from_ffi_handle().current_turn()
}
/// The time in nanoseconds the last turn took to run. Defaults to 0.
#[no_mangle]
extern "C" fn battle_last_turn_time(ptr: ExternPointer<Arc<Battle>>) -> u64 {
ptr.as_ref().last_turn_time()
extern "C" fn battle_last_turn_time(ptr: FFIHandle<Battle>) -> u64 {
ptr.from_ffi_handle().last_turn_time()
}
/// Get a Pokemon on the battlefield, on a specific side and an index on that side.
#[no_mangle]
extern "C" fn battle_get_pokemon(ptr: ExternPointer<Arc<Battle>>, side: u8, index: u8) -> IdentifiablePointer<Pokemon> {
if let Some(v) = ptr.as_ref().get_pokemon(side, index) {
v.into()
extern "C" fn battle_get_pokemon(ptr: FFIHandle<Battle>, side: u8, index: u8) -> FFIHandle<Pokemon> {
if let Some(v) = ptr.from_ffi_handle().get_pokemon(side, index) {
FFIHandle::get_handle(v.into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
@@ -165,47 +166,51 @@ extern "C" fn battle_get_pokemon(ptr: ExternPointer<Arc<Battle>>, side: u8, inde
/// for that slot, or a party is responsible, but has no remaining Pokemon to throw out anymore,
/// this returns false.
#[no_mangle]
extern "C" fn battle_can_slot_be_filled(ptr: ExternPointer<Arc<Battle>>, side: u8, index: u8) -> u8 {
u8::from(ptr.as_ref().can_slot_be_filled(side, index))
extern "C" fn battle_can_slot_be_filled(ptr: FFIHandle<Battle>, side: u8, index: u8) -> u8 {
u8::from(ptr.from_ffi_handle().can_slot_be_filled(side, index))
}
/// Checks whether a choice is actually possible.
#[no_mangle]
extern "C" fn battle_can_use(ptr: ExternPointer<Arc<Battle>>, choice: ExternPointer<TurnChoice>) -> u8 {
u8::from(ptr.as_ref().can_use(choice.as_ref()))
extern "C" fn battle_can_use(ptr: FFIHandle<Battle>, choice: FFIHandle<Arc<TurnChoice>>) -> u8 {
u8::from(ptr.from_ffi_handle().can_use(choice.from_ffi_handle().deref()))
}
/// Checks to see whether all Pokemon on the field have set their choices. If so, we then run
/// the turn.
#[no_mangle]
extern "C" fn battle_try_set_choice(ptr: ExternPointer<Arc<Battle>>, choice: OwnedPtr<TurnChoice>) -> NativeResult<u8> {
let choice = unsafe { choice.read() };
let result = ptr.as_ref().try_set_choice(choice);
extern "C" fn battle_try_set_choice(ptr: FFIHandle<Battle>, choice: FFIHandle<Arc<TurnChoice>>) -> FFIResult<u8> {
let choice = choice.from_ffi_handle();
let result = ptr.from_ffi_handle().try_set_choice(choice);
match result {
Ok(b) => NativeResult::ok(u8::from(b)),
Err(e) => NativeResult::err(e),
Ok(b) => FFIResult::ok(u8::from(b)),
Err(e) => FFIResult::err(e),
}
}
/// Sets the current weather for the battle. If nullptr is passed, this clears the weather.
#[no_mangle]
extern "C" fn battle_set_weather(ptr: ExternPointer<Arc<Battle>>, weather: *const c_char) -> NativeResult<()> {
extern "C" fn battle_set_weather(ptr: FFIHandle<Battle>, weather: *const c_char) -> FFIResult<()> {
if weather.is_null() {
ptr.as_ref().set_weather(None).into()
ptr.from_ffi_handle().set_weather(None).into()
} else {
unsafe { ptr.as_ref().set_weather(Some(CStr::from_ptr(weather).into())).into() }
unsafe {
ptr.from_ffi_handle()
.set_weather(Some(CStr::from_ptr(weather).into()))
.into()
}
}
}
/// Gets the current weather of the battle. If no weather is present, this returns nullptr.
#[no_mangle]
extern "C" fn battle_weather_name(ptr: ExternPointer<Arc<Battle>>) -> NativeResult<*mut c_char> {
match ptr.as_ref().weather_name() {
extern "C" fn battle_weather_name(ptr: FFIHandle<Battle>) -> FFIResult<*mut c_char> {
match ptr.from_ffi_handle().weather_name() {
Ok(Some(w)) => match CString::new(w.str()) {
Ok(s) => s.into_raw().into(),
Err(e) => NativeResult::err(anyhow!("Failed to convert weather name to CString: {}", e)),
Err(e) => FFIResult::err(anyhow!("Failed to convert weather name to CString: {}", e)),
},
Ok(None) => std::ptr::null_mut::<c_char>().into(),
Err(e) => NativeResult::err(e),
Err(e) => FFIResult::err(e),
}
}

View File

@@ -1,5 +1,6 @@
use crate::dynamic_data::{BattleParty, Pokemon, PokemonParty};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::VecExt;
use anyhow::{anyhow, Result};
use std::sync::Arc;
@@ -8,12 +9,12 @@ use std::sync::Arc;
/// on the field attached. The indices are stored
#[no_mangle]
extern "C" fn battle_party_new(
party: ExternPointer<Arc<PokemonParty>>,
party: FFIHandle<Arc<PokemonParty>>,
responsible_indices_ptr: *const u8,
responsible_indices_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<BattleParty>>> {
) -> FFIResult<FFIHandle<Arc<BattleParty>>> {
if responsible_indices_length % 2 != 0 {
return NativeResult::err(anyhow!("The length of responsible indices should be dividable by two"));
return FFIResult::err(anyhow!("The length of responsible indices should be dividable by two"));
}
let responsible_indices_slice =
@@ -31,43 +32,40 @@ extern "C" fn battle_party_new(
for i in 0..responsible_indices_length / 2 {
match split(i) {
Ok(_) => (),
Err(e) => return NativeResult::err(e),
Err(e) => return FFIResult::err(e),
}
}
match BattleParty::new(party.as_ref().clone(), responsible_indices) {
Ok(v) => NativeResult::ok(Arc::new(v).into()),
Err(e) => NativeResult::err(e),
match BattleParty::new(party.from_ffi_handle(), responsible_indices) {
Ok(v) => FFIResult::ok(FFIHandle::get_handle(Arc::new(v).into())),
Err(e) => FFIResult::err(e),
}
}
/// Checks whether the party is responsible for the given index.
#[no_mangle]
extern "C" fn battle_party_is_responsible_for_index(ptr: ExternPointer<Arc<BattleParty>>, side: u8, index: u8) -> u8 {
u8::from(ptr.as_ref().is_responsible_for_index(side, index))
extern "C" fn battle_party_is_responsible_for_index(ptr: FFIHandle<Arc<BattleParty>>, side: u8, index: u8) -> u8 {
u8::from(ptr.from_ffi_handle().is_responsible_for_index(side, index))
}
/// Whether or not the party has non fainted Pokemon that could be thrown out into the field.
#[no_mangle]
extern "C" fn battle_party_has_pokemon_not_in_field(ptr: ExternPointer<Arc<BattleParty>>) -> u8 {
u8::from(ptr.as_ref().has_pokemon_not_in_field())
extern "C" fn battle_party_has_pokemon_not_in_field(ptr: FFIHandle<Arc<BattleParty>>) -> u8 {
u8::from(ptr.from_ffi_handle().has_pokemon_not_in_field())
}
/// Gets a Pokemon at an index.
#[no_mangle]
extern "C" fn battle_party_get_pokemon(
ptr: ExternPointer<Arc<BattleParty>>,
index: usize,
) -> IdentifiablePointer<Pokemon> {
if let Some(v) = ptr.as_ref().get_pokemon(index) {
v.into()
extern "C" fn battle_party_get_pokemon(ptr: FFIHandle<Arc<BattleParty>>, index: usize) -> FFIHandle<Pokemon> {
if let Some(v) = ptr.from_ffi_handle().get_pokemon(index) {
FFIHandle::get_handle(v.into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Gets the underlying Pokemon Party
#[no_mangle]
extern "C" fn battle_party_party(ptr: ExternPointer<Arc<BattleParty>>) -> IdentifiablePointer<Arc<PokemonParty>> {
ptr.as_ref().party().clone().into()
extern "C" fn battle_party_party(ptr: FFIHandle<Arc<BattleParty>>) -> FFIHandle<Arc<PokemonParty>> {
FFIHandle::get_handle(ptr.from_ffi_handle().party().clone().into())
}

View File

@@ -1,5 +1,6 @@
use crate::dynamic_data::{Event, Pokemon};
use crate::ffi::{ExternPointer, IdentifiablePointer};
use crate::ffi::ExternPointer;
use crate::ffi::FFIHandle;
/// The kind of the event.
#[no_mangle]
@@ -66,13 +67,18 @@ event_ffi!(
/// The index of the Pokemon that got switched in/out on its side
index: u8,
/// The new Pokemon that will be on the spot. If none, the spot will be null.
pokemon: IdentifiablePointer<Pokemon>,
pokemon: FFIHandle<Pokemon>,
},
{
let pokemon_handle = match pokemon {
Some(pokemon) => FFIHandle::get_handle(pokemon.clone().into()),
None => FFIHandle::none(),
};
return SwitchData{
side_index: *side_index,
index: *index,
pokemon: pokemon.clone().into(),
pokemon: pokemon_handle,
}
}
);

View File

@@ -1,66 +1,58 @@
use crate::dynamic_data::{LearnedMove, MoveLearnMethod};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::static_data::MoveData;
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Instantiate a new learned move.
#[no_mangle]
extern "C" fn learned_move_new(
move_data: ExternPointer<Arc<dyn MoveData>>,
move_data: FFIHandle<Arc<dyn MoveData>>,
learn_method: MoveLearnMethod,
) -> IdentifiablePointer<Arc<LearnedMove>> {
Arc::new(LearnedMove::new(move_data.as_ref().clone(), learn_method)).into()
}
/// Drops a learned move.
#[no_mangle]
extern "C" fn learned_move_drop(learned_move: OwnedPtr<Arc<LearnedMove>>) {
unsafe { drop_in_place(learned_move) }
) -> FFIHandle<Arc<LearnedMove>> {
FFIHandle::get_handle(Arc::new(LearnedMove::new(move_data.from_ffi_handle().clone(), learn_method)).into())
}
/// The immutable move information of the move.
#[no_mangle]
extern "C" fn learned_move_move_data(
learned_move: ExternPointer<Arc<LearnedMove>>,
) -> IdentifiablePointer<Arc<dyn MoveData>> {
learned_move.as_ref().move_data().clone().into()
extern "C" fn learned_move_move_data(learned_move: FFIHandle<Arc<LearnedMove>>) -> FFIHandle<Arc<dyn MoveData>> {
FFIHandle::get_handle(learned_move.from_ffi_handle().move_data().clone().into())
}
/// The maximal power points for this move.
#[no_mangle]
extern "C" fn learned_move_max_pp(learned_move: ExternPointer<Arc<LearnedMove>>) -> u8 {
learned_move.as_ref().max_pp()
extern "C" fn learned_move_max_pp(learned_move: FFIHandle<Arc<LearnedMove>>) -> u8 {
learned_move.from_ffi_handle().max_pp()
}
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
#[no_mangle]
extern "C" fn learned_move_remaining_pp(learned_move: ExternPointer<Arc<LearnedMove>>) -> u8 {
learned_move.as_ref().remaining_pp()
extern "C" fn learned_move_remaining_pp(learned_move: FFIHandle<Arc<LearnedMove>>) -> u8 {
learned_move.from_ffi_handle().remaining_pp()
}
/// The way the move was learned.
#[no_mangle]
extern "C" fn learned_move_learn_method(learned_move: ExternPointer<Arc<LearnedMove>>) -> MoveLearnMethod {
learned_move.as_ref().learn_method()
extern "C" fn learned_move_learn_method(learned_move: FFIHandle<Arc<LearnedMove>>) -> MoveLearnMethod {
learned_move.from_ffi_handle().learn_method()
}
/// Try and reduce the PP by a certain amount. If the amount is higher than the current uses,
/// return 0. Otherwise, reduce the PP, and return 1.
#[no_mangle]
extern "C" fn learned_move_try_use(learned_move: ExternPointer<Arc<LearnedMove>>, amount: u8) -> u8 {
u8::from(learned_move.as_ref().try_use(amount))
extern "C" fn learned_move_try_use(learned_move: FFIHandle<Arc<LearnedMove>>, amount: u8) -> u8 {
u8::from(learned_move.from_ffi_handle().try_use(amount))
}
/// Set the remaining PP to the max amount of PP.
#[no_mangle]
extern "C" fn learned_move_restore_all_uses(learned_move: ExternPointer<Arc<LearnedMove>>) {
learned_move.as_ref().restore_all_uses();
extern "C" fn learned_move_restore_all_uses(learned_move: FFIHandle<Arc<LearnedMove>>) {
learned_move.from_ffi_handle().restore_all_uses();
}
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
#[no_mangle]
extern "C" fn learned_move_restore_uses(learned_move: ExternPointer<Arc<LearnedMove>>, amount: u8) -> NativeResult<()> {
learned_move.as_ref().restore_uses(amount);
NativeResult::ok(())
extern "C" fn learned_move_restore_uses(learned_move: FFIHandle<Arc<LearnedMove>>, amount: u8) -> FFIResult<()> {
learned_move.from_ffi_handle().restore_uses(amount);
FFIResult::ok(())
}

View File

@@ -1,11 +1,10 @@
use crate::dynamic_data::Event;
use crate::ffi::BorrowedPtr;
/// Wrapper class for easier use of an external function pointer.
#[repr(C)]
pub(super) struct NativeEventHook {
/// The actual C function to be called.
f: extern "C" fn(BorrowedPtr<Event>),
f: extern "C" fn(*const Event<'_>),
}
impl NativeEventHook {

View File

@@ -1,20 +1,21 @@
use crate::defines::LevelInt;
use crate::dynamic_data::{Battle, DamageSource, DynamicLibrary, LearnedMove, MoveLearnMethod, Pokemon};
use crate::ffi::{ffi_arc_getter, ffi_vec_value_getters, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::static_data::{
Ability, AbilityIndex, Form, Gender, Item, Nature, Species, Statistic, StatisticSet, TypeIdentifier,
};
use crate::VecExt;
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Instantiates a new Pokemon.
#[no_mangle]
extern "C" fn pokemon_new(
library: ExternPointer<Arc<dyn DynamicLibrary>>,
species: ExternPointer<Arc<dyn Species>>,
form: ExternPointer<Arc<dyn Form>>,
library: FFIHandle<Arc<dyn DynamicLibrary>>,
species: FFIHandle<Arc<dyn Species>>,
form: FFIHandle<Arc<dyn Form>>,
hidden_ability: u8,
ability_index: u8,
level: LevelInt,
@@ -22,12 +23,12 @@ extern "C" fn pokemon_new(
gender: Gender,
coloring: u8,
nature: *const c_char,
) -> NativeResult<IdentifiablePointer<Pokemon>> {
) -> FFIResult<FFIHandle<Pokemon>> {
let nature = unsafe { CStr::from_ptr(nature) }.into();
let pokemon = Pokemon::new(
library.as_ref().clone(),
species.as_ref().clone(),
form.as_ref(),
library.from_ffi_handle(),
species.from_ffi_handle(),
&form.from_ffi_handle(),
AbilityIndex {
hidden: hidden_ability == 1,
index: ability_index,
@@ -39,337 +40,373 @@ extern "C" fn pokemon_new(
&nature,
);
match pokemon {
Ok(pokemon) => NativeResult::ok(pokemon.into()),
Err(err) => NativeResult::err(err),
Ok(pokemon) => FFIResult::ok(FFIHandle::get_handle(pokemon.into())),
Err(err) => FFIResult::err(err),
}
}
/// Drops an Arc reference held by the FFI.
#[no_mangle]
unsafe extern "C" fn pokemon_drop(ptr: OwnedPtr<Pokemon>) {
drop_in_place(ptr);
}
/// The library data of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_library(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn DynamicLibrary>> {
ptr.as_ref().library().clone().into()
extern "C" fn pokemon_library(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn DynamicLibrary>> {
FFIHandle::get_handle(handle.from_ffi_handle().library().clone().into())
}
/// The species of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_species(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Species>> {
ptr.as_ref().species().into()
extern "C" fn pokemon_species(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Species>> {
FFIHandle::get_handle(handle.from_ffi_handle().species().into())
}
/// The form of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_form(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Form>> {
ptr.as_ref().form().into()
extern "C" fn pokemon_form(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Form>> {
FFIHandle::get_handle(handle.from_ffi_handle().form().into())
}
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
#[no_mangle]
extern "C" fn pokemon_display_species(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Species>> {
ptr.as_ref().display_species().into()
extern "C" fn pokemon_display_species(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Species>> {
FFIHandle::get_handle(handle.from_ffi_handle().display_species().into())
}
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
#[no_mangle]
extern "C" fn pokemon_display_form(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Form>> {
ptr.as_ref().display_form().into()
extern "C" fn pokemon_display_form(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Form>> {
FFIHandle::get_handle(handle.from_ffi_handle().display_form().into())
}
ffi_arc_getter!(Pokemon, level, LevelInt);
ffi_arc_getter!(Pokemon, experience, u32);
ffi_arc_getter!(Pokemon, unique_identifier, u32);
ffi_arc_getter!(Pokemon, gender, Gender);
ffi_arc_getter!(Pokemon, coloring, u8);
#[no_mangle]
extern "C" fn pokemon_level(handle: FFIHandle<Pokemon>) -> LevelInt {
handle.from_ffi_handle().level()
}
#[no_mangle]
extern "C" fn pokemon_experience(handle: FFIHandle<Pokemon>) -> u32 {
handle.from_ffi_handle().experience()
}
#[no_mangle]
extern "C" fn pokemon_unique_identifier(handle: FFIHandle<Pokemon>) -> u32 {
handle.from_ffi_handle().unique_identifier()
}
#[no_mangle]
extern "C" fn pokemon_gender(handle: FFIHandle<Pokemon>) -> Gender {
handle.from_ffi_handle().gender()
}
#[no_mangle]
extern "C" fn pokemon_coloring(handle: FFIHandle<Pokemon>) -> u8 {
handle.from_ffi_handle().coloring()
}
/// Gets the held item of a Pokemon
#[no_mangle]
extern "C" fn pokemon_held_item(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Item>> {
if let Some(v) = ptr.as_ref().held_item().read().as_ref() {
v.clone().into()
extern "C" fn pokemon_held_item(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Item>> {
if let Some(v) = handle.from_ffi_handle().held_item().read().as_ref() {
FFIHandle::get_handle(v.clone().into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Checks whether the Pokemon is holding a specific item.
#[no_mangle]
extern "C" fn pokemon_has_held_item(ptr: ExternPointer<Pokemon>, name: *const c_char) -> u8 {
extern "C" fn pokemon_has_held_item(handle: FFIHandle<Pokemon>, name: *const c_char) -> u8 {
let name = unsafe { CStr::from_ptr(name) }.into();
u8::from(ptr.as_ref().has_held_item(&name))
u8::from(handle.from_ffi_handle().has_held_item(&name))
}
/// Changes the held item of the Pokemon. Returns the previously held item.
#[no_mangle]
extern "C" fn pokemon_set_held_item(
ptr: ExternPointer<Pokemon>,
item: ExternPointer<Arc<dyn Item>>,
) -> IdentifiablePointer<Arc<dyn Item>> {
if let Some(v) = ptr.as_ref().set_held_item(item.as_ref()) {
v.into()
handle: FFIHandle<Pokemon>,
item: FFIHandle<Arc<dyn Item>>,
) -> FFIHandle<Arc<dyn Item>> {
if let Some(v) = handle.from_ffi_handle().set_held_item(&item.from_ffi_handle()) {
FFIHandle::get_handle(v.into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Removes the held item from the Pokemon. Returns the previously held item.
#[no_mangle]
extern "C" fn pokemon_remove_held_item(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Item>> {
if let Some(v) = ptr.as_ref().remove_held_item() {
v.into()
extern "C" fn pokemon_remove_held_item(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Item>> {
if let Some(v) = handle.from_ffi_handle().remove_held_item() {
FFIHandle::get_handle(v.into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Makes the Pokemon uses its held item.
#[no_mangle]
extern "C" fn pokemon_consume_held_item(ptr: ExternPointer<Pokemon>) -> NativeResult<u8> {
match ptr.as_ref().consume_held_item() {
Ok(v) => NativeResult::ok(u8::from(v)),
Err(err) => NativeResult::err(err),
extern "C" fn pokemon_consume_held_item(handle: FFIHandle<Pokemon>) -> FFIResult<u8> {
match handle.from_ffi_handle().consume_held_item() {
Ok(v) => FFIResult::ok(u8::from(v)),
Err(err) => FFIResult::err(err),
}
}
ffi_arc_getter!(Pokemon, current_health, u32);
ffi_arc_getter!(Pokemon, max_health, u32);
ffi_arc_getter!(Pokemon, weight, f32);
ffi_arc_getter!(Pokemon, height, f32);
#[no_mangle]
extern "C" fn pokemon_current_health(handle: FFIHandle<Pokemon>) -> u32 {
handle.from_ffi_handle().current_health()
}
#[no_mangle]
extern "C" fn pokemon_max_health(handle: FFIHandle<Pokemon>) -> u32 {
handle.from_ffi_handle().max_health()
}
#[no_mangle]
extern "C" fn pokemon_weight(handle: FFIHandle<Pokemon>) -> f32 {
handle.from_ffi_handle().weight()
}
#[no_mangle]
extern "C" fn pokemon_height(handle: FFIHandle<Pokemon>) -> f32 {
handle.from_ffi_handle().height()
}
/// An optional nickname of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_nickname(ptr: ExternPointer<Pokemon>) -> NativeResult<*mut c_char> {
let name = ptr.as_ref().nickname();
extern "C" fn pokemon_nickname(handle: FFIHandle<Pokemon>) -> FFIResult<*mut c_char> {
let form = handle.from_ffi_handle();
let name = form.nickname();
if let Some(v) = name {
match CString::new(v.as_str()) {
Ok(v) => NativeResult::ok(v.into_raw()),
Err(err) => NativeResult::err(anyhow!("Could not convert nickname to CString: {}", err)),
Ok(v) => FFIResult::ok(v.into_raw()),
Err(err) => FFIResult::err(anyhow!("Could not convert nickname to CString: {}", err)),
}
} else {
NativeResult::ok(std::ptr::null_mut())
FFIResult::ok(std::ptr::null_mut())
}
}
/// Whether the actual ability on the form is a hidden ability.
#[no_mangle]
extern "C" fn pokemon_real_ability_is_hidden(ptr: ExternPointer<Pokemon>) -> u8 {
u8::from(ptr.as_ref().real_ability().hidden)
extern "C" fn pokemon_real_ability_is_hidden(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(handle.from_ffi_handle().real_ability().hidden)
}
/// The index of the actual ability on the form.
#[no_mangle]
extern "C" fn pokemon_real_ability_index(ptr: ExternPointer<Pokemon>) -> u8 {
ptr.as_ref().real_ability().index
extern "C" fn pokemon_real_ability_index(handle: FFIHandle<Pokemon>) -> u8 {
handle.from_ffi_handle().real_ability().index
}
ffi_vec_value_getters!(Pokemon, Pokemon, types, TypeIdentifier);
#[no_mangle]
extern "C" fn pokemon_types_length(ptr: FFIHandle<Pokemon>) -> usize {
ptr.from_ffi_handle().types().len()
}
#[no_mangle]
extern "C" fn pokemon_types_get(ptr: FFIHandle<Pokemon>, index: usize) -> FFIResult<TypeIdentifier> {
match ptr.from_ffi_handle().types().get_res(index) {
Ok(v) => FFIResult::ok(*v),
Err(err) => FFIResult::err(err),
}
}
/// Gets a learned move of the Pokemon. Index should generally be below [`MAX_MOVES`], you will get
/// a null pointer otherwise.
#[no_mangle]
extern "C" fn pokemon_learned_move_get(
ptr: ExternPointer<Pokemon>,
index: usize,
) -> IdentifiablePointer<Arc<LearnedMove>> {
if let Some(Some(v)) = ptr.as_ref().learned_moves().read().get(index) {
v.clone().into()
extern "C" fn pokemon_learned_move_get(handle: FFIHandle<Pokemon>, index: usize) -> FFIHandle<Arc<LearnedMove>> {
if let Some(Some(v)) = handle.from_ffi_handle().learned_moves().read().get(index) {
FFIHandle::get_handle(v.clone().into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// The stats of the Pokemon when disregarding any stat boosts.
#[no_mangle]
extern "C" fn pokemon_flat_stats(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<StatisticSet<u32>>> {
ptr.as_ref().flat_stats().clone().into()
extern "C" fn pokemon_flat_stats(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<StatisticSet<u32>>> {
FFIHandle::get_handle(handle.from_ffi_handle().flat_stats().clone().into())
}
/// The stats of the Pokemon including the stat boosts.
#[no_mangle]
extern "C" fn pokemon_boosted_stats(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<StatisticSet<u32>>> {
ptr.as_ref().boosted_stats().clone().into()
extern "C" fn pokemon_boosted_stats(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<StatisticSet<u32>>> {
FFIHandle::get_handle(handle.from_ffi_handle().boosted_stats().clone().into())
}
/// Get the stat boosts for a specific stat.
#[no_mangle]
extern "C" fn pokemon_get_stat_boost(ptr: ExternPointer<Pokemon>, statistic: Statistic) -> i8 {
ptr.as_ref().stat_boost(statistic)
extern "C" fn pokemon_get_stat_boost(handle: FFIHandle<Pokemon>, statistic: Statistic) -> i8 {
handle.from_ffi_handle().stat_boost(statistic)
}
/// Change a boosted stat by a certain amount.
#[no_mangle]
extern "C" fn pokemon_change_stat_boost(
ptr: ExternPointer<Pokemon>,
handle: FFIHandle<Pokemon>,
stat: Statistic,
diff_amount: i8,
self_inflicted: u8,
) -> NativeResult<u8> {
match ptr.as_ref().change_stat_boost(stat, diff_amount, self_inflicted == 1) {
Ok(v) => NativeResult::ok(u8::from(v)),
Err(e) => NativeResult::err(e),
) -> FFIResult<u8> {
match handle
.from_ffi_handle()
.change_stat_boost(stat, diff_amount, self_inflicted == 1)
{
Ok(v) => FFIResult::ok(u8::from(v)),
Err(e) => FFIResult::err(e),
}
}
/// Gets a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_get_individual_value(ptr: ExternPointer<Pokemon>, stat: Statistic) -> u8 {
ptr.as_ref().individual_values().get_stat(stat)
extern "C" fn pokemon_get_individual_value(handle: FFIHandle<Pokemon>, stat: Statistic) -> u8 {
handle.from_ffi_handle().individual_values().get_stat(stat)
}
/// Modifies a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_set_individual_value(
ptr: ExternPointer<Pokemon>,
stat: Statistic,
value: u8,
) -> NativeResult<()> {
ptr.as_ref().individual_values().set_stat(stat, value);
ptr.as_ref().recalculate_flat_stats().into()
extern "C" fn pokemon_set_individual_value(handle: FFIHandle<Pokemon>, stat: Statistic, value: u8) -> FFIResult<()> {
handle.from_ffi_handle().individual_values().set_stat(stat, value);
handle.from_ffi_handle().recalculate_flat_stats().into()
}
/// Gets a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_get_effort_value(ptr: ExternPointer<Pokemon>, stat: Statistic) -> u8 {
ptr.as_ref().effort_values().get_stat(stat)
extern "C" fn pokemon_get_effort_value(handle: FFIHandle<Pokemon>, stat: Statistic) -> u8 {
handle.from_ffi_handle().effort_values().get_stat(stat)
}
/// Modifies a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_set_effort_value(ptr: ExternPointer<Pokemon>, stat: Statistic, value: u8) -> NativeResult<()> {
ptr.as_ref().effort_values().set_stat(stat, value);
ptr.as_ref().recalculate_flat_stats().into()
extern "C" fn pokemon_set_effort_value(handle: FFIHandle<Pokemon>, stat: Statistic, value: u8) -> FFIResult<()> {
handle.from_ffi_handle().effort_values().set_stat(stat, value);
handle.from_ffi_handle().recalculate_flat_stats().into()
}
/// Gets the data for the battle the Pokemon is currently in. If the Pokemon is not in a battle, this
/// returns null.
#[no_mangle]
extern "C" fn pokemon_get_battle(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Battle> {
if let Some(v) = ptr.as_ref().get_battle() {
v.into()
extern "C" fn pokemon_get_battle(handle: FFIHandle<Pokemon>) -> FFIHandle<Battle> {
if let Some(v) = handle.from_ffi_handle().get_battle() {
FFIHandle::get_handle(v.into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Get the index of the side of the battle the Pokemon is in. If the Pokemon
/// is not on the battlefield, this always returns 0.
#[no_mangle]
extern "C" fn pokemon_get_battle_side_index(ptr: ExternPointer<Pokemon>) -> u8 {
ptr.as_ref().get_battle_side_index().unwrap_or_default()
extern "C" fn pokemon_get_battle_side_index(handle: FFIHandle<Pokemon>) -> u8 {
handle.from_ffi_handle().get_battle_side_index().unwrap_or_default()
}
/// Get the index of the slot on the side of the battle the Pokemon is in. If the Pokemon
/// is not on the battlefield, this always returns 0.
#[no_mangle]
extern "C" fn pokemon_get_battle_index(ptr: ExternPointer<Pokemon>) -> u8 {
ptr.as_ref().get_battle_index().unwrap_or_default()
extern "C" fn pokemon_get_battle_index(handle: FFIHandle<Pokemon>) -> u8 {
handle.from_ffi_handle().get_battle_index().unwrap_or_default()
}
/// Returns whether something overrides the ability.
#[no_mangle]
extern "C" fn pokemon_is_ability_overriden(ptr: ExternPointer<Pokemon>) -> u8 {
u8::from(ptr.as_ref().is_ability_overriden())
extern "C" fn pokemon_is_ability_overriden(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(handle.from_ffi_handle().is_ability_overriden())
}
/// Returns the currently active ability.
#[no_mangle]
extern "C" fn pokemon_active_ability(
ptr: ExternPointer<Pokemon>,
) -> NativeResult<IdentifiablePointer<Arc<dyn Ability>>> {
match ptr.as_ref().active_ability() {
Ok(v) => NativeResult::ok(v.clone().into()),
Err(e) => NativeResult::err(e),
extern "C" fn pokemon_active_ability(handle: FFIHandle<Pokemon>) -> FFIResult<FFIHandle<Arc<dyn Ability>>> {
match handle.from_ffi_handle().active_ability() {
Ok(v) => FFIResult::ok(FFIHandle::get_handle(v.clone().into())),
Err(e) => FFIResult::err(e),
}
}
/// Whether or not the Pokemon is allowed to gain experience.
#[no_mangle]
extern "C" fn pokemon_allowed_experience_gain(ptr: ExternPointer<Pokemon>) -> u8 {
u8::from(ptr.as_ref().allowed_experience_gain())
extern "C" fn pokemon_allowed_experience_gain(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(handle.from_ffi_handle().allowed_experience_gain())
}
/// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_nature(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Nature>> {
ptr.as_ref().nature().clone().into()
extern "C" fn pokemon_nature(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Nature>> {
FFIHandle::get_handle(handle.from_ffi_handle().nature().clone().into())
}
/// Calculates the flat stats on the Pokemon. This should be called when for example the base
/// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted
/// stats, as those depend on the flat stats.
#[no_mangle]
extern "C" fn pokemon_recalculate_flat_stats(ptr: ExternPointer<Pokemon>) -> NativeResult<()> {
ptr.as_ref().recalculate_flat_stats().into()
extern "C" fn pokemon_recalculate_flat_stats(handle: FFIHandle<Pokemon>) -> FFIResult<()> {
handle.from_ffi_handle().recalculate_flat_stats().into()
}
/// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes.
#[no_mangle]
extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer<Pokemon>) -> NativeResult<()> {
ptr.as_ref().recalculate_boosted_stats().into()
extern "C" fn pokemon_recalculate_boosted_stats(handle: FFIHandle<Pokemon>) -> FFIResult<()> {
handle.from_ffi_handle().recalculate_boosted_stats().into()
}
/// Change the species of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_change_species(
ptr: ExternPointer<Pokemon>,
species: ExternPointer<Arc<dyn Species>>,
form: ExternPointer<Arc<dyn Form>>,
) -> NativeResult<()> {
ptr.as_ref()
.change_species(species.as_ref().clone(), form.as_ref().clone())
handle: FFIHandle<Pokemon>,
species: FFIHandle<Arc<dyn Species>>,
form: FFIHandle<Arc<dyn Form>>,
) -> FFIResult<()> {
handle
.from_ffi_handle()
.change_species(species.from_ffi_handle().clone(), form.from_ffi_handle().clone())
.into()
}
/// Change the form of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_change_form(ptr: ExternPointer<Pokemon>, form: ExternPointer<Arc<dyn Form>>) -> NativeResult<()> {
ptr.as_ref().change_form(form.as_ref()).into()
extern "C" fn pokemon_change_form(handle: FFIHandle<Pokemon>, form: FFIHandle<Arc<dyn Form>>) -> FFIResult<()> {
handle.from_ffi_handle().change_form(&form.from_ffi_handle()).into()
}
/// Whether or not the Pokemon is useable in a battle.
#[no_mangle]
extern "C" fn pokemon_is_usable(ptr: ExternPointer<Pokemon>) -> u8 {
u8::from(ptr.as_ref().is_usable())
extern "C" fn pokemon_is_usable(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(handle.from_ffi_handle().is_usable())
}
/// Returns whether the Pokemon is fainted.
#[no_mangle]
extern "C" fn pokemon_is_fainted(ptr: ExternPointer<Pokemon>) -> u8 {
u8::from(ptr.as_ref().is_fainted())
extern "C" fn pokemon_is_fainted(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(handle.from_ffi_handle().is_fainted())
}
/// Whether or not the Pokemon is on the battlefield.
#[no_mangle]
extern "C" fn pokemon_is_on_battlefield(ptr: ExternPointer<Pokemon>) -> u8 {
u8::from(ptr.as_ref().is_on_battlefield())
extern "C" fn pokemon_is_on_battlefield(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(handle.from_ffi_handle().is_on_battlefield())
}
/// Damages the Pokemon by a certain amount of damage, from a damage source.
#[no_mangle]
extern "C" fn pokemon_damage(ptr: ExternPointer<Pokemon>, damage: u32, source: DamageSource) -> NativeResult<()> {
ptr.as_ref().damage(damage, source).into()
extern "C" fn pokemon_damage(handle: FFIHandle<Pokemon>, damage: u32, source: DamageSource) -> FFIResult<()> {
handle.from_ffi_handle().damage(damage, source).into()
}
/// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not
/// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false.
#[no_mangle]
extern "C" fn pokemon_heal(ptr: ExternPointer<Pokemon>, amount: u32, allow_revive: u8) -> bool {
ptr.as_ref().heal(amount, allow_revive == 1)
extern "C" fn pokemon_heal(handle: FFIHandle<Pokemon>, amount: u32, allow_revive: u8) -> bool {
handle.from_ffi_handle().heal(amount, allow_revive == 1)
}
/// Learn a move.
#[no_mangle]
extern "C" fn pokemon_learn_move(
ptr: ExternPointer<Pokemon>,
handle: FFIHandle<Pokemon>,
move_name: *const c_char,
learn_method: MoveLearnMethod,
) -> NativeResult<()> {
) -> FFIResult<()> {
unsafe {
ptr.as_ref()
handle
.from_ffi_handle()
.learn_move(&CStr::from_ptr(move_name).into(), learn_method)
.into()
}
@@ -377,6 +414,6 @@ extern "C" fn pokemon_learn_move(
/// Removes the current non-volatile status from the Pokemon.
#[no_mangle]
extern "C" fn pokemon_clear_status(ptr: ExternPointer<Pokemon>) {
ptr.as_ref().clear_status()
extern "C" fn pokemon_clear_status(handle: FFIHandle<Pokemon>) {
handle.from_ffi_handle().clear_status()
}

View File

@@ -1,68 +1,69 @@
use crate::dynamic_data::{Pokemon, PokemonParty};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use std::sync::Arc;
/// Instantiates a party with a set size.
#[no_mangle]
extern "C" fn pokemon_party_new(capacity: usize) -> IdentifiablePointer<Arc<PokemonParty>> {
Arc::new(PokemonParty::new(capacity)).into()
extern "C" fn pokemon_party_new(capacity: usize) -> FFIHandle<Arc<PokemonParty>> {
FFIHandle::get_handle(Arc::new(PokemonParty::new(capacity)).into())
}
/// Gets a Pokemon at an index in the party.
#[no_mangle]
extern "C" fn pokemon_party_at(ptr: ExternPointer<Arc<PokemonParty>>, index: usize) -> IdentifiablePointer<Pokemon> {
if let Some(v) = ptr.as_ref().at(index) {
v.into()
extern "C" fn pokemon_party_at(ptr: FFIHandle<Arc<PokemonParty>>, index: usize) -> FFIHandle<Pokemon> {
if let Some(v) = ptr.from_ffi_handle().at(index) {
FFIHandle::get_handle(v.into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Gets a Pokemon at an index in the party.
#[no_mangle]
extern "C" fn pokemon_party_switch(ptr: ExternPointer<Arc<PokemonParty>>, a: usize, b: usize) {
ptr.as_ref().switch(a, b);
extern "C" fn pokemon_party_switch(ptr: FFIHandle<Arc<PokemonParty>>, a: usize, b: usize) {
ptr.from_ffi_handle().switch(a, b);
}
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
#[no_mangle]
extern "C" fn pokemon_party_swap_into(
ptr: ExternPointer<Arc<PokemonParty>>,
ptr: FFIHandle<Arc<PokemonParty>>,
index: usize,
pokemon: ExternPointer<Pokemon>,
) -> NativeResult<IdentifiablePointer<Pokemon>> {
let pokemon = if pokemon.ptr.is_null() {
pokemon: FFIHandle<Pokemon>,
) -> FFIResult<FFIHandle<Pokemon>> {
let pokemon = if pokemon.is_none() {
None
} else {
Some(pokemon.as_ref().clone())
Some(pokemon.from_ffi_handle())
};
match ptr.as_ref().swap_into(index, pokemon) {
Ok(Some(v)) => NativeResult::ok(v.into()),
Ok(None) => NativeResult::ok(IdentifiablePointer::none()),
Err(e) => NativeResult::err(e),
match ptr.from_ffi_handle().swap_into(index, pokemon) {
Ok(Some(v)) => FFIResult::ok(FFIHandle::get_handle(v.into())),
Ok(None) => FFIResult::ok(FFIHandle::none()),
Err(e) => FFIResult::err(e),
}
}
/// Whether or not the party still has Pokemon that can be used in battle.
#[no_mangle]
extern "C" fn pokemon_party_has_usable_pokemon(ptr: ExternPointer<Arc<PokemonParty>>) -> u8 {
u8::from(ptr.as_ref().has_usable_pokemon())
extern "C" fn pokemon_party_has_usable_pokemon(ptr: FFIHandle<Arc<PokemonParty>>) -> u8 {
u8::from(ptr.from_ffi_handle().has_usable_pokemon())
}
/// Get the length of the underlying list of Pokemon.
#[no_mangle]
extern "C" fn pokemon_party_length(ptr: ExternPointer<Arc<PokemonParty>>) -> usize {
ptr.as_ref().length()
extern "C" fn pokemon_party_length(ptr: FFIHandle<Arc<PokemonParty>>) -> usize {
ptr.from_ffi_handle().length()
}
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
#[no_mangle]
extern "C" fn pokemon_party_pack_party(ptr: ExternPointer<Arc<PokemonParty>>) -> NativeResult<()> {
ptr.as_ref().pack_party().into()
extern "C" fn pokemon_party_pack_party(ptr: FFIHandle<Arc<PokemonParty>>) -> FFIResult<()> {
ptr.from_ffi_handle().pack_party().into()
}
/// Checks if the party contains a given pokemon.
#[no_mangle]
extern "C" fn pokemon_party_has_pokemon(ptr: ExternPointer<Arc<PokemonParty>>, pokemon: ExternPointer<Pokemon>) -> u8 {
u8::from(ptr.as_ref().has_pokemon(pokemon.as_ref()))
extern "C" fn pokemon_party_has_pokemon(ptr: FFIHandle<Arc<PokemonParty>>, pokemon: FFIHandle<Pokemon>) -> u8 {
u8::from(ptr.from_ffi_handle().has_pokemon(&pokemon.from_ffi_handle()))
}

296
src/ffi/ffi_handle.rs Normal file
View File

@@ -0,0 +1,296 @@
use crate::static_data::{
Ability, EffectParameter, Form, GrowthRate, Item, LearnableMoves, MoveData, Nature, SecondaryEffect, Species,
StaticStatisticSet, StatisticSet,
};
use anyhow::anyhow;
use hashbrown::HashMap;
use parking_lot::RwLock;
use std::hash::Hash;
use std::sync::atomic::AtomicUsize;
use std::sync::{Arc, LazyLock};
#[repr(C)]
pub(super) struct FFIHandle<T> {
handle: usize,
_marker: std::marker::PhantomData<T>,
}
impl<T> Clone for FFIHandle<T> {
fn clone(&self) -> Self {
Self {
handle: self.handle,
_marker: std::marker::PhantomData,
}
}
}
impl<T> Copy for FFIHandle<T> {}
#[derive(Clone)]
pub(super) enum FFIObject {
Ability(Arc<dyn Ability>),
EffectParameter(Arc<EffectParameter>),
StatisticSetU8(Arc<StatisticSet<u8>>),
StatisticSetI8(Arc<StatisticSet<i8>>),
StatisticSetU32(Arc<StatisticSet<u32>>),
StaticStatisticSetU16(Arc<StaticStatisticSet<u16>>),
Form(Arc<dyn Form>),
LearnableMoves(Arc<dyn LearnableMoves>),
GrowthRate(Arc<dyn GrowthRate>),
Item(Arc<dyn Item>),
SecondaryEffect(Arc<dyn SecondaryEffect>),
MoveData(Arc<dyn MoveData>),
Nature(Arc<dyn Nature>),
Species(Arc<dyn Species>),
SpeciesLibrary(Arc<dyn crate::static_data::SpeciesLibrary>),
MoveLibrary(Arc<dyn crate::static_data::MoveLibrary>),
AbilityLibrary(Arc<dyn crate::static_data::AbilityLibrary>),
ItemLibrary(Arc<dyn crate::static_data::ItemLibrary>),
GrowthRateLibrary(Arc<dyn crate::static_data::GrowthRateLibrary>),
LibrarySettings(Arc<dyn crate::static_data::LibrarySettings>),
NatureLibrary(Arc<dyn crate::static_data::NatureLibrary>),
TypeLibrary(Arc<dyn crate::static_data::TypeLibrary>),
StaticData(Arc<dyn crate::static_data::StaticData>),
// DynamicData
TurnChoice(Arc<crate::dynamic_data::TurnChoice>),
Pokemon(crate::dynamic_data::Pokemon),
LearnedMove(Arc<crate::dynamic_data::LearnedMove>),
PokemonParty(Arc<crate::dynamic_data::PokemonParty>),
BattleParty(Arc<crate::dynamic_data::BattleParty>),
Battle(crate::dynamic_data::Battle),
BattleSide(crate::dynamic_data::BattleSide),
BattleRandom(Arc<crate::dynamic_data::BattleRandom>),
// DynamicLibrary
BattleStatCalculator(Arc<dyn crate::dynamic_data::BattleStatCalculator>),
DamageLibrary(Arc<dyn crate::dynamic_data::DamageLibrary>),
MiscLibrary(Arc<dyn crate::dynamic_data::MiscLibrary>),
ScriptResolver(Arc<dyn crate::dynamic_data::ScriptResolver>),
DynamicLibrary(Arc<dyn crate::dynamic_data::DynamicLibrary>),
}
unsafe impl Send for FFIObject {}
unsafe impl Sync for FFIObject {}
static NEXT_HANDLE: AtomicUsize = AtomicUsize::new(0);
static FFI_OBJECTS: LazyLock<RwLock<HashMap<usize, FFIObject>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
static FFI_OBJECTS_INVERSE: LazyLock<RwLock<HashMap<FFIObject, usize>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
impl<T> FFIHandle<T> {
pub fn get_handle(o: FFIObject) -> Self {
if let Some(handle) = FFI_OBJECTS_INVERSE.read().get(&o) {
return Self {
handle: *handle,
_marker: std::marker::PhantomData,
};
}
let handle = NEXT_HANDLE.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
FFI_OBJECTS.write().insert(handle, o.clone());
FFI_OBJECTS_INVERSE.write().insert(o, handle);
Self {
handle,
_marker: std::marker::PhantomData,
}
}
pub fn none() -> Self {
Self {
handle: 0,
_marker: std::marker::PhantomData,
}
}
#[allow(clippy::unwrap_used)] // Unwrap used, as it is a potential security bug if this fails
pub fn resolve(&self) -> FFIObject {
FFI_OBJECTS
.read()
.get(&self.handle)
.ok_or(anyhow!("Unable to get handle"))
.unwrap()
.clone()
}
pub fn is_none(&self) -> bool {
self.handle == 0
}
}
#[allow(clippy::from_over_into)]
impl<T> Into<anyhow_ext::Result<FFIObject>> for FFIHandle<T> {
fn into(self) -> anyhow_ext::Result<FFIObject> {
Ok(FFI_OBJECTS
.read()
.get(&self.handle)
.ok_or(anyhow!("Unable to get handle"))?
.clone())
}
}
impl Eq for FFIObject {}
#[allow(clippy::wrong_self_convention)]
pub(super) trait FromFFIHandle<T> {
fn from_ffi_handle(&self) -> T;
fn from_ffi_handle_opt(&self) -> Option<T>;
}
impl Hash for FFIObject {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Ability(a) => Arc::as_ptr(a).hash(state),
Self::EffectParameter(a) => Arc::as_ptr(a).hash(state),
Self::StatisticSetU8(a) => Arc::as_ptr(a).hash(state),
Self::StatisticSetI8(a) => Arc::as_ptr(a).hash(state),
Self::StatisticSetU32(a) => Arc::as_ptr(a).hash(state),
Self::StaticStatisticSetU16(a) => Arc::as_ptr(a).hash(state),
Self::Form(a) => Arc::as_ptr(a).hash(state),
Self::LearnableMoves(a) => Arc::as_ptr(a).hash(state),
Self::GrowthRate(a) => Arc::as_ptr(a).hash(state),
Self::Item(a) => Arc::as_ptr(a).hash(state),
Self::SecondaryEffect(a) => Arc::as_ptr(a).hash(state),
Self::MoveData(a) => Arc::as_ptr(a).hash(state),
Self::Nature(a) => Arc::as_ptr(a).hash(state),
Self::Species(a) => Arc::as_ptr(a).hash(state),
Self::SpeciesLibrary(a) => Arc::as_ptr(a).hash(state),
Self::MoveLibrary(a) => Arc::as_ptr(a).hash(state),
Self::AbilityLibrary(a) => Arc::as_ptr(a).hash(state),
Self::ItemLibrary(a) => Arc::as_ptr(a).hash(state),
Self::GrowthRateLibrary(a) => Arc::as_ptr(a).hash(state),
Self::LibrarySettings(a) => Arc::as_ptr(a).hash(state),
Self::NatureLibrary(a) => Arc::as_ptr(a).hash(state),
Self::TypeLibrary(a) => Arc::as_ptr(a).hash(state),
Self::StaticData(a) => Arc::as_ptr(a).hash(state),
Self::TurnChoice(a) => Arc::as_ptr(a).hash(state),
Self::Pokemon(a) => a.as_ptr().hash(state),
Self::LearnedMove(a) => Arc::as_ptr(a).hash(state),
Self::PokemonParty(a) => Arc::as_ptr(a).hash(state),
Self::BattleParty(a) => Arc::as_ptr(a).hash(state),
Self::Battle(a) => a.as_ptr().hash(state),
Self::BattleSide(a) => a.as_ptr().hash(state),
Self::BattleRandom(a) => Arc::as_ptr(a).hash(state),
Self::BattleStatCalculator(a) => Arc::as_ptr(a).hash(state),
Self::DamageLibrary(a) => Arc::as_ptr(a).hash(state),
Self::MiscLibrary(a) => Arc::as_ptr(a).hash(state),
Self::ScriptResolver(a) => Arc::as_ptr(a).hash(state),
Self::DynamicLibrary(a) => Arc::as_ptr(a).hash(state),
}
}
}
impl PartialEq for FFIObject {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Ability(a), Self::Ability(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::EffectParameter(a), Self::EffectParameter(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StatisticSetU8(a), Self::StatisticSetU8(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StatisticSetI8(a), Self::StatisticSetI8(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StatisticSetU32(a), Self::StatisticSetU32(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StaticStatisticSetU16(a), Self::StaticStatisticSetU16(b)) => {
Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr()
}
(Self::Form(a), Self::Form(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::LearnableMoves(a), Self::LearnableMoves(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::GrowthRate(a), Self::GrowthRate(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Item(a), Self::Item(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::SecondaryEffect(a), Self::SecondaryEffect(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::MoveData(a), Self::MoveData(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Nature(a), Self::Nature(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Species(a), Self::Species(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::SpeciesLibrary(a), Self::SpeciesLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::MoveLibrary(a), Self::MoveLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::AbilityLibrary(a), Self::AbilityLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::ItemLibrary(a), Self::ItemLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::GrowthRateLibrary(a), Self::GrowthRateLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::LibrarySettings(a), Self::LibrarySettings(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::NatureLibrary(a), Self::NatureLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::TypeLibrary(a), Self::TypeLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StaticData(a), Self::StaticData(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::TurnChoice(a), Self::TurnChoice(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Pokemon(a), Self::Pokemon(b)) => a.eq(b),
(Self::LearnedMove(a), Self::LearnedMove(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::PokemonParty(a), Self::PokemonParty(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::BattleParty(a), Self::BattleParty(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Battle(a), Self::Battle(b)) => a.eq(b),
(Self::BattleSide(a), Self::BattleSide(b)) => a.eq(b),
(Self::BattleRandom(a), Self::BattleRandom(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::BattleStatCalculator(a), Self::BattleStatCalculator(b)) => {
Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr()
}
(Self::DamageLibrary(a), Self::DamageLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::MiscLibrary(a), Self::MiscLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::ScriptResolver(a), Self::ScriptResolver(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::DynamicLibrary(a), Self::DynamicLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
_ => false,
}
}
}
macro_rules! ffi_obj_conversions {
($res_type:ty, $ffi_obj_name:ident) => {
impl From<$res_type> for FFIObject {
fn from(a: $res_type) -> Self {
Self::$ffi_obj_name(a)
}
}
impl FromFFIHandle<$res_type> for FFIHandle<$res_type> {
fn from_ffi_handle(&self) -> $res_type {
match self.resolve() {
FFIObject::$ffi_obj_name(a) => a.clone(),
_ => panic!("Invalid handle"),
}
}
fn from_ffi_handle_opt(&self) -> Option<$res_type> {
if (self.is_none()) {
return None;
}
match self.resolve() {
FFIObject::$ffi_obj_name(a) => Some(a.clone()),
_ => panic!("Invalid handle"),
}
}
}
};
}
ffi_obj_conversions!(Arc<dyn Ability>, Ability);
ffi_obj_conversions!(Arc<EffectParameter>, EffectParameter);
ffi_obj_conversions!(Arc<StatisticSet<i8>>, StatisticSetI8);
ffi_obj_conversions!(Arc<StatisticSet<u8>>, StatisticSetU8);
ffi_obj_conversions!(Arc<StatisticSet<u32>>, StatisticSetU32);
ffi_obj_conversions!(Arc<StaticStatisticSet<u16>>, StaticStatisticSetU16);
ffi_obj_conversions!(Arc<dyn Form>, Form);
ffi_obj_conversions!(Arc<dyn LearnableMoves>, LearnableMoves);
ffi_obj_conversions!(Arc<dyn GrowthRate>, GrowthRate);
ffi_obj_conversions!(Arc<dyn Item>, Item);
ffi_obj_conversions!(Arc<dyn SecondaryEffect>, SecondaryEffect);
ffi_obj_conversions!(Arc<dyn MoveData>, MoveData);
ffi_obj_conversions!(Arc<dyn Nature>, Nature);
ffi_obj_conversions!(Arc<dyn Species>, Species);
ffi_obj_conversions!(Arc<dyn crate::static_data::SpeciesLibrary>, SpeciesLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::MoveLibrary>, MoveLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::AbilityLibrary>, AbilityLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::ItemLibrary>, ItemLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::GrowthRateLibrary>, GrowthRateLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::LibrarySettings>, LibrarySettings);
ffi_obj_conversions!(Arc<dyn crate::static_data::NatureLibrary>, NatureLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::TypeLibrary>, TypeLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::StaticData>, StaticData);
ffi_obj_conversions!(Arc<crate::dynamic_data::TurnChoice>, TurnChoice);
ffi_obj_conversions!(crate::dynamic_data::Pokemon, Pokemon);
ffi_obj_conversions!(Arc<crate::dynamic_data::LearnedMove>, LearnedMove);
ffi_obj_conversions!(Arc<crate::dynamic_data::PokemonParty>, PokemonParty);
ffi_obj_conversions!(Arc<crate::dynamic_data::BattleParty>, BattleParty);
ffi_obj_conversions!(crate::dynamic_data::Battle, Battle);
ffi_obj_conversions!(crate::dynamic_data::BattleSide, BattleSide);
ffi_obj_conversions!(Arc<crate::dynamic_data::BattleRandom>, BattleRandom);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::BattleStatCalculator>, BattleStatCalculator);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::DamageLibrary>, DamageLibrary);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::MiscLibrary>, MiscLibrary);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::ScriptResolver>, ScriptResolver);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::DynamicLibrary>, DynamicLibrary);

View File

@@ -1,68 +1,57 @@
/// The foreign function interfaces for the dynamic data
mod dynamic_data;
mod ffi_handle;
/// The foreign function interfaces for that static data
mod static_data;
pub(self) use ffi_handle::*;
/// Helper type for clearer functions.
type OwnedPtr<T> = *mut T;
type OwnedPtrString = *mut c_char;
/// Helper type for clearer functions.
type BorrowedPtr<T> = *const T;
type NonOwnedPtrString = *const c_char;
/// Generates a basic getter foreign function interface.
macro_rules! ffi_arc_getter {
macro_rules! ffi_handle_arc_dyn_getter {
(
$type:ty, $func:ident, $returns: ty
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer<Arc<$type>>) -> $returns {
ptr.as_ref().$func()
}
}
};
}
/// Generates a basic getter foreign function interface.
macro_rules! ffi_arc_dyn_getter {
(
$type:ty, $func:ident, $returns: ty
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer<Arc<dyn $type>>) -> $returns {
ptr.as_ref().$func()
extern "C" fn [< $type:snake _ $func >](ptr: FFIHandle<Arc<dyn $type>>) -> $returns {
ptr.from_ffi_handle().$func()
}
}
};
}
/// Generates a basic getter foreign function interface where the return type is a [`crate::StringKey`].
macro_rules! ffi_arc_stringkey_getter {
macro_rules! ffi_handle_arc_stringkey_getter {
(
$type:ty, $func:ident
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:lower _ $func >](ptr: ExternPointer<Arc<dyn $type>>) -> OwnedPtr<c_char> {
std::ffi::CString::new(ptr.as_ref().$func().str()).unwrap().into_raw()
extern "C" fn [< $type:lower _ $func >](ptr: FFIHandle<Arc<dyn $type>>) -> NonOwnedPtrString {
std::ffi::CString::new(ptr.from_ffi_handle().$func().str()).unwrap().into_raw()
}
}
};
}
/// Generates a foreign function interface for a vec. This generates a length function, and a getter.
macro_rules! ffi_vec_value_getters {
macro_rules! ffi_handle_vec_value_getters {
(
$name:ident, $type:ty, $func:ident, $returns: ty
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $name:lower _ $func _length>](ptr: ExternPointer<Arc<$type>>) -> usize {
ptr.as_ref().$func().len()
extern "C" fn [< $name:lower _ $func _length>](ptr: FFIHandle<Arc<$type>>) -> usize {
ptr.from_ffi_handle().$func().len()
}
#[no_mangle]
extern "C" fn [< $name:lower _ $func _get>](ptr: ExternPointer<Arc<$type>>, index: usize) -> $returns {
*ptr.as_ref().$func().get(index).unwrap()
extern "C" fn [< $name:lower _ $func _get>](ptr: FFIHandle<Arc<$type>>, index: usize) -> $returns {
*ptr.from_ffi_handle().$func().get(index).unwrap()
}
}
};
@@ -70,33 +59,28 @@ macro_rules! ffi_vec_value_getters {
/// Generates a foreign function interface for a vec of [`crate::StringKey`]. This generates a
/// length function, and a getter.
macro_rules! ffi_vec_stringkey_getters {
macro_rules! ffi_handle_vec_stringkey_getters {
(
$type:ty, $func:ident
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:lower _ $func _length>](ptr: ExternPointer<Arc<dyn $type>>) -> usize {
ptr.as_ref().$func().len()
extern "C" fn [< $type:lower _ $func _length>](ptr: FFIHandle<Arc<dyn $type>>) -> usize {
ptr.from_ffi_handle().$func().len()
}
#[no_mangle]
extern "C" fn [< $type:lower _ $func _get>](ptr: ExternPointer<Arc<dyn $type>>, index: usize) -> OwnedPtr<c_char> {
CString::new(ptr.as_ref().$func().get(index).unwrap().str()).unwrap().into_raw()
extern "C" fn [< $type:lower _ $func _get>](ptr: FFIHandle<Arc<dyn $type>>, index: usize) -> OwnedPtrString {
CString::new(ptr.from_ffi_handle().$func().get(index).unwrap().str()).unwrap().into_raw()
}
}
};
}
use crate::dynamic_data::{Battle, Pokemon};
use crate::{ValueIdentifiable, ValueIdentifier};
pub(self) use ffi_arc_dyn_getter;
pub(self) use ffi_arc_getter;
pub(self) use ffi_arc_stringkey_getter;
pub(self) use ffi_vec_stringkey_getters;
pub(self) use ffi_vec_value_getters;
pub(self) use ffi_handle_arc_dyn_getter;
pub(self) use ffi_handle_arc_stringkey_getter;
pub(self) use ffi_handle_vec_stringkey_getters;
pub(self) use ffi_handle_vec_value_getters;
use std::ffi::{c_char, CString};
use std::mem::transmute;
use std::sync::Arc;
/// Helper utility class to wrap a pointer for extern functions.
#[repr(C)]
@@ -115,184 +99,6 @@ impl<T: ?Sized> ExternPointer<T> {
.unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::<T>()))
}
}
/// Get the internal pointer as mutable reference.
#[allow(clippy::panic)] // We currently allow this as these should never be null, but we might want to change this in the future.
pub(self) fn as_mut(&mut self) -> &mut T {
unsafe {
self.ptr
.as_mut()
.unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::<T>()))
}
}
}
/// Helper utility class to give both the pointer and identifier to a FFI.
#[repr(C)]
pub(self) struct IdentifiablePointer<T> {
/// The wrapped pointer.
pub ptr: *const T,
/// The identifier of the pointer.
pub id: usize,
}
impl<T> Clone for IdentifiablePointer<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
ptr: self.ptr,
}
}
}
impl<T> Copy for IdentifiablePointer<T> {}
impl<T> IdentifiablePointer<T> {
/// Creates a new IdentifiablePointer.
pub(self) fn new(ptr: *const T, id: ValueIdentifier) -> Self {
unsafe { Self { ptr, id: transmute(id) } }
}
}
impl<T> From<*mut T> for ExternPointer<T> {
fn from(ptr: *mut T) -> Self {
ExternPointer { ptr }
}
}
impl<T: ValueIdentifiable + ?Sized> From<Arc<T>> for IdentifiablePointer<Arc<T>> {
fn from(v: Arc<T>) -> Self {
let id = v.value_identifier().value();
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Option<Arc<T>>> for IdentifiablePointer<Arc<T>> {
fn from(v: Option<Arc<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Box<T>> for IdentifiablePointer<Box<T>> {
fn from(v: Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<&Box<T>> for IdentifiablePointer<Box<T>> {
fn from(v: &Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: v as *const Box<T>,
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Option<Box<T>>> for IdentifiablePointer<Box<T>> {
fn from(v: Option<Box<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<&Option<Box<T>>> for IdentifiablePointer<Box<T>> {
fn from(v: &Option<Box<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
unsafe {
Self {
ptr: *Box::into_raw(Box::new(v as *const Box<T>)),
id,
}
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable> From<Box<T>> for IdentifiablePointer<T> {
fn from(v: Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(v),
id,
}
}
}
impl<T: ValueIdentifiable> From<*const T> for IdentifiablePointer<T> {
#[allow(clippy::unwrap_used)] // We currently allow this as these should never be null, but we might want to change this in the future.
fn from(v: *const T) -> Self {
let id = unsafe { transmute(v.as_ref().unwrap().value_identifier()) };
Self { ptr: v, id }
}
}
impl From<Pokemon> for IdentifiablePointer<Pokemon> {
fn from(v: Pokemon) -> Self {
let id = v.value_identifier().value();
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl From<Option<Pokemon>> for IdentifiablePointer<Pokemon> {
fn from(v: Option<Pokemon>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl From<Battle> for IdentifiablePointer<Battle> {
fn from(v: Battle) -> Self {
let id = v.value_identifier().value();
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T> IdentifiablePointer<T> {
/// Returns an identifiable pointer with null as pointer, and 0 as identifier.
pub fn none() -> Self {
Self {
ptr: std::ptr::null(),
id: Default::default(),
}
}
}
/// Helper utility class to give either the data or an error to a FFI.
@@ -301,19 +107,19 @@ union ResultUnion<T: Copy> {
/// If the result is ok, this contains the value.
ok: T,
/// If the result is an error, this contains the error message.
err: OwnedPtr<c_char>,
err: NonOwnedPtrString,
}
/// The result of a FFI call that can either be an error or a value.
#[repr(C)]
pub struct NativeResult<T: Copy> {
pub struct FFIResult<T: Copy> {
/// If the result is ok, this is 1, otherwise 0.
ok: u8,
/// The value or error.
value: ResultUnion<T>,
}
impl<T: Copy> NativeResult<T> {
impl<T: Copy> FFIResult<T> {
/// Creates a new NativeResult with the given value.
pub fn ok(value: T) -> Self {
Self {
@@ -344,7 +150,7 @@ impl<T: Copy> NativeResult<T> {
}
}
impl<T: Copy> From<anyhow::Result<T>> for NativeResult<T> {
impl<T: Copy> From<anyhow::Result<T>> for FFIResult<T> {
fn from(value: anyhow::Result<T>) -> Self {
match value {
Ok(v) => Self::ok(v),
@@ -353,7 +159,7 @@ impl<T: Copy> From<anyhow::Result<T>> for NativeResult<T> {
}
}
impl<T: Copy> From<T> for NativeResult<T> {
impl<T: Copy> From<T> for FFIResult<T> {
fn from(value: T) -> Self {
Self::ok(value)
}

View File

@@ -1,9 +1,10 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::FFIHandle;
use crate::ffi::FromFFIHandle;
use crate::ffi::{FFIResult, OwnedPtrString};
use crate::static_data::{Ability, AbilityImpl, EffectParameter};
use crate::StringKey;
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Instantiates a new ability.
@@ -11,67 +12,61 @@ use std::sync::Arc;
unsafe extern "C" fn ability_new(
name: *const c_char,
effect: *const c_char,
parameters: *const OwnedPtr<Arc<EffectParameter>>,
parameters: *const FFIHandle<Arc<EffectParameter>>,
parameters_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn Ability>>> {
) -> FFIResult<FFIHandle<Arc<dyn Ability>>> {
let parameters = std::slice::from_raw_parts(parameters, parameters_length);
let mut parameters_vec: Vec<Arc<EffectParameter>> = Vec::with_capacity(parameters_length);
for parameter in parameters {
parameters_vec.push(parameter.read());
parameters_vec.push(parameter.from_ffi_handle());
}
let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(s) => s.into(),
Err(_) => return NativeResult::err(anyhow!("Failed to convert name to CStr")),
Err(_) => return FFIResult::err(anyhow!("Failed to convert name to CStr")),
};
let effect: StringKey = match CStr::from_ptr(effect).to_str() {
Ok(s) => s.into(),
Err(_) => return NativeResult::err(anyhow!("Failed to convert effect to CStr")),
Err(_) => return FFIResult::err(anyhow!("Failed to convert effect to CStr")),
};
let arc: Arc<dyn Ability> = Arc::new(AbilityImpl::new(&name, &effect, parameters_vec));
NativeResult::ok(arc.into())
}
/// Drops a reference counted ability.
#[no_mangle]
unsafe extern "C" fn ability_drop(ptr: OwnedPtr<Arc<dyn Ability>>) {
drop_in_place(ptr)
FFIResult::ok(FFIHandle::get_handle(arc.into()))
}
/// The name of the ability.
#[no_mangle]
unsafe extern "C" fn ability_name(ptr: ExternPointer<Arc<dyn Ability>>) -> NativeResult<OwnedPtr<c_char>> {
match CString::new(ptr.as_ref().name().str()) {
Ok(s) => NativeResult::ok(s.into_raw()),
Err(_) => NativeResult::err(anyhow!("Failed to convert name to CString")),
unsafe extern "C" fn ability_name(handle: FFIHandle<Arc<dyn Ability>>) -> FFIResult<OwnedPtrString> {
match CString::new(handle.from_ffi_handle().name().str()) {
Ok(s) => FFIResult::ok(s.into_raw()),
Err(_) => FFIResult::err(anyhow!("Failed to convert name to CString")),
}
}
/// The name of the script effect of the ability.
#[no_mangle]
unsafe extern "C" fn ability_effect(ptr: ExternPointer<Arc<dyn Ability>>) -> NativeResult<OwnedPtr<c_char>> {
match CString::new(ptr.as_ref().effect().str()) {
Ok(s) => NativeResult::ok(s.into_raw()),
Err(_) => NativeResult::err(anyhow!("Failed to convert effect to CString")),
unsafe extern "C" fn ability_effect(ptr: FFIHandle<Arc<dyn Ability>>) -> FFIResult<OwnedPtrString> {
match CString::new(ptr.from_ffi_handle().effect().str()) {
Ok(s) => FFIResult::ok(s.into_raw()),
Err(_) => FFIResult::err(anyhow!("Failed to convert effect to CString")),
}
}
/// The length of the parameters for the script effect of the ability.
#[no_mangle]
unsafe extern "C" fn ability_parameter_length(ptr: ExternPointer<Arc<dyn Ability>>) -> usize {
ptr.as_ref().parameters().len()
unsafe extern "C" fn ability_parameter_length(ptr: FFIHandle<Arc<dyn Ability>>) -> usize {
ptr.from_ffi_handle().parameters().len()
}
/// Gets a parameter for the script effect of the ability.
#[no_mangle]
unsafe extern "C" fn ability_parameter_get(
ptr: ExternPointer<Arc<dyn Ability>>,
ptr: FFIHandle<Arc<dyn Ability>>,
index: usize,
) -> IdentifiablePointer<Arc<EffectParameter>> {
if let Some(p) = ptr.as_ref().parameters().get(index) {
p.clone().into()
) -> FFIHandle<Arc<EffectParameter>> {
if let Some(p) = ptr.from_ffi_handle().parameters().get(index) {
FFIHandle::get_handle(p.clone().into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}

View File

@@ -1,13 +1,13 @@
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{
ffi_arc_dyn_getter, ffi_vec_stringkey_getters, ffi_vec_value_getters, BorrowedPtr, ExternPointer,
IdentifiablePointer, NativeResult, OwnedPtr,
ffi_handle_arc_dyn_getter, ffi_handle_vec_stringkey_getters, ffi_handle_vec_value_getters, FFIResult,
NonOwnedPtrString, OwnedPtrString,
};
use crate::static_data::{Form, FormImpl, LearnableMoves, StaticStatisticSet, TypeIdentifier};
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 a new form.
@@ -19,18 +19,18 @@ unsafe extern "C" fn form_new(
base_experience: u32,
types: *const TypeIdentifier,
types_length: usize,
base_stats: OwnedPtr<StaticStatisticSet<u16>>,
abilities: *const BorrowedPtr<c_char>,
base_stats: FFIHandle<Arc<StaticStatisticSet<u16>>>,
abilities: *const NonOwnedPtrString,
abilities_length: usize,
hidden_abilities: *const BorrowedPtr<c_char>,
hidden_abilities: *const NonOwnedPtrString,
hidden_abilities_length: usize,
moves: OwnedPtr<Box<dyn LearnableMoves>>,
moves: FFIHandle<Arc<dyn LearnableMoves>>,
flags: *const *const c_char,
flags_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn Form>>> {
) -> FFIResult<FFIHandle<Arc<dyn Form>>> {
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")),
Err(_) => return FFIResult::err(anyhow!("Unable to convert name to string")),
};
let abilities = std::slice::from_raw_parts(abilities, abilities_length);
@@ -49,7 +49,7 @@ unsafe extern "C" fn form_new(
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")),
Err(_) => return FFIResult::err(anyhow!("Unable to convert flag to string")),
};
flags_set.insert(flag.into());
}
@@ -60,57 +60,50 @@ unsafe extern "C" fn form_new(
weight,
base_experience,
std::slice::from_raw_parts(types, types_length).to_vec(),
*Box::from_raw(base_stats),
base_stats.from_ffi_handle(),
abilities_vec,
hidden_abilities_vec,
*Box::from_raw(moves),
moves.from_ffi_handle(),
flags_set,
));
NativeResult::ok(a.into())
}
/// Drops a reference count for a form.
#[no_mangle]
unsafe extern "C" fn form_drop(ptr: OwnedPtr<Arc<dyn Form>>) {
drop_in_place(ptr)
FFIResult::ok(FFIHandle::get_handle(a.into()))
}
/// The name of the form.
#[no_mangle]
unsafe extern "C" fn form_name(ptr: ExternPointer<Arc<dyn Form>>) -> NativeResult<OwnedPtr<c_char>> {
let name = ptr.as_ref().name();
unsafe extern "C" fn form_name(ptr: FFIHandle<Arc<dyn Form>>) -> FFIResult<OwnedPtrString> {
let obj = ptr.from_ffi_handle();
let name = obj.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())),
Ok(name) => FFIResult::ok(name.into_raw()),
Err(_) => FFIResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())),
}
}
ffi_arc_dyn_getter!(Form, height, f32);
ffi_arc_dyn_getter!(Form, weight, f32);
ffi_arc_dyn_getter!(Form, base_experience, u32);
ffi_handle_arc_dyn_getter!(Form, height, f32);
ffi_handle_arc_dyn_getter!(Form, weight, f32);
ffi_handle_arc_dyn_getter!(Form, base_experience, u32);
ffi_vec_value_getters!(Form, dyn Form, types, TypeIdentifier);
ffi_handle_vec_value_getters!(Form, dyn Form, types, TypeIdentifier);
/// The inherent values of a form of species that are used for the stats of a Pokemon.
#[no_mangle]
unsafe extern "C" fn form_base_stats(
ptr: ExternPointer<Arc<dyn Form>>,
) -> IdentifiablePointer<Arc<StaticStatisticSet<u16>>> {
ptr.as_ref().base_stats().clone().into()
unsafe extern "C" fn form_base_stats(ptr: FFIHandle<Arc<dyn Form>>) -> FFIHandle<Arc<StaticStatisticSet<u16>>> {
FFIHandle::get_handle(ptr.from_ffi_handle().base_stats().clone().into())
}
ffi_vec_stringkey_getters!(Form, abilities);
ffi_vec_stringkey_getters!(Form, hidden_abilities);
ffi_handle_vec_stringkey_getters!(Form, abilities);
ffi_handle_vec_stringkey_getters!(Form, hidden_abilities);
/// The moves a Pokemon with this form can learn.
#[no_mangle]
extern "C" fn form_moves(ptr: ExternPointer<Arc<dyn Form>>) -> BorrowedPtr<Box<dyn LearnableMoves>> {
ptr.as_ref().moves() as *const Box<dyn LearnableMoves>
extern "C" fn form_moves(ptr: FFIHandle<Arc<dyn Form>>) -> FFIHandle<Arc<dyn LearnableMoves>> {
FFIHandle::get_handle(ptr.from_ffi_handle().moves().clone().into())
}
/// Check if the form has a specific flag set.
#[no_mangle]
unsafe extern "C" fn form_has_flag(ptr: ExternPointer<Arc<dyn Form>>, flag: *const c_char) -> u8 {
unsafe extern "C" fn form_has_flag(ptr: FFIHandle<Arc<dyn Form>>, flag: *const c_char) -> u8 {
let flag = CStr::from_ptr(flag).into();
u8::from(ptr.as_ref().has_flag(&flag))
u8::from(ptr.from_ffi_handle().has_flag(&flag))
}

View File

@@ -1,33 +1,26 @@
use crate::defines::LevelInt;
use crate::ffi::{ExternPointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::static_data::{GrowthRate, LookupGrowthRate};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Instantiates a new lookup growth rate. The experience array should be the amount of experience
/// required per level, with the first element being the experience required for level 1 (generally 0).
#[no_mangle]
unsafe extern "C" fn growth_rate_lookup_new(array: *const u32, length: usize) -> OwnedPtr<Box<dyn GrowthRate>> {
unsafe extern "C" fn growth_rate_lookup_new(array: *const u32, length: usize) -> FFIHandle<Arc<dyn GrowthRate>> {
let array = std::slice::from_raw_parts(array, length);
Box::into_raw(Box::new(Box::new(LookupGrowthRate::new(array.to_vec()))))
}
/// Drops the growth rate.
#[no_mangle]
unsafe extern "C" fn growth_rate_lookup_drop(ptr: OwnedPtr<Box<dyn GrowthRate>>) {
drop_in_place(ptr)
let g: Arc<dyn GrowthRate> = Arc::new(LookupGrowthRate::new(array.to_vec()));
FFIHandle::get_handle(g.into())
}
/// Calculate the level something with this growth rate would have at a certain experience.
#[no_mangle]
extern "C" fn growth_rate_calculate_level(ptr: ExternPointer<Box<dyn GrowthRate>>, experience: u32) -> LevelInt {
ptr.as_ref().calculate_level(experience)
extern "C" fn growth_rate_calculate_level(ptr: FFIHandle<Arc<dyn GrowthRate>>, experience: u32) -> LevelInt {
ptr.from_ffi_handle().calculate_level(experience)
}
/// Calculate the experience something with this growth rate would have at a certain level.
#[no_mangle]
extern "C" fn growth_rate_calculate_experience(
ptr: ExternPointer<Box<dyn GrowthRate>>,
level: LevelInt,
) -> NativeResult<u32> {
ptr.as_ref().calculate_experience(level).into()
extern "C" fn growth_rate_calculate_experience(ptr: FFIHandle<Arc<dyn GrowthRate>>, level: LevelInt) -> FFIResult<u32> {
ptr.from_ffi_handle().calculate_experience(level).into()
}

View File

@@ -1,10 +1,10 @@
use crate::ffi::{ffi_arc_dyn_getter, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{ffi_handle_arc_dyn_getter, FFIResult, OwnedPtrString};
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.
@@ -16,48 +16,43 @@ unsafe extern "C" fn item_new(
price: i32,
flags: *const *const c_char,
flags_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn Item>>> {
) -> FFIResult<FFIHandle<Arc<dyn Item>>> {
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")),
Err(_) => return FFIResult::err(anyhow!("Unable to convert name to string")),
};
let mut flags_set: HashSet<StringKey> = 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")),
Err(_) => return FFIResult::err(anyhow!("Unable to convert flag to string")),
};
flags_set.insert(flag.into());
}
let item: Arc<dyn Item> = 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<Arc<dyn Item>>) {
drop_in_place(ptr)
FFIResult::ok(FFIHandle::get_handle(item.into()))
}
/// The name of the item.
#[no_mangle]
unsafe extern "C" fn item_name(ptr: ExternPointer<Arc<dyn Item>>) -> NativeResult<OwnedPtr<c_char>> {
let name = ptr.as_ref().name();
unsafe extern "C" fn item_name(ptr: FFIHandle<Arc<dyn Item>>) -> FFIResult<OwnedPtrString> {
let item = ptr.from_ffi_handle();
let name = item.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())),
Ok(name) => FFIResult::ok(name.into_raw()),
Err(_) => FFIResult::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);
ffi_handle_arc_dyn_getter!(Item, category, ItemCategory);
ffi_handle_arc_dyn_getter!(Item, battle_category, BattleItemCategory);
ffi_handle_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<Arc<dyn Item>>, flag: *const c_char) -> u8 {
unsafe extern "C" fn item_has_flag(ptr: FFIHandle<Arc<dyn Item>>, flag: *const c_char) -> u8 {
let flag = CStr::from_ptr(flag).into();
u8::from(ptr.as_ref().has_flag(&flag))
u8::from(ptr.from_ffi_handle().has_flag(&flag))
}

View File

@@ -1,29 +1,25 @@
use crate::defines::LevelInt;
use crate::ffi::{BorrowedPtr, ExternPointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, NonOwnedPtrString};
use crate::static_data::{LearnableMoves, LearnableMovesImpl};
use std::ffi::{c_char, CStr};
use std::ptr::drop_in_place;
use std::ffi::CStr;
use std::sync::Arc;
/// Instantiates a new Learnable Moves.
#[no_mangle]
extern "C" fn learnable_moves_new(max_level: LevelInt) -> OwnedPtr<Box<dyn LearnableMoves>> {
Box::into_raw(Box::new(Box::new(LearnableMovesImpl::new(max_level))))
}
/// drops a learnablemoves struct.
#[no_mangle]
unsafe extern "C" fn learnable_moves_drop(ptr: OwnedPtr<Box<dyn LearnableMoves>>) {
drop_in_place(ptr)
extern "C" fn learnable_moves_new(max_level: LevelInt) -> FFIHandle<Arc<dyn LearnableMoves>> {
let p: Arc<dyn LearnableMoves> = Arc::new(LearnableMovesImpl::new(max_level));
FFIHandle::get_handle(p.into())
}
/// Adds a new level move the Pokemon can learn.
#[no_mangle]
unsafe extern "C" fn learnable_moves_add_level_move(
mut ptr: ExternPointer<Box<dyn LearnableMoves>>,
ptr: FFIHandle<Arc<dyn LearnableMoves>>,
level: LevelInt,
move_name: BorrowedPtr<c_char>,
) -> NativeResult<()> {
ptr.as_mut()
move_name: NonOwnedPtrString,
) -> FFIResult<()> {
ptr.from_ffi_handle()
.add_level_move(level, &CStr::from_ptr(move_name).into())
.into()
}

View File

@@ -1,30 +1,25 @@
use crate::defines::LevelInt;
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, NonOwnedPtrString};
use crate::static_data::{GrowthRate, GrowthRateLibrary, GrowthRateLibraryImpl};
use std::ffi::{c_char, CStr};
use std::ptr::drop_in_place;
use std::ffi::CStr;
use std::sync::Arc;
/// Instantiates a new growth rate library with a capacity
#[no_mangle]
extern "C" fn growth_rate_library_new(capacity: usize) -> IdentifiablePointer<Box<dyn GrowthRateLibrary>> {
let b: Box<dyn GrowthRateLibrary> = Box::new(GrowthRateLibraryImpl::new(capacity));
b.into()
}
/// Drops the growthrate library.
#[no_mangle]
unsafe extern "C" fn growth_rate_library_drop(ptr: OwnedPtr<Box<dyn GrowthRateLibrary>>) {
drop_in_place(ptr)
extern "C" fn growth_rate_library_new(capacity: usize) -> FFIHandle<Arc<dyn GrowthRateLibrary>> {
let b: Arc<dyn GrowthRateLibrary> = Arc::new(GrowthRateLibraryImpl::new(capacity));
FFIHandle::get_handle(b.into())
}
/// Calculates the level for a given growth key name and a certain experience.
#[no_mangle]
unsafe extern "C" fn growth_rate_library_calculate_level(
ptr: ExternPointer<Box<dyn GrowthRateLibrary>>,
growth_rate: BorrowedPtr<c_char>,
ptr: FFIHandle<Arc<dyn GrowthRateLibrary>>,
growth_rate: NonOwnedPtrString,
experience: u32,
) -> NativeResult<LevelInt> {
ptr.as_ref()
) -> FFIResult<LevelInt> {
ptr.from_ffi_handle()
.calculate_level(&CStr::from_ptr(growth_rate).into(), experience)
.into()
}
@@ -32,11 +27,11 @@ unsafe extern "C" fn growth_rate_library_calculate_level(
/// Calculates the experience for a given growth key name and a certain level.
#[no_mangle]
unsafe extern "C" fn growth_rate_library_calculate_experience(
ptr: ExternPointer<Box<dyn GrowthRateLibrary>>,
growth_rate: BorrowedPtr<c_char>,
ptr: FFIHandle<Arc<dyn GrowthRateLibrary>>,
growth_rate: NonOwnedPtrString,
level: LevelInt,
) -> NativeResult<u32> {
ptr.as_ref()
) -> FFIResult<u32> {
ptr.from_ffi_handle()
.calculate_experience(&CStr::from_ptr(growth_rate).into(), level)
.into()
}
@@ -44,10 +39,10 @@ unsafe extern "C" fn growth_rate_library_calculate_experience(
/// Adds a new growth rate with a name and value.
#[no_mangle]
unsafe extern "C" fn growth_rate_library_add_growth_rate(
mut ptr: ExternPointer<Box<dyn GrowthRateLibrary>>,
name: BorrowedPtr<c_char>,
growth_rate: OwnedPtr<Box<dyn GrowthRate>>,
ptr: FFIHandle<Arc<dyn GrowthRateLibrary>>,
name: NonOwnedPtrString,
growth_rate: FFIHandle<Arc<dyn GrowthRate>>,
) {
ptr.as_mut()
.add_growth_rate(&CStr::from_ptr(name).into(), *Box::from_raw(growth_rate));
ptr.from_ffi_handle()
.add_growth_rate(&CStr::from_ptr(name).into(), growth_rate.from_ffi_handle());
}

View File

@@ -1,7 +1,8 @@
use crate::defines::LevelInt;
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::static_data::{LibrarySettings, LibrarySettingsImpl};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Creates a new settings library.
/// - `maximum_level` is the highest level a Pokemon can be.
@@ -12,32 +13,26 @@ use std::ptr::drop_in_place;
extern "C" fn library_settings_new(
max_level: LevelInt,
shiny_rate: u32,
) -> NativeResult<IdentifiablePointer<Box<dyn LibrarySettings>>> {
) -> FFIResult<FFIHandle<Arc<dyn LibrarySettings>>> {
match LibrarySettingsImpl::new(max_level, shiny_rate) {
Ok(settings) => {
let b: Box<dyn LibrarySettings> = Box::new(settings);
let p: IdentifiablePointer<Box<dyn LibrarySettings>> = b.into();
p.into()
let b: Arc<dyn LibrarySettings> = Arc::new(settings);
let p: FFIHandle<Arc<dyn LibrarySettings>> = FFIHandle::get_handle(b.into());
FFIResult::ok(p)
}
Err(e) => NativeResult::err(e),
Err(e) => FFIResult::err(e),
}
}
/// Drop a library settings object.
#[no_mangle]
unsafe extern "C" fn library_settings_drop(ptr: OwnedPtr<Box<dyn LibrarySettings>>) {
drop_in_place(ptr)
}
/// The highest level a Pokemon can be.
#[no_mangle]
extern "C" fn library_settings_maximum_level(ptr: ExternPointer<Box<dyn LibrarySettings>>) -> LevelInt {
ptr.as_ref().maximum_level()
extern "C" fn library_settings_maximum_level(ptr: FFIHandle<Arc<dyn LibrarySettings>>) -> LevelInt {
ptr.from_ffi_handle().maximum_level()
}
/// The chance of a Pokemon being shiny, as the denominator of a fraction, where the nominator
/// is 1. For example, if this is 1000, then the chance of a Pokemon being shiny is 1/1000.
#[no_mangle]
extern "C" fn library_settings_shiny_rate(ptr: ExternPointer<Box<dyn LibrarySettings>>) -> u32 {
ptr.as_ref().shiny_rate()
extern "C" fn library_settings_shiny_rate(ptr: FFIHandle<Arc<dyn LibrarySettings>>) -> u32 {
ptr.from_ffi_handle().shiny_rate()
}

View File

@@ -9,10 +9,10 @@ mod static_data;
/// The foreign function interface for the type library.
mod type_library;
use crate::ffi::{BorrowedPtr, IdentifiablePointer, OwnedPtr};
use crate::ffi::{FFIHandle, FromFFIHandle};
use crate::ffi::{NonOwnedPtrString, OwnedPtrString};
use crate::static_data::*;
use std::ffi::{c_char, CStr};
use std::ptr::drop_in_place;
use std::ffi::CStr;
use std::sync::Arc;
/// Generates foreign function interfaces for a DataLibrary trait implementation.
@@ -20,42 +20,37 @@ macro_rules! library_interface {
($library_type_name:ident, $library_type:ty, $return_type:ty) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $library_type_name:snake _new >](capacity: usize) -> IdentifiablePointer<$library_type> {
let value: $library_type = Box::new([<$library_type_name Impl>]::new(capacity));
value.into()
extern "C" fn [< $library_type_name:snake _new >](capacity: usize) -> FFIHandle<$library_type> {
let value: $library_type = Arc::new([<$library_type_name Impl>]::new(capacity));
FFIHandle::get_handle(value.into())
}
#[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _drop >](ptr: OwnedPtr<$library_type>) {
drop_in_place(ptr);
unsafe extern "C" fn [< $library_type_name:snake _add >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString, value: FFIHandle<Arc<$return_type>>) {
let lib = ptr.from_ffi_handle();
lib.add(&CStr::from_ptr(key).into(), value.from_ffi_handle());
}
#[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _add >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr<c_char>, value: OwnedPtr<Arc<$return_type>>) {
let lib = ptr.as_mut().unwrap();
lib.add(&CStr::from_ptr(key).into(), *Box::from_raw(value));
}
#[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _remove >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr<c_char>) {
let lib = ptr.as_mut().unwrap();
unsafe extern "C" fn [< $library_type_name:snake _remove >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString) {
let lib = ptr.from_ffi_handle();
lib.remove(&CStr::from_ptr(key).into());
}
#[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _get >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr<c_char>) -> IdentifiablePointer<Arc<$return_type>> {
let lib = ptr.as_mut().unwrap();
unsafe extern "C" fn [< $library_type_name:snake _get >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString) -> FFIHandle<Arc<$return_type>> {
let lib = ptr.from_ffi_handle();
let v = lib.get(&CStr::from_ptr(key).into());
if let Some(value) = v {
value.clone().into()
FFIHandle::get_handle(value.clone().into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
#[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _get_key_by_index >](ptr: OwnedPtr<$library_type>, index: usize) -> OwnedPtr<c_char> {
let lib = ptr.as_mut().unwrap();
unsafe extern "C" fn [< $library_type_name:snake _get_key_by_index >](ptr: FFIHandle<$library_type>, index: usize) -> OwnedPtrString {
let lib = ptr.from_ffi_handle();
let v = lib.get_key_by_index(index);
if let Some(value) = v {
std::ffi::CString::new(value.str()).unwrap().into_raw()
@@ -65,15 +60,15 @@ macro_rules! library_interface {
}
#[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _len >](ptr: OwnedPtr<$library_type>) -> usize {
let lib = ptr.as_mut().unwrap();
unsafe extern "C" fn [< $library_type_name:snake _len >](ptr: FFIHandle<$library_type>) -> usize {
let lib = ptr.from_ffi_handle();
lib.len()
}
}
};
}
library_interface!(SpeciesLibrary, Box<dyn SpeciesLibrary>, dyn Species);
library_interface!(MoveLibrary, Box<dyn MoveLibrary>, dyn MoveData);
library_interface!(AbilityLibrary, Box<dyn AbilityLibrary>, dyn Ability);
library_interface!(ItemLibrary, Box<dyn ItemLibrary>, dyn Item);
library_interface!(SpeciesLibrary, Arc<dyn SpeciesLibrary>, dyn Species);
library_interface!(MoveLibrary, Arc<dyn MoveLibrary>, dyn MoveData);
library_interface!(AbilityLibrary, Arc<dyn AbilityLibrary>, dyn Ability);
library_interface!(ItemLibrary, Arc<dyn ItemLibrary>, dyn Item);

View File

@@ -1,84 +1,79 @@
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, NonOwnedPtrString, OwnedPtrString};
use crate::static_data::{Nature, NatureLibrary, NatureLibraryImpl};
use crate::{PkmnError, Random};
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::ffi::{CStr, CString};
use std::sync::Arc;
/// Creates a new nature library with a given capacity.
#[no_mangle]
extern "C" fn nature_library_new(capacity: usize) -> IdentifiablePointer<Box<dyn NatureLibrary>> {
let b: Box<dyn NatureLibrary> = Box::new(NatureLibraryImpl::new(capacity));
b.into()
}
/// Drop a nature library.
#[no_mangle]
unsafe extern "C" fn nature_library_drop(ptr: OwnedPtr<Box<dyn NatureLibrary>>) {
drop_in_place(ptr);
extern "C" fn nature_library_new(capacity: usize) -> FFIHandle<Arc<dyn NatureLibrary>> {
let b: Arc<dyn NatureLibrary> = Arc::new(NatureLibraryImpl::new(capacity));
FFIHandle::get_handle(b.into())
}
/// Adds a new nature with name to the library.
#[no_mangle]
unsafe extern "C" fn nature_library_load_nature(
mut ptr: ExternPointer<Box<dyn NatureLibrary>>,
name: BorrowedPtr<c_char>,
nature: OwnedPtr<Arc<dyn Nature>>,
) -> NativeResult<()> {
let nature = nature.as_ref().ok_or(PkmnError::NullReference);
ptr: FFIHandle<Arc<dyn NatureLibrary>>,
name: NonOwnedPtrString,
nature: FFIHandle<Arc<dyn Nature>>,
) -> FFIResult<()> {
let nature = nature.from_ffi_handle_opt().ok_or(PkmnError::NullReference);
match nature {
Ok(nature) => {
ptr.as_mut().load_nature(CStr::from_ptr(name).into(), nature.clone());
NativeResult::ok(())
ptr.from_ffi_handle()
.load_nature(CStr::from_ptr(name).into(), nature.clone());
FFIResult::ok(())
}
Err(e) => NativeResult::err(e.into()),
Err(e) => FFIResult::err(e.into()),
}
}
/// Gets a nature by name.
#[no_mangle]
unsafe extern "C" fn nature_library_get_nature(
ptr: ExternPointer<Box<dyn NatureLibrary>>,
name: BorrowedPtr<c_char>,
) -> IdentifiablePointer<Arc<dyn Nature>> {
if let Some(nature) = ptr.as_ref().get_nature(&CStr::from_ptr(name).into()) {
nature.into()
ptr: FFIHandle<Arc<dyn NatureLibrary>>,
name: NonOwnedPtrString,
) -> FFIHandle<Arc<dyn Nature>> {
if let Some(nature) = ptr.from_ffi_handle().get_nature(&CStr::from_ptr(name).into()) {
FFIHandle::get_handle(nature.into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Gets a random nature.
#[no_mangle]
unsafe extern "C" fn nature_library_get_random_nature(
ptr: ExternPointer<Box<dyn NatureLibrary>>,
ptr: FFIHandle<Arc<dyn NatureLibrary>>,
seed: u64,
) -> NativeResult<IdentifiablePointer<Arc<dyn Nature>>> {
) -> FFIResult<FFIHandle<Arc<dyn Nature>>> {
let mut rand = Random::new(seed as u128);
match ptr.as_ref().get_random_nature(&mut rand) {
Ok(nature) => NativeResult::ok(nature.into()),
Err(e) => NativeResult::err(e),
match ptr.from_ffi_handle().get_random_nature(&mut rand) {
Ok(nature) => FFIResult::ok(FFIHandle::get_handle(nature.into())),
Err(e) => FFIResult::err(e),
}
}
/// Finds a nature name by nature.
#[no_mangle]
unsafe extern "C" fn nature_library_get_nature_name(
ptr: ExternPointer<Box<dyn NatureLibrary>>,
nature: BorrowedPtr<Arc<dyn Nature>>,
) -> NativeResult<OwnedPtr<c_char>> {
match nature.as_ref() {
ptr: FFIHandle<Arc<dyn NatureLibrary>>,
nature: FFIHandle<Arc<dyn Nature>>,
) -> FFIResult<OwnedPtrString> {
match nature.from_ffi_handle_opt() {
Some(nature) => {
let name = ptr.as_ref().get_nature_name(nature);
let name = ptr.from_ffi_handle().get_nature_name(&nature);
match name {
Ok(name) => match CString::new(name.str()) {
Ok(cstr) => NativeResult::ok(cstr.into_raw()),
Err(_) => NativeResult::err(anyhow!("Failed to convert nature name to C string")),
Ok(cstr) => FFIResult::ok(cstr.into_raw()),
Err(_) => FFIResult::err(anyhow!("Failed to convert nature name to C string")),
},
Err(e) => NativeResult::err(e),
Err(e) => FFIResult::err(e),
}
}
None => NativeResult::err(PkmnError::NullReference.into()),
None => FFIResult::err(PkmnError::NullReference.into()),
}
}

View File

@@ -1,102 +1,81 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::static_data::{
AbilityLibrary, GrowthRateLibrary, ItemLibrary, LibrarySettings, MoveLibrary, NatureLibrary, SpeciesLibrary,
StaticData, StaticDataImpl, TypeLibrary,
};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Instantiates a new data collection.
#[no_mangle]
unsafe extern "C" fn static_data_new(
settings: OwnedPtr<Arc<dyn LibrarySettings>>,
species: OwnedPtr<Arc<dyn SpeciesLibrary>>,
moves: OwnedPtr<Arc<dyn MoveLibrary>>,
items: OwnedPtr<Arc<dyn ItemLibrary>>,
growth_rates: OwnedPtr<Arc<dyn GrowthRateLibrary>>,
types: OwnedPtr<Arc<dyn TypeLibrary>>,
natures: OwnedPtr<Arc<dyn NatureLibrary>>,
abilities: OwnedPtr<Arc<dyn AbilityLibrary>>,
) -> IdentifiablePointer<Arc<dyn StaticData>> {
settings: FFIHandle<Arc<dyn LibrarySettings>>,
species: FFIHandle<Arc<dyn SpeciesLibrary>>,
moves: FFIHandle<Arc<dyn MoveLibrary>>,
items: FFIHandle<Arc<dyn ItemLibrary>>,
growth_rates: FFIHandle<Arc<dyn GrowthRateLibrary>>,
types: FFIHandle<Arc<dyn TypeLibrary>>,
natures: FFIHandle<Arc<dyn NatureLibrary>>,
abilities: FFIHandle<Arc<dyn AbilityLibrary>>,
) -> FFIHandle<Arc<dyn StaticData>> {
let b: Arc<dyn StaticData> = Arc::new(StaticDataImpl::new(
settings.read(),
species.read(),
moves.read(),
items.read(),
growth_rates.read(),
types.read(),
natures.read(),
abilities.read(),
settings.from_ffi_handle(),
species.from_ffi_handle(),
moves.from_ffi_handle(),
items.from_ffi_handle(),
growth_rates.from_ffi_handle(),
types.from_ffi_handle(),
natures.from_ffi_handle(),
abilities.from_ffi_handle(),
));
b.into()
}
/// Drop a static data.
#[no_mangle]
unsafe extern "C" fn static_data_drop(ptr: OwnedPtr<Box<dyn StaticData>>) {
drop_in_place(ptr)
FFIHandle::get_handle(b.into())
}
/// Several misc settings for the library.
#[no_mangle]
unsafe extern "C" fn static_data_settings(
mut data: ExternPointer<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn LibrarySettings>> {
data.as_mut().settings().clone().into()
unsafe extern "C" fn static_data_settings(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn LibrarySettings>> {
FFIHandle::get_handle(data.from_ffi_handle().settings().clone().into())
}
/// All data for Pokemon species.
#[no_mangle]
unsafe extern "C" fn static_data_species(
mut data: ExternPointer<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn SpeciesLibrary>> {
data.as_mut().species().clone().into()
unsafe extern "C" fn static_data_species(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn SpeciesLibrary>> {
FFIHandle::get_handle(data.from_ffi_handle().species().clone().into())
}
/// All data for the moves.
#[no_mangle]
unsafe extern "C" fn static_data_moves(
mut data: ExternPointer<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn MoveLibrary>> {
data.as_mut().moves().clone().into()
unsafe extern "C" fn static_data_moves(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn MoveLibrary>> {
FFIHandle::get_handle(data.from_ffi_handle().moves().clone().into())
}
/// All data for the items.
#[no_mangle]
unsafe extern "C" fn static_data_items(
mut data: ExternPointer<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn ItemLibrary>> {
(data.as_mut().items()).clone().into()
unsafe extern "C" fn static_data_items(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn ItemLibrary>> {
FFIHandle::get_handle((data.from_ffi_handle().items()).clone().into())
}
/// All data for growth rates.
#[no_mangle]
unsafe extern "C" fn static_data_growth_rates(
mut data: ExternPointer<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn GrowthRateLibrary>> {
data.as_mut().growth_rates().clone().into()
data: FFIHandle<Arc<dyn StaticData>>,
) -> FFIHandle<Arc<dyn GrowthRateLibrary>> {
FFIHandle::get_handle(data.from_ffi_handle().growth_rates().clone().into())
}
/// All data related to types and type effectiveness.
#[no_mangle]
unsafe extern "C" fn static_data_types(
mut data: ExternPointer<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn TypeLibrary>> {
data.as_mut().types().clone().into()
unsafe extern "C" fn static_data_types(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn TypeLibrary>> {
FFIHandle::get_handle(data.from_ffi_handle().types().clone().into())
}
/// All data related to natures.
#[no_mangle]
unsafe extern "C" fn static_data_natures(
data: ExternPointer<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn NatureLibrary>> {
data.as_ref().natures().clone().into()
unsafe extern "C" fn static_data_natures(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn NatureLibrary>> {
FFIHandle::get_handle(data.from_ffi_handle().natures().clone().into())
}
/// All data related to abilities.
#[no_mangle]
unsafe extern "C" fn static_data_abilities(
mut data: ExternPointer<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn AbilityLibrary>> {
(data.as_mut().abilities()).clone().into()
unsafe extern "C" fn static_data_abilities(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn AbilityLibrary>> {
FFIHandle::get_handle((data.from_ffi_handle().abilities()).clone().into())
}

View File

@@ -1,29 +1,24 @@
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, NonOwnedPtrString};
use crate::static_data::{TypeIdentifier, TypeLibrary, TypeLibraryImpl};
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Instantiates a new type library with a specific capacity.
#[no_mangle]
extern "C" fn type_library_new(capacity: usize) -> IdentifiablePointer<Box<dyn TypeLibrary>> {
let b: Box<dyn TypeLibrary> = Box::new(TypeLibraryImpl::new(capacity));
b.into()
}
/// Drops a type library.
#[no_mangle]
unsafe extern "C" fn type_library_drop(ptr: OwnedPtr<Box<dyn TypeLibrary>>) {
drop_in_place(ptr);
extern "C" fn type_library_new(capacity: usize) -> FFIHandle<Arc<dyn TypeLibrary>> {
let b: Arc<dyn TypeLibrary> = Arc::new(TypeLibraryImpl::new(capacity));
FFIHandle::get_handle(b.into())
}
/// Gets the type identifier for a type with a name.
#[no_mangle]
unsafe extern "C" fn type_library_get_type_id(
ptr: ExternPointer<Box<dyn TypeLibrary>>,
key: BorrowedPtr<c_char>,
ptr: FFIHandle<Arc<dyn TypeLibrary>>,
key: NonOwnedPtrString,
found: *mut bool,
) -> TypeIdentifier {
if let Some(v) = ptr.as_ref().get_type_id(&CStr::from_ptr(key).into()) {
if let Some(v) = ptr.from_ffi_handle().get_type_id(&CStr::from_ptr(key).into()) {
*found = true;
v
} else {
@@ -35,31 +30,33 @@ unsafe extern "C" fn type_library_get_type_id(
/// Gets the type name from the type identifier.
#[no_mangle]
unsafe extern "C" fn type_library_get_type_name(
ptr: ExternPointer<Box<dyn TypeLibrary>>,
ptr: FFIHandle<Arc<dyn TypeLibrary>>,
type_id: TypeIdentifier,
found: *mut bool,
) -> NativeResult<*mut c_char> {
if let Some(v) = ptr.as_ref().get_type_name(type_id) {
) -> FFIResult<*mut c_char> {
if let Some(v) = ptr.from_ffi_handle().get_type_name(type_id) {
*found = true;
match CString::new(v.str()) {
Ok(v) => NativeResult::ok(v.into_raw()),
Err(e) => NativeResult::err(e.into()),
Ok(v) => FFIResult::ok(v.into_raw()),
Err(e) => FFIResult::err(e.into()),
}
} else {
*found = false;
NativeResult::ok(std::ptr::null_mut())
FFIResult::ok(std::ptr::null_mut())
}
}
/// Gets the effectiveness for a single attacking type against a single defending type.
#[no_mangle]
extern "C" fn type_library_get_single_effectiveness(
ptr: ExternPointer<Box<dyn TypeLibrary>>,
ptr: FFIHandle<Arc<dyn TypeLibrary>>,
attacking: TypeIdentifier,
defending: TypeIdentifier,
) -> NativeResult<f32> {
ptr.as_ref().get_single_effectiveness(attacking, defending).into()
) -> FFIResult<f32> {
ptr.from_ffi_handle()
.get_single_effectiveness(attacking, defending)
.into()
}
/// Gets the effectiveness for a single attacking type against an amount of defending types.
@@ -67,33 +64,33 @@ extern "C" fn type_library_get_single_effectiveness(
/// and multiplying the results with each other.
#[no_mangle]
unsafe extern "C" fn type_library_get_effectiveness(
ptr: ExternPointer<Box<dyn TypeLibrary>>,
ptr: FFIHandle<Arc<dyn TypeLibrary>>,
attacking: TypeIdentifier,
defending: OwnedPtr<TypeIdentifier>,
defending: *const TypeIdentifier,
defending_length: usize,
) -> NativeResult<f32> {
) -> FFIResult<f32> {
let v = std::slice::from_raw_parts(defending, defending_length);
ptr.as_ref().get_effectiveness(attacking, v).into()
ptr.from_ffi_handle().get_effectiveness(attacking, v).into()
}
/// Registers a new type in the library.
#[no_mangle]
unsafe extern "C" fn type_library_register_type(
mut ptr: ExternPointer<Box<dyn TypeLibrary>>,
name: BorrowedPtr<c_char>,
ptr: FFIHandle<Arc<dyn TypeLibrary>>,
name: NonOwnedPtrString,
) -> TypeIdentifier {
ptr.as_mut().register_type(&CStr::from_ptr(name).into())
ptr.from_ffi_handle().register_type(&CStr::from_ptr(name).into())
}
/// Sets the effectiveness for an attacking type against a defending type.
#[no_mangle]
unsafe extern "C" fn type_library_set_effectiveness(
mut ptr: ExternPointer<Box<dyn TypeLibrary>>,
ptr: FFIHandle<Arc<dyn TypeLibrary>>,
attacking: TypeIdentifier,
defending: TypeIdentifier,
effectiveness: f32,
) -> NativeResult<()> {
ptr.as_mut()
) -> FFIResult<()> {
ptr.from_ffi_handle()
.set_effectiveness(attacking, defending, effectiveness)
.into()
}

View File

@@ -1,9 +1,11 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FFIObject, FromFFIHandle};
use crate::ffi::{FFIResult, OwnedPtrString};
use crate::static_data::EffectParameter;
use crate::{PkmnError, StringKey};
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::ops::Deref;
use std::sync::Arc;
/// The Foreign Function Interface for abilities
mod ability;
@@ -28,94 +30,88 @@ mod statistic_set;
/// Instantiates an effect parameter with a boolean.
#[no_mangle]
extern "C" fn effect_parameter_new_bool(value: u8) -> IdentifiablePointer<EffectParameter> {
Box::<EffectParameter>::new((value == 1).into()).into()
extern "C" fn effect_parameter_new_bool(value: u8) -> FFIHandle<Arc<EffectParameter>> {
FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value == 1))))
}
/// Instantiates an effect parameter with an integer.
#[no_mangle]
extern "C" fn effect_parameter_new_int(value: i64) -> IdentifiablePointer<EffectParameter> {
Box::<EffectParameter>::new(value.into()).into()
extern "C" fn effect_parameter_new_int(value: i64) -> FFIHandle<Arc<EffectParameter>> {
FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value))))
}
/// Instantiates an effect parameter with a float.
#[no_mangle]
extern "C" fn effect_parameter_new_float(value: f32) -> IdentifiablePointer<EffectParameter> {
Box::<EffectParameter>::new(value.into()).into()
extern "C" fn effect_parameter_new_float(value: f32) -> FFIHandle<Arc<EffectParameter>> {
FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value))))
}
/// Instantiates an effect parameter with a string.
#[no_mangle]
unsafe extern "C" fn effect_parameter_new_string(
value: *const c_char,
) -> NativeResult<IdentifiablePointer<EffectParameter>> {
unsafe extern "C" fn effect_parameter_new_string(value: *const c_char) -> FFIResult<FFIHandle<Arc<EffectParameter>>> {
let sk: StringKey = match CStr::from_ptr(value).to_str() {
Ok(sk) => sk.into(),
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()),
Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
};
NativeResult::ok(Box::<EffectParameter>::new(sk.into()).into())
}
/// Drop an effect parameter.
#[no_mangle]
unsafe extern "C" fn effect_parameter_drop(ptr: OwnedPtr<EffectParameter>) {
drop_in_place(ptr)
FFIResult::ok(FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(
EffectParameter::from(sk),
))))
}
/// Get the type of an effect parameter.
#[no_mangle]
extern "C" fn effect_parameter_get_type(ptr: ExternPointer<EffectParameter>) -> u8 {
match ptr.as_ref() {
EffectParameter::Bool(_, _) => 0,
EffectParameter::Int(_, _) => 1,
EffectParameter::Float(_, _) => 2,
EffectParameter::String(_, _) => 3,
extern "C" fn effect_parameter_get_type(ptr: FFIHandle<Arc<EffectParameter>>) -> u8 {
match ptr.from_ffi_handle().deref() {
EffectParameter::Bool(_) => 0,
EffectParameter::Int(_) => 1,
EffectParameter::Float(_) => 2,
EffectParameter::String(_) => 3,
}
}
/// Get the boolean contained in the effect parameter, panics if the effect parameter is not a bool.
#[no_mangle]
extern "C" fn effect_parameter_get_as_bool(ptr: ExternPointer<EffectParameter>) -> NativeResult<u8> {
let p = ptr.as_ref();
if let EffectParameter::Bool(_, b) = p {
NativeResult::ok(u8::from(*b))
extern "C" fn effect_parameter_get_as_bool(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<u8> {
let p = ptr.from_ffi_handle();
if let EffectParameter::Bool(b) = p.deref() {
FFIResult::ok(u8::from(*b))
} else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p))
FFIResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p))
}
}
/// Get the int contained in the effect parameter, panics if the effect parameter is not a int.
#[no_mangle]
extern "C" fn effect_parameter_get_as_int(ptr: ExternPointer<EffectParameter>) -> NativeResult<i64> {
let p = ptr.as_ref();
if let EffectParameter::Int(_, b) = p {
NativeResult::ok(*b)
extern "C" fn effect_parameter_get_as_int(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<i64> {
let p = ptr.from_ffi_handle();
if let EffectParameter::Int(b) = p.deref() {
FFIResult::ok(*b)
} else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p))
FFIResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p))
}
}
/// Get the float contained in the effect parameter, panics if the effect parameter is not a float.
#[no_mangle]
extern "C" fn effect_parameter_get_as_float(ptr: ExternPointer<EffectParameter>) -> NativeResult<f32> {
let p = ptr.as_ref();
if let EffectParameter::Float(_, b) = p {
NativeResult::ok(*b)
extern "C" fn effect_parameter_get_as_float(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<f32> {
let p = ptr.from_ffi_handle();
if let EffectParameter::Float(b) = p.deref() {
FFIResult::ok(*b)
} else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p))
FFIResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p))
}
}
/// Get the string contained in the effect parameter, panics if the effect parameter is not a string.
#[no_mangle]
extern "C" fn effect_parameter_get_as_string(ptr: ExternPointer<EffectParameter>) -> NativeResult<OwnedPtr<c_char>> {
let p = ptr.as_ref();
if let EffectParameter::String(_, b) = p {
extern "C" fn effect_parameter_get_as_string(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<OwnedPtrString> {
let p = ptr.from_ffi_handle();
if let EffectParameter::String(b) = p.deref() {
match CString::new(b.str().to_string()) {
Ok(cstr) => NativeResult::ok(cstr.into_raw()),
Err(_) => NativeResult::err(PkmnError::InvalidCString.into()),
Ok(cstr) => FFIResult::ok(cstr.into_raw()),
Err(_) => FFIResult::err(PkmnError::InvalidCString.into()),
}
} else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected string, was: {}", p))
FFIResult::err(anyhow!("Unexpected effect parameter. Expected string, was: {}", p))
}
}

View File

@@ -1,4 +1,5 @@
use crate::ffi::{ffi_arc_dyn_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{ffi_handle_arc_dyn_getter, ExternPointer, FFIResult, NonOwnedPtrString, OwnedPtrString};
use crate::static_data::{
EffectParameter, MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffect, SecondaryEffectImpl,
TypeIdentifier,
@@ -7,7 +8,6 @@ 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 a new move.
@@ -21,27 +21,27 @@ unsafe extern "C" fn move_data_new(
base_usages: u8,
target: MoveTarget,
priority: i8,
secondary_effect: *mut Box<dyn SecondaryEffect>,
secondary_effect: FFIHandle<Arc<dyn SecondaryEffect>>,
flags: *const *const c_char,
flags_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn MoveData>>> {
) -> FFIResult<FFIHandle<Arc<dyn MoveData>>> {
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_from_str("Unable to convert name to string"),
Err(_) => return FFIResult::err_from_str("Unable to convert name to string"),
};
let mut flags_set: HashSet<StringKey> = 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_from_str("Unable to convert flag to string"),
Err(_) => return FFIResult::err_from_str("Unable to convert flag to string"),
};
flags_set.insert(flag.into());
}
let secondary_effect = if secondary_effect.is_null() {
let secondary_effect = if secondary_effect.is_none() {
None
} else {
Some(*Box::from_raw(secondary_effect))
Some(secondary_effect.from_ffi_handle())
};
let a: Arc<dyn MoveData> = Arc::new(MoveDataImpl::new(
&name,
@@ -55,39 +55,37 @@ unsafe extern "C" fn move_data_new(
secondary_effect,
flags_set,
));
NativeResult::ok(a.into())
}
/// Drops a reference counted move.
#[no_mangle]
unsafe extern "C" fn move_data_drop(ptr: OwnedPtr<Arc<dyn MoveData>>) {
drop_in_place(ptr)
FFIResult::ok(FFIHandle::get_handle(a.into()))
}
/// The name of the move.
#[no_mangle]
unsafe extern "C" fn move_data_name(ptr: ExternPointer<Arc<dyn MoveData>>) -> NativeResult<OwnedPtr<c_char>> {
let name = ptr.as_ref().name();
unsafe extern "C" fn move_data_name(ptr: FFIHandle<Arc<dyn MoveData>>) -> FFIResult<OwnedPtrString> {
let move_data = ptr.from_ffi_handle();
let name = move_data.name();
match CString::new(name.str()) {
Ok(name) => NativeResult::ok(name.into_raw()),
Err(_) => NativeResult::err_from_str("Unable to convert name to string"),
Ok(name) => FFIResult::ok(name.into_raw()),
Err(_) => FFIResult::err_from_str("Unable to convert name to string"),
}
}
ffi_arc_dyn_getter!(MoveData, move_type, TypeIdentifier);
ffi_arc_dyn_getter!(MoveData, category, MoveCategory);
ffi_arc_dyn_getter!(MoveData, base_power, u8);
ffi_arc_dyn_getter!(MoveData, accuracy, u8);
ffi_arc_dyn_getter!(MoveData, base_usages, u8);
ffi_arc_dyn_getter!(MoveData, target, MoveTarget);
ffi_arc_dyn_getter!(MoveData, priority, i8);
ffi_handle_arc_dyn_getter!(MoveData, move_type, TypeIdentifier);
ffi_handle_arc_dyn_getter!(MoveData, category, MoveCategory);
ffi_handle_arc_dyn_getter!(MoveData, base_power, u8);
ffi_handle_arc_dyn_getter!(MoveData, accuracy, u8);
ffi_handle_arc_dyn_getter!(MoveData, base_usages, u8);
ffi_handle_arc_dyn_getter!(MoveData, target, MoveTarget);
ffi_handle_arc_dyn_getter!(MoveData, priority, i8);
/// The optional secondary effect the move has.
#[no_mangle]
unsafe extern "C" fn move_data_secondary_effect(
ptr: ExternPointer<Arc<dyn MoveData>>,
) -> IdentifiablePointer<Box<dyn SecondaryEffect>> {
ptr.as_ref().secondary_effect().into()
ptr: FFIHandle<Arc<dyn MoveData>>,
) -> FFIHandle<Arc<dyn SecondaryEffect>> {
match ptr.from_ffi_handle().secondary_effect() {
Some(secondary_effect) => FFIHandle::get_handle(secondary_effect.clone().into()),
None => FFIHandle::none(),
}
}
/// Arbitrary flags that can be applied to the move.
@@ -101,28 +99,22 @@ unsafe extern "C" fn move_data_has_flag(ptr: ExternPointer<Arc<dyn MoveData>>, f
#[no_mangle]
unsafe extern "C" fn secondary_effect_new(
chance: f32,
effect_name: BorrowedPtr<c_char>,
parameters: *mut OwnedPtr<Arc<EffectParameter>>,
effect_name: NonOwnedPtrString,
parameters: *mut FFIHandle<Arc<EffectParameter>>,
parameters_length: usize,
) -> IdentifiablePointer<Box<dyn SecondaryEffect>> {
) -> FFIHandle<Box<dyn SecondaryEffect>> {
let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length);
let mut parameters = Vec::with_capacity(parameters_length);
for parameter in parameter_slice {
parameters.push(*Box::from_raw(*parameter))
parameters.push(parameter.from_ffi_handle())
}
let b: Box<dyn SecondaryEffect> = Box::new(SecondaryEffectImpl::new(
let b: Arc<dyn SecondaryEffect> = Arc::new(SecondaryEffectImpl::new(
chance,
CStr::from_ptr(effect_name).into(),
parameters,
));
b.into()
}
/// Drop a secondary effect.
#[no_mangle]
unsafe extern "C" fn secondary_effect_drop(ptr: OwnedPtr<Box<dyn SecondaryEffect>>) {
drop_in_place(ptr)
FFIHandle::get_handle(b.into())
}
/// The chance the effect triggers.
@@ -135,10 +127,10 @@ unsafe extern "C" fn secondary_effect_chance(ptr: ExternPointer<Box<dyn Secondar
#[no_mangle]
unsafe extern "C" fn secondary_effect_effect_name(
ptr: ExternPointer<Box<dyn SecondaryEffect>>,
) -> NativeResult<OwnedPtr<c_char>> {
) -> FFIResult<OwnedPtrString> {
match CString::new(ptr.as_ref().effect_name().str()) {
Ok(name) => NativeResult::ok(name.into_raw()),
Err(_) => NativeResult::err(anyhow!(
Ok(name) => FFIResult::ok(name.into_raw()),
Err(_) => FFIResult::err(anyhow!(
"Unable to convert effect name '{}' to CString",
ptr.as_ref().effect_name()
)),
@@ -156,10 +148,10 @@ unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer<Box<dy
unsafe extern "C" fn secondary_effect_parameter_get(
ptr: ExternPointer<Box<dyn SecondaryEffect>>,
index: usize,
) -> IdentifiablePointer<Arc<EffectParameter>> {
) -> FFIHandle<Arc<EffectParameter>> {
if let Some(v) = ptr.as_ref().parameters().get(index) {
v.clone().into()
FFIHandle::get_handle(v.clone().into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}

View File

@@ -1,6 +1,5 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::static_data::{Nature, NatureImpl, Statistic};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Instantiates a new statistic.
@@ -10,32 +9,26 @@ extern "C" fn nature_new(
decrease_stat: Statistic,
increase_modifier: f32,
decrease_modifier: f32,
) -> IdentifiablePointer<Arc<dyn Nature>> {
) -> FFIHandle<Arc<dyn Nature>> {
let arc: Arc<dyn Nature> = NatureImpl::new(increase_stat, decrease_stat, increase_modifier, decrease_modifier);
arc.into()
}
/// Reduce the reference count for a nature.
#[no_mangle]
unsafe extern "C" fn nature_drop(ptr: OwnedPtr<Arc<dyn Nature>>) {
drop_in_place(ptr)
FFIHandle::get_handle(arc.into())
}
/// The stat that should receive the increased modifier.
#[no_mangle]
extern "C" fn nature_increased_stat(ptr: ExternPointer<Arc<dyn Nature>>) -> Statistic {
ptr.as_ref().increased_stat()
extern "C" fn nature_increased_stat(ptr: FFIHandle<Arc<dyn Nature>>) -> Statistic {
ptr.from_ffi_handle().increased_stat()
}
/// The stat that should receive the decreased modifier.
#[no_mangle]
extern "C" fn nature_decreased_stat(ptr: ExternPointer<Arc<dyn Nature>>) -> Statistic {
ptr.as_ref().decreased_stat()
extern "C" fn nature_decreased_stat(ptr: FFIHandle<Arc<dyn Nature>>) -> Statistic {
ptr.from_ffi_handle().decreased_stat()
}
/// Calculates the modifier for a given stat. If it's the increased stat, returns the increased
/// modifier, if it's the decreased stat, returns the decreased modifier. Otherwise returns 1.0
#[no_mangle]
extern "C" fn nature_get_stat_modifier(ptr: ExternPointer<Arc<dyn Nature>>, stat: Statistic) -> f32 {
ptr.as_ref().get_stat_modifier(stat)
extern "C" fn nature_get_stat_modifier(ptr: FFIHandle<Arc<dyn Nature>>, stat: Statistic) -> f32 {
ptr.from_ffi_handle().get_stat_modifier(stat)
}

View File

@@ -1,33 +1,32 @@
use crate::ffi::ffi_handle::FFIHandle;
use crate::ffi::{
ffi_arc_dyn_getter, ffi_arc_stringkey_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult,
OwnedPtr,
ffi_handle_arc_dyn_getter, ffi_handle_arc_stringkey_getter, FFIResult, FromFFIHandle, NonOwnedPtrString,
};
use crate::static_data::{Form, Gender, Species, SpeciesImpl};
use crate::{PkmnError, Random, StringKey};
use hashbrown::HashSet;
use std::ffi::{c_char, CStr};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Creates a new species.
#[no_mangle]
unsafe extern "C" fn species_new(
id: u16,
name: BorrowedPtr<c_char>,
name: NonOwnedPtrString,
gender_rate: f32,
growth_rate: BorrowedPtr<c_char>,
growth_rate: NonOwnedPtrString,
capture_rate: u8,
default_form: OwnedPtr<Arc<dyn Form>>,
default_form: FFIHandle<Arc<dyn Form>>,
flags: *const *const c_char,
flags_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn Species>>> {
) -> FFIResult<FFIHandle<Arc<dyn Species>>> {
let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(name) => name.into(),
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()),
Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
};
let growth_rate: StringKey = match CStr::from_ptr(growth_rate).to_str() {
Ok(growth_rate) => growth_rate.into(),
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()),
Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
};
let flags = std::slice::from_raw_parts(flags, flags_length);
@@ -35,13 +34,14 @@ unsafe extern "C" fn species_new(
for flag in flags {
let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag,
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()),
Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
};
flags_set.insert(flag.into());
}
let default_form = match default_form.as_ref() {
Some(default_form) => default_form,
None => return NativeResult::err(PkmnError::NullReference.into()),
let default_form = if default_form.is_none() {
return FFIResult::err(PkmnError::NullReference.into());
} else {
default_form.from_ffi_handle()
};
let a: Arc<dyn Species> = Arc::new(SpeciesImpl::new(
@@ -53,53 +53,48 @@ unsafe extern "C" fn species_new(
default_form.clone(),
flags_set,
));
NativeResult::ok(a.into())
FFIResult::ok(FFIHandle::get_handle(a.into()))
}
/// Drop a reference to the species.
#[no_mangle]
unsafe extern "C" fn species_drop(ptr: OwnedPtr<Arc<dyn Species>>) {
drop_in_place(ptr);
}
ffi_arc_dyn_getter!(Species, id, u16);
ffi_arc_stringkey_getter!(Species, name);
ffi_arc_dyn_getter!(Species, gender_rate, f32);
ffi_arc_stringkey_getter!(Species, growth_rate);
ffi_arc_dyn_getter!(Species, capture_rate, u8);
ffi_handle_arc_dyn_getter!(Species, id, u16);
ffi_handle_arc_stringkey_getter!(Species, name);
ffi_handle_arc_dyn_getter!(Species, gender_rate, f32);
ffi_handle_arc_stringkey_getter!(Species, growth_rate);
ffi_handle_arc_dyn_getter!(Species, capture_rate, u8);
/// Adds a new form to the species.
#[no_mangle]
unsafe extern "C" fn species_add_form(
mut species: ExternPointer<Arc<dyn Species>>,
name: BorrowedPtr<c_char>,
form: OwnedPtr<Arc<dyn Form>>,
) -> NativeResult<()> {
let form = match form.as_ref() {
Some(form) => form.clone(),
None => return NativeResult::err(PkmnError::NullReference.into()),
species: FFIHandle<Arc<dyn Species>>,
name: NonOwnedPtrString,
form: FFIHandle<Arc<dyn Form>>,
) -> FFIResult<()> {
let form = if form.is_none() {
return FFIResult::err(PkmnError::NullReference.into());
} else {
form.from_ffi_handle()
};
species.as_mut().add_form(CStr::from_ptr(name).into(), form);
NativeResult::ok(())
species.from_ffi_handle().add_form(CStr::from_ptr(name).into(), form);
FFIResult::ok(())
}
/// Gets a form by name.
#[no_mangle]
unsafe extern "C" fn species_get_form(
species: ExternPointer<Arc<dyn Species>>,
name: BorrowedPtr<c_char>,
) -> IdentifiablePointer<Arc<dyn Form>> {
let form = species.as_ref().get_form(&CStr::from_ptr(name).into());
species: FFIHandle<Arc<dyn Species>>,
name: NonOwnedPtrString,
) -> FFIHandle<Arc<dyn Form>> {
let form = species.from_ffi_handle().get_form(&CStr::from_ptr(name).into());
if let Some(form) = form {
form.into()
FFIHandle::get_handle(form.into())
} else {
IdentifiablePointer::none()
FFIHandle::none()
}
}
/// Gets a form by name.
#[no_mangle]
unsafe extern "C" fn species_get_random_gender(species: ExternPointer<Arc<dyn Species>>, seed: u64) -> Gender {
unsafe extern "C" fn species_get_random_gender(species: FFIHandle<Arc<dyn Species>>, seed: u64) -> Gender {
let mut rand = Random::new(seed as u128);
species.as_ref().get_random_gender(&mut rand)
species.from_ffi_handle().get_random_gender(&mut rand)
}

View File

@@ -1,6 +1,7 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::FFIHandle;
use crate::ffi::FromFFIHandle;
use crate::static_data::{StaticStatisticSet, Statistic, StatisticSet};
use std::ptr::drop_in_place;
use std::sync::Arc;
/// Basic foreign function interface for a statistic set.
macro_rules! statistic_set {
@@ -15,40 +16,35 @@ extern "C" fn [<statistic_set_ $num_type _new>](
special_attack: $num_type,
special_defense: $num_type,
speed: $num_type,
) -> IdentifiablePointer<StatisticSet<$num_type>> {
Box::new(StatisticSet::new(
) -> FFIHandle<Arc<StatisticSet<$num_type>>> {
FFIHandle::get_handle(Arc::new(StatisticSet::new(
hp,
attack,
defense,
special_attack,
special_defense,
speed,
)).into()
)).into())
}
#[no_mangle]
unsafe extern "C" fn [<statistic_set_ $num_type _drop>](ptr: OwnedPtr<StatisticSet<$num_type>>) {
drop_in_place(ptr)
extern "C" fn [<statistic_set_ $num_type _get_stat>](ptr: FFIHandle<Arc<StatisticSet<$num_type>>>, stat: Statistic) -> $num_type {
ptr.from_ffi_handle().get_stat(stat)
}
#[no_mangle]
extern "C" fn [<statistic_set_ $num_type _get_stat>](ptr: ExternPointer<StatisticSet<$num_type>>, stat: Statistic) -> $num_type {
ptr.as_ref().get_stat(stat)
extern "C" fn [<statistic_set_ $num_type _set_stat>](ptr: FFIHandle<Arc<StatisticSet<$num_type>>>, stat: Statistic, value: $num_type) {
ptr.from_ffi_handle().set_stat(stat, value)
}
#[no_mangle]
extern "C" fn [<statistic_set_ $num_type _set_stat>](ptr: ExternPointer<StatisticSet<$num_type>>, stat: Statistic, value: $num_type) {
ptr.as_ref().set_stat(stat, value)
extern "C" fn [<statistic_set_ $num_type _increase_stat>](ptr: FFIHandle<Arc<StatisticSet<$num_type>>>, stat: Statistic, value: $num_type) {
ptr.from_ffi_handle().increase_stat(stat, value)
}
#[no_mangle]
extern "C" fn [<statistic_set_ $num_type _increase_stat>](ptr: ExternPointer<StatisticSet<$num_type>>, stat: Statistic, value: $num_type) {
ptr.as_ref().increase_stat(stat, value)
}
#[no_mangle]
extern "C" fn [<statistic_set_ $num_type _decrease_stat>](ptr: ExternPointer<StatisticSet<$num_type>>, stat: Statistic, value: $num_type) {
ptr.as_ref().decrease_stat(stat, value)
extern "C" fn [<statistic_set_ $num_type _decrease_stat>](ptr: FFIHandle<Arc<StatisticSet<$num_type>>>, stat: Statistic, value: $num_type) {
ptr.from_ffi_handle().decrease_stat(stat, value)
}
}
@@ -56,11 +52,11 @@ extern "C" fn [<statistic_set_ $num_type _decrease_stat>](ptr: ExternPointer<Sta
}
statistic_set!(u8);
statistic_set!(u16);
// statistic_set!(u16);
statistic_set!(u32);
statistic_set!(i8);
statistic_set!(i16);
statistic_set!(i32);
// statistic_set!(i16);
// statistic_set!(i32);
/// Basic foreign function interface for a static statistic set.
macro_rules! static_statistic_set {
@@ -75,34 +71,29 @@ extern "C" fn [<static_statistic_set_ $num_type _new>](
special_attack: $num_type,
special_defense: $num_type,
speed: $num_type,
) -> IdentifiablePointer<StaticStatisticSet<$num_type>> {
Box::new(StaticStatisticSet::new(
) -> FFIHandle<Arc<StaticStatisticSet<$num_type>>> {
FFIHandle::get_handle(Arc::new(StaticStatisticSet::new(
hp,
attack,
defense,
special_attack,
special_defense,
speed,
)).into()
)).into())
}
#[no_mangle]
unsafe extern "C" fn [<static_statistic_set_ $num_type _drop>](ptr: OwnedPtr<StaticStatisticSet<$num_type>>) {
drop_in_place(ptr)
}
#[no_mangle]
extern "C" fn [<static_statistic_set_ $num_type _get_stat>](ptr: ExternPointer<StaticStatisticSet<$num_type>>, stat: Statistic) -> $num_type {
ptr.as_ref().get_stat(stat)
extern "C" fn [<static_statistic_set_ $num_type _get_stat>](ptr: FFIHandle<Arc<StaticStatisticSet<$num_type>>>, stat: Statistic) -> $num_type {
ptr.from_ffi_handle().get_stat(stat)
}
}
};
}
static_statistic_set!(u8);
// static_statistic_set!(u8);
static_statistic_set!(u16);
static_statistic_set!(u32);
static_statistic_set!(i8);
static_statistic_set!(i16);
static_statistic_set!(i32);
// static_statistic_set!(u32);
// static_statistic_set!(i8);
// static_statistic_set!(i16);
// static_statistic_set!(i32);