use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; use crate::ffi::{ 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::sync::Arc; /// Instantiates a new form. #[no_mangle] unsafe extern "C" fn form_new( name: *const c_char, height: f32, weight: f32, base_experience: u32, types: *const TypeIdentifier, types_length: usize, base_stats: FFIHandle>>, abilities: *const NonOwnedPtrString, abilities_length: usize, hidden_abilities: *const NonOwnedPtrString, hidden_abilities_length: usize, moves: FFIHandle>, flags: *const *const c_char, flags_length: usize, ) -> FFIResult>> { let name: StringKey = match CStr::from_ptr(name).to_str() { Ok(name) => name.into(), Err(_) => return FFIResult::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); for ability in abilities { abilities_vec.push(CStr::from_ptr(*ability).into()) } let hidden_abilities = std::slice::from_raw_parts(hidden_abilities, hidden_abilities_length); let mut hidden_abilities_vec = Vec::with_capacity(hidden_abilities_length); for ability in hidden_abilities { hidden_abilities_vec.push(CStr::from_ptr(*ability).into()) } let flags = std::slice::from_raw_parts(flags, flags_length); let mut flags_set: HashSet = HashSet::with_capacity(flags_length); for flag in flags { let flag = match CStr::from_ptr(*flag).to_str() { Ok(flag) => flag, Err(_) => return FFIResult::err(anyhow!("Unable to convert flag to string")), }; flags_set.insert(flag.into()); } let a: Arc = Arc::new(FormImpl::new( &name, height, weight, base_experience, std::slice::from_raw_parts(types, types_length).to_vec(), base_stats.from_ffi_handle(), abilities_vec, hidden_abilities_vec, moves.from_ffi_handle(), flags_set, )); FFIResult::ok(FFIHandle::get_handle(a.into())) } /// The name of the form. #[no_mangle] unsafe extern "C" fn form_name(ptr: FFIHandle>) -> FFIResult { let obj = ptr.from_ffi_handle(); let name = obj.name(); match CString::new(name.str()) { Ok(name) => FFIResult::ok(OwnedPtrString(name.into_raw())), Err(_) => FFIResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())), } } 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_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: FFIHandle>) -> FFIHandle>> { FFIHandle::get_handle(ptr.from_ffi_handle().base_stats().clone().into()) } 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: FFIHandle>) -> FFIHandle> { 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: FFIHandle>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); u8::from(ptr.from_ffi_handle().has_flag(&flag)) }