From 8bf5a728437ea7d8b271789db75e9c0ed6fa670b Mon Sep 17 00:00:00 2001 From: matejcik Date: Wed, 17 Jan 2024 15:40:19 +0100 Subject: [PATCH] refactor(core/rust): move iter_into_array to micropython::utils --- core/embed/rust/build.rs | 2 + core/embed/rust/src/micropython/ffi.rs | 1 + core/embed/rust/src/micropython/util.rs | 47 +++++++++++++++++++---- core/embed/rust/src/ui/layout/util.rs | 28 +------------- core/embed/rust/src/ui/model_tr/layout.rs | 14 +++---- core/embed/rust/src/ui/model_tt/layout.rs | 20 +++++----- 6 files changed, 61 insertions(+), 51 deletions(-) diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs index 8257d1082..cfacf306a 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -241,6 +241,8 @@ fn generate_micropython_bindings() { .allowlist_var("mp_type_module") // qstr .allowlist_function("qstr_data") + // tuple + .allowlist_type("mp_obj_tuple_t") // `ffi::mp_map_t` type is not allowed to be `Clone` or `Copy` because we tie it // to the data lifetimes with the `MapRef` type, see `src/micropython/map.rs`. // TODO: We should disable `Clone` and `Copy` for all types and only allow-list diff --git a/core/embed/rust/src/micropython/ffi.rs b/core/embed/rust/src/micropython/ffi.rs index 245a5fa89..6816addd5 100644 --- a/core/embed/rust/src/micropython/ffi.rs +++ b/core/embed/rust/src/micropython/ffi.rs @@ -2,5 +2,6 @@ #![allow(non_upper_case_globals)] #![allow(dead_code)] #![allow(clippy::unnecessary_cast)] +#![allow(unsafe_op_in_unsafe_fn)] include!(concat!(env!("OUT_DIR"), "/micropython.rs")); diff --git a/core/embed/rust/src/micropython/util.rs b/core/embed/rust/src/micropython/util.rs index 7a836d05b..168c34ca2 100644 --- a/core/embed/rust/src/micropython/util.rs +++ b/core/embed/rust/src/micropython/util.rs @@ -1,13 +1,15 @@ use core::slice; -use crate::{ - error::Error, - micropython::{ - map::{Map, MapElem}, - obj::Obj, - runtime::raise_exception, - }, +use heapless::Vec; + +use super::{ + ffi, + iter::IterBuf, + map::{Map, MapElem}, + obj::Obj, + runtime::{catch_exception, raise_exception}, }; +use crate::error::Error; /// Perform a call and convert errors into a raised MicroPython exception. /// Should only called when returning from Rust to C. See `raise_exception` for @@ -82,3 +84,34 @@ pub unsafe fn try_with_args_and_kwargs_inline( }; unsafe { try_or_raise(block) } } + +pub fn new_tuple(args: &[Obj]) -> Result { + // SAFETY: Safe. + // EXCEPTION: Raises if allocation fails, does not return NULL. + let obj = catch_exception(|| unsafe { ffi::mp_obj_new_tuple(args.len(), args.as_ptr()) })?; + Ok(obj) +} + +pub fn iter_into_array(iterable: Obj) -> Result<[T; N], Error> +where + T: TryFrom, + Error: From, +{ + let vec: Vec = iter_into_vec(iterable)?; + // Returns error if array.len() != N + vec.into_array() + .map_err(|_| value_error!("Invalid iterable length")) +} + +pub fn iter_into_vec(iterable: Obj) -> Result, Error> +where + T: TryFrom, + Error: From, +{ + let mut vec = Vec::::new(); + for item in IterBuf::new().try_iterate(iterable)? { + vec.push(item.try_into()?) + .map_err(|_| value_error!("Invalid iterable length"))?; + } + Ok(vec) +} diff --git a/core/embed/rust/src/ui/layout/util.rs b/core/embed/rust/src/ui/layout/util.rs index 7e0c06e7b..0b2f12a69 100644 --- a/core/embed/rust/src/ui/layout/util.rs +++ b/core/embed/rust/src/ui/layout/util.rs @@ -3,10 +3,9 @@ use crate::{ micropython::{ buffer::{hexlify_bytes, StrBuffer}, gc::Gc, - iter::IterBuf, list::List, obj::Obj, - util::try_or_raise, + util::{iter_into_array, try_or_raise}, }, storage::{get_avatar_len, load_avatar}, strutil::SkipPrefix, @@ -18,31 +17,6 @@ use crate::{ util::set_animation_disabled, }, }; -use heapless::Vec; - -pub fn iter_into_array(iterable: Obj) -> Result<[T; N], Error> -where - T: TryFrom, - Error: From, -{ - let vec: Vec = iter_into_vec(iterable)?; - // Returns error if array.len() != N - vec.into_array() - .map_err(|_| value_error!("Invalid iterable length")) -} - -pub fn iter_into_vec(iterable: Obj) -> Result, Error> -where - T: TryFrom, - Error: From, -{ - let mut vec = Vec::::new(); - for item in IterBuf::new().try_iterate(iterable)? { - vec.push(item.try_into()?) - .map_err(|_| value_error!("Invalid iterable length"))?; - } - Ok(vec) -} /// Maximum number of characters that can be displayed on screen at once. Used /// for on-the-fly conversion of binary data to hexadecimal representation. diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index e20fd2ba2..4dc3b36fd 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -38,7 +38,7 @@ use crate::{ layout::{ obj::{ComponentMsgObj, LayoutObj}, result::{CANCELLED, CONFIRMED, INFO}, - util::{iter_into_array, iter_into_vec, upy_disable_animation, ConfirmBlob}, + util::{upy_disable_animation, ConfirmBlob}, }, model_tr::component::check_homescreen_format, }, @@ -380,7 +380,7 @@ extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *m let mut paragraphs = ParagraphVecLong::new(); for para in IterBuf::new().try_iterate(items)? { - let [key, value, is_data]: [Obj; 3] = iter_into_array(para)?; + let [key, value, is_data]: [Obj; 3] = util::iter_into_array(para)?; let key = key.try_into_option::()?; let value = value.try_into_option::()?; let is_data: bool = is_data.try_into()?; @@ -506,7 +506,7 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: let mut ad = AddressDetails::new(address, case_sensitive, account, path)?; for i in IterBuf::new().try_iterate(xpubs)? { - let [xtitle, text]: [StrBuffer; 2] = iter_into_array(i)?; + let [xtitle, text]: [StrBuffer; 2] = util::iter_into_array(i)?; ad.add_xpub(xtitle, text)?; } @@ -796,7 +796,7 @@ extern "C" fn new_altcoin_tx_summary(n_args: usize, args: *const Obj, kwargs: *m let mut ops = OpTextLayout::new(theme::TEXT_MONO); for item in unwrap!(IterBuf::new().try_iterate(items)) { - let [key, value]: [Obj; 2] = unwrap!(iter_into_array(item)); + let [key, value]: [Obj; 2] = unwrap!(util::iter_into_array(item)); if !ops.is_empty() { // Each key-value pair is on its own page ops = ops.next_page(); @@ -1247,7 +1247,7 @@ extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mu let mut paragraphs = ParagraphVecShort::new(); for para in IterBuf::new().try_iterate(items)? { - let [font, text]: [Obj; 2] = iter_into_array(para)?; + let [font, text]: [Obj; 2] = util::iter_into_array(para)?; let style: &TextStyle = theme::textstyle_number(font.try_into()?); let text: StrBuffer = text.try_into()?; paragraphs.add(Paragraph::new(style, text)); @@ -1278,7 +1278,7 @@ extern "C" fn new_confirm_more(n_args: usize, args: *const Obj, kwargs: *mut Map let mut paragraphs = ParagraphVecLong::new(); for para in IterBuf::new().try_iterate(items)? { - let [font, text]: [Obj; 2] = iter_into_array(para)?; + let [font, text]: [Obj; 2] = util::iter_into_array(para)?; let style: &TextStyle = theme::textstyle_number(font.try_into()?); let text: StrBuffer = text.try_into()?; paragraphs.add(Paragraph::new(style, text)); @@ -1527,7 +1527,7 @@ extern "C" fn new_show_group_share_success( ) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let lines_iterable: Obj = kwargs.get(Qstr::MP_QSTR_lines)?; - let lines: [StrBuffer; 4] = iter_into_array(lines_iterable)?; + let lines: [StrBuffer; 4] = util::iter_into_array(lines_iterable)?; let [l0, l1, l2, l3] = lines; diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index 6590b476f..c995640fe 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -39,7 +39,7 @@ use crate::{ layout::{ obj::{ComponentMsgObj, LayoutObj}, result::{CANCELLED, CONFIRMED, INFO}, - util::{iter_into_array, upy_disable_animation, ConfirmBlob, PropsList}, + util::{upy_disable_animation, ConfirmBlob, PropsList}, }, model_tt::component::check_homescreen_format, }, @@ -430,7 +430,7 @@ extern "C" fn new_confirm_emphasized(n_args: usize, args: *const Obj, kwargs: *m if item.is_str() { ops = ops.text_normal(item.try_into()?) } else { - let [emphasis, text]: [Obj; 2] = iter_into_array(item)?; + let [emphasis, text]: [Obj; 2] = util::iter_into_array(item)?; let text: StrBuffer = text.try_into()?; if emphasis.try_into()? { ops = ops.text_demibold(text); @@ -721,7 +721,7 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: )?; for i in IterBuf::new().try_iterate(xpubs)? { - let [xtitle, text]: [StrBuffer; 2] = iter_into_array(i)?; + let [xtitle, text]: [StrBuffer; 2] = util::iter_into_array(i)?; ad.add_xpub(xtitle, text)?; } @@ -741,7 +741,7 @@ extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs: let mut paragraphs = ParagraphVecShort::new(); for para in IterBuf::new().try_iterate(items)? { - let [key, value]: [Obj; 2] = iter_into_array(para)?; + let [key, value]: [Obj; 2] = util::iter_into_array(para)?; let key: StrBuffer = key.try_into()?; let value: StrBuffer = value.try_into()?; paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, key).no_break()); @@ -806,7 +806,7 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma let mut paragraphs = ParagraphVecShort::new(); for pair in IterBuf::new().try_iterate(items)? { - let [label, value]: [StrBuffer; 2] = iter_into_array(pair)?; + let [label, value]: [StrBuffer; 2] = util::iter_into_array(pair)?; paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, label).no_break()); paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value)); } @@ -1165,7 +1165,7 @@ extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mu let mut paragraphs = ParagraphVecShort::new(); for para in IterBuf::new().try_iterate(items)? { - let [font, text]: [Obj; 2] = iter_into_array(para)?; + let [font, text]: [Obj; 2] = util::iter_into_array(para)?; let style: &TextStyle = theme::textstyle_number(font.try_into()?); let text: StrBuffer = text.try_into()?; paragraphs.add(Paragraph::new(style, text)); @@ -1195,7 +1195,7 @@ extern "C" fn new_confirm_more(n_args: usize, args: *const Obj, kwargs: *mut Map let mut paragraphs = ParagraphVecLong::new(); for para in IterBuf::new().try_iterate(items)? { - let [font, text]: [Obj; 2] = iter_into_array(para)?; + let [font, text]: [Obj; 2] = util::iter_into_array(para)?; let style: &TextStyle = theme::textstyle_number(font.try_into()?); let text: StrBuffer = text.try_into()?; paragraphs.add(Paragraph::new(style, text)); @@ -1290,7 +1290,7 @@ extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map) let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let description: StrBuffer = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?; - let words: [StrBuffer; 3] = iter_into_array(words_iterable)?; + let words: [StrBuffer; 3] = util::iter_into_array(words_iterable)?; let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_DEMIBOLD, description)]); let obj = LayoutObj::new(Frame::left_aligned( @@ -1472,7 +1472,7 @@ extern "C" fn new_show_group_share_success( ) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let lines_iterable: Obj = kwargs.get(Qstr::MP_QSTR_lines)?; - let lines: [StrBuffer; 4] = iter_into_array(lines_iterable)?; + let lines: [StrBuffer; 4] = util::iter_into_array(lines_iterable)?; let obj = LayoutObj::new(IconDialog::new_shares( lines, @@ -1493,7 +1493,7 @@ extern "C" fn new_show_remaining_shares(n_args: usize, args: *const Obj, kwargs: let mut paragraphs = ParagraphVecLong::new(); for page in IterBuf::new().try_iterate(pages_iterable)? { - let [title, description]: [StrBuffer; 2] = iter_into_array(page)?; + let [title, description]: [StrBuffer; 2] = util::iter_into_array(page)?; paragraphs .add(Paragraph::new(&theme::TEXT_DEMIBOLD, title)) .add(Paragraph::new(&theme::TEXT_NORMAL, description).break_after());