1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-08-04 04:48:48 +00:00

refactor(core/rust): unify String usage

This commit is contained in:
matejcik 2024-06-13 15:51:10 +02:00 committed by matejcik
parent da37bce59d
commit 8e52081d8a
13 changed files with 58 additions and 68 deletions

View File

@ -1,4 +1,7 @@
use crate::ui::{component::EventCtx, util::ResultExt}; use crate::{
strutil::ShortString,
ui::{component::EventCtx, util::ResultExt},
};
use heapless::String; use heapless::String;
/// Reified editing operations of `TextBox`. /// Reified editing operations of `TextBox`.
@ -13,19 +16,20 @@ pub enum TextEdit {
/// Wraps a character buffer of maximum length `L` and provides text editing /// Wraps a character buffer of maximum length `L` and provides text editing
/// operations over it. Text ops usually take a `EventCtx` to request a paint /// operations over it. Text ops usually take a `EventCtx` to request a paint
/// pass in case of any state modification. /// pass in case of any state modification.
pub struct TextBox<const L: usize> { pub struct TextBox {
text: String<L>, text: ShortString,
} }
impl<const L: usize> TextBox<L> { impl TextBox {
/// Create a new `TextBox` with content `text`. /// Create a new `TextBox` with content `text`.
pub fn new(text: String<L>) -> Self { pub fn new(text: &str) -> Self {
let text = unwrap!(String::try_from(text));
Self { text } Self { text }
} }
/// Create an empty `TextBox`. /// Create an empty `TextBox`.
pub fn empty() -> Self { pub fn empty() -> Self {
Self::new(String::new()) Self::new("")
} }
pub fn content(&self) -> &str { pub fn content(&self) -> &str {
@ -40,10 +44,6 @@ impl<const L: usize> TextBox<L> {
self.text.is_empty() self.text.is_empty()
} }
pub fn is_full(&self) -> bool {
self.text.len() == self.text.capacity()
}
/// Delete the last character of content, if any. /// Delete the last character of content, if any.
pub fn delete_last(&mut self, ctx: &mut EventCtx) { pub fn delete_last(&mut self, ctx: &mut EventCtx) {
let changed = self.text.pop().is_some(); let changed = self.text.pop().is_some();
@ -107,7 +107,7 @@ impl<const L: usize> TextBox<L> {
// DEBUG-ONLY SECTION BELOW // DEBUG-ONLY SECTION BELOW
#[cfg(feature = "ui_debug")] #[cfg(feature = "ui_debug")]
impl<const L: usize> crate::trace::Trace for TextBox<L> { impl crate::trace::Trace for TextBox {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("TextBox"); t.component("TextBox");
t.string("text", self.text.as_str().into()); t.string("text", self.text.as_str().into());

View File

@ -18,7 +18,6 @@ use crate::{
shape::Renderer, shape::Renderer,
}, },
}; };
use heapless::String;
const MAX_LENGTH: usize = 8; const MAX_LENGTH: usize = 8;
@ -26,7 +25,7 @@ pub struct Bip39Input {
button: Button, button: Button,
// used only to keep track of suggestion text color // used only to keep track of suggestion text color
button_suggestion: Button, button_suggestion: Button,
textbox: TextBox<MAX_LENGTH>, textbox: TextBox,
multi_tap: MultiTapKeyboard, multi_tap: MultiTapKeyboard,
options_num: Option<usize>, options_num: Option<usize>,
suggested_word: Option<&'static str>, suggested_word: Option<&'static str>,
@ -194,7 +193,7 @@ impl Bip39Input {
// Styling the input to reflect already filled word // Styling the input to reflect already filled word
Self { Self {
button: Button::empty().styled(theme::button_recovery_confirm()), button: Button::empty().styled(theme::button_recovery_confirm()),
textbox: TextBox::new(unwrap!(String::try_from(word))), textbox: TextBox::new(word),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
options_num: bip39::options_num(word), options_num: bip39::options_num(word),
suggested_word: bip39::complete_word(word), suggested_word: bip39::complete_word(word),

View File

@ -236,7 +236,7 @@ impl PassphraseKeyboard {
/// We should disable the input when the passphrase has reached maximum /// We should disable the input when the passphrase has reached maximum
/// length and we are not cycling through the characters. /// length and we are not cycling through the characters.
fn is_button_active(&self, key: usize) -> bool { fn is_button_active(&self, key: usize) -> bool {
let textbox_not_full = !self.input.inner().textbox.is_full(); let textbox_not_full = self.input.inner().textbox.len() < MAX_LENGTH;
let key_is_pending = { let key_is_pending = {
if let Some(pending) = self.input.inner().multi_tap.pending_key() { if let Some(pending) = self.input.inner().multi_tap.pending_key() {
pending == key pending == key
@ -406,7 +406,7 @@ impl Component for PassphraseKeyboard {
struct Input { struct Input {
area: Rect, area: Rect,
textbox: TextBox<MAX_LENGTH>, textbox: TextBox,
multi_tap: MultiTapKeyboard, multi_tap: MultiTapKeyboard,
} }

View File

@ -2,7 +2,7 @@ use core::mem;
use heapless::String; use heapless::String;
use crate::{ use crate::{
strutil::TString, strutil::{ShortString, TString},
time::Duration, time::Duration,
trezorhal::random, trezorhal::random,
ui::{ ui::{
@ -14,11 +14,10 @@ use crate::{
event::TouchEvent, event::TouchEvent,
geometry::{Alignment, Alignment2D, Grid, Insets, Offset, Rect}, geometry::{Alignment, Alignment2D, Grid, Insets, Offset, Rect},
model_mercury::component::{ model_mercury::component::{
button::{Button, ButtonContent, ButtonMsg, ButtonMsg::Clicked}, button::{Button, ButtonContent, ButtonMsg::{self, Clicked}},
theme, theme,
}, },
shape, shape::{self, Renderer},
shape::Renderer,
}, },
}; };
@ -278,7 +277,7 @@ struct PinDots {
area: Rect, area: Rect,
pad: Pad, pad: Pad,
style: TextStyle, style: TextStyle,
digits: String<MAX_LENGTH>, digits: ShortString,
display_digits: bool, display_digits: bool,
} }
@ -309,7 +308,7 @@ impl PinDots {
} }
fn is_full(&self) -> bool { fn is_full(&self) -> bool {
self.digits.len() == self.digits.capacity() self.digits.len() >= MAX_LENGTH
} }
fn clear(&mut self, ctx: &mut EventCtx) { fn clear(&mut self, ctx: &mut EventCtx) {
@ -455,7 +454,7 @@ impl crate::trace::Trace for PinKeyboard<'_> {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("PinKeyboard"); t.component("PinKeyboard");
// So that debuglink knows the locations of the buttons // So that debuglink knows the locations of the buttons
let mut digits_order: String<10> = String::new(); let mut digits_order = ShortString::new();
for btn in self.digit_btns.iter() { for btn in self.digit_btns.iter() {
let btn_content = btn.inner().content(); let btn_content = btn.inner().content();
if let ButtonContent::Text(text) = btn_content { if let ButtonContent::Text(text) = btn_content {

View File

@ -3,8 +3,7 @@ use core::iter;
use heapless::String; use heapless::String;
use crate::{ use crate::{
trezorhal::slip39, strutil::ShortString, trezorhal::slip39, ui::{
ui::{
component::{ component::{
text::common::{TextBox, TextEdit}, text::common::{TextBox, TextEdit},
Component, Event, EventCtx, Component, Event, EventCtx,
@ -21,17 +20,16 @@ use crate::{
}, },
theme, theme,
}, },
shape, shape::{self, Renderer},
shape::Renderer,
util::ResultExt, util::ResultExt,
}, }
}; };
const MAX_LENGTH: usize = 8; const MAX_LENGTH: usize = 8;
pub struct Slip39Input { pub struct Slip39Input {
button: Button, button: Button,
textbox: TextBox<MAX_LENGTH>, textbox: TextBox,
multi_tap: MultiTapKeyboard, multi_tap: MultiTapKeyboard,
final_word: Option<&'static str>, final_word: Option<&'static str>,
input_mask: Slip39Mask, input_mask: Slip39Mask,
@ -137,7 +135,7 @@ impl Component for Slip39Input {
// To simplify things, we always copy the printed string here, even if it // To simplify things, we always copy the printed string here, even if it
// wouldn't be strictly necessary. // wouldn't be strictly necessary.
let mut text: String<MAX_LENGTH> = String::new(); let mut text = ShortString::new();
if let Some(word) = self.final_word { if let Some(word) = self.final_word {
// We're done with input, paint the full word. // We're done with input, paint the full word.
text.push_str(word) text.push_str(word)
@ -222,7 +220,7 @@ impl Slip39Input {
Self { Self {
// Button has the same style the whole time // Button has the same style the whole time
button: Button::empty().styled(theme::button_recovery_confirm()), button: Button::empty().styled(theme::button_recovery_confirm()),
textbox: TextBox::new(buff), textbox: TextBox::new(&buff),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
final_word, final_word,
input_mask, input_mask,
@ -231,8 +229,8 @@ impl Slip39Input {
fn setup_from_prefilled_word( fn setup_from_prefilled_word(
word: &str, word: &str,
) -> (String<MAX_LENGTH>, Slip39Mask, Option<&'static str>) { ) -> (ShortString, Slip39Mask, Option<&'static str>) {
let mut buff: String<MAX_LENGTH> = String::new(); let mut buff = ShortString::new();
// Gradually appending encoded key digits to the buffer and checking if // Gradually appending encoded key digits to the buffer and checking if
// have not already formed a final word. // have not already formed a final word.

View File

@ -1,14 +1,12 @@
use crate::{ use crate::{
translations::TR, strutil::ShortString, translations::TR, ui::{
ui::{
component::{Component, Event, EventCtx}, component::{Component, Event, EventCtx},
geometry::Rect, geometry::Rect,
shape::Renderer, shape::Renderer,
}, }
}; };
use super::super::{ButtonLayout, ChoiceFactory, ChoiceItem, ChoicePage}; use super::super::{ButtonLayout, ChoiceFactory, ChoiceItem, ChoicePage};
use heapless::String;
struct ChoiceFactoryNumberInput { struct ChoiceFactoryNumberInput {
min: u32, min: u32,
@ -31,7 +29,7 @@ impl ChoiceFactory for ChoiceFactoryNumberInput {
fn get(&self, choice_index: usize) -> (Self::Item, Self::Action) { fn get(&self, choice_index: usize) -> (Self::Item, Self::Action) {
let num = self.min + choice_index as u32; let num = self.min + choice_index as u32;
let text: String<10> = unwrap!(String::try_from(num)); let text = unwrap!(ShortString::try_from(num));
let mut choice_item = ChoiceItem::new( let mut choice_item = ChoiceItem::new(
text, text,
ButtonLayout::arrow_armed_arrow(TR::buttons__select.into()), ButtonLayout::arrow_armed_arrow(TR::buttons__select.into()),

View File

@ -273,7 +273,7 @@ pub struct PassphraseEntry {
passphrase_dots: Child<ChangingTextLine>, passphrase_dots: Child<ChangingTextLine>,
show_plain_passphrase: bool, show_plain_passphrase: bool,
show_last_digit: bool, show_last_digit: bool,
textbox: TextBox<MAX_PASSPHRASE_LENGTH>, textbox: TextBox,
current_category: ChoiceCategory, current_category: ChoiceCategory,
} }
@ -355,7 +355,7 @@ impl PassphraseEntry {
} }
fn is_full(&self) -> bool { fn is_full(&self) -> bool {
self.textbox.is_full() self.textbox.len() >= MAX_PASSPHRASE_LENGTH
} }
/// Randomly choose an index in the current category /// Randomly choose an index in the current category

View File

@ -140,7 +140,7 @@ pub struct PinEntry<'a> {
showing_real_prompt: bool, showing_real_prompt: bool,
show_real_pin: bool, show_real_pin: bool,
show_last_digit: bool, show_last_digit: bool,
textbox: TextBox<MAX_PIN_LENGTH>, textbox: TextBox,
} }
impl<'a> PinEntry<'a> { impl<'a> PinEntry<'a> {
@ -236,7 +236,7 @@ impl<'a> PinEntry<'a> {
} }
fn is_full(&self) -> bool { fn is_full(&self) -> bool {
self.textbox.is_full() self.textbox.len() >= MAX_PIN_LENGTH
} }
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {

View File

@ -158,7 +158,7 @@ impl ChoiceFactory for ChoiceFactoryWordlist {
pub struct WordlistEntry { pub struct WordlistEntry {
choice_page: ChoicePage<ChoiceFactoryWordlist, WordlistAction>, choice_page: ChoicePage<ChoiceFactoryWordlist, WordlistAction>,
chosen_letters: Child<ChangingTextLine>, chosen_letters: Child<ChangingTextLine>,
textbox: TextBox<MAX_WORD_LENGTH>, textbox: TextBox,
offer_words: bool, offer_words: bool,
wordlist_type: WordlistType, wordlist_type: WordlistType,
/// Whether going back is allowed (is not on the very first word). /// Whether going back is allowed (is not on the very first word).
@ -196,7 +196,7 @@ impl WordlistEntry {
.with_incomplete(true) .with_incomplete(true)
.with_initial_page_counter(1), .with_initial_page_counter(1),
chosen_letters: Child::new(ChangingTextLine::center_mono(word, LINE_CAPACITY)), chosen_letters: Child::new(ChangingTextLine::center_mono(word, LINE_CAPACITY)),
textbox: TextBox::new(unwrap!(String::try_from(word))), textbox: TextBox::new(word),
offer_words: false, offer_words: false,
wordlist_type, wordlist_type,
can_go_back, can_go_back,

View File

@ -18,7 +18,6 @@ use crate::{
shape::Renderer, shape::Renderer,
}, },
}; };
use heapless::String;
const MAX_LENGTH: usize = 8; const MAX_LENGTH: usize = 8;
@ -26,7 +25,7 @@ pub struct Bip39Input {
button: Button, button: Button,
// used only to keep track of suggestion text color // used only to keep track of suggestion text color
button_suggestion: Button, button_suggestion: Button,
textbox: TextBox<MAX_LENGTH>, textbox: TextBox,
multi_tap: MultiTapKeyboard, multi_tap: MultiTapKeyboard,
options_num: Option<usize>, options_num: Option<usize>,
suggested_word: Option<&'static str>, suggested_word: Option<&'static str>,
@ -228,7 +227,7 @@ impl Bip39Input {
// Styling the input to reflect already filled word // Styling the input to reflect already filled word
Self { Self {
button: Button::with_icon(theme::ICON_LIST_CHECK).styled(theme::button_pin_confirm()), button: Button::with_icon(theme::ICON_LIST_CHECK).styled(theme::button_pin_confirm()),
textbox: TextBox::new(unwrap!(String::try_from(word))), textbox: TextBox::new(word),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
options_num: bip39::options_num(word), options_num: bip39::options_num(word),
suggested_word: bip39::complete_word(word), suggested_word: bip39::complete_word(word),

View File

@ -163,7 +163,7 @@ impl PassphraseKeyboard {
/// We should disable the input when the passphrase has reached maximum /// We should disable the input when the passphrase has reached maximum
/// length and we are not cycling through the characters. /// length and we are not cycling through the characters.
fn is_button_active(&self, key: usize) -> bool { fn is_button_active(&self, key: usize) -> bool {
let textbox_not_full = !self.input.inner().textbox.is_full(); let textbox_not_full = self.input.inner().textbox.len() < MAX_LENGTH;
let key_is_pending = { let key_is_pending = {
if let Some(pending) = self.input.inner().multi_tap.pending_key() { if let Some(pending) = self.input.inner().multi_tap.pending_key() {
pending == key pending == key
@ -329,7 +329,7 @@ impl Component for PassphraseKeyboard {
struct Input { struct Input {
area: Rect, area: Rect,
textbox: TextBox<MAX_LENGTH>, textbox: TextBox,
multi_tap: MultiTapKeyboard, multi_tap: MultiTapKeyboard,
} }

View File

@ -1,8 +1,8 @@
use core::mem; use core::{char::MAX, mem};
use heapless::String; use heapless::String;
use crate::{ use crate::{
strutil::TString, strutil::{ShortString, TString},
time::Duration, time::Duration,
trezorhal::random, trezorhal::random,
ui::{ ui::{
@ -14,11 +14,10 @@ use crate::{
event::TouchEvent, event::TouchEvent,
geometry::{Alignment, Alignment2D, Grid, Insets, Offset, Rect}, geometry::{Alignment, Alignment2D, Grid, Insets, Offset, Rect},
model_tt::component::{ model_tt::component::{
button::{Button, ButtonContent, ButtonMsg, ButtonMsg::Clicked}, button::{Button, ButtonContent, ButtonMsg::{self, Clicked}},
theme, theme,
}, },
shape, shape::{self, Renderer},
shape::Renderer,
}, },
}; };
@ -304,7 +303,7 @@ struct PinDots {
area: Rect, area: Rect,
pad: Pad, pad: Pad,
style: TextStyle, style: TextStyle,
digits: String<MAX_LENGTH>, digits: ShortString,
display_digits: bool, display_digits: bool,
} }
@ -335,7 +334,7 @@ impl PinDots {
} }
fn is_full(&self) -> bool { fn is_full(&self) -> bool {
self.digits.len() == self.digits.capacity() self.digits.len() >= MAX_LENGTH
} }
fn clear(&mut self, ctx: &mut EventCtx) { fn clear(&mut self, ctx: &mut EventCtx) {
@ -552,7 +551,7 @@ impl crate::trace::Trace for PinKeyboard<'_> {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("PinKeyboard"); t.component("PinKeyboard");
// So that debuglink knows the locations of the buttons // So that debuglink knows the locations of the buttons
let mut digits_order: String<10> = String::new(); let mut digits_order = ShortString::new();
for btn in self.digit_btns.iter() { for btn in self.digit_btns.iter() {
let btn_content = btn.inner().content(); let btn_content = btn.inner().content();

View File

@ -3,8 +3,7 @@ use core::iter;
use heapless::String; use heapless::String;
use crate::{ use crate::{
trezorhal::slip39, strutil::ShortString, trezorhal::slip39, ui::{
ui::{
component::{ component::{
text::common::{TextBox, TextEdit}, text::common::{TextBox, TextEdit},
Component, Event, EventCtx, Component, Event, EventCtx,
@ -21,17 +20,16 @@ use crate::{
}, },
theme, theme,
}, },
shape, shape::{self, Renderer},
shape::Renderer,
util::ResultExt, util::ResultExt,
}, }
}; };
const MAX_LENGTH: usize = 8; const MAX_LENGTH: usize = 8;
pub struct Slip39Input { pub struct Slip39Input {
button: Button, button: Button,
textbox: TextBox<MAX_LENGTH>, textbox: TextBox,
multi_tap: MultiTapKeyboard, multi_tap: MultiTapKeyboard,
final_word: Option<&'static str>, final_word: Option<&'static str>,
input_mask: Slip39Mask, input_mask: Slip39Mask,
@ -136,7 +134,7 @@ impl Component for Slip39Input {
// To simplify things, we always copy the printed string here, even if it // To simplify things, we always copy the printed string here, even if it
// wouldn't be strictly necessary. // wouldn't be strictly necessary.
let mut text: String<MAX_LENGTH> = String::new(); let mut text = ShortString::new();
if let Some(word) = self.final_word { if let Some(word) = self.final_word {
// We're done with input, paint the full word. // We're done with input, paint the full word.
@ -200,7 +198,7 @@ impl Component for Slip39Input {
// To simplify things, we always copy the printed string here, even if it // To simplify things, we always copy the printed string here, even if it
// wouldn't be strictly necessary. // wouldn't be strictly necessary.
let mut text: String<MAX_LENGTH> = String::new(); let mut text = ShortString::new();
if let Some(word) = self.final_word { if let Some(word) = self.final_word {
// We're done with input, paint the full word. // We're done with input, paint the full word.
@ -281,7 +279,7 @@ impl Slip39Input {
Self { Self {
// Button has the same style the whole time // Button has the same style the whole time
button: Button::empty().styled(theme::button_pin_confirm()), button: Button::empty().styled(theme::button_pin_confirm()),
textbox: TextBox::new(buff), textbox: TextBox::new(&buff),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
final_word, final_word,
input_mask, input_mask,
@ -290,8 +288,8 @@ impl Slip39Input {
fn setup_from_prefilled_word( fn setup_from_prefilled_word(
word: &str, word: &str,
) -> (String<MAX_LENGTH>, Slip39Mask, Option<&'static str>) { ) -> (ShortString, Slip39Mask, Option<&'static str>) {
let mut buff: String<MAX_LENGTH> = String::new(); let mut buff = ShortString::new();
// Gradually appending encoded key digits to the buffer and checking if // Gradually appending encoded key digits to the buffer and checking if
// have not already formed a final word. // have not already formed a final word.