1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-19 21:08:07 +00:00

feat(core/rust): expose attrtuple to Rust

This commit is contained in:
matejcik 2024-02-06 10:57:12 +01:00 committed by Jiří Musil
parent 6af7b4a4b7
commit 02557ad6c0
3 changed files with 67 additions and 0 deletions

View File

@ -183,6 +183,7 @@ fn generate_micropython_bindings() {
.allowlist_function("mp_obj_new_bytes")
.allowlist_function("mp_obj_new_str")
.allowlist_function("mp_obj_new_tuple")
.allowlist_function("mp_obj_new_attrtuple")
.allowlist_function("mp_obj_get_int_maybe")
.allowlist_function("mp_obj_is_true")
.allowlist_function("mp_call_function_n_kw")

View File

@ -228,6 +228,39 @@ macro_rules! obj_module {
});
}
macro_rules! attr_tuple {
(@append
fields: [$($fields:expr,)*],
values: [$($values:expr,)*],
rest: {
$field:expr => $val:expr,
$($rest:tt)*
}
) => {
attr_tuple! {
@append
fields: [$($fields,)* $field,],
values: [$($values,)* $val,],
rest: {$($rest)*}
}
};
(@append
fields: [$($fields:expr,)*],
values: [$($values:expr,)*],
rest: {}
) => {
$crate::micropython::util::new_attrtuple(&[$($fields,)*], &[$($values,)*])
};
// version without trailing comma
($($key:expr => $val:expr),*) => ({
attr_tuple!(@append fields: [], values: [], rest: { $($key => $val,)* })
});
// version with trailing comma
($($key:expr => $val:expr,)*) => ({
attr_tuple!(@append fields: [], values: [], rest: { $($key => $val,)* })
});
}
/// Print arbitrary amounts of slices into a terminal.
/// Does not include a newline at the end.
/// Does not do anything when not in debugging mode.

View File

@ -7,6 +7,7 @@ use super::{
iter::IterBuf,
map::{Map, MapElem},
obj::Obj,
qstr::Qstr,
runtime::{catch_exception, raise_exception},
};
use crate::error::Error;
@ -92,6 +93,38 @@ pub fn new_tuple(args: &[Obj]) -> Result<Obj, Error> {
Ok(obj)
}
/// Create a new "attrtuple", which is essentially a namedtuple / ad-hoc object.
///
/// It is recommended to use the attr_tuple! macro instead of this function:
/// ```
/// let obj = attr_tuple! {
/// Qstr::MP_QSTR_language => header.language.try_into()?,
/// Qstr::MP_QSTR_version => util::new_tuple(&version_objs)?,
/// // ...
/// }
/// ```
pub fn new_attrtuple(field_qstrs: &'static [Qstr], values: &[Obj]) -> Result<Obj, Error> {
if field_qstrs.len() != values.len() {
return Err(Error::TypeError);
}
// SAFETY:
// * `values` are copied into the tuple, but the `fields` array is stored as a
// pointer in the last tuple item. Hence the requirement that `fields` is
// 'static. See objattrtuple.c:79
// * we cast `field_qstrs` to the required type `qstr`, which is internally
// usize. (py/qstr.h:48). This is valid for as long as Qstr is
// repr(transparent) and the only field is a usize. Check generated qstr.rs.
// EXCEPTION: Raises if allocation fails, does not return NULL.
let obj = catch_exception(|| unsafe {
ffi::mp_obj_new_attrtuple(
field_qstrs.as_ptr() as *const _,
values.len(),
values.as_ptr(),
)
})?;
Ok(obj)
}
pub fn iter_into_array<T, E, const N: usize>(iterable: Obj) -> Result<[T; N], Error>
where
T: TryFrom<Obj, Error = E>,