A bunch more work on replacing every potential panic with results
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-04-16 19:57:21 +02:00
parent 1b8403ecda
commit 00d596d656
37 changed files with 526 additions and 300 deletions

View File

@@ -1,5 +1,6 @@
use crate::dynamic_data::{FleeChoice, LearnedMove, MoveChoice, PassChoice, Pokemon, TurnChoice};
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use anyhow::anyhow;
use std::ptr::drop_in_place;
use std::sync::Arc;
@@ -57,38 +58,38 @@ extern "C" fn turn_choice_move_new(
#[no_mangle]
extern "C" fn turn_choice_move_learned_move(
choice: ExternPointer<TurnChoice>,
) -> IdentifiablePointer<Arc<LearnedMove>> {
) -> NativeResult<IdentifiablePointer<Arc<LearnedMove>>> {
if let TurnChoice::Move(c) = choice.as_ref() {
return c.used_move().clone().into();
return NativeResult::ok(c.used_move().clone().into());
}
panic!("Turn choice was not a learned move");
NativeResult::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>) -> u8 {
extern "C" fn turn_choice_move_target_side(choice: ExternPointer<TurnChoice>) -> NativeResult<u8> {
if let TurnChoice::Move(c) = choice.as_ref() {
return c.target_side();
return NativeResult::ok(c.target_side());
}
panic!("Turn choice was not a learned move");
NativeResult::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>) -> u8 {
extern "C" fn turn_choice_move_target_index(choice: ExternPointer<TurnChoice>) -> NativeResult<u8> {
if let TurnChoice::Move(c) = choice.as_ref() {
return c.target_index();
return NativeResult::ok(c.target_index());
}
panic!("Turn choice was not a learned move");
NativeResult::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>) -> i8 {
extern "C" fn turn_choice_move_priority(choice: ExternPointer<TurnChoice>) -> NativeResult<i8> {
if let TurnChoice::Move(c) = choice.as_ref() {
return c.priority();
return NativeResult::ok(c.priority());
}
panic!("Turn choice was not a learned move");
NativeResult::err(anyhow!("Turn choice was not a learned move"))
}
/// Creates a new Turn Choice for the user to flee.

View File

@@ -3,6 +3,7 @@ use crate::dynamic_data::{
};
use crate::ffi::dynamic_data::models::native_event_hook::NativeEventHook;
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::sync::Arc;
@@ -178,14 +179,12 @@ extern "C" fn battle_can_use(ptr: ExternPointer<Arc<Battle>>, choice: ExternPoin
/// 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>) -> u8 {
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);
match result {
Ok(b) => u8::from(b),
Err(e) => {
panic!("Encountered error: {}", e)
}
Ok(b) => NativeResult::ok(u8::from(b)),
Err(e) => NativeResult::err(e),
}
}
@@ -203,7 +202,10 @@ extern "C" fn battle_set_weather(ptr: ExternPointer<Arc<Battle>>, weather: *cons
#[no_mangle]
extern "C" fn battle_weather_name(ptr: ExternPointer<Arc<Battle>>) -> NativeResult<*mut c_char> {
match ptr.as_ref().weather_name() {
Ok(Some(w)) => CString::new(w.str()).unwrap().into_raw().into(),
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)),
},
Ok(None) => std::ptr::null_mut::<c_char>().into(),
Err(e) => NativeResult::err(e),
}

View File

@@ -1,5 +1,7 @@
use crate::dynamic_data::{BattleParty, Pokemon, PokemonParty};
use crate::ffi::{ExternPointer, IdentifiablePointer};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult};
use crate::VecExt;
use anyhow::{anyhow, Result};
use std::sync::Arc;
/// A battle party is a wrapper around a party, with the indices for which the party is responsible
@@ -9,18 +11,34 @@ extern "C" fn battle_party_new(
party: ExternPointer<Arc<PokemonParty>>,
responsible_indices_ptr: *const u8,
responsible_indices_length: usize,
) -> IdentifiablePointer<Arc<BattleParty>> {
if responsible_indices_length % 2 == 1 {
panic!("The length of responsible indices should be dividable by two");
) -> NativeResult<IdentifiablePointer<Arc<BattleParty>>> {
if responsible_indices_length % 2 != 0 {
return NativeResult::err(anyhow!("The length of responsible indices should be dividable by two"));
}
let responsible_indices_slice =
unsafe { std::slice::from_raw_parts(responsible_indices_ptr, responsible_indices_length) };
let mut responsible_indices: Vec<(u8, u8)> = Vec::with_capacity(responsible_indices_length / 2);
let mut split = |i| -> Result<()> {
*responsible_indices.get_mut_res(i)? = (
*responsible_indices_slice.get_res(i * 2)?,
*responsible_indices_slice.get_res(i * 2 + 1)?,
);
Ok(())
};
for i in 0..responsible_indices_length / 2 {
responsible_indices[i] = (responsible_indices_slice[i * 2], responsible_indices_slice[i * 2 + 1])
match split(i) {
Ok(_) => (),
Err(e) => return NativeResult::err(e),
}
}
Arc::new(BattleParty::new(party.as_ref().clone(), responsible_indices)).into()
match BattleParty::new(party.as_ref().clone(), responsible_indices) {
Ok(v) => NativeResult::ok(Arc::new(v).into()),
Err(e) => NativeResult::err(e),
}
}
/// Checks whether the party is responsible for the given index.

View File

@@ -4,6 +4,7 @@ use crate::ffi::{ffi_arc_getter, ffi_vec_value_getters, ExternPointer, Identifia
use crate::static_data::{
Ability, AbilityIndex, Form, Gender, Item, Nature, Species, Statistic, StatisticSet, TypeIdentifier,
};
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc;
@@ -141,12 +142,15 @@ ffi_arc_getter!(Pokemon, height, f32);
/// An optional nickname of the Pokemon.
#[no_mangle]
extern "C" fn pokemon_nickname(ptr: ExternPointer<Arc<Pokemon>>) -> *mut c_char {
extern "C" fn pokemon_nickname(ptr: ExternPointer<Arc<Pokemon>>) -> NativeResult<*mut c_char> {
let name = ptr.as_ref().nickname();
if let Some(v) = name {
CString::new(v.as_str()).unwrap().into_raw()
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)),
}
} else {
std::ptr::null_mut()
NativeResult::ok(std::ptr::null_mut())
}
}

View File

@@ -1,5 +1,5 @@
use crate::dynamic_data::{Pokemon, PokemonParty};
use crate::ffi::{ExternPointer, IdentifiablePointer};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult};
use std::sync::Arc;
/// Instantiates a party with a set size.
@@ -33,16 +33,16 @@ extern "C" fn pokemon_party_swap_into(
ptr: ExternPointer<Arc<PokemonParty>>,
index: usize,
pokemon: ExternPointer<Arc<Pokemon>>,
) -> IdentifiablePointer<Arc<Pokemon>> {
) -> NativeResult<IdentifiablePointer<Arc<Pokemon>>> {
let pokemon = if pokemon.ptr.is_null() {
None
} else {
Some(pokemon.as_ref().clone())
};
if let Some(v) = ptr.as_ref().swap_into(index, pokemon) {
v.into()
} else {
IdentifiablePointer::none()
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),
}
}
@@ -60,8 +60,8 @@ extern "C" fn pokemon_party_length(ptr: ExternPointer<Arc<PokemonParty>>) -> usi
/// 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>>) {
ptr.as_ref().pack_party()
extern "C" fn pokemon_party_pack_party(ptr: ExternPointer<Arc<PokemonParty>>) -> NativeResult<()> {
ptr.as_ref().pack_party().into()
}
/// Checks if the party contains a given pokemon.