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.

View File

@@ -106,6 +106,7 @@ pub(self) struct ExternPointer<T: ?Sized> {
impl<T: ?Sized> ExternPointer<T> {
/// Get the internal pointer as 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_ref(&self) -> &T {
unsafe {
self.ptr
@@ -114,6 +115,7 @@ impl<T: ?Sized> ExternPointer<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
@@ -241,6 +243,7 @@ impl<T: ValueIdentifiable> From<Box<T>> for IdentifiablePointer<T> {
}
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 }
@@ -284,7 +287,8 @@ impl<T: Copy> NativeResult<T> {
}
}
/// Creates a new NativeResult with the given error.
pub fn err(err: anyhow::Error) -> Self {
#[allow(clippy::unwrap_used)] // We know for certain this is not empty.
pub fn err(err: anyhow_ext::Error) -> Self {
Self {
ok: 0,
value: ResultUnion {
@@ -292,6 +296,17 @@ impl<T: Copy> NativeResult<T> {
},
}
}
/// Creates a new NativeResult with the given error string.
#[allow(clippy::unwrap_used)] // We know for certain this is not empty.
pub fn err_from_str(err: &str) -> Self {
Self {
ok: 0,
value: ResultUnion {
err: CString::new(err).unwrap().into_raw(),
},
}
}
}
impl<T: Copy> From<anyhow::Result<T>> for NativeResult<T> {

View File

@@ -1,6 +1,7 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
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;
@@ -12,18 +13,24 @@ unsafe extern "C" fn ability_new(
effect: *const c_char,
parameters: *const OwnedPtr<EffectParameter>,
parameters_length: usize,
) -> IdentifiablePointer<Arc<dyn Ability>> {
) -> NativeResult<IdentifiablePointer<Arc<dyn Ability>>> {
let parameters = std::slice::from_raw_parts(parameters, parameters_length);
let mut parameters_vec: Vec<EffectParameter> = Vec::with_capacity(parameters_length);
for parameter in parameters {
parameters_vec.push(*Box::from_raw(*parameter));
}
let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into();
let effect: StringKey = CStr::from_ptr(effect).to_str().unwrap().into();
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")),
};
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")),
};
let arc: Arc<dyn Ability> = Arc::new(AbilityImpl::new(&name, &effect, parameters_vec));
arc.into()
NativeResult::ok(arc.into())
}
/// Drops a reference counted ability.
@@ -34,14 +41,20 @@ unsafe extern "C" fn ability_drop(ptr: OwnedPtr<Arc<dyn Ability>>) {
/// The name of the ability.
#[no_mangle]
unsafe extern "C" fn ability_name(ptr: ExternPointer<Arc<dyn Ability>>) -> OwnedPtr<c_char> {
CString::new(ptr.as_ref().name().str()).unwrap().into_raw()
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")),
}
}
/// The name of the script effect of the ability.
#[no_mangle]
unsafe extern "C" fn ability_effect(ptr: ExternPointer<Arc<dyn Ability>>) -> OwnedPtr<c_char> {
CString::new(ptr.as_ref().effect().str()).unwrap().into_raw()
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")),
}
}
/// The length of the parameters for the script effect of the ability.

View File

@@ -1,9 +1,10 @@
use crate::ffi::{
ffi_arc_dyn_getter, ffi_vec_stringkey_getters, ffi_vec_value_getters, BorrowedPtr, ExternPointer,
IdentifiablePointer, OwnedPtr,
IdentifiablePointer, NativeResult, OwnedPtr,
};
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;
@@ -26,8 +27,11 @@ unsafe extern "C" fn form_new(
moves: OwnedPtr<Box<dyn LearnableMoves>>,
flags: *const *const c_char,
flags_length: usize,
) -> IdentifiablePointer<Arc<dyn Form>> {
let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into();
) -> NativeResult<IdentifiablePointer<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")),
};
let abilities = std::slice::from_raw_parts(abilities, abilities_length);
let mut abilities_vec = Vec::with_capacity(abilities_length);
@@ -43,7 +47,11 @@ unsafe extern "C" fn form_new(
let flags = std::slice::from_raw_parts(flags, flags_length);
let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length);
for flag in flags {
flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into());
let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag,
Err(_) => return NativeResult::err(anyhow!("Unable to convert flag to string")),
};
flags_set.insert(flag.into());
}
let a: Arc<dyn Form> = Arc::new(FormImpl::new(
@@ -58,7 +66,7 @@ unsafe extern "C" fn form_new(
*Box::from_raw(moves),
flags_set,
));
a.into()
NativeResult::ok(a.into())
}
/// Drops a reference count for a form.
@@ -69,9 +77,12 @@ unsafe extern "C" fn form_drop(ptr: OwnedPtr<Arc<dyn Form>>) {
/// The name of the form.
#[no_mangle]
unsafe extern "C" fn form_name(ptr: ExternPointer<Arc<dyn Form>>) -> OwnedPtr<c_char> {
unsafe extern "C" fn form_name(ptr: ExternPointer<Arc<dyn Form>>) -> NativeResult<OwnedPtr<c_char>> {
let name = ptr.as_ref().name();
CString::new(name.str()).unwrap().into_raw()
match CString::new(name.str()) {
Ok(name) => NativeResult::ok(name.into_raw()),
Err(_) => NativeResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())),
}
}
ffi_arc_dyn_getter!(Form, height, f32);

View File

@@ -1,6 +1,7 @@
use crate::ffi::{ffi_arc_dyn_getter, ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::{ffi_arc_dyn_getter, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::static_data::{BattleItemCategory, Item, ItemCategory, ItemImpl};
use crate::StringKey;
use anyhow::anyhow;
use hashbrown::HashSet;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
@@ -15,16 +16,23 @@ unsafe extern "C" fn item_new(
price: i32,
flags: *const *const c_char,
flags_length: usize,
) -> IdentifiablePointer<Arc<dyn Item>> {
) -> NativeResult<IdentifiablePointer<Arc<dyn Item>>> {
let flags = std::slice::from_raw_parts(flags, flags_length);
let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into();
let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(name) => name.into(),
Err(_) => return NativeResult::err(anyhow!("Unable to convert name to string")),
};
let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length);
for flag in flags {
flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into());
let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag,
Err(_) => return NativeResult::err(anyhow!("Unable to convert flag to string")),
};
flags_set.insert(flag.into());
}
let item: Arc<dyn Item> = Arc::new(ItemImpl::new(&name, category, battle_category, price, flags_set));
item.into()
NativeResult::ok(item.into())
}
/// Drops a reference counted item.
@@ -35,9 +43,12 @@ unsafe extern "C" fn item_drop(ptr: OwnedPtr<Arc<dyn Item>>) {
/// The name of the item.
#[no_mangle]
unsafe extern "C" fn item_name(ptr: ExternPointer<Arc<dyn Item>>) -> OwnedPtr<c_char> {
unsafe extern "C" fn item_name(ptr: ExternPointer<Arc<dyn Item>>) -> NativeResult<OwnedPtr<c_char>> {
let name = ptr.as_ref().name();
CString::new(name.str()).unwrap().into_raw()
match CString::new(name.str()) {
Ok(name) => NativeResult::ok(name.into_raw()),
Err(_) => NativeResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())),
}
}
ffi_arc_dyn_getter!(Item, category, ItemCategory);

View File

@@ -1,6 +1,7 @@
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::static_data::{Nature, NatureLibrary, NatureLibraryImpl};
use crate::Random;
use crate::{PkmnError, Random};
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc;
@@ -24,9 +25,15 @@ unsafe extern "C" fn nature_library_load_nature(
mut ptr: ExternPointer<Box<dyn NatureLibrary>>,
name: BorrowedPtr<c_char>,
nature: OwnedPtr<Arc<dyn Nature>>,
) {
ptr.as_mut()
.load_nature(CStr::from_ptr(name).into(), nature.as_ref().unwrap().clone())
) -> NativeResult<()> {
let nature = nature.as_ref().ok_or(PkmnError::NullReference);
match nature {
Ok(nature) => {
ptr.as_mut().load_nature(CStr::from_ptr(name).into(), nature.clone());
NativeResult::ok(())
}
Err(e) => NativeResult::err(e.into()),
}
}
/// Gets a nature by name.
@@ -57,8 +64,15 @@ unsafe extern "C" fn nature_library_get_random_nature(
unsafe extern "C" fn nature_library_get_nature_name(
ptr: ExternPointer<Box<dyn NatureLibrary>>,
nature: BorrowedPtr<Arc<dyn Nature>>,
) -> OwnedPtr<c_char> {
CString::new(ptr.as_ref().get_nature_name(nature.as_ref().unwrap()).str())
.unwrap()
.into_raw()
) -> NativeResult<OwnedPtr<c_char>> {
match nature.as_ref() {
Some(nature) => {
let name = ptr.as_ref().get_nature_name(nature);
match CString::new(name.str()) {
Ok(cstr) => NativeResult::ok(cstr.into_raw()),
Err(_) => NativeResult::err(anyhow!("Failed to convert nature name to C string")),
}
}
None => NativeResult::err(PkmnError::NullReference.into()),
}
}

View File

@@ -1,4 +1,4 @@
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::static_data::{TypeIdentifier, TypeLibrary, TypeLibraryImpl};
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
@@ -38,13 +38,17 @@ unsafe extern "C" fn type_library_get_type_name(
ptr: ExternPointer<Box<dyn TypeLibrary>>,
type_id: TypeIdentifier,
found: *mut bool,
) -> *mut c_char {
) -> NativeResult<*mut c_char> {
if let Some(v) = ptr.as_ref().get_type_name(type_id) {
*found = true;
CString::new(v.str()).unwrap().into_raw()
match CString::new(v.str()) {
Ok(v) => NativeResult::ok(v.into_raw()),
Err(e) => NativeResult::err(e.into()),
}
} else {
*found = false;
std::ptr::null_mut()
NativeResult::ok(std::ptr::null_mut())
}
}

View File

@@ -1,6 +1,7 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::static_data::EffectParameter;
use crate::StringKey;
use crate::{PkmnError, StringKey};
use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
@@ -45,9 +46,14 @@ extern "C" fn effect_parameter_new_float(value: f32) -> IdentifiablePointer<Effe
/// Instantiates an effect parameter with a string.
#[no_mangle]
unsafe extern "C" fn effect_parameter_new_string(value: *const c_char) -> IdentifiablePointer<EffectParameter> {
let sk: StringKey = CStr::from_ptr(value).to_str().unwrap().into();
Box::<EffectParameter>::new(sk.into()).into()
unsafe extern "C" fn effect_parameter_new_string(
value: *const c_char,
) -> NativeResult<IdentifiablePointer<EffectParameter>> {
let sk: StringKey = match CStr::from_ptr(value).to_str() {
Ok(sk) => sk.into(),
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()),
};
NativeResult::ok(Box::<EffectParameter>::new(sk.into()).into())
}
/// Drop an effect parameter.
@@ -69,40 +75,47 @@ extern "C" fn effect_parameter_get_type(ptr: ExternPointer<EffectParameter>) ->
/// 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>) -> u8 {
extern "C" fn effect_parameter_get_as_bool(ptr: ExternPointer<EffectParameter>) -> NativeResult<u8> {
let p = ptr.as_ref();
if let EffectParameter::Bool(_, b) = p {
return u8::from(*b);
NativeResult::ok(u8::from(*b))
} else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p))
}
panic!("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>) -> i64 {
extern "C" fn effect_parameter_get_as_int(ptr: ExternPointer<EffectParameter>) -> NativeResult<i64> {
let p = ptr.as_ref();
if let EffectParameter::Int(_, b) = p {
return *b;
NativeResult::ok(*b)
} else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p))
}
panic!("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>) -> f32 {
extern "C" fn effect_parameter_get_as_float(ptr: ExternPointer<EffectParameter>) -> NativeResult<f32> {
let p = ptr.as_ref();
if let EffectParameter::Float(_, b) = p {
return *b;
NativeResult::ok(*b)
} else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p))
}
panic!("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>) -> OwnedPtr<c_char> {
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 {
return CString::new(b.str().to_string()).unwrap().into_raw();
match CString::new(b.str().to_string()) {
Ok(cstr) => NativeResult::ok(cstr.into_raw()),
Err(_) => NativeResult::err(PkmnError::InvalidCString.into()),
}
} else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected string, was: {}", p))
}
panic!("Unexpected effect parameter. Expected string, was: {}", p);
}

View File

@@ -1,9 +1,10 @@
use crate::ffi::{ffi_arc_dyn_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::ffi::{ffi_arc_dyn_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr};
use crate::static_data::{
EffectParameter, MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffect, SecondaryEffectImpl,
TypeIdentifier,
};
use crate::StringKey;
use anyhow::anyhow;
use hashbrown::HashSet;
use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
@@ -23,12 +24,19 @@ unsafe extern "C" fn move_data_new(
secondary_effect: *mut Box<dyn SecondaryEffect>,
flags: *const *const c_char,
flags_length: usize,
) -> IdentifiablePointer<Arc<dyn MoveData>> {
) -> NativeResult<IdentifiablePointer<Arc<dyn MoveData>>> {
let flags = std::slice::from_raw_parts(flags, flags_length);
let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into();
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"),
};
let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length);
for flag in flags {
flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into());
let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag,
Err(_) => return NativeResult::err_from_str("Unable to convert flag to string"),
};
flags_set.insert(flag.into());
}
let secondary_effect = if secondary_effect.is_null() {
None
@@ -47,7 +55,7 @@ unsafe extern "C" fn move_data_new(
secondary_effect,
flags_set,
));
a.into()
NativeResult::ok(a.into())
}
/// Drops a reference counted move.
@@ -58,9 +66,12 @@ unsafe extern "C" fn move_data_drop(ptr: OwnedPtr<Arc<dyn MoveData>>) {
/// The name of the move.
#[no_mangle]
unsafe extern "C" fn move_data_name(ptr: ExternPointer<Arc<dyn MoveData>>) -> OwnedPtr<c_char> {
unsafe extern "C" fn move_data_name(ptr: ExternPointer<Arc<dyn MoveData>>) -> NativeResult<OwnedPtr<c_char>> {
let name = ptr.as_ref().name();
CString::new(name.str()).unwrap().into_raw()
match CString::new(name.str()) {
Ok(name) => NativeResult::ok(name.into_raw()),
Err(_) => NativeResult::err_from_str("Unable to convert name to string"),
}
}
ffi_arc_dyn_getter!(MoveData, move_type, TypeIdentifier);
@@ -122,8 +133,16 @@ unsafe extern "C" fn secondary_effect_chance(ptr: ExternPointer<Box<dyn Secondar
/// The name of the effect.
#[no_mangle]
unsafe extern "C" fn secondary_effect_effect_name(ptr: ExternPointer<Box<dyn SecondaryEffect>>) -> OwnedPtr<c_char> {
CString::new(ptr.as_ref().effect_name().str()).unwrap().into_raw()
unsafe extern "C" fn secondary_effect_effect_name(
ptr: ExternPointer<Box<dyn SecondaryEffect>>,
) -> NativeResult<OwnedPtr<c_char>> {
match CString::new(ptr.as_ref().effect_name().str()) {
Ok(name) => NativeResult::ok(name.into_raw()),
Err(_) => NativeResult::err(anyhow!(
"Unable to convert effect name '{}' to CString",
ptr.as_ref().effect_name()
)),
}
}
/// The length of parameters of the effect.

View File

@@ -1,8 +1,9 @@
use crate::ffi::{
ffi_arc_dyn_getter, ffi_arc_stringkey_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr,
ffi_arc_dyn_getter, ffi_arc_stringkey_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult,
OwnedPtr,
};
use crate::static_data::{Form, Gender, Species, SpeciesImpl};
use crate::{Random, StringKey};
use crate::{PkmnError, Random, StringKey};
use hashbrown::HashSet;
use std::ffi::{c_char, CStr};
use std::ptr::drop_in_place;
@@ -19,25 +20,40 @@ unsafe extern "C" fn species_new(
default_form: OwnedPtr<Arc<dyn Form>>,
flags: *const *const c_char,
flags_length: usize,
) -> IdentifiablePointer<Arc<dyn Species>> {
let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into();
let growth_rate: StringKey = CStr::from_ptr(growth_rate).to_str().unwrap().into();
) -> NativeResult<IdentifiablePointer<Arc<dyn Species>>> {
let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(name) => name.into(),
Err(_) => return NativeResult::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()),
};
let flags = std::slice::from_raw_parts(flags, flags_length);
let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length);
for flag in flags {
flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into());
let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag,
Err(_) => return NativeResult::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 a: Arc<dyn Species> = Arc::new(SpeciesImpl::new(
id,
&name,
gender_rate,
&growth_rate,
capture_rate,
default_form.as_ref().unwrap().clone(),
default_form.clone(),
flags_set,
));
a.into()
NativeResult::ok(a.into())
}
/// Drop a reference to the species.
@@ -58,9 +74,13 @@ unsafe extern "C" fn species_add_form(
mut species: ExternPointer<Arc<dyn Species>>,
name: BorrowedPtr<c_char>,
form: OwnedPtr<Arc<dyn Form>>,
) {
let form = form.as_ref().unwrap().clone();
species.as_mut().add_form(CStr::from_ptr(name).into(), form)
) -> NativeResult<()> {
let form = match form.as_ref() {
Some(form) => form.clone(),
None => return NativeResult::err(PkmnError::NullReference.into()),
};
species.as_mut().add_form(CStr::from_ptr(name).into(), form);
NativeResult::ok(())
}
/// Gets a form by name.