mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-18 05:28:40 +00:00
feat(core/rust): expose attrtuple to Rust
This commit is contained in:
parent
6af7b4a4b7
commit
02557ad6c0
@ -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")
|
||||
|
@ -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.
|
||||
|
@ -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>,
|
||||
|
Loading…
Reference in New Issue
Block a user