Skip to content

Commit

Permalink
Clumsy workaround for rustc complaint
Browse files Browse the repository at this point in the history
  • Loading branch information
kornelski committed Aug 17, 2022
1 parent aed9e2e commit d69cbfd
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 22 deletions.
9 changes: 5 additions & 4 deletions src/capi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<crate::image::Image<'rows>> {
let rows = SeaCow::borrowed(rows);
let rows = SeaCow::borrowed(std::mem::transmute::<&'rows [*const RGBA], &'rows [Pointer<RGBA>]>(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<crate::image::Image<'rows>> {
let rows = SeaCow::boxed(rows);
let rows = SeaCow::boxed(std::mem::transmute::<Box<[*const RGBA]>, Box<[Pointer<RGBA>]>>(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()
Expand Down
3 changes: 2 additions & 1 deletion src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/rows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<RGBA>], 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<SeaCow<'pixels, RGBA>> },
Pixels { rows: SeaCow<'rows, Pointer<RGBA>>, pixels: Option<SeaCow<'pixels, RGBA>> },
Callback(Box<RowCallback<'rows>>),
}

Expand Down Expand Up @@ -71,7 +72,7 @@ impl<'pixels,'rows> DynamicRows<'pixels,'rows> {
fn row_rgba<'px>(&'px self, temp_row: &'px mut [MaybeUninit<RGBA>], 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);
Expand Down Expand Up @@ -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),
Expand Down
36 changes: 22 additions & 14 deletions src/seacow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@ pub struct SeaCow<'a, T> {
unsafe impl<T: Send> Send for SeaCowInner<'_, T> {}
unsafe impl<T: Sync> Sync for SeaCowInner<'_, T> {}

unsafe impl<T: Send> Send for SeaCow<'_, *const T> {}
unsafe impl<T: Sync> 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<T>(pub *const T);

#[derive(Copy, Clone)]
#[repr(transparent)]
pub(crate) struct PointerMut<T>(pub *mut T);

unsafe impl<T: Send + Sync> Send for Pointer<T> {}
unsafe impl<T: Send + Sync> Sync for Pointer<T> {}
unsafe impl<T: Send + Sync> Send for PointerMut<T> {}
unsafe impl<T: Send + Sync> Sync for PointerMut<T> {}

impl<'a, T> SeaCow<'a, T> {
#[inline]
Expand Down Expand Up @@ -78,13 +90,13 @@ impl<'a, T> SeaCow<'a, T> {
}

pub(crate) struct RowBitmap<'a, T> {
rows: &'a [*const T],
rows: &'a [Pointer<T>],
width: usize,
}
unsafe impl<T: Send + Sync> Send for RowBitmap<'_, T> {}

pub(crate) struct RowBitmapMut<'a, T> {
rows: MutCow<'a, [*mut T]>,
rows: MutCow<'a, [PointerMut<T>]>,
width: usize,
}
unsafe impl<T: Send + Sync> Send for RowBitmapMut<'_, T> {}
Expand All @@ -94,16 +106,16 @@ impl<'a, T> RowBitmapMut<'a, MaybeUninit<T>> {
pub(crate) unsafe fn assume_init<'maybeowned>(&'maybeowned mut self) -> RowBitmap<'maybeowned, T> {
RowBitmap {
width: self.width,
rows: std::mem::transmute::<&'maybeowned [*mut MaybeUninit<T>], &'maybeowned [*const T]>(self.rows.borrow()),
rows: std::mem::transmute::<&'maybeowned [PointerMut<MaybeUninit<T>>], &'maybeowned [Pointer<T>]>(self.rows.borrow()),
}
}
}

impl<'a, T> RowBitmap<'a, T> {
pub fn rows(&self) -> impl Iterator<Item = &[T]> {
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) }
})
}
}
Expand All @@ -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,
}
}
Expand All @@ -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<T>]>(rows)),
width,
}
}

pub fn rows_mut(&mut self) -> impl Iterator<Item = &mut [T]> + Send {
let width = self.width;
// Rust is pessimistic about `*mut` pointers
struct ItIsSync<T>(*mut T);
unsafe impl<T: Send + Sync> Sync for ItIsSync<T> {}
let send_slice = unsafe { std::mem::transmute::<&mut [*mut T], &mut [ItIsSync<T>]>(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) }
})
}
Expand Down

0 comments on commit d69cbfd

Please sign in to comment.