diff --git a/crates/byondapi-rs-test/dm_project/dm_project.dme b/crates/byondapi-rs-test/dm_project/dm_project.dme index 6b2ac65..3177d19 100644 --- a/crates/byondapi-rs-test/dm_project/dm_project.dme +++ b/crates/byondapi-rs-test/dm_project/dm_project.dme @@ -34,7 +34,6 @@ /test/proc/test_ref() var/turf/T = locate(1,1,1) var/ret = call_ext("byondapi_test.dll", "byond:test_ref")(T) - world.log << ret /test/proc/test_ptr() var/x = "meow" @@ -127,6 +126,11 @@ if(ret != 7) throw EXCEPTION("str length failed [json_encode(ret)]") +/test/proc/test_list_non_assoc() + var/list/L = list("cat", "dog", "parrot") + + call_ext("byondapi_test.dll", "byond:test_non_assoc_list")(L) + /test/proc/test_list_key_lookup() var/list/L = list("cat" = 7, "dog" = 5, "parrot" = 4) diff --git a/crates/byondapi-rs-test/src/lib.rs b/crates/byondapi-rs-test/src/lib.rs index db991ca..57c0d92 100644 --- a/crates/byondapi-rs-test/src/lib.rs +++ b/crates/byondapi-rs-test/src/lib.rs @@ -260,7 +260,7 @@ pub unsafe extern "C" fn test_list_key_lookup( argv: *mut ByondValue, ) -> ByondValue { setup_panic_handler(); - let mut args = parse_args(argc, argv); + let args = parse_args(argc, argv); let list = args.get_mut(0).unwrap(); @@ -293,12 +293,7 @@ pub unsafe extern "C" fn test_list_key_lookup( let map = list .iter() .unwrap() - .map(|(k, v)| { - ( - k.get_string().unwrap(), - v.unwrap().get_number().unwrap() as u32, - ) - }) + .map(|(k, v)| (k.get_string().unwrap(), v.get_number().unwrap() as u32)) .collect::>(); assert_eq!( @@ -324,3 +319,31 @@ pub unsafe extern "C" fn test_ref(argc: byondapi_sys::u4c, argv: *mut ByondValue ByondValue::try_from(format!("turf_id: {turf_id}, turf_type: {turf_type}")).unwrap() } + +#[no_mangle] +pub unsafe extern "C" fn test_non_assoc_list( + argc: byondapi_sys::u4c, + argv: *mut ByondValue, +) -> ByondValue { + setup_panic_handler(); + let args = parse_args(argc, argv); + let list = args.get(0).unwrap(); + + let map = list + .iter() + .unwrap() + .map(|(k, v)| { + if !v.is_null() { + panic!("value is not null") + } + k.get_string().unwrap() + }) + .collect::>(); + + assert_eq!( + map, + vec!["cat".to_owned(), "dog".to_owned(), "parrot".to_owned()] + ); + + ByondValue::new() +} diff --git a/crates/byondapi-rs/src/lib.rs b/crates/byondapi-rs/src/lib.rs index 3b630c6..7c6868f 100644 --- a/crates/byondapi-rs/src/lib.rs +++ b/crates/byondapi-rs/src/lib.rs @@ -15,8 +15,11 @@ use crate::value::ByondValue; /// # Safety /// Don't pass in a null argv pointer please god /// Just give this what BYOND gives you and pray for the best -pub unsafe fn parse_args(argc: byondapi_sys::u4c, argv: *mut ByondValue) -> Vec { - unsafe { std::slice::from_raw_parts_mut(argv, argc as usize).to_vec() } +pub unsafe fn parse_args( + argc: byondapi_sys::u4c, + argv: *mut ByondValue, +) -> &'static mut [ByondValue] { + unsafe { std::slice::from_raw_parts_mut(argv, argc as usize) } } /// Re-export of byondapi_sys for all low level things you may run into. diff --git a/crates/byondapi-rs/src/value/functions.rs b/crates/byondapi-rs/src/value/functions.rs index 726a446..3062158 100644 --- a/crates/byondapi-rs/src/value/functions.rs +++ b/crates/byondapi-rs/src/value/functions.rs @@ -3,7 +3,7 @@ use std::ffi::CString; use byondapi_sys::{u4c, ByondValueType, CByondValue}; use super::ByondValue; -use crate::{static_global::byond, typecheck_trait::ByondTypeCheck, Error}; +use crate::{map::byond_length, static_global::byond, typecheck_trait::ByondTypeCheck, Error}; /// # Compatibility with the C++ API impl ByondValue { @@ -199,17 +199,17 @@ impl ByondValue { self.read_var(name)?.try_into() } - /// Iterates through the assoc values of the list if this value is a list, if the value isn't a list then the iterator will be empty. + /// Iterates through the assoc values of the list if this value is a list, if the value isn't a list then it returns an error. /// Non assoc lists will have the second field of the tuple be None always, and the value in the first field /// (key, value) for proper assoc lists - pub fn iter( - &self, - ) -> Result)> + '_, Error> { + pub fn iter(&self) -> Result + '_, Error> { if !self.is_list() { return Err(Error::NotAList); } + let len: f32 = byond_length(self)?.try_into()?; Ok(ListIterator { value: self, + len: len as u32, ctr: 1, }) } @@ -217,17 +217,25 @@ impl ByondValue { struct ListIterator<'a> { value: &'a ByondValue, + len: u32, ctr: u32, } impl<'a> Iterator for ListIterator<'a> { - type Item = (ByondValue, Option); + type Item = (ByondValue, ByondValue); fn next(&mut self) -> Option { - let key = self - .value - .read_list_index_internal(&ByondValue::from(self.ctr as f32)) - .ok()?; - let value = self.value.read_list_index_internal(&key).ok(); - self.ctr += 1; - return Some((key, value)); + if self.ctr <= self.len { + let key = self + .value + .read_list_index_internal(&ByondValue::from(self.ctr as f32)) + .ok()?; + let value = self.value.read_list_index_internal(&key).ok()?; + self.ctr += 1; + Some((key, value)) + } else { + None + } + } + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.len as usize)) } }