From d69cbfd6629d9869eebcfefaeb93605a8aa0828c Mon Sep 17 00:00:00 2001 From: Kornel Date: Wed, 17 Aug 2022 01:26:32 +0100 Subject: [PATCH] Clumsy workaround for rustc complaint https://github.com/rust-lang/rust/issues/93367 --- src/capi.rs | 9 +++++---- src/image.rs | 3 ++- src/rows.rs | 7 ++++--- src/seacow.rs | 36 ++++++++++++++++++++++-------------- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/capi.rs b/src/capi.rs index 6932bc7..4e22341 100644 --- a/src/capi.rs +++ b/src/capi.rs @@ -11,6 +11,7 @@ use crate::Image; use crate::rows::RowCallback; use crate::seacow::RowBitmapMut; use crate::seacow::SeaCow; +use crate::seacow::Pointer; use std::mem::MaybeUninit; pub const LIQ_VERSION: u32 = 40000; @@ -20,18 +21,18 @@ pub fn liq_get_palette_impl(r: &mut QuantizationResult) -> &Palette { } pub unsafe fn liq_image_create_rgba_rows_impl<'rows>(attr: &Attributes, rows: &'rows [*const RGBA], width: u32, height: u32, gamma: f64) -> Option> { - let rows = SeaCow::borrowed(rows); + let rows = SeaCow::borrowed(std::mem::transmute::<&'rows [*const RGBA], &'rows [Pointer]>(rows)); let rows_slice = rows.as_slice(); - if rows_slice.iter().any(|r| r.is_null()) { + if rows_slice.iter().any(|r| r.0.is_null()) { return None; } crate::image::Image::new_internal(attr, crate::rows::PixelsSource::Pixels { rows, pixels: None }, width, height, gamma).ok() } pub unsafe fn liq_image_create_rgba_bitmap_impl<'rows>(attr: &Attributes, rows: Box<[*const RGBA]>, width: u32, height: u32, gamma: f64) -> Option> { - let rows = SeaCow::boxed(rows); + let rows = SeaCow::boxed(std::mem::transmute::, Box<[Pointer]>>(rows)); let rows_slice = rows.as_slice(); - if rows_slice.iter().any(|r| r.is_null()) { + if rows_slice.iter().any(|r| r.0.is_null()) { return None; } crate::image::Image::new_internal(attr, crate::rows::PixelsSource::Pixels { rows, pixels: None }, width, height, gamma).ok() diff --git a/src/image.rs b/src/image.rs index fc9ae78..0b49f1d 100644 --- a/src/image.rs +++ b/src/image.rs @@ -6,6 +6,7 @@ use crate::remap::DitherMapMode; use crate::rows::{DynamicRows, PixelsSource}; use crate::seacow::RowBitmap; use crate::seacow::SeaCow; +use crate::seacow::Pointer; use crate::LIQ_HIGH_MEMORY_LIMIT; use rgb::ComponentMap; use std::mem::MaybeUninit; @@ -329,7 +330,7 @@ impl<'pixels> Image<'pixels> { return Err(BufferTooSmall); } - let rows = SeaCow::boxed(slice.chunks(stride).map(|row| row.as_ptr()).take(height).collect()); + let rows = SeaCow::boxed(slice.chunks(stride).map(|row| Pointer(row.as_ptr())).take(height).collect()); Image::new_internal(attr, PixelsSource::Pixels { rows, pixels: Some(pixels) }, width as u32, height as u32, gamma) } } diff --git a/src/rows.rs b/src/rows.rs index 73a7448..6c1b133 100644 --- a/src/rows.rs +++ b/src/rows.rs @@ -3,13 +3,14 @@ use crate::pal::{f_pixel, gamma_lut, RGBA}; use crate::seacow::SeaCow; use crate::LIQ_HIGH_MEMORY_LIMIT; use std::mem::MaybeUninit; +use crate::seacow::Pointer; pub(crate) type RowCallback<'a> = dyn Fn(&mut [MaybeUninit], usize) + Send + Sync + 'a; pub(crate) enum PixelsSource<'pixels, 'rows> { /// The `pixels` field is never read, but it is used to store the rows. #[allow(dead_code)] - Pixels { rows: SeaCow<'rows, *const RGBA>, pixels: Option> }, + Pixels { rows: SeaCow<'rows, Pointer>, pixels: Option> }, Callback(Box>), } @@ -71,7 +72,7 @@ impl<'pixels,'rows> DynamicRows<'pixels,'rows> { fn row_rgba<'px>(&'px self, temp_row: &'px mut [MaybeUninit], row: usize) -> &[RGBA] { match &self.pixels { PixelsSource::Pixels { rows, .. } => unsafe { - std::slice::from_raw_parts(rows.as_slice()[row], self.width()) + std::slice::from_raw_parts(rows.as_slice()[row].0, self.width()) }, PixelsSource::Callback(cb) => { cb(temp_row, row); @@ -168,7 +169,7 @@ impl<'pixels,'rows> DynamicRows<'pixels,'rows> { PixelsSource::Pixels { pixels: Some(pixels), .. } => pixels.make_owned(free_fn), PixelsSource::Pixels { pixels, rows } => { // the row with the lowest address is assumed to be at the start of the bitmap - let ptr = rows.as_slice().iter().copied().min().ok_or(Error::Unsupported)?; + let ptr = rows.as_slice().iter().map(|p| p.0).min().ok_or(Error::Unsupported)?; *pixels = Some(SeaCow::c_owned(ptr as *mut _, len, free_fn)); }, PixelsSource::Callback(_) => return Err(Error::ValueOutOfRange), diff --git a/src/seacow.rs b/src/seacow.rs index 3a35216..a472471 100644 --- a/src/seacow.rs +++ b/src/seacow.rs @@ -9,8 +9,20 @@ pub struct SeaCow<'a, T> { unsafe impl Send for SeaCowInner<'_, T> {} unsafe impl Sync for SeaCowInner<'_, T> {} -unsafe impl Send for SeaCow<'_, *const T> {} -unsafe impl Sync for SeaCow<'_, *const T> {} +/// Rust assumes `*const T` is never `Send`/`Sync`, but it can be. +/// This is fudge for https://github.com/rust-lang/rust/issues/93367 +#[repr(transparent)] +#[derive(Copy, Clone)] +pub(crate) struct Pointer(pub *const T); + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub(crate) struct PointerMut(pub *mut T); + +unsafe impl Send for Pointer {} +unsafe impl Sync for Pointer {} +unsafe impl Send for PointerMut {} +unsafe impl Sync for PointerMut {} impl<'a, T> SeaCow<'a, T> { #[inline] @@ -78,13 +90,13 @@ impl<'a, T> SeaCow<'a, T> { } pub(crate) struct RowBitmap<'a, T> { - rows: &'a [*const T], + rows: &'a [Pointer], width: usize, } unsafe impl Send for RowBitmap<'_, T> {} pub(crate) struct RowBitmapMut<'a, T> { - rows: MutCow<'a, [*mut T]>, + rows: MutCow<'a, [PointerMut]>, width: usize, } unsafe impl Send for RowBitmapMut<'_, T> {} @@ -94,7 +106,7 @@ impl<'a, T> RowBitmapMut<'a, MaybeUninit> { pub(crate) unsafe fn assume_init<'maybeowned>(&'maybeowned mut self) -> RowBitmap<'maybeowned, T> { RowBitmap { width: self.width, - rows: std::mem::transmute::<&'maybeowned [*mut MaybeUninit], &'maybeowned [*const T]>(self.rows.borrow()), + rows: std::mem::transmute::<&'maybeowned [PointerMut>], &'maybeowned [Pointer]>(self.rows.borrow()), } } } @@ -102,8 +114,8 @@ impl<'a, T> RowBitmapMut<'a, MaybeUninit> { impl<'a, T> RowBitmap<'a, T> { pub fn rows(&self) -> impl Iterator { let width = self.width; - self.rows.iter().map(move |&row| { - unsafe { std::slice::from_raw_parts(row, width) } + self.rows.iter().map(move |row| { + unsafe { std::slice::from_raw_parts(row.0, width) } }) } } @@ -127,7 +139,7 @@ impl<'a, T: Sync + Send + Copy + 'static> RowBitmapMut<'a, T> { #[inline] pub fn new_contiguous(data: &mut [T], width: usize) -> Self { Self { - rows: MutCow::Owned(data.chunks_exact_mut(width).map(|r| r.as_mut_ptr()).collect()), + rows: MutCow::Owned(data.chunks_exact_mut(width).map(|r| PointerMut(r.as_mut_ptr())).collect()), width, } } @@ -137,18 +149,14 @@ impl<'a, T: Sync + Send + Copy + 'static> RowBitmapMut<'a, T> { #[cfg(feature = "_internal_c_ffi")] pub unsafe fn new(rows: &'a mut [*mut T], width: usize) -> Self { Self { - rows: MutCow::Borrowed(rows), + rows: MutCow::Borrowed(std::mem::transmute::<&'a mut [*mut T], &'a mut [PointerMut]>(rows)), width, } } pub fn rows_mut(&mut self) -> impl Iterator + Send { let width = self.width; - // Rust is pessimistic about `*mut` pointers - struct ItIsSync(*mut T); - unsafe impl Sync for ItIsSync {} - let send_slice = unsafe { std::mem::transmute::<&mut [*mut T], &mut [ItIsSync]>(self.rows.borrow()) }; - send_slice.iter().map(move |row| { + self.rows.borrow().iter().map(move |row| { unsafe { std::slice::from_raw_parts_mut(row.0, width) } }) }