From 95d9d94e9c2d4fbe0454844dfdbd683eeb431476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 14 Oct 2023 21:25:46 +0200 Subject: [PATCH 01/20] Don't copy render state --- src/plugin/ansi/mod.rs | 4 ++-- src/rendering/line.rs | 48 ++++++++++++++++++------------------------ src/rendering/mod.rs | 13 ++++++------ 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/plugin/ansi/mod.rs b/src/plugin/ansi/mod.rs index a9ba9f8a..9277f644 100644 --- a/src/plugin/ansi/mod.rs +++ b/src/plugin/ansi/mod.rs @@ -343,14 +343,14 @@ mod test { ); let plugin = PluginWrapper::new(Ansi::new()); - let state = LineRenderState { + let mut state = LineRenderState { parser, character_style, style: &style, end_type: LineEndType::EndOfText, plugin: &plugin, }; - StyledLineRenderer::new(cursor, state) + StyledLineRenderer::new(cursor, &mut state) .draw(&mut display) .unwrap(); diff --git a/src/rendering/line.rs b/src/rendering/line.rs index 698b4de5..f3b9b3ba 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -21,7 +21,6 @@ use embedded_graphics::{ renderer::{CharacterStyle, TextRenderer}, Baseline, DecorationColor, }, - Drawable, }; impl ChangeTextStyle @@ -45,13 +44,13 @@ where } /// Render a single line of styled text. -pub(crate) struct StyledLineRenderer<'a, 'b, S, M> +pub(crate) struct StyledLineRenderer<'a, 'b, 'c, S, M> where S: TextRenderer + Clone, M: Plugin<'a, ::Color>, { cursor: LineCursor, - state: LineRenderState<'a, 'b, S, M>, + state: &'c mut LineRenderState<'a, 'b, S, M>, } #[derive(Clone)] @@ -67,14 +66,14 @@ where pub plugin: &'b PluginWrapper<'a, M, S::Color>, } -impl<'a, 'b, F, M> StyledLineRenderer<'a, 'b, F, M> +impl<'a, 'b, 'c, F, M> StyledLineRenderer<'a, 'b, 'c, F, M> where F: TextRenderer::Color> + CharacterStyle, ::Color: From, M: Plugin<'a, ::Color>, { /// Creates a new line renderer. - pub fn new(cursor: LineCursor, state: LineRenderState<'a, 'b, F, M>) -> Self { + pub fn new(cursor: LineCursor, state: &'c mut LineRenderState<'a, 'b, F, M>) -> Self { Self { cursor, state } } } @@ -158,19 +157,16 @@ where } } -impl<'a, 'b, F, M> Drawable for StyledLineRenderer<'a, 'b, F, M> +impl<'a, 'b, 'c, F, M> StyledLineRenderer<'a, 'b, 'c, F, M> where F: TextRenderer::Color> + CharacterStyle, ::Color: From, M: Plugin<'a, ::Color> + Plugin<'a, ::Color>, { - type Color = ::Color; - type Output = LineRenderState<'a, 'b, F, M>; - #[inline] - fn draw(&self, display: &mut D) -> Result + pub(crate) fn draw(&mut self, display: &mut D) -> Result<(), D::Error> where - D: DrawTarget, + D: DrawTarget::Color>, { let LineRenderState { mut parser, @@ -211,7 +207,16 @@ where let end_type = elements.process(&mut render_element_handler)?; let end_pos = render_element_handler.pos; - let next_state = LineRenderState { + if end_type == LineEndType::EndOfText { + plugin.post_render( + display, + &character_style, + None, + Rectangle::new(end_pos, Size::new(0, character_style.line_height())), + )?; + } + + *self.state = LineRenderState { parser, character_style, style, @@ -219,19 +224,7 @@ where plugin, }; - if next_state.end_type == LineEndType::EndOfText { - next_state.plugin.post_render( - display, - &next_state.character_style, - None, - Rectangle::new( - end_pos, - Size::new(0, next_state.character_style.line_height()), - ), - )?; - } - - Ok(next_state) + Ok(()) } } @@ -255,7 +248,6 @@ mod test { pixelcolor::{BinaryColor, Rgb888}, primitives::Rectangle, text::renderer::{CharacterStyle, TextRenderer}, - Drawable, }; fn test_rendered_text<'a, S>( @@ -276,7 +268,7 @@ mod test { let plugin = PluginWrapper::new(NoPlugin::new()); - let state = LineRenderState { + let mut state = LineRenderState { parser, character_style, style: &style, @@ -284,7 +276,7 @@ mod test { plugin: &plugin, }; - let renderer = StyledLineRenderer::new(cursor, state); + let mut renderer = StyledLineRenderer::new(cursor, &mut state); let mut display = MockDisplay::new(); display.set_allow_overdraw(true); diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index debc60e0..bd3dc411 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -113,20 +113,19 @@ where .style .height_mode .calculate_displayed_row_range(&cursor); - let display_size = Size::new( - cursor.line_width(), - display_range.clone().count().saturating_as(), - ); + let display_range_start = display_range.start; + let display_range_count = (display_range.end - display_range.start).saturating_as(); + let display_size = Size::new(cursor.line_width(), display_range_count); let line_start = line_cursor.pos(); // FIXME: cropping isn't necessary for whole lines, but make sure not to blow up the // binary size as well. let mut display = display.clipped(&Rectangle::new( - line_start + Point::new(0, display_range.start), + line_start + Point::new(0, display_range_start), display_size, )); - if display_range.start >= display_range.end { + if display_range_count == 0 { if anything_drawn { let remaining_bytes = state.parser.as_str().len(); let consumed_bytes = self.text.len() - remaining_bytes; @@ -147,7 +146,7 @@ where anything_drawn = true; } - state = StyledLineRenderer::new(line_cursor, state).draw(&mut display)?; + StyledLineRenderer::new(line_cursor, &mut state).draw(&mut display)?; match state.end_type { LineEndType::EndOfText => { From 6a50e052fc2274dfd51c2784be85bc4f5272aa09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 14 Oct 2023 21:36:49 +0200 Subject: [PATCH 02/20] Copy even less --- src/rendering/line.rs | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/rendering/line.rs b/src/rendering/line.rs index f3b9b3ba..46637263 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -169,12 +169,12 @@ where D: DrawTarget::Color>, { let LineRenderState { - mut parser, - mut character_style, + ref mut parser, + ref mut character_style, style, plugin, .. - } = self.state.clone(); + } = self.state; let lm = { // Ensure the clone lives for as short as possible. @@ -183,46 +183,39 @@ where measure_plugin.set_state(ProcessingState::Measure); style.measure_line( &measure_plugin, - &character_style, + character_style, &mut cloned_parser, self.cursor.line_width(), ) }; - let (left, space_config) = style.alignment.place_line(&character_style, lm); + let (left, space_config) = style.alignment.place_line(character_style, lm); let mut cursor = self.cursor.clone(); cursor.move_cursor(left.saturating_as()).ok(); let pos = cursor.pos(); - let mut elements = - LineElementParser::new(&mut parser, plugin, cursor, space_config, &style); + let mut elements = LineElementParser::new(parser, plugin, cursor, space_config, &style); let mut render_element_handler = RenderElementHandler { - style: &mut character_style, + style: character_style, display, pos, - plugin, + plugin: &*plugin, }; let end_type = elements.process(&mut render_element_handler)?; - let end_pos = render_element_handler.pos; if end_type == LineEndType::EndOfText { + let end_pos = render_element_handler.pos; plugin.post_render( display, - &character_style, + character_style, None, Rectangle::new(end_pos, Size::new(0, character_style.line_height())), )?; } - *self.state = LineRenderState { - parser, - character_style, - style, - end_type, - plugin, - }; + self.state.end_type = end_type; Ok(()) } From e399e7410c14bacb83f517c34619d3f82e28d11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 14 Oct 2023 21:41:52 +0200 Subject: [PATCH 03/20] Clean up clippy warnings --- src/plugin/mod.rs | 2 +- src/rendering/line.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index ac80684f..af13bebd 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -90,7 +90,7 @@ impl<'a, M: Clone, C: Clone> Clone for PluginWrapper<'a, M, C> { Self { inner: UnsafeCell::new(self.with(|this| PluginInner { plugin: this.plugin.clone(), - state: this.state.clone(), + state: this.state, peeked_token: unsafe { addr_of!(this.peeked_token).read() }, })), } diff --git a/src/rendering/line.rs b/src/rendering/line.rs index 46637263..8340c659 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -195,13 +195,13 @@ where cursor.move_cursor(left.saturating_as()).ok(); let pos = cursor.pos(); - let mut elements = LineElementParser::new(parser, plugin, cursor, space_config, &style); + let mut elements = LineElementParser::new(parser, plugin, cursor, space_config, style); let mut render_element_handler = RenderElementHandler { style: character_style, display, pos, - plugin: &*plugin, + plugin: *plugin, }; let end_type = elements.process(&mut render_element_handler)?; From 35094487246d06d5d8ae707dcd483358808f48a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 14 Oct 2023 21:43:48 +0200 Subject: [PATCH 04/20] Shuffle lines around a bit --- src/rendering/line.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/rendering/line.rs b/src/rendering/line.rs index 8340c659..27cd8469 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -194,16 +194,14 @@ where let mut cursor = self.cursor.clone(); cursor.move_cursor(left.saturating_as()).ok(); - let pos = cursor.pos(); - let mut elements = LineElementParser::new(parser, plugin, cursor, space_config, style); - let mut render_element_handler = RenderElementHandler { style: character_style, display, - pos, + pos: cursor.pos(), plugin: *plugin, }; - let end_type = elements.process(&mut render_element_handler)?; + let end_type = LineElementParser::new(parser, plugin, cursor, space_config, style) + .process(&mut render_element_handler)?; if end_type == LineEndType::EndOfText { let end_pos = render_element_handler.pos; From 11913c512f44b244084cc11718cc7fd4c9b9b24d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 14 Oct 2023 21:51:06 +0200 Subject: [PATCH 05/20] Consume renderer, don't clone cursor --- src/rendering/line.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/rendering/line.rs b/src/rendering/line.rs index 27cd8469..2b164bd1 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -164,7 +164,7 @@ where M: Plugin<'a, ::Color> + Plugin<'a, ::Color>, { #[inline] - pub(crate) fn draw(&mut self, display: &mut D) -> Result<(), D::Error> + pub(crate) fn draw(mut self, display: &mut D) -> Result<(), D::Error> where D: DrawTarget::Color>, { @@ -191,16 +191,15 @@ where let (left, space_config) = style.alignment.place_line(character_style, lm); - let mut cursor = self.cursor.clone(); - cursor.move_cursor(left.saturating_as()).ok(); + self.cursor.move_cursor(left.saturating_as()).ok(); let mut render_element_handler = RenderElementHandler { style: character_style, display, - pos: cursor.pos(), + pos: self.cursor.pos(), plugin: *plugin, }; - let end_type = LineElementParser::new(parser, plugin, cursor, space_config, style) + let end_type = LineElementParser::new(parser, plugin, self.cursor, space_config, style) .process(&mut render_element_handler)?; if end_type == LineEndType::EndOfText { @@ -267,7 +266,7 @@ mod test { plugin: &plugin, }; - let mut renderer = StyledLineRenderer::new(cursor, &mut state); + let renderer = StyledLineRenderer::new(cursor, &mut state); let mut display = MockDisplay::new(); display.set_allow_overdraw(true); From 878098fcc659d1b11b7b6547b1d45e5fa21adee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 14 Oct 2023 22:00:26 +0200 Subject: [PATCH 06/20] Only create line cursor right before rendering --- src/rendering/cursor.rs | 10 ++++++++-- src/rendering/mod.rs | 5 ++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/rendering/cursor.rs b/src/rendering/cursor.rs index 89701a8b..52cd6662 100644 --- a/src/rendering/cursor.rs +++ b/src/rendering/cursor.rs @@ -113,20 +113,26 @@ impl Cursor { #[must_use] pub(crate) fn line(&self) -> LineCursor { LineCursor { - start: Point::new(self.bounds.top_left.x, self.y), + start: self.line_start(), width: self.bounds.size.width, position: 0, tab_width: self.tab_width, } } + /// Returns the coordinates of the start of the current line. + #[inline] + pub(crate) fn line_start(&self) -> Point { + Point::new(self.bounds.top_left.x, self.y) + } + /// Returns the coordinates of the bottom right corner. #[inline] pub fn bottom_right(&self) -> Point { self.bounds.bottom_right().unwrap_or(self.bounds.top_left) } - /// Returns the coordinates of the bottom right corner. + /// Returns the coordinates of the top left corner. #[inline] pub fn top_left(&self) -> Point { self.bounds.top_left diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index bd3dc411..874d652e 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -107,7 +107,6 @@ where let mut anything_drawn = false; loop { state.plugin.new_line(); - let line_cursor = cursor.line(); let display_range = self .style @@ -117,7 +116,7 @@ where let display_range_count = (display_range.end - display_range.start).saturating_as(); let display_size = Size::new(cursor.line_width(), display_range_count); - let line_start = line_cursor.pos(); + let line_start = cursor.line_start(); // FIXME: cropping isn't necessary for whole lines, but make sure not to blow up the // binary size as well. @@ -146,7 +145,7 @@ where anything_drawn = true; } - StyledLineRenderer::new(line_cursor, &mut state).draw(&mut display)?; + StyledLineRenderer::new(cursor.line(), &mut state).draw(&mut display)?; match state.end_type { LineEndType::EndOfText => { From f938739380e6c476b875c02a909e48d90f697bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 14 Oct 2023 22:07:19 +0200 Subject: [PATCH 07/20] Simplify move_cursor --- src/rendering/line.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendering/line.rs b/src/rendering/line.rs index 2b164bd1..c8ba2246 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -144,7 +144,7 @@ where fn move_cursor(&mut self, by: i32) -> Result<(), Self::Error> { // LineElementIterator ensures this new pos is valid. - self.pos = Point::new(self.pos.x + by, self.pos.y); + self.pos += Point::new(by, 0); Ok(()) } From f2a5a88413a7974a01caeb658996a524cdef0e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 07:53:40 +0200 Subject: [PATCH 08/20] Remove constructor, extract style from renderer state --- src/plugin/ansi/mod.rs | 17 +++++---- src/rendering/line.rs | 85 +++++++++++++++++++----------------------- src/rendering/mod.rs | 10 +++-- 3 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/plugin/ansi/mod.rs b/src/plugin/ansi/mod.rs index 9277f644..8333911e 100644 --- a/src/plugin/ansi/mod.rs +++ b/src/plugin/ansi/mod.rs @@ -329,7 +329,7 @@ mod test { let parser = Parser::parse("foo\x1b[2Dsample"); - let character_style = MonoTextStyleBuilder::new() + let text_renderer = MonoTextStyleBuilder::new() .font(&FONT_6X9) .text_color(BinaryColor::On) .background_color(BinaryColor::Off) @@ -339,20 +339,23 @@ mod test { let cursor = LineCursor::new( size_for(&FONT_6X9, 7, 1).width, - TabSize::Spaces(4).into_pixels(&character_style), + TabSize::Spaces(4).into_pixels(&text_renderer), ); let plugin = PluginWrapper::new(Ansi::new()); let mut state = LineRenderState { parser, - character_style, - style: &style, + text_renderer, end_type: LineEndType::EndOfText, plugin: &plugin, }; - StyledLineRenderer::new(cursor, &mut state) - .draw(&mut display) - .unwrap(); + StyledLineRenderer { + cursor, + state: &mut state, + style: &style, + } + .draw(&mut display) + .unwrap(); display.assert_pattern(&[ "..........................................", diff --git a/src/rendering/line.rs b/src/rendering/line.rs index c8ba2246..5af9db79 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -27,18 +27,18 @@ impl ChangeTextStyle where C: PixelColor + From, { - pub(crate) fn apply>(self, style: &mut S) { + pub(crate) fn apply>(self, text_renderer: &mut S) { match self { ChangeTextStyle::Reset => { - style.set_text_color(Some(Into::::into(BinaryColor::On).into())); - style.set_background_color(None); - style.set_underline_color(DecorationColor::None); - style.set_strikethrough_color(DecorationColor::None); + text_renderer.set_text_color(Some(Into::::into(BinaryColor::On).into())); + text_renderer.set_background_color(None); + text_renderer.set_underline_color(DecorationColor::None); + text_renderer.set_strikethrough_color(DecorationColor::None); } - ChangeTextStyle::TextColor(color) => style.set_text_color(color), - ChangeTextStyle::BackgroundColor(color) => style.set_background_color(color), - ChangeTextStyle::Underline(color) => style.set_underline_color(color), - ChangeTextStyle::Strikethrough(color) => style.set_strikethrough_color(color), + ChangeTextStyle::TextColor(color) => text_renderer.set_text_color(color), + ChangeTextStyle::BackgroundColor(color) => text_renderer.set_background_color(color), + ChangeTextStyle::Underline(color) => text_renderer.set_underline_color(color), + ChangeTextStyle::Strikethrough(color) => text_renderer.set_strikethrough_color(color), } } } @@ -49,8 +49,9 @@ where S: TextRenderer + Clone, M: Plugin<'a, ::Color>, { - cursor: LineCursor, - state: &'c mut LineRenderState<'a, 'b, S, M>, + pub(crate) cursor: LineCursor, + pub(crate) state: &'c mut LineRenderState<'a, 'b, S, M>, + pub(crate) style: &'c TextBoxStyle, } #[derive(Clone)] @@ -60,30 +61,17 @@ where M: Plugin<'a, S::Color>, { pub parser: Parser<'a, S::Color>, - pub character_style: S, - pub style: &'b TextBoxStyle, + pub text_renderer: S, pub end_type: LineEndType, pub plugin: &'b PluginWrapper<'a, M, S::Color>, } -impl<'a, 'b, 'c, F, M> StyledLineRenderer<'a, 'b, 'c, F, M> -where - F: TextRenderer::Color> + CharacterStyle, - ::Color: From, - M: Plugin<'a, ::Color>, -{ - /// Creates a new line renderer. - pub fn new(cursor: LineCursor, state: &'c mut LineRenderState<'a, 'b, F, M>) -> Self { - Self { cursor, state } - } -} - struct RenderElementHandler<'a, 'b, F, D, M> where F: TextRenderer, D: DrawTarget, { - style: &'b mut F, + text_renderer: &'b mut F, display: &'b mut D, pos: Point, plugin: &'b PluginWrapper<'a, M, F::Color>, @@ -99,13 +87,13 @@ where fn post_print(&mut self, width: u32, st: &str) -> Result<(), D::Error> { let bounds = Rectangle::new( self.pos, - Size::new(width, self.style.line_height().saturating_as()), + Size::new(width, self.text_renderer.line_height().saturating_as()), ); self.pos += Point::new(width.saturating_as(), 0); self.plugin - .post_render(self.display, self.style, Some(st), bounds) + .post_render(self.display, self.text_renderer, Some(st), bounds) } } @@ -120,12 +108,12 @@ where type Color = ::Color; fn measure(&self, st: &str) -> u32 { - str_width(self.style, st) + str_width(self.text_renderer, st) } fn whitespace(&mut self, st: &str, _space_count: u32, width: u32) -> Result<(), Self::Error> { if width > 0 { - self.style + self.text_renderer .draw_whitespace(width, self.pos, Baseline::Top, self.display)?; } @@ -133,9 +121,9 @@ where } fn printed_characters(&mut self, st: &str, width: Option) -> Result<(), Self::Error> { - let render_width = self - .style - .draw_string(st, self.pos, Baseline::Top, self.display)?; + let render_width = + self.text_renderer + .draw_string(st, self.pos, Baseline::Top, self.display)?; let width = width.unwrap_or((render_width - self.pos).x as u32); @@ -152,7 +140,7 @@ where &mut self, change: ChangeTextStyle<::Color>, ) -> Result<(), Self::Error> { - change.apply(self.style); + change.apply(self.text_renderer); Ok(()) } } @@ -170,8 +158,7 @@ where { let LineRenderState { ref mut parser, - ref mut character_style, - style, + ref mut text_renderer, plugin, .. } = self.state; @@ -181,34 +168,35 @@ where let mut cloned_parser = parser.clone(); let measure_plugin = plugin.clone(); measure_plugin.set_state(ProcessingState::Measure); - style.measure_line( + self.style.measure_line( &measure_plugin, - character_style, + text_renderer, &mut cloned_parser, self.cursor.line_width(), ) }; - let (left, space_config) = style.alignment.place_line(character_style, lm); + let (left, space_config) = self.style.alignment.place_line(text_renderer, lm); self.cursor.move_cursor(left.saturating_as()).ok(); let mut render_element_handler = RenderElementHandler { - style: character_style, + text_renderer, display, pos: self.cursor.pos(), plugin: *plugin, }; - let end_type = LineElementParser::new(parser, plugin, self.cursor, space_config, style) - .process(&mut render_element_handler)?; + let end_type = + LineElementParser::new(parser, plugin, self.cursor, space_config, self.style) + .process(&mut render_element_handler)?; if end_type == LineEndType::EndOfText { let end_pos = render_element_handler.pos; plugin.post_render( display, - character_style, + text_renderer, None, - Rectangle::new(end_pos, Size::new(0, character_style.line_height())), + Rectangle::new(end_pos, Size::new(0, text_renderer.line_height())), )?; } @@ -260,13 +248,16 @@ mod test { let mut state = LineRenderState { parser, - character_style, - style: &style, + text_renderer: character_style, end_type: LineEndType::EndOfText, plugin: &plugin, }; - let renderer = StyledLineRenderer::new(cursor, &mut state); + let renderer = StyledLineRenderer { + cursor, + state: &mut state, + style: &style, + }; let mut display = MockDisplay::new(); display.set_allow_overdraw(true); diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index 874d652e..3e6e9d4e 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -95,8 +95,7 @@ where self.plugin.on_start_render(&mut cursor, props); let mut state = LineRenderState { - style: &self.style, - character_style: self.character_style.clone(), + text_renderer: self.character_style.clone(), parser: Parser::parse(self.text), end_type: LineEndType::EndOfText, plugin: &self.plugin, @@ -145,7 +144,12 @@ where anything_drawn = true; } - StyledLineRenderer::new(cursor.line(), &mut state).draw(&mut display)?; + StyledLineRenderer { + cursor: cursor.line(), + state: &mut state, + style: &self.style, + } + .draw(&mut display)?; match state.end_type { LineEndType::EndOfText => { From af87ee0d78fb10440173006900bfc70c0a1badbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 08:11:22 +0200 Subject: [PATCH 09/20] Simplify whitespace condition --- src/rendering/line_iter.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/rendering/line_iter.rs b/src/rendering/line_iter.rs index 2604f8e9..1ee3e065 100644 --- a/src/rendering/line_iter.rs +++ b/src/rendering/line_iter.rs @@ -198,8 +198,8 @@ where self.style.trailing_spaces } - fn render_leading_spaces(&self) -> bool { - self.style.leading_spaces + fn skip_leading_spaces(&self) -> bool { + self.empty && !self.style.leading_spaces } fn draw_whitespace( @@ -209,7 +209,7 @@ where space_count: u32, space_width: u32, ) -> Result { - if self.empty && !self.render_leading_spaces() { + if self.skip_leading_spaces() { handler.whitespace(string, space_count, 0)?; return Ok(false); } @@ -259,7 +259,7 @@ where handler: &mut E, space_width: u32, ) -> Result<(), E::Error> { - if self.empty && !self.render_leading_spaces() { + if self.skip_leading_spaces() { return Ok(()); } @@ -446,7 +446,8 @@ where } fn should_draw_whitespace(&self, handler: &E) -> bool { - (self.empty && self.render_leading_spaces()) + self.empty // We know that when this function is called, + // an empty line means leading spaces are allowed || self.render_trailing_spaces() || self.next_word_fits(handler) } From e6495de5218f939db82a8a0f9b5414204cfb4c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 08:15:53 +0200 Subject: [PATCH 10/20] Only consume in one place in next_word_fits --- src/rendering/line_iter.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/rendering/line_iter.rs b/src/rendering/line_iter.rs index 1ee3e065..125b5345 100644 --- a/src/rendering/line_iter.rs +++ b/src/rendering/line_iter.rs @@ -162,11 +162,9 @@ where let lookahead = self.plugin.clone(); let mut lookahead_parser = self.parser.clone(); - // We don't want to count the current token. - lookahead.consume_peeked_token(); - let mut exit = false; while !exit { + lookahead.consume_peeked_token(); let width = match lookahead.peek_token(&mut lookahead_parser) { Some(Token::Word(w)) | Some(Token::Break(w, _)) => { exit = true; @@ -185,7 +183,6 @@ where _ => return false, }; - lookahead.consume_peeked_token(); if cursor.move_cursor(width).is_err() { return false; } From a8ab7a2c3b6d19f02f21ac7574dca8996fc360a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 08:29:54 +0200 Subject: [PATCH 11/20] Discard the original separator character --- examples/plugin.rs | 4 ++-- src/parser/mod.rs | 17 ++++------------- src/rendering/line_iter.rs | 8 ++++---- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/examples/plugin.rs b/examples/plugin.rs index 5822c9d6..ce4b6c0c 100644 --- a/examples/plugin.rs +++ b/examples/plugin.rs @@ -89,7 +89,7 @@ where Some(Token::Word(word)) } - Some(Token::Break(_, _)) => { + Some(Token::Break(_)) => { self.measured += 1; token } @@ -115,7 +115,7 @@ where Some(Token::Whitespace(to_render, s.first_n_chars(to_render))) } Token::Word(s) => Some(Token::Word(s.first_n_chars(to_render))), - Token::Break(repl, orig) => Some(Token::Break(repl.first_n_chars(to_render), orig)), + Token::Break(repl) => Some(Token::Break(repl.first_n_chars(to_render))), _ => Some(token), } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index c5f525e8..b8a23d6f 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -56,8 +56,8 @@ pub enum Token<'a, C> { /// A word (a sequence of non-whitespace characters). Word(&'a str), - /// A possible wrapping point - Break(&'a str, &'a str), + /// A possible wrapping point. Contains the separator character(s). + Break(&'a str), /// Change of text style. ChangeTextStyle(ChangeTextStyle), @@ -170,11 +170,6 @@ where })), SPEC_CHAR_SHY => Some(Token::Break( "-", // translate SHY to a printable character - unsafe { - // SAFETY: we only work with character boundaries and - // offset is <= length - string.get_unchecked(0..c.len_utf8()) - }, )), // count consecutive whitespace @@ -232,7 +227,7 @@ mod test { Token::Word("sit"), Token::Whitespace(1, " "), Token::Word("am"), - Token::Break("-", "\u{ad}"), + Token::Break("-"), Token::Word("et,"), Token::Tab, Token::Word("conse😅ctetur"), @@ -280,11 +275,7 @@ mod test { fn parse_shy_issue_42() { assert_tokens( "foo\u{AD}bar", - vec![ - Token::Word("foo"), - Token::Break("-", "\u{ad}"), - Token::Word("bar"), - ], + vec![Token::Word("foo"), Token::Break("-"), Token::Word("bar")], ); } } diff --git a/src/rendering/line_iter.rs b/src/rendering/line_iter.rs index 125b5345..f68d0f8e 100644 --- a/src/rendering/line_iter.rs +++ b/src/rendering/line_iter.rs @@ -110,7 +110,7 @@ where width_set = true; } - Some(Token::Break(w, _original)) => return Some(width + handler.measure(w)), + Some(Token::Break(w)) => return Some(width + handler.measure(w)), Some(Token::ChangeTextStyle(_)) | Some(Token::MoveCursor { .. }) => {} _ => { @@ -166,7 +166,7 @@ where while !exit { lookahead.consume_peeked_token(); let width = match lookahead.peek_token(&mut lookahead_parser) { - Some(Token::Word(w)) | Some(Token::Break(w, _)) => { + Some(Token::Word(w)) | Some(Token::Break(w)) => { exit = true; handler.measure(w).saturating_as() } @@ -297,7 +297,7 @@ where self.draw_tab(handler, space_width)?; } - Token::Break(c, _original) => { + Token::Break(c) => { if let Some(word_width) = self.next_word_width(handler) { if !self.cursor.fits_in_line(word_width) || self.empty { // this line is done, decide how to end @@ -305,7 +305,7 @@ where // If the next Word token does not fit the line, display break character let width = handler.measure(c); if self.move_cursor(width.saturating_as()).is_ok() { - if let Some(Token::Break(c, _)) = self.plugin.render_token(token) { + if let Some(Token::Break(c)) = self.plugin.render_token(token) { handler.printed_characters(c, Some(width))?; } self.consume_token(); From 3eda5f6c46cb482524a75511d883b10feac39c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 08:39:13 +0200 Subject: [PATCH 12/20] Specialize forward-only cursor moving --- src/rendering/cursor.rs | 12 ++++++++++++ src/rendering/line_iter.rs | 20 ++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/rendering/cursor.rs b/src/rendering/cursor.rs index 52cd6662..3c79d8b3 100644 --- a/src/rendering/cursor.rs +++ b/src/rendering/cursor.rs @@ -73,6 +73,18 @@ impl LineCursor { } } } + + /// Moves the cursor forward by a given amount. + pub fn move_cursor_forward(&mut self, by: u32) -> Result { + let space = self.space(); + if by <= space { + // Here we know by > 0, cast is safe + self.position += by; + Ok(by) + } else { + Err(space) + } + } } /// Internal structure that keeps track of position information while rendering a [`TextBox`]. diff --git a/src/rendering/line_iter.rs b/src/rendering/line_iter.rs index f68d0f8e..9f946c2f 100644 --- a/src/rendering/line_iter.rs +++ b/src/rendering/line_iter.rs @@ -127,6 +127,10 @@ where self.cursor.move_cursor(by) } + fn move_cursor_forward(&mut self, by: u32) -> Result { + self.cursor.move_cursor_forward(by) + } + fn longest_fitting_substr( &mut self, handler: &E, @@ -211,18 +215,18 @@ where return Ok(false); } - match self.move_cursor(space_width.saturating_as()) { + match self.move_cursor_forward(space_width) { Ok(moved) => { handler.whitespace( string, space_count, - moved.saturating_as::() * self.should_draw_whitespace(handler) as u32, + moved * self.should_draw_whitespace(handler) as u32, )?; } Err(moved) => { let single = space_width / space_count; - let consumed = moved as u32 / single; + let consumed = moved / single; if consumed > 0 { let consumed_str = string .char_indices() @@ -235,7 +239,7 @@ where let consumed_width = consumed * single; - let _ = self.move_cursor(consumed_width.saturating_as()); + let _ = self.move_cursor_forward(consumed_width); handler.whitespace( consumed_str, consumed, @@ -260,12 +264,12 @@ where return Ok(()); } - match self.move_cursor(space_width.saturating_as()) { + match self.move_cursor_forward(space_width) { Ok(moved) if self.should_draw_whitespace(handler) => { handler.whitespace("\t", 0, moved.saturating_as())? } - Ok(moved) | Err(moved) => handler.move_cursor(moved)?, + Ok(moved) | Err(moved) => handler.move_cursor(moved.saturating_as())?, } Ok(()) } @@ -304,7 +308,7 @@ where // If the next Word token does not fit the line, display break character let width = handler.measure(c); - if self.move_cursor(width.saturating_as()).is_ok() { + if self.move_cursor_forward(width).is_ok() { if let Some(Token::Break(c)) = self.plugin.render_token(token) { handler.printed_characters(c, Some(width))?; } @@ -322,7 +326,7 @@ where Token::Word(w) => { let width = handler.measure(w); - let (word, remainder) = if self.move_cursor(width.saturating_as()).is_ok() { + let (word, remainder) = if self.move_cursor_forward(width).is_ok() { // We can move the cursor here since `process_word()` // doesn't depend on it. (w, "") From 0eeb8035f8ac2711a5615fb048b7b788286d31ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 08:45:29 +0200 Subject: [PATCH 13/20] Streamline return points --- src/rendering/line_iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rendering/line_iter.rs b/src/rendering/line_iter.rs index 9f946c2f..48abc5f5 100644 --- a/src/rendering/line_iter.rs +++ b/src/rendering/line_iter.rs @@ -222,6 +222,7 @@ where space_count, moved * self.should_draw_whitespace(handler) as u32, )?; + Ok(false) } Err(moved) => { @@ -249,10 +250,9 @@ where self.plugin .consume_partial((consumed + 1).min(space_count) as usize); - return Ok(true); + Ok(true) } } - Ok(false) } fn draw_tab( From be88ce5a8067a1b6c2e9f904c334c7bbe816face Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 08:47:31 +0200 Subject: [PATCH 14/20] Remove unnecessary cast --- src/rendering/line_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendering/line_iter.rs b/src/rendering/line_iter.rs index 48abc5f5..971a147d 100644 --- a/src/rendering/line_iter.rs +++ b/src/rendering/line_iter.rs @@ -266,7 +266,7 @@ where match self.move_cursor_forward(space_width) { Ok(moved) if self.should_draw_whitespace(handler) => { - handler.whitespace("\t", 0, moved.saturating_as())? + handler.whitespace("\t", 0, moved)? } Ok(moved) | Err(moved) => handler.move_cursor(moved.saturating_as())?, From 631c8ca19878fe61fe4f67575728045ef68a83e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 08:53:36 +0200 Subject: [PATCH 15/20] Merge draw_tab with tab width calculation --- src/rendering/line_iter.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/rendering/line_iter.rs b/src/rendering/line_iter.rs index 971a147d..008b60c3 100644 --- a/src/rendering/line_iter.rs +++ b/src/rendering/line_iter.rs @@ -255,15 +255,12 @@ where } } - fn draw_tab( - &mut self, - handler: &mut E, - space_width: u32, - ) -> Result<(), E::Error> { + fn draw_tab(&mut self, handler: &mut E) -> Result<(), E::Error> { if self.skip_leading_spaces() { return Ok(()); } + let space_width = self.cursor.next_tab_width(); match self.move_cursor_forward(space_width) { Ok(moved) if self.should_draw_whitespace(handler) => { handler.whitespace("\t", 0, moved)? @@ -297,8 +294,7 @@ where } Token::Tab => { - let space_width = self.cursor.next_tab_width(); - self.draw_tab(handler, space_width)?; + self.draw_tab(handler)?; } Token::Break(c) => { From c331bafe1ee4e3d280d6f3b60d4b56b3c9f8965a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 10:01:06 +0200 Subject: [PATCH 16/20] Precompute bottom offset in cursor --- src/rendering/cursor.rs | 36 ++++++++++++++++++++-------------- src/rendering/mod.rs | 5 +---- src/style/vertical_overdraw.rs | 6 ++++-- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/rendering/cursor.rs b/src/rendering/cursor.rs index 3c79d8b3..f35e8065 100644 --- a/src/rendering/cursor.rs +++ b/src/rendering/cursor.rs @@ -1,5 +1,5 @@ //! Cursor to track rendering position. -use embedded_graphics::{geometry::Point, prelude::Size, primitives::Rectangle, text::LineHeight}; +use embedded_graphics::{geometry::Point, primitives::Rectangle, text::LineHeight}; use az::{SaturatingAs, SaturatingCast}; @@ -95,10 +95,11 @@ pub struct Cursor { /// Current cursor position pub y: i32, - /// TextBox bounding rectangle - bounds: Rectangle, + top_left: Point, + bottom: i32, - line_height: i32, + line_width: u32, + line_height: u32, line_spacing: i32, tab_width: u32, } @@ -115,9 +116,14 @@ impl Cursor { ) -> Self { Self { y: bounds.top_left.y, - line_height: base_line_height.saturating_as(), + + top_left: bounds.top_left, + bottom: bounds.top_left.y + bounds.size.height.saturating_as::() + - base_line_height.saturating_as::(), + + line_width: bounds.size.width, + line_height: base_line_height, line_spacing: line_height.to_absolute(base_line_height).saturating_as(), - bounds: Rectangle::new(bounds.top_left, bounds.size + Size::new(0, 1)), tab_width, } } @@ -126,7 +132,7 @@ impl Cursor { pub(crate) fn line(&self) -> LineCursor { LineCursor { start: self.line_start(), - width: self.bounds.size.width, + width: self.line_width, position: 0, tab_width: self.tab_width, } @@ -135,30 +141,30 @@ impl Cursor { /// Returns the coordinates of the start of the current line. #[inline] pub(crate) fn line_start(&self) -> Point { - Point::new(self.bounds.top_left.x, self.y) + Point::new(self.top_left.x, self.y) } - /// Returns the coordinates of the bottom right corner. + /// Returns the vertical offset of the bottom of the last visible line. #[inline] - pub fn bottom_right(&self) -> Point { - self.bounds.bottom_right().unwrap_or(self.bounds.top_left) + pub fn bottom(&self) -> i32 { + self.bottom } /// Returns the coordinates of the top left corner. #[inline] pub fn top_left(&self) -> Point { - self.bounds.top_left + self.top_left } /// Returns the width of the text box. #[inline] pub fn line_width(&self) -> u32 { - self.bounds.size.width + self.line_width } /// Returns the height of a line. #[inline] - pub fn line_height(&self) -> i32 { + pub fn line_height(&self) -> u32 { self.line_height } @@ -177,6 +183,6 @@ impl Cursor { #[inline] #[must_use] pub fn in_display_area(&self) -> bool { - self.bounds.top_left.y <= self.y && self.y + self.line_height <= self.bottom_right().y + self.top_left.y <= self.y && self.y <= self.bottom } } diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index 3e6e9d4e..83d37257 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -132,10 +132,7 @@ where &mut display, &self.character_style, None, - Rectangle::new( - line_start, - Size::new(0, cursor.line_height().saturating_as()), - ), + Rectangle::new(line_start, Size::new(0, cursor.line_height())), )?; state.plugin.on_rendering_finished(); return Ok(self.text.get(consumed_bytes..).unwrap()); diff --git a/src/style/vertical_overdraw.rs b/src/style/vertical_overdraw.rs index d0bbb746..18d5351d 100644 --- a/src/style/vertical_overdraw.rs +++ b/src/style/vertical_overdraw.rs @@ -1,5 +1,7 @@ //! Vertical overdraw options. +use az::SaturatingAs; + use crate::rendering::cursor::Cursor; use core::ops::Range; @@ -17,7 +19,7 @@ pub enum VerticalOverdraw { impl VerticalOverdraw { /// Calculate the range of rows of the current line that can be drawn. pub(crate) fn calculate_displayed_row_range(self, cursor: &Cursor) -> Range { - let line_height = cursor.line_height(); + let line_height = cursor.line_height().saturating_as::(); match self { VerticalOverdraw::FullRowsOnly => { if cursor.in_display_area() { @@ -29,7 +31,7 @@ impl VerticalOverdraw { VerticalOverdraw::Hidden => { let offset_top = (cursor.top_left().y - cursor.y).max(0); - let offset_bottom = (cursor.bottom_right().y - cursor.y).min(line_height); + let offset_bottom = (cursor.bottom() - cursor.y).min(0) + line_height; offset_top..offset_bottom } From bc04e19f2ec546622b4c0f8c37e79fda05a3bd51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 10:15:46 +0200 Subject: [PATCH 17/20] Return visible range as u32 range --- src/rendering/mod.rs | 8 +++++--- src/style/height_mode.rs | 2 +- src/style/vertical_overdraw.rs | 9 +++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index 83d37257..eb0c8ce5 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -111,20 +111,22 @@ where .style .height_mode .calculate_displayed_row_range(&cursor); - let display_range_start = display_range.start; - let display_range_count = (display_range.end - display_range.start).saturating_as(); + let display_range_start = display_range.start.saturating_as::(); + let display_range_count = display_range.count() as u32; let display_size = Size::new(cursor.line_width(), display_range_count); let line_start = cursor.line_start(); // FIXME: cropping isn't necessary for whole lines, but make sure not to blow up the - // binary size as well. + // binary size as well. We could also use a different way to consume invisible text. let mut display = display.clipped(&Rectangle::new( line_start + Point::new(0, display_range_start), display_size, )); if display_range_count == 0 { + // Display range can be empty if we are above, or below the visible text section if anything_drawn { + // We are below, so we won't be drawing anything else let remaining_bytes = state.parser.as_str().len(); let consumed_bytes = self.text.len() - remaining_bytes; diff --git a/src/style/height_mode.rs b/src/style/height_mode.rs index b45ba582..d3fce6c5 100644 --- a/src/style/height_mode.rs +++ b/src/style/height_mode.rs @@ -202,7 +202,7 @@ impl HeightMode { /// If a line does not fully fit in the bounding box, some `HeightMode` options allow drawing /// partial lines. For a partial line, this function calculates, which rows of each character /// should be displayed. - pub(crate) fn calculate_displayed_row_range(self, cursor: &Cursor) -> Range { + pub(crate) fn calculate_displayed_row_range(self, cursor: &Cursor) -> Range { let overdraw = match self { HeightMode::Exact(overdraw) | HeightMode::ShrinkToText(overdraw) => overdraw, HeightMode::FitToText => VerticalOverdraw::Visible, diff --git a/src/style/vertical_overdraw.rs b/src/style/vertical_overdraw.rs index 18d5351d..ef0d78a9 100644 --- a/src/style/vertical_overdraw.rs +++ b/src/style/vertical_overdraw.rs @@ -18,8 +18,8 @@ pub enum VerticalOverdraw { impl VerticalOverdraw { /// Calculate the range of rows of the current line that can be drawn. - pub(crate) fn calculate_displayed_row_range(self, cursor: &Cursor) -> Range { - let line_height = cursor.line_height().saturating_as::(); + pub(crate) fn calculate_displayed_row_range(self, cursor: &Cursor) -> Range { + let line_height = cursor.line_height(); match self { VerticalOverdraw::FullRowsOnly => { if cursor.in_display_area() { @@ -30,8 +30,9 @@ impl VerticalOverdraw { } VerticalOverdraw::Hidden => { - let offset_top = (cursor.top_left().y - cursor.y).max(0); - let offset_bottom = (cursor.bottom() - cursor.y).min(0) + line_height; + let offset_top = (cursor.top_left().y - cursor.y).saturating_as::(); + let offset_bottom = + line_height - (cursor.y - cursor.bottom()).saturating_as::(); offset_top..offset_bottom } From a68b552a7a09c457442a80f17656ead9e8bf489c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 11:12:33 +0200 Subject: [PATCH 18/20] Simplify casts --- src/rendering/line.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/rendering/line.rs b/src/rendering/line.rs index 5af9db79..328384c4 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -85,12 +85,9 @@ where M: Plugin<'a, ::Color>, { fn post_print(&mut self, width: u32, st: &str) -> Result<(), D::Error> { - let bounds = Rectangle::new( - self.pos, - Size::new(width, self.text_renderer.line_height().saturating_as()), - ); + let bounds = Rectangle::new(self.pos, Size::new(width, self.text_renderer.line_height())); - self.pos += Point::new(width.saturating_as(), 0); + self.pos += Point::new(width as i32, 0); self.plugin .post_render(self.display, self.text_renderer, Some(st), bounds) From 88ec3a8b86143679762098b5d31305a15bb14afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 11:13:25 +0200 Subject: [PATCH 19/20] Only use saturating_as --- src/rendering/cursor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rendering/cursor.rs b/src/rendering/cursor.rs index f35e8065..beff8b26 100644 --- a/src/rendering/cursor.rs +++ b/src/rendering/cursor.rs @@ -1,7 +1,7 @@ //! Cursor to track rendering position. use embedded_graphics::{geometry::Point, primitives::Rectangle, text::LineHeight}; -use az::{SaturatingAs, SaturatingCast}; +use az::SaturatingAs; /// Tracks position within a line. #[derive(Debug, Clone)] @@ -63,7 +63,7 @@ impl LineCursor { Err(-self.position.saturating_as::()) } } else { - let space = self.space().saturating_cast(); + let space = self.space().saturating_as(); if by <= space { // Here we know by > 0, cast is safe self.position += by as u32; From 65b0c389e789c416497a5fc5b0952c526f8a0779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Oct 2023 11:14:39 +0200 Subject: [PATCH 20/20] Remove unnecessary saturating casts --- src/alignment/mod.rs | 6 +++--- src/rendering/cursor.rs | 4 ++-- src/rendering/line.rs | 3 +-- src/rendering/line_iter.rs | 2 +- src/style/mod.rs | 3 +-- src/utils.rs | 4 +--- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/alignment/mod.rs b/src/alignment/mod.rs index db2642f4..5f1441fc 100644 --- a/src/alignment/mod.rs +++ b/src/alignment/mod.rs @@ -31,14 +31,14 @@ impl HorizontalAlignment { self, renderer: &impl TextRenderer, measurement: LineMeasurement, - ) -> (u32, SpaceConfig) { + ) -> (i32, SpaceConfig) { let space_width = str_width(renderer, " "); let space_config = SpaceConfig::new(space_width, None); let remaining_space = measurement.max_line_width - measurement.width; match self { HorizontalAlignment::Left => (0, space_config), - HorizontalAlignment::Center => ((remaining_space + 1) / 2, space_config), - HorizontalAlignment::Right => (remaining_space, space_config), + HorizontalAlignment::Center => ((remaining_space as i32 + 1) / 2, space_config), + HorizontalAlignment::Right => (remaining_space as i32, space_config), HorizontalAlignment::Justified => { let space_count = measurement.space_count; let space_info = if !measurement.last_line() && space_count != 0 { diff --git a/src/rendering/cursor.rs b/src/rendering/cursor.rs index beff8b26..a332c820 100644 --- a/src/rendering/cursor.rs +++ b/src/rendering/cursor.rs @@ -60,10 +60,10 @@ impl LineCursor { self.position -= abs; Ok(by) } else { - Err(-self.position.saturating_as::()) + Err(-(self.position as i32)) } } else { - let space = self.space().saturating_as(); + let space = self.space() as i32; if by <= space { // Here we know by > 0, cast is safe self.position += by as u32; diff --git a/src/rendering/line.rs b/src/rendering/line.rs index 328384c4..7ad0daa2 100644 --- a/src/rendering/line.rs +++ b/src/rendering/line.rs @@ -10,7 +10,6 @@ use crate::{ style::TextBoxStyle, utils::str_width, }; -use az::SaturatingAs; use embedded_graphics::{ draw_target::DrawTarget, geometry::Point, @@ -175,7 +174,7 @@ where let (left, space_config) = self.style.alignment.place_line(text_renderer, lm); - self.cursor.move_cursor(left.saturating_as()).ok(); + self.cursor.move_cursor(left as i32).ok(); let mut render_element_handler = RenderElementHandler { text_renderer, diff --git a/src/rendering/line_iter.rs b/src/rendering/line_iter.rs index 008b60c3..6846fd28 100644 --- a/src/rendering/line_iter.rs +++ b/src/rendering/line_iter.rs @@ -266,7 +266,7 @@ where handler.whitespace("\t", 0, moved)? } - Ok(moved) | Err(moved) => handler.move_cursor(moved.saturating_as())?, + Ok(moved) | Err(moved) => handler.move_cursor(moved as i32)?, } Ok(()) } diff --git a/src/style/mod.rs b/src/style/mod.rs index 918c1346..c2646917 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -194,7 +194,6 @@ use crate::{ }, utils::str_width, }; -use az::SaturatingAs; use embedded_graphics::{ pixelcolor::Rgb888, text::{renderer::TextRenderer, LineHeight}, @@ -407,7 +406,7 @@ impl<'a, S: TextRenderer> ElementHandler for MeasureLineElementHandler<'a, S> { } fn move_cursor(&mut self, by: i32) -> Result<(), Self::Error> { - self.cursor = (self.cursor.saturating_as::() + by) as u32; + self.cursor = (self.cursor as i32 + by) as u32; Ok(()) } diff --git a/src/utils.rs b/src/utils.rs index f25c92ff..16ca47f2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,5 @@ //! Misc utilities -use az::SaturatingAs; use embedded_graphics::{ prelude::Point, text::{renderer::TextRenderer, Baseline}, @@ -11,8 +10,7 @@ pub fn str_width(renderer: &impl TextRenderer, s: &str) -> u32 { renderer .measure_string(s, Point::zero(), Baseline::Top) .next_position - .x - .saturating_as() + .x as u32 } #[cfg(test)]