From b91e2250765c047f2e08eca0625478db3f11bf83 Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 20 Jun 2023 11:51:40 +0200 Subject: [PATCH] refactor(core/rust): expose obj types and (debug only) type names --- core/embed/rust/build.rs | 2 ++ core/embed/rust/src/micropython/obj.rs | 17 +++++++++++++++++ core/embed/rust/src/micropython/qstr.rs | 19 +++++++++++++++++-- core/embed/rust/src/micropython/typ.rs | 19 ++++++++++--------- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs index 09cfa1643c..130bc7cbd9 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -222,6 +222,8 @@ fn generate_micropython_bindings() { // module .allowlist_type("mp_obj_module_t") .allowlist_var("mp_type_module") + // qstr + .allowlist_function("qstr_data") // `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/obj.rs b/core/embed/rust/src/micropython/obj.rs index 76039834e9..d8749b4ff7 100644 --- a/core/embed/rust/src/micropython/obj.rs +++ b/core/embed/rust/src/micropython/obj.rs @@ -441,4 +441,21 @@ impl Obj { let is_type_str = unsafe { ffi::mp_type_str.is_type_of(self) }; is_type_str || self.is_qstr() } + + pub fn type_<'a>(self) -> Option<&'a super::typ::Type> { + if self.is_ptr() { + // SAFETY: + // Safe for pointers, for as long as MicroPython behaves sanely. + // We assume that: + // * The pointer is a valid MicroPython object, which has `ObjBase` + // as its first element. + // * The type pointer points to a valid type object. + // * The pointee has a 'static lifetime, i.e., either is + // ROM-based, or GC allocated. + let base = self.as_ptr() as *const ObjBase; + unsafe { (*base).type_.as_ref() } + } else { + None + } + } } diff --git a/core/embed/rust/src/micropython/qstr.rs b/core/embed/rust/src/micropython/qstr.rs index 0eda8d33f1..41cc741adb 100644 --- a/core/embed/rust/src/micropython/qstr.rs +++ b/core/embed/rust/src/micropython/qstr.rs @@ -2,9 +2,11 @@ #![allow(non_upper_case_globals)] #![allow(dead_code)] -use core::convert::TryFrom; +use core::{convert::TryFrom, slice, str::from_utf8}; -use crate::{error::Error, micropython::obj::Obj}; +use crate::error::Error; + +use super::{ffi, obj::Obj}; impl Qstr { pub const fn to_obj(self) -> Obj { @@ -30,6 +32,19 @@ impl Qstr { // TODO: Change the internal representation of Qstr to u16. Self(val as _) } + + pub fn as_str(self) -> &'static str { + let mut len = 0usize; + let slice = unsafe { + // SAFETY: qstr_data should always return a valid string, even for unknown ids. + let ptr = ffi::qstr_data(self.0 as _, &mut len as *mut _); + slice::from_raw_parts(ptr, len) + }; + // SAFETY: Qstr pools are either ROM-based or permanently allocated in the GC + // arena. The MicroPython runtime holds the respective head pointers so we don't + // need to care. + unwrap!(from_utf8(slice)) + } } impl From for Qstr { diff --git a/core/embed/rust/src/micropython/typ.rs b/core/embed/rust/src/micropython/typ.rs index 700cf71a50..0647ab3714 100644 --- a/core/embed/rust/src/micropython/typ.rs +++ b/core/embed/rust/src/micropython/typ.rs @@ -7,21 +7,22 @@ pub type Type = ffi::mp_obj_type_t; impl Type { pub fn is_type_of(&'static self, obj: Obj) -> bool { - if obj.is_ptr() { - // SAFETY: If `obj` is a pointer, it should always point to an object having - // `ObjBase` as the first field, making this cast safe. - unsafe { - let base = obj.as_ptr() as *const ObjBase; - (*base).type_ == self - } - } else { - false + match obj.type_() { + Some(type_) => core::ptr::eq(type_, self), + None => false, } } pub const fn as_base(&'static self) -> ObjBase { ObjBase { type_: self } } + + #[cfg(feature = "debug")] + pub fn name(&self) -> &'static str { + use super::qstr::Qstr; + + Qstr::from(self.name).as_str() + } } // SAFETY: We are in a single-threaded environment.