mirror of
https://github.com/itsjunetime/tdf.git
synced 2026-06-02 08:01:47 -04:00
Very minor performance improvements
This commit is contained in:
Generated
+27
@@ -415,6 +415,17 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flume"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsevent-sys"
|
name = "fsevent-sys"
|
||||||
version = "4.1.0"
|
version = "4.1.0"
|
||||||
@@ -467,6 +478,12 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
@@ -1287,6 +1304,15 @@ version = "1.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stability"
|
name = "stability"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -1362,6 +1388,7 @@ dependencies = [
|
|||||||
"cairo-rs",
|
"cairo-rs",
|
||||||
"criterion",
|
"criterion",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
"flume",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"glib",
|
"glib",
|
||||||
"image",
|
"image",
|
||||||
|
|||||||
+2
-1
@@ -24,10 +24,11 @@ ratatui-image = { git = "https://github.com/itsjunetime/ratatui-image.git", bran
|
|||||||
crossterm = { version = "0.27.0", features = ["event-stream"] }
|
crossterm = { version = "0.27.0", features = ["event-stream"] }
|
||||||
image = { version = "0.25.1", features = ["png", "rayon"], default-features = false }
|
image = { version = "0.25.1", features = ["png", "rayon"], default-features = false }
|
||||||
notify = "6.1.1"
|
notify = "6.1.1"
|
||||||
tokio = { version = "1.37.0", features = ["rt-multi-thread", "sync", "macros"] }
|
tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros"] }
|
||||||
futures-util = { version = "0.3.30", default-features = false }
|
futures-util = { version = "0.3.30", default-features = false }
|
||||||
glib = "0.19.6"
|
glib = "0.19.6"
|
||||||
itertools = "*"
|
itertools = "*"
|
||||||
|
flume = { version = "0.11.0", default-features = false, features = ["async"] }
|
||||||
|
|
||||||
[profile.production]
|
[profile.production]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
|||||||
@@ -26,5 +26,9 @@ fn render_example(c: &mut Criterion) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(benches, render_dict, render_example);
|
criterion_group!(
|
||||||
|
name = benches;
|
||||||
|
config = Criterion::default().sample_size(10);
|
||||||
|
targets = render_dict, render_example
|
||||||
|
);
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|||||||
+13
-9
@@ -1,17 +1,18 @@
|
|||||||
use std::{hint::black_box, path::Path};
|
use std::{hint::black_box, path::Path};
|
||||||
|
|
||||||
use crossterm::terminal::WindowSize;
|
use crossterm::terminal::WindowSize;
|
||||||
|
use flume::{unbounded, Sender};
|
||||||
use ratatui::layout::Rect;
|
use ratatui::layout::Rect;
|
||||||
use ratatui_image::picker::{Picker, ProtocolType};
|
use ratatui_image::picker::{Picker, ProtocolType};
|
||||||
use tdf::{converter::{run_conversion_loop, ConvertedPage, ConverterMsg}, renderer::{fill_default, start_rendering, RenderError, RenderInfo, RenderNotif}};
|
use tdf::{converter::{run_conversion_loop, ConvertedPage, ConverterMsg}, renderer::{fill_default, start_rendering, RenderError, RenderInfo, RenderNotif}};
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
|
use futures_util::stream::StreamExt as _;
|
||||||
|
|
||||||
pub async fn render_doc(path: impl AsRef<Path>) {
|
pub async fn render_doc(path: impl AsRef<Path>) {
|
||||||
let pathbuf = path.as_ref().canonicalize().unwrap();
|
let pathbuf = path.as_ref().canonicalize().unwrap();
|
||||||
let str_path = format!("file://{}", pathbuf.into_os_string().to_string_lossy());
|
let str_path = format!("file://{}", pathbuf.into_os_string().to_string_lossy());
|
||||||
|
|
||||||
let (to_render_tx, from_main_rx) = unbounded_channel();
|
let (to_render_tx, from_main_rx) = unbounded();
|
||||||
let (to_main_tx, mut from_render_rx) = unbounded_channel();
|
let (to_main_tx, from_render_rx) = unbounded();
|
||||||
|
|
||||||
let font_size = (8, 14);
|
let font_size = (8, 14);
|
||||||
let (columns, rows) = (60, 180);
|
let (columns, rows) = (60, 180);
|
||||||
@@ -27,8 +28,8 @@ pub async fn render_doc(path: impl AsRef<Path>) {
|
|||||||
start_rendering(str_path, to_main_tx, from_main_rx, size)
|
start_rendering(str_path, to_main_tx, from_main_rx, size)
|
||||||
});
|
});
|
||||||
|
|
||||||
let (mut to_converter_tx, from_main_rx) = unbounded_channel();
|
let (mut to_converter_tx, from_main_rx) = unbounded();
|
||||||
let (to_main_tx, mut from_converter_rx) = unbounded_channel();
|
let (to_main_tx, from_converter_rx) = unbounded();
|
||||||
|
|
||||||
let mut picker = Picker::new(font_size);
|
let mut picker = Picker::new(font_size);
|
||||||
picker.protocol_type = ProtocolType::Kitty;
|
picker.protocol_type = ProtocolType::Kitty;
|
||||||
@@ -40,7 +41,7 @@ pub async fn render_doc(path: impl AsRef<Path>) {
|
|||||||
fn handle_renderer_msg(
|
fn handle_renderer_msg(
|
||||||
msg: Result<RenderInfo, RenderError>,
|
msg: Result<RenderInfo, RenderError>,
|
||||||
pages: &mut Vec<Option<ConvertedPage>>,
|
pages: &mut Vec<Option<ConvertedPage>>,
|
||||||
to_converter_tx: &mut UnboundedSender<tdf::converter::ConverterMsg>,
|
to_converter_tx: &mut Sender<tdf::converter::ConverterMsg>,
|
||||||
) {
|
) {
|
||||||
match msg {
|
match msg {
|
||||||
Ok(RenderInfo::NumPages(num)) => {
|
Ok(RenderInfo::NumPages(num)) => {
|
||||||
@@ -55,7 +56,7 @@ pub async fn render_doc(path: impl AsRef<Path>) {
|
|||||||
fn handle_converter_msg(
|
fn handle_converter_msg(
|
||||||
msg: Result<ConvertedPage, RenderError>,
|
msg: Result<ConvertedPage, RenderError>,
|
||||||
pages: &mut [Option<ConvertedPage>],
|
pages: &mut [Option<ConvertedPage>],
|
||||||
to_converter_tx: &mut UnboundedSender<ConverterMsg>
|
to_converter_tx: &mut Sender<ConverterMsg>
|
||||||
) {
|
) {
|
||||||
let page = msg.expect("Got error from converter");
|
let page = msg.expect("Got error from converter");
|
||||||
let num = page.num;
|
let num = page.num;
|
||||||
@@ -79,12 +80,15 @@ pub async fn render_doc(path: impl AsRef<Path>) {
|
|||||||
};
|
};
|
||||||
to_render_tx.send(RenderNotif::Area(main_area)).unwrap();
|
to_render_tx.send(RenderNotif::Area(main_area)).unwrap();
|
||||||
|
|
||||||
|
let mut from_render_rx = from_render_rx.into_stream();
|
||||||
|
let mut from_converter_rx = from_converter_rx.into_stream();
|
||||||
|
|
||||||
while pages.is_empty() || pages.iter().any(|p| p.is_none()) {
|
while pages.is_empty() || pages.iter().any(|p| p.is_none()) {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
Some(renderer_msg) = from_render_rx.recv() => {
|
Some(renderer_msg) = from_render_rx.next() => {
|
||||||
handle_renderer_msg(renderer_msg, &mut pages, &mut to_converter_tx);
|
handle_renderer_msg(renderer_msg, &mut pages, &mut to_converter_tx);
|
||||||
},
|
},
|
||||||
Some(converter_msg) = from_converter_rx.recv() => {
|
Some(converter_msg) = from_converter_rx.next() => {
|
||||||
handle_converter_msg(converter_msg, &mut pages, &mut to_converter_tx);
|
handle_converter_msg(converter_msg, &mut pages, &mut to_converter_tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -1,10 +1,8 @@
|
|||||||
|
use flume::{Receiver, SendError, Sender, TryRecvError};
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ratatui_image::{picker::Picker, protocol::Protocol, Resize};
|
use ratatui_image::{picker::Picker, protocol::Protocol, Resize};
|
||||||
use tokio::sync::mpsc::{
|
use futures_util::stream::StreamExt;
|
||||||
error::{SendError, TryRecvError},
|
|
||||||
UnboundedReceiver, UnboundedSender
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::renderer::{fill_default, PageInfo, RenderError};
|
use crate::renderer::{fill_default, PageInfo, RenderError};
|
||||||
|
|
||||||
@@ -23,8 +21,8 @@ pub enum ConverterMsg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_conversion_loop(
|
pub async fn run_conversion_loop(
|
||||||
sender: UnboundedSender<Result<ConvertedPage, RenderError>>,
|
sender: Sender<Result<ConvertedPage, RenderError>>,
|
||||||
mut receiver: UnboundedReceiver<ConverterMsg>,
|
receiver: Receiver<ConverterMsg>,
|
||||||
mut picker: Picker
|
mut picker: Picker
|
||||||
) -> Result<(), SendError<Result<ConvertedPage, RenderError>>> {
|
) -> Result<(), SendError<Result<ConvertedPage, RenderError>>> {
|
||||||
let mut images = vec![];
|
let mut images = vec![];
|
||||||
@@ -119,7 +117,7 @@ pub async fn run_conversion_loop(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(msg) = receiver.recv().await else {
|
let Some(msg) = receiver.stream().next().await else {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+10
-6
@@ -44,7 +44,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let file = std::env::args().nth(1).ok_or("Program requires a file to process")?;
|
let file = std::env::args().nth(1).ok_or("Program requires a file to process")?;
|
||||||
let path = PathBuf::from_str(&file)?.canonicalize()?;
|
let path = PathBuf::from_str(&file)?.canonicalize()?;
|
||||||
|
|
||||||
let (watch_tx, render_rx) = tokio::sync::mpsc::unbounded_channel();
|
//let (watch_tx, render_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
let (watch_tx, render_rx) = flume::unbounded();
|
||||||
let tui_tx = watch_tx.clone();
|
let tui_tx = watch_tx.clone();
|
||||||
|
|
||||||
// we need to call this outside the recommended_watcher call because if we call it inside, that
|
// we need to call this outside the recommended_watcher call because if we call it inside, that
|
||||||
@@ -62,7 +63,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
watcher.watch(&path, RecursiveMode::NonRecursive)?;
|
watcher.watch(&path, RecursiveMode::NonRecursive)?;
|
||||||
|
|
||||||
let file_path = format!("file://{}", path.clone().into_os_string().to_string_lossy());
|
let file_path = format!("file://{}", path.clone().into_os_string().to_string_lossy());
|
||||||
let (render_tx, mut tui_rx) = tokio::sync::mpsc::unbounded_channel();
|
let (render_tx, tui_rx) = flume::unbounded();
|
||||||
|
|
||||||
let mut window_size = window_size()?;
|
let mut window_size = window_size()?;
|
||||||
|
|
||||||
@@ -132,8 +133,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let mut ev_stream = crossterm::event::EventStream::new();
|
let mut ev_stream = crossterm::event::EventStream::new();
|
||||||
|
|
||||||
let (to_converter, from_main) = tokio::sync::mpsc::unbounded_channel();
|
let (to_converter, from_main) = flume::unbounded();
|
||||||
let (to_main, mut from_converter) = tokio::sync::mpsc::unbounded_channel();
|
let (to_main, from_converter) = flume::unbounded();
|
||||||
|
|
||||||
tokio::spawn(run_conversion_loop(to_main, from_main, picker));
|
tokio::spawn(run_conversion_loop(to_main, from_main, picker));
|
||||||
|
|
||||||
@@ -163,6 +164,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let mut main_area = tui::Tui::main_layout(&term.get_frame());
|
let mut main_area = tui::Tui::main_layout(&term.get_frame());
|
||||||
tui_tx.send(RenderNotif::Area(main_area[1]))?;
|
tui_tx.send(RenderNotif::Area(main_area[1]))?;
|
||||||
|
|
||||||
|
let mut tui_rx = tui_rx.into_stream();
|
||||||
|
let mut from_converter = from_converter.into_stream();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut needs_redraw = tokio::select! {
|
let mut needs_redraw = tokio::select! {
|
||||||
// First we check if we have any keystrokes
|
// First we check if we have any keystrokes
|
||||||
@@ -186,7 +190,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(renderer_msg) = tui_rx.recv() => {
|
Some(renderer_msg) = tui_rx.next() => {
|
||||||
match renderer_msg {
|
match renderer_msg {
|
||||||
Ok(RenderInfo::NumPages(num)) => {
|
Ok(RenderInfo::NumPages(num)) => {
|
||||||
tui.set_n_pages(num);
|
tui.set_n_pages(num);
|
||||||
@@ -200,7 +204,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Some(img_res) = from_converter.recv() => {
|
Some(img_res) = from_converter.next() => {
|
||||||
match img_res {
|
match img_res {
|
||||||
Ok(ConvertedPage { page, num, num_results }) => tui.page_ready(page, num, num_results),
|
Ok(ConvertedPage { page, num, num_results }) => tui.page_ready(page, num, num_results),
|
||||||
Err(e) => tui.show_error(e),
|
Err(e) => tui.show_error(e),
|
||||||
|
|||||||
+9
-11
@@ -1,9 +1,9 @@
|
|||||||
use cairo::{Antialias, Format};
|
use cairo::{Antialias, Format};
|
||||||
use crossterm::terminal::WindowSize;
|
use crossterm::terminal::WindowSize;
|
||||||
|
use flume::{Receiver, Sender, TryRecvError};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use poppler::{Color, Document, FindFlags, Page, Rectangle, SelectionStyle};
|
use poppler::{Color, Document, FindFlags, Page, Rectangle, SelectionStyle};
|
||||||
use ratatui::layout::Rect;
|
use ratatui::layout::Rect;
|
||||||
use tokio::sync::mpsc::{error::TryRecvError, UnboundedReceiver, UnboundedSender};
|
|
||||||
|
|
||||||
pub enum RenderNotif {
|
pub enum RenderNotif {
|
||||||
Area(Rect),
|
Area(Rect),
|
||||||
@@ -61,15 +61,15 @@ pub fn fill_default<T: Default>(vec: &mut Vec<T>, size: usize) {
|
|||||||
// we're done.
|
// we're done.
|
||||||
pub fn start_rendering(
|
pub fn start_rendering(
|
||||||
path: String,
|
path: String,
|
||||||
sender: UnboundedSender<Result<RenderInfo, RenderError>>,
|
sender: Sender<Result<RenderInfo, RenderError>>,
|
||||||
mut receiver: UnboundedReceiver<RenderNotif>,
|
receiver: Receiver<RenderNotif>,
|
||||||
size: WindowSize
|
size: WindowSize
|
||||||
) {
|
) {
|
||||||
// first, wait 'til we get told what the current starting area is so that we can set it to
|
// first, wait 'til we get told what the current starting area is so that we can set it to
|
||||||
// know what to render to
|
// know what to render to
|
||||||
let mut area;
|
let mut area;
|
||||||
loop {
|
loop {
|
||||||
if let RenderNotif::Area(r) = receiver.blocking_recv().unwrap() {
|
if let RenderNotif::Area(r) = receiver.recv().unwrap() {
|
||||||
area = r;
|
area = r;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,7 @@ pub fn start_rendering(
|
|||||||
loop {
|
loop {
|
||||||
// This once returned None despite the main thing being still connected (I think, at
|
// This once returned None despite the main thing being still connected (I think, at
|
||||||
// last), so I'm just being safe here
|
// last), so I'm just being safe here
|
||||||
let Some(msg) = receiver.blocking_recv() else {
|
let Ok(msg) = receiver.recv() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
handle_notif!(msg);
|
handle_notif!(msg);
|
||||||
@@ -293,7 +293,7 @@ fn render_single_page(
|
|||||||
let surface_height = p_height * scale_factor;
|
let surface_height = p_height * scale_factor;
|
||||||
|
|
||||||
let surface = cairo::ImageSurface::create(
|
let surface = cairo::ImageSurface::create(
|
||||||
Format::ARgb32,
|
Format::Rgb16_565,
|
||||||
// No matter how big you make these arguments, the image will be drawn at the same
|
// No matter how big you make these arguments, the image will be drawn at the same
|
||||||
// size. So if you make them really big, the image will be drawn on a quarter of it. If
|
// size. So if you make them really big, the image will be drawn on a quarter of it. If
|
||||||
// you make them really small, the image will cover more than all of the surface.
|
// you make them really small, the image will cover more than all of the surface.
|
||||||
@@ -306,9 +306,9 @@ fn render_single_page(
|
|||||||
surface_height as i32
|
surface_height as i32
|
||||||
)
|
)
|
||||||
.map_err(|e| format!("Couldn't create ImageSurface: {e}"))?;
|
.map_err(|e| format!("Couldn't create ImageSurface: {e}"))?;
|
||||||
let ctx = cairo::Context::new(surface).map_err(|e| format!("Couldn't create Context: {e}"))?;
|
surface.set_device_scale(scale_factor, scale_factor);
|
||||||
|
|
||||||
ctx.scale(scale_factor, scale_factor);
|
let ctx = cairo::Context::new(surface).map_err(|e| format!("Couldn't create Context: {e}"))?;
|
||||||
|
|
||||||
// The default background color of PDFs (at least, I think) is white, so we need to set
|
// The default background color of PDFs (at least, I think) is white, so we need to set
|
||||||
// that as the background color, then paint, then render.
|
// that as the background color, then paint, then render.
|
||||||
@@ -344,9 +344,7 @@ fn render_single_page(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.scale(1. / scale_factor, 1. / scale_factor);
|
let mut img_data = Vec::with_capacity((surface_height * surface_width) as usize);
|
||||||
|
|
||||||
let mut img_data = Vec::new();
|
|
||||||
ctx.target()
|
ctx.target()
|
||||||
.write_to_png(&mut img_data)
|
.write_to_png(&mut img_data)
|
||||||
.map_err(|e| format!("Couldn't write surface to png: {e}"))?;
|
.map_err(|e| format!("Couldn't write surface to png: {e}"))?;
|
||||||
|
|||||||
Reference in New Issue
Block a user