Refactor large functions into smaller components
This commit is contained in:
@@ -99,7 +99,7 @@ fn select_cursor(
|
|||||||
|
|
||||||
let cursor = &app_state.cursors[index];
|
let cursor = &app_state.cursors[index];
|
||||||
|
|
||||||
let filename = Path::new(&cursor.path)
|
let _filename = Path::new(&cursor.path)
|
||||||
.file_name()
|
.file_name()
|
||||||
.and_then(|name| name.to_str())
|
.and_then(|name| name.to_str())
|
||||||
.ok_or_else(|| format!("Invalid cursor path: {}", cursor.path))?;
|
.ok_or_else(|| format!("Invalid cursor path: {}", cursor.path))?;
|
||||||
@@ -123,7 +123,7 @@ fn next_cursor(
|
|||||||
|
|
||||||
let cursor = &app_state.cursors[app_state.current_index];
|
let cursor = &app_state.cursors[app_state.current_index];
|
||||||
|
|
||||||
let filename = Path::new(&cursor.path)
|
let _filename = Path::new(&cursor.path)
|
||||||
.file_name()
|
.file_name()
|
||||||
.and_then(|name| name.to_str())
|
.and_then(|name| name.to_str())
|
||||||
.ok_or_else(|| format!("Invalid cursor path: {}", cursor.path))?;
|
.ok_or_else(|| format!("Invalid cursor path: {}", cursor.path))?;
|
||||||
@@ -200,71 +200,90 @@ fn restore_default_cursors() -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to load cursor files from src/cursors directory
|
// Get possible cursor directory paths
|
||||||
fn load_cursor_files() -> Vec<Cursor> {
|
fn get_cursor_directory_paths() -> Vec<PathBuf> {
|
||||||
let mut cursors = Vec::new();
|
|
||||||
|
|
||||||
// Determine the path to src/cursors relative to src-tauri (CARGO_MANIFEST_DIR)
|
|
||||||
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
|
||||||
// Check multiple possible locations
|
vec![
|
||||||
let possible_cursor_dirs = vec![
|
|
||||||
manifest_dir.join("../src/cursors"),
|
manifest_dir.join("../src/cursors"),
|
||||||
manifest_dir.join("src/cursors"),
|
manifest_dir.join("src/cursors"),
|
||||||
manifest_dir.join("cursors"),
|
manifest_dir.join("cursors"),
|
||||||
manifest_dir.clone(), // Check manifest dir itself
|
manifest_dir.clone(), // Check manifest dir itself
|
||||||
];
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process a single cursor file entry
|
||||||
|
fn process_cursor_file(entry: std::fs::DirEntry) -> Option<Cursor> {
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if path.is_file()
|
||||||
|
&& path
|
||||||
|
.extension()
|
||||||
|
.map_or(false, |ext| ext == "png" || ext == "cur")
|
||||||
|
{
|
||||||
|
let name = path
|
||||||
|
.file_stem()
|
||||||
|
.and_then(|s| s.to_str())
|
||||||
|
.unwrap_or("Unknown")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
Some(Cursor {
|
||||||
|
name,
|
||||||
|
path: path.to_string_lossy().to_string(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan cursor directories for cursor files
|
||||||
|
fn scan_cursor_directories() -> Vec<Cursor> {
|
||||||
|
let possible_cursor_dirs = get_cursor_directory_paths();
|
||||||
|
|
||||||
for cursors_dir in possible_cursor_dirs.iter() {
|
for cursors_dir in possible_cursor_dirs.iter() {
|
||||||
if cursors_dir.exists() {
|
if cursors_dir.exists() {
|
||||||
if let Ok(entries) = std::fs::read_dir(cursors_dir) {
|
if let Ok(entries) = std::fs::read_dir(cursors_dir) {
|
||||||
for entry in entries.filter_map(Result::ok) {
|
let cursors: Vec<Cursor> = entries
|
||||||
let path = entry.path();
|
.filter_map(Result::ok)
|
||||||
|
.filter_map(process_cursor_file)
|
||||||
|
.collect();
|
||||||
|
|
||||||
if path.is_file()
|
if !cursors.is_empty() {
|
||||||
&& path
|
return cursors;
|
||||||
.extension()
|
|
||||||
.map_or(false, |ext| ext == "png" || ext == "cur")
|
|
||||||
{
|
|
||||||
let name = path
|
|
||||||
.file_stem()
|
|
||||||
.and_then(|s| s.to_str())
|
|
||||||
.unwrap_or("Unknown")
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
cursors.push(Cursor {
|
|
||||||
name,
|
|
||||||
path: path.to_string_lossy().to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cursors.is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we found no cursors, use mock data with paths relative to what resolve_resource expects
|
Vec::new()
|
||||||
if cursors.is_empty() {
|
}
|
||||||
eprintln!("No cursor files found, using fallback cursors");
|
|
||||||
|
|
||||||
// Mock data paths should reflect their eventual resource path structure
|
// Create fallback cursors when no files are found
|
||||||
cursors.push(Cursor {
|
fn create_fallback_cursors() -> Vec<Cursor> {
|
||||||
|
eprintln!("No cursor files found, using fallback cursors");
|
||||||
|
|
||||||
|
vec![
|
||||||
|
Cursor {
|
||||||
name: "Default".to_string(),
|
name: "Default".to_string(),
|
||||||
path: "src/cursors/default.png".to_string(), // Filename will be 'default.png'
|
path: "src/cursors/default.png".to_string(),
|
||||||
});
|
},
|
||||||
|
Cursor {
|
||||||
cursors.push(Cursor {
|
|
||||||
name: "Icon".to_string(),
|
name: "Icon".to_string(),
|
||||||
path: "src/cursors/icon.png".to_string(), // Filename will be 'icon.png'
|
path: "src/cursors/icon.png".to_string(),
|
||||||
});
|
},
|
||||||
|
Cursor {
|
||||||
cursors.push(Cursor {
|
|
||||||
name: "Red".to_string(),
|
name: "Red".to_string(),
|
||||||
path: "src/cursors/red.png".to_string(), // Filename will be 'red.png'
|
path: "src/cursors/red.png".to_string(),
|
||||||
});
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to load cursor files from src/cursors directory
|
||||||
|
fn load_cursor_files() -> Vec<Cursor> {
|
||||||
|
let mut cursors = scan_cursor_directories();
|
||||||
|
|
||||||
|
if cursors.is_empty() {
|
||||||
|
cursors = create_fallback_cursors();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort cursors by name for consistent ordering
|
// Sort cursors by name for consistent ordering
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use winapi::{
|
|||||||
},
|
},
|
||||||
um::consoleapi::SetConsoleCtrlHandler,
|
um::consoleapi::SetConsoleCtrlHandler,
|
||||||
shared::minwindef::{TRUE, FALSE, DWORD},
|
shared::minwindef::{TRUE, FALSE, DWORD},
|
||||||
|
shared::windef::{HDC, HBITMAP, HGDIOBJ},
|
||||||
};
|
};
|
||||||
use ::image::{RgbaImage, open as image_open};
|
use ::image::{RgbaImage, open as image_open};
|
||||||
|
|
||||||
@@ -27,20 +28,48 @@ extern "system" fn ctrl_handler(_ctrl_type: u32) -> i32 {
|
|||||||
FALSE // Allow other handlers (like default exit) to run
|
FALSE // Allow other handlers (like default exit) to run
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a cursor from an RGBA image
|
// Device context setup result
|
||||||
unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
struct DeviceContexts {
|
||||||
let (width, height) = image.dimensions();
|
screen_dc: HDC,
|
||||||
let width_i32 = width as i32;
|
color_dc: HDC,
|
||||||
let height_i32 = height as i32;
|
mask_dc: HDC,
|
||||||
|
}
|
||||||
|
|
||||||
// Create device context and bitmap for the color data
|
impl DeviceContexts {
|
||||||
|
unsafe fn cleanup(&self) {
|
||||||
|
DeleteDC(self.mask_dc);
|
||||||
|
DeleteDC(self.color_dc);
|
||||||
|
ReleaseDC(null_mut(), self.screen_dc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitmap creation result
|
||||||
|
struct CursorBitmaps {
|
||||||
|
color_bitmap: HBITMAP,
|
||||||
|
mask_bitmap: HBITMAP,
|
||||||
|
color_bits_ptr: *mut winapi::ctypes::c_void,
|
||||||
|
mask_bits_ptr: *mut winapi::ctypes::c_void,
|
||||||
|
old_color_bitmap: HGDIOBJ,
|
||||||
|
old_mask_bitmap: HGDIOBJ,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CursorBitmaps {
|
||||||
|
unsafe fn cleanup(&self, contexts: &DeviceContexts) {
|
||||||
|
SelectObject(contexts.color_dc, self.old_color_bitmap);
|
||||||
|
SelectObject(contexts.mask_dc, self.old_mask_bitmap);
|
||||||
|
DeleteObject(self.color_bitmap as _);
|
||||||
|
DeleteObject(self.mask_bitmap as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup device contexts for cursor creation
|
||||||
|
unsafe fn setup_device_contexts() -> Option<DeviceContexts> {
|
||||||
let screen_dc = GetDC(null_mut());
|
let screen_dc = GetDC(null_mut());
|
||||||
if screen_dc.is_null() {
|
if screen_dc.is_null() {
|
||||||
eprintln!("Failed to get screen DC");
|
eprintln!("Failed to get screen DC");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a compatible DC for our bitmap
|
|
||||||
let color_dc = CreateCompatibleDC(screen_dc);
|
let color_dc = CreateCompatibleDC(screen_dc);
|
||||||
if color_dc.is_null() {
|
if color_dc.is_null() {
|
||||||
eprintln!("Failed to create compatible DC for color");
|
eprintln!("Failed to create compatible DC for color");
|
||||||
@@ -48,7 +77,6 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a compatible DC for our mask bitmap
|
|
||||||
let mask_dc = CreateCompatibleDC(screen_dc);
|
let mask_dc = CreateCompatibleDC(screen_dc);
|
||||||
if mask_dc.is_null() {
|
if mask_dc.is_null() {
|
||||||
eprintln!("Failed to create compatible DC for mask");
|
eprintln!("Failed to create compatible DC for mask");
|
||||||
@@ -57,11 +85,24 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(DeviceContexts {
|
||||||
|
screen_dc,
|
||||||
|
color_dc,
|
||||||
|
mask_dc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create bitmaps for cursor creation
|
||||||
|
unsafe fn create_cursor_bitmaps(
|
||||||
|
contexts: &DeviceContexts,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
) -> Option<CursorBitmaps> {
|
||||||
// Set up BITMAPINFO structure for DIB
|
// Set up BITMAPINFO structure for DIB
|
||||||
let mut bitmap_info: BITMAPINFO = std::mem::zeroed();
|
let mut bitmap_info: BITMAPINFO = std::mem::zeroed();
|
||||||
bitmap_info.bmiHeader.biSize = std::mem::size_of::<BITMAPINFOHEADER>() as u32;
|
bitmap_info.bmiHeader.biSize = std::mem::size_of::<BITMAPINFOHEADER>() as u32;
|
||||||
bitmap_info.bmiHeader.biWidth = width_i32;
|
bitmap_info.bmiHeader.biWidth = width;
|
||||||
bitmap_info.bmiHeader.biHeight = -height_i32; // Negative for top-down DIB
|
bitmap_info.bmiHeader.biHeight = -height; // Negative for top-down DIB
|
||||||
bitmap_info.bmiHeader.biPlanes = 1;
|
bitmap_info.bmiHeader.biPlanes = 1;
|
||||||
bitmap_info.bmiHeader.biBitCount = 32; // 32 bits per pixel (BGRA)
|
bitmap_info.bmiHeader.biBitCount = 32; // 32 bits per pixel (BGRA)
|
||||||
bitmap_info.bmiHeader.biCompression = BI_RGB;
|
bitmap_info.bmiHeader.biCompression = BI_RGB;
|
||||||
@@ -70,7 +111,7 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
|||||||
let mut color_bits_ptr: *mut winapi::ctypes::c_void = null_mut();
|
let mut color_bits_ptr: *mut winapi::ctypes::c_void = null_mut();
|
||||||
let mut ppv_bits_color: *mut winapi::ctypes::c_void = color_bits_ptr;
|
let mut ppv_bits_color: *mut winapi::ctypes::c_void = color_bits_ptr;
|
||||||
let color_bitmap = CreateDIBSection(
|
let color_bitmap = CreateDIBSection(
|
||||||
color_dc,
|
contexts.color_dc,
|
||||||
&bitmap_info,
|
&bitmap_info,
|
||||||
DIB_RGB_COLORS,
|
DIB_RGB_COLORS,
|
||||||
&mut ppv_bits_color,
|
&mut ppv_bits_color,
|
||||||
@@ -81,9 +122,7 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
|||||||
|
|
||||||
if color_bitmap.is_null() || color_bits_ptr.is_null() {
|
if color_bitmap.is_null() || color_bits_ptr.is_null() {
|
||||||
eprintln!("Failed to create color DIB section");
|
eprintln!("Failed to create color DIB section");
|
||||||
DeleteDC(mask_dc);
|
contexts.cleanup();
|
||||||
DeleteDC(color_dc);
|
|
||||||
ReleaseDC(null_mut(), screen_dc);
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +131,7 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
|||||||
let mut mask_bits_ptr: *mut winapi::ctypes::c_void = null_mut();
|
let mut mask_bits_ptr: *mut winapi::ctypes::c_void = null_mut();
|
||||||
let mut ppv_bits: *mut winapi::ctypes::c_void = mask_bits_ptr;
|
let mut ppv_bits: *mut winapi::ctypes::c_void = mask_bits_ptr;
|
||||||
let mask_bitmap = CreateDIBSection(
|
let mask_bitmap = CreateDIBSection(
|
||||||
mask_dc,
|
contexts.mask_dc,
|
||||||
&bitmap_info,
|
&bitmap_info,
|
||||||
DIB_RGB_COLORS,
|
DIB_RGB_COLORS,
|
||||||
&mut ppv_bits,
|
&mut ppv_bits,
|
||||||
@@ -104,32 +143,51 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
|||||||
if mask_bitmap.is_null() || mask_bits_ptr.is_null() {
|
if mask_bitmap.is_null() || mask_bits_ptr.is_null() {
|
||||||
eprintln!("Failed to create mask DIB section");
|
eprintln!("Failed to create mask DIB section");
|
||||||
DeleteObject(color_bitmap as _);
|
DeleteObject(color_bitmap as _);
|
||||||
DeleteDC(mask_dc);
|
contexts.cleanup();
|
||||||
DeleteDC(color_dc);
|
|
||||||
ReleaseDC(null_mut(), screen_dc);
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the bitmaps into the DCs
|
// Select the bitmaps into the DCs
|
||||||
let old_color_bitmap = SelectObject(color_dc, color_bitmap as _);
|
let old_color_bitmap = SelectObject(contexts.color_dc, color_bitmap as _);
|
||||||
let old_mask_bitmap = SelectObject(mask_dc, mask_bitmap as _);
|
let old_mask_bitmap = SelectObject(contexts.mask_dc, mask_bitmap as _);
|
||||||
|
|
||||||
if old_color_bitmap.is_null() || old_mask_bitmap.is_null() {
|
if old_color_bitmap.is_null() || old_mask_bitmap.is_null() {
|
||||||
eprintln!("Failed to select bitmaps into DCs");
|
eprintln!("Failed to select bitmaps into DCs");
|
||||||
DeleteObject(mask_bitmap as _);
|
DeleteObject(mask_bitmap as _);
|
||||||
DeleteObject(color_bitmap as _);
|
DeleteObject(color_bitmap as _);
|
||||||
DeleteDC(mask_dc);
|
contexts.cleanup();
|
||||||
DeleteDC(color_dc);
|
|
||||||
ReleaseDC(null_mut(), screen_dc);
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(CursorBitmaps {
|
||||||
|
color_bitmap,
|
||||||
|
mask_bitmap,
|
||||||
|
color_bits_ptr,
|
||||||
|
mask_bits_ptr,
|
||||||
|
old_color_bitmap,
|
||||||
|
old_mask_bitmap,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process image data and populate bitmaps
|
||||||
|
unsafe fn process_image_data(
|
||||||
|
image: &RgbaImage,
|
||||||
|
bitmaps: &CursorBitmaps,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
) {
|
||||||
// Copy the image data to the color DIB, converting RGBA to BGRA
|
// Copy the image data to the color DIB, converting RGBA to BGRA
|
||||||
let color_bits = std::slice::from_raw_parts_mut(color_bits_ptr as *mut u8, (width * height * 4) as usize);
|
let color_bits = std::slice::from_raw_parts_mut(
|
||||||
|
bitmaps.color_bits_ptr as *mut u8,
|
||||||
|
(width * height * 4) as usize,
|
||||||
|
);
|
||||||
|
|
||||||
// Calculate mask stride in bytes (1 bit per pixel, padded to DWORD)
|
// Calculate mask stride in bytes (1 bit per pixel, padded to DWORD)
|
||||||
let mask_stride = ((width + 31) / 32) * 4;
|
let mask_stride = ((width + 31) / 32) * 4;
|
||||||
let mask_bits = std::slice::from_raw_parts_mut(mask_bits_ptr as *mut u8, (mask_stride * height) as usize);
|
let mask_bits = std::slice::from_raw_parts_mut(
|
||||||
|
bitmaps.mask_bits_ptr as *mut u8,
|
||||||
|
(mask_stride * height) as usize,
|
||||||
|
);
|
||||||
|
|
||||||
// Clear mask bits (all transparent initially)
|
// Clear mask bits (all transparent initially)
|
||||||
for i in 0..(mask_stride * height) as usize {
|
for i in 0..(mask_stride * height) as usize {
|
||||||
@@ -165,29 +223,25 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create cursor from prepared bitmaps
|
||||||
|
unsafe fn create_cursor_from_bitmaps(
|
||||||
|
bitmaps: &CursorBitmaps,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
) -> Option<SyncHCURSOR> {
|
||||||
// Create ICONINFO structure
|
// Create ICONINFO structure
|
||||||
let mut icon_info: ICONINFO = std::mem::zeroed();
|
let mut icon_info: ICONINFO = std::mem::zeroed();
|
||||||
icon_info.fIcon = FALSE; // This is a cursor, not an icon
|
icon_info.fIcon = FALSE; // This is a cursor, not an icon
|
||||||
icon_info.xHotspot = width as DWORD / 2; // Center hotspot
|
icon_info.xHotspot = width as DWORD / 2; // Center hotspot
|
||||||
icon_info.yHotspot = height as DWORD / 2;
|
icon_info.yHotspot = height as DWORD / 2;
|
||||||
icon_info.hbmMask = mask_bitmap;
|
icon_info.hbmMask = bitmaps.mask_bitmap;
|
||||||
icon_info.hbmColor = color_bitmap;
|
icon_info.hbmColor = bitmaps.color_bitmap;
|
||||||
|
|
||||||
// Create the cursor
|
// Create the cursor
|
||||||
let cursor = CreateIconIndirect(&mut icon_info as *mut _);
|
let cursor = CreateIconIndirect(&mut icon_info as *mut _);
|
||||||
|
|
||||||
// Clean up resources
|
|
||||||
SelectObject(color_dc, old_color_bitmap);
|
|
||||||
SelectObject(mask_dc, old_mask_bitmap);
|
|
||||||
DeleteDC(color_dc);
|
|
||||||
DeleteDC(mask_dc);
|
|
||||||
ReleaseDC(null_mut(), screen_dc);
|
|
||||||
|
|
||||||
// Windows makes a copy of the bitmaps for the cursor, so we can delete them
|
|
||||||
DeleteObject(color_bitmap as _);
|
|
||||||
DeleteObject(mask_bitmap as _);
|
|
||||||
|
|
||||||
if cursor.is_null() {
|
if cursor.is_null() {
|
||||||
eprintln!("Failed to create cursor");
|
eprintln!("Failed to create cursor");
|
||||||
return None;
|
return None;
|
||||||
@@ -197,6 +251,25 @@ unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
|||||||
Some(SyncHCURSOR(cursor))
|
Some(SyncHCURSOR(cursor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a cursor from an RGBA image
|
||||||
|
unsafe fn create_cursor_from_image(image: &RgbaImage) -> Option<SyncHCURSOR> {
|
||||||
|
let (width, height) = image.dimensions();
|
||||||
|
let width_i32 = width as i32;
|
||||||
|
let height_i32 = height as i32;
|
||||||
|
|
||||||
|
let contexts = setup_device_contexts()?;
|
||||||
|
let bitmaps = create_cursor_bitmaps(&contexts, width_i32, height_i32)?;
|
||||||
|
|
||||||
|
process_image_data(image, &bitmaps, width, height);
|
||||||
|
|
||||||
|
let cursor = create_cursor_from_bitmaps(&bitmaps, width, height);
|
||||||
|
|
||||||
|
bitmaps.cleanup(&contexts);
|
||||||
|
contexts.cleanup();
|
||||||
|
|
||||||
|
cursor
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to safely lock a mutex with error handling
|
// Helper function to safely lock a mutex with error handling
|
||||||
fn safe_lock<'a, T>(mutex: &'a std::sync::Mutex<T>, operation_name: &str) -> Option<std::sync::MutexGuard<'a, T>> {
|
fn safe_lock<'a, T>(mutex: &'a std::sync::Mutex<T>, operation_name: &str) -> Option<std::sync::MutexGuard<'a, T>> {
|
||||||
match mutex.lock() {
|
match mutex.lock() {
|
||||||
|
|||||||
Reference in New Issue
Block a user