1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-20 14:39:22 +00:00

feat(core/rust): List::from_iter

[no changelog]
This commit is contained in:
matejcik 2022-04-20 16:52:10 +02:00 committed by matejcik
parent b3b3e0efa4
commit 187ca8ad50
2 changed files with 56 additions and 1 deletions

View File

@ -95,6 +95,7 @@ fn generate_micropython_bindings() {
.allowlist_type("mp_obj_list_t")
.allowlist_function("mp_obj_new_list")
.allowlist_function("mp_obj_list_append")
.allowlist_function("mp_obj_list_set_len")
.allowlist_var("mp_type_list")
// map
.allowlist_type("mp_map_elem_t")

View File

@ -1,4 +1,4 @@
use core::convert::TryFrom;
use core::{convert::TryFrom, ptr};
use crate::error::Error;
@ -17,6 +17,31 @@ impl List {
})
}
pub fn with_capacity(capacity: usize) -> Result<Gc<Self>, Error> {
// EXCEPTION: Will raise if allocation fails.
catch_exception(|| unsafe {
let list = ffi::mp_obj_new_list(capacity, ptr::null_mut());
// By default, the new list will have its len set to n. We want to preallocate
// to a specific size and then use append() to add items, so we reset len to 0.
ffi::mp_obj_list_set_len(list, 0);
Gc::from_raw(list.as_ptr().cast())
})
}
pub fn from_iter<T, E>(iter: impl Iterator<Item = T>) -> Result<Gc<List>, Error>
where
T: TryInto<Obj, Error = E>,
Error: From<E>,
{
let max_size = iter.size_hint().1.unwrap_or(0);
let mut gc_list = List::with_capacity(max_size)?;
let list = unsafe { Gc::as_mut(&mut gc_list) };
for value in iter {
list.append(value.try_into()?)?;
}
Ok(gc_list)
}
pub fn append(&mut self, value: Obj) -> Result<(), Error> {
unsafe {
let ptr = self as *mut Self;
@ -52,3 +77,32 @@ impl TryFrom<Obj> for Gc<List> {
}
}
}
#[cfg(test)]
mod tests {
use crate::micropython::{
iter::{Iter, IterBuf},
testutil::mpy_init,
};
use super::*;
use heapless::Vec;
#[test]
fn list_from_iter() {
unsafe { mpy_init() };
// create an upy list of 5 elements
let vec: Vec<u8, 10> = (0..5).collect();
let list: Obj = List::from_iter(vec.iter().copied()).unwrap().into();
let mut buf = IterBuf::new();
let iter = Iter::try_from_obj_with_buf(list, &mut buf).unwrap();
// collect the elements into a Vec of maximum length 10, through an iterator
let retrieved_vec: Vec<u8, 10> = iter
.map(TryInto::try_into)
.collect::<Result<Vec<u8, 10>, Error>>()
.unwrap();
assert_eq!(vec, retrieved_vec);
}
}