safe conversions
This commit is contained in:
@@ -16,6 +16,8 @@ pub struct TerminalText {
|
|||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod safe_casts;
|
||||||
|
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
|
|
||||||
impl TerminalText {
|
impl TerminalText {
|
||||||
@@ -55,10 +57,11 @@ impl TerminalText {
|
|||||||
|
|
||||||
pub fn resize(&mut self, width: u32, height: u32) {
|
pub fn resize(&mut self, width: u32, height: u32) {
|
||||||
trace!("Resizing window - Width: {width} Height: {height}");
|
trace!("Resizing window - Width: {width} Height: {height}");
|
||||||
|
|
||||||
self.buffer.set_size(
|
self.buffer.set_size(
|
||||||
&mut self.font_system,
|
&mut self.font_system,
|
||||||
Some(width as f32),
|
Some(safe_casts::u32_to_f32_or_max(width)),
|
||||||
Some(height as f32),
|
Some(safe_casts::u32_to_f32_or_max(height)),
|
||||||
);
|
);
|
||||||
// Update the buffer's wrapping based on the new width
|
// Update the buffer's wrapping based on the new width
|
||||||
self.buffer.set_wrap(&mut self.font_system, Wrap::Glyph);
|
self.buffer.set_wrap(&mut self.font_system, Wrap::Glyph);
|
||||||
@@ -68,6 +71,14 @@ impl TerminalText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn merge_dirty_regions(&self) -> TextBounds {
|
fn merge_dirty_regions(&self) -> TextBounds {
|
||||||
|
if self.dirty_regions.is_empty() {
|
||||||
|
return TextBounds {
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
TextBounds {
|
TextBounds {
|
||||||
left: self
|
left: self
|
||||||
.dirty_regions
|
.dirty_regions
|
||||||
@@ -101,7 +112,6 @@ impl TerminalText {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if !self.dirty_regions.is_empty() {
|
|
||||||
let region = self.merge_dirty_regions();
|
let region = self.merge_dirty_regions();
|
||||||
trace!("Preparing region {:?}", region);
|
trace!("Preparing region {:?}", region);
|
||||||
self.renderer
|
self.renderer
|
||||||
@@ -123,7 +133,6 @@ impl TerminalText {
|
|||||||
&mut self.cache,
|
&mut self.cache,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
self.dirty_regions.clear();
|
self.dirty_regions.clear();
|
||||||
}
|
}
|
||||||
@@ -235,28 +244,15 @@ impl TerminalText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate bounds based on visual line positions
|
// Calculate bounds based on visual line positions
|
||||||
let top_f32 = (top_line as f32 * line_height).floor();
|
let top_f32 = (safe_casts::usize_to_f32_or_max(top_line) * line_height).floor();
|
||||||
let bottom_f32 = (bottom_line as f32 * line_height).ceil();
|
let bottom_f32 = (safe_casts::usize_to_f32_or_max(bottom_line) * line_height).ceil();
|
||||||
|
|
||||||
// Safe conversions with overflow checks
|
// Safe conversions with overflow checks
|
||||||
let top = if top_f32 > i32::MAX as f32 {
|
let top = safe_casts::f32_to_i32_or_bound(top_f32);
|
||||||
i32::MAX
|
let bottom = safe_casts::f32_to_i32_or_bound(bottom_f32);
|
||||||
} else if top_f32 < i32::MIN as f32 {
|
|
||||||
i32::MIN
|
|
||||||
} else {
|
|
||||||
top_f32 as i32
|
|
||||||
};
|
|
||||||
|
|
||||||
let bottom = if bottom_f32 > i32::MAX as f32 {
|
|
||||||
i32::MAX
|
|
||||||
} else if bottom_f32 < i32::MIN as f32 {
|
|
||||||
i32::MIN
|
|
||||||
} else {
|
|
||||||
bottom_f32 as i32
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ensure viewport width doesn't exceed i32::MAX
|
// Ensure viewport width doesn't exceed i32::MAX
|
||||||
let right = viewport_width.min(i32::MAX as u32) as i32;
|
let right = safe_casts::u32_to_i32_or_max(viewport_width.min(i32::MAX as u32));
|
||||||
|
|
||||||
TextBounds {
|
TextBounds {
|
||||||
left: 0,
|
left: 0,
|
||||||
@@ -267,7 +263,7 @@ impl TerminalText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_visible_line_range(&self) -> (usize, usize) {
|
fn get_visible_line_range(&self) -> (usize, usize) {
|
||||||
let viewport_height = self.viewport.resolution().height as f32;
|
let viewport_height = safe_casts::u32_to_f32_or_max(self.viewport.resolution().height);
|
||||||
let line_height = self.buffer.metrics().line_height;
|
let line_height = self.buffer.metrics().line_height;
|
||||||
|
|
||||||
// Start from line 0 (no scrolling yet)
|
// Start from line 0 (no scrolling yet)
|
||||||
@@ -282,7 +278,9 @@ impl TerminalText {
|
|||||||
last_logical_line = run.line_i;
|
last_logical_line = run.line_i;
|
||||||
|
|
||||||
// If we've exceeded the viewport height, we can stop counting
|
// If we've exceeded the viewport height, we can stop counting
|
||||||
if ((start_line + visual_line_count) as f32 * line_height) > viewport_height {
|
if (safe_casts::usize_to_f32_or_max(start_line + visual_line_count) * line_height)
|
||||||
|
> viewport_height
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
57
src/app/rendering/terminal_text/safe_casts.rs
Normal file
57
src/app/rendering/terminal_text/safe_casts.rs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
use log::trace;
|
||||||
|
|
||||||
|
// Safe conversions with overflow checks
|
||||||
|
|
||||||
|
pub fn u32_to_i32_or_max(n: u32) -> i32 {
|
||||||
|
if n > i32::MAX as u32 {
|
||||||
|
trace!(
|
||||||
|
"Overflow casting {n}::u32 as i32, defaulting to {}",
|
||||||
|
i32::MAX
|
||||||
|
);
|
||||||
|
i32::MAX
|
||||||
|
} else {
|
||||||
|
n as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u32_to_f32_or_max(n: u32) -> f32 {
|
||||||
|
if n > f32::MAX as u32 {
|
||||||
|
trace!(
|
||||||
|
"Overflow casting {n}::u32 as f32, defaulting to {}",
|
||||||
|
f32::MAX
|
||||||
|
);
|
||||||
|
f32::MAX
|
||||||
|
} else {
|
||||||
|
n as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn usize_to_f32_or_max(n: usize) -> f32 {
|
||||||
|
if n > f32::MAX as usize {
|
||||||
|
trace!(
|
||||||
|
"Overflow casting {n}::usize as f32, defaulting to {}",
|
||||||
|
f32::MAX
|
||||||
|
);
|
||||||
|
f32::MAX
|
||||||
|
} else {
|
||||||
|
n as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f32_to_i32_or_bound(n: f32) -> i32 {
|
||||||
|
if n > i32::MAX as f32 {
|
||||||
|
trace!(
|
||||||
|
"Overflow casting {n}::f32 as i32, defaulting to {}",
|
||||||
|
i32::MAX
|
||||||
|
);
|
||||||
|
i32::MAX
|
||||||
|
} else if n < i32::MIN as f32 {
|
||||||
|
trace!(
|
||||||
|
"Underflow casting {n}::f32 as i32, defaulting to {}",
|
||||||
|
i32::MIN
|
||||||
|
);
|
||||||
|
i32::MIN
|
||||||
|
} else {
|
||||||
|
n as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user