Skip to content

Commit

Permalink
Fix Gif codec to not use unsafe lifetimes
Browse files Browse the repository at this point in the history
  • Loading branch information
lilith committed Oct 17, 2017
1 parent db36f2e commit b0f5132
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 17 deletions.
20 changes: 13 additions & 7 deletions imageflow_core/src/codecs/gif/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ use self::bgra::BGRA8;
use self::screen::Screen;
use ::gif::Frame;
use ::gif::SetParameter;
use std::rc::Rc;
use io::IoProxyProxy;
use io::IoProxyRef;

pub struct GifDecoder{
reader: ::gif::Reader<IoProxy>,
Expand Down Expand Up @@ -155,18 +158,21 @@ impl Decoder for GifDecoder {

pub struct GifEncoder{
io_id: i32,
encoder: ::gif::Encoder<IoProxy>,
io_ref: &'static IoProxy, //unsafe self-referential,
encoder: ::gif::Encoder<IoProxyProxy>,
io_ref: Rc<RefCell<IoProxy>>,
frame_ix: i32
}

impl GifEncoder{
pub(crate) fn create(c: &Context, preset: &s::EncoderPreset, io: IoProxy, first_frame: &BitmapBgra) -> Result<GifEncoder>{
let io_id = io.io_id();
let io_ref = Rc::new(RefCell::new(io));

Ok(GifEncoder{
io_id: io.io_id(),
io_ref: unsafe { &*(&io as *const IoProxy) },
io_id,
io_ref: io_ref.clone(),
// Global color table??
encoder: ::gif::Encoder::new(io, first_frame.w as u16, first_frame.h as u16, &[]).map_err(|e| FlowError::from_gif_encoder(e).at(here!()))?,
encoder: ::gif::Encoder::new(IoProxyProxy(io_ref), first_frame.w as u16, first_frame.h as u16, &[]).map_err(|e| FlowError::from_gif_encoder(e).at(here!()))?,
frame_ix: 0
})
}
Expand Down Expand Up @@ -241,8 +247,8 @@ impl Encoder for GifEncoder{
)
}
}
fn get_io(&self) -> Result<&IoProxy> {
Ok(self.io_ref)
fn get_io(&self) -> Result<IoProxyRef> {
Ok(IoProxyRef::Ref(self.io_ref.borrow()))
}
}

Expand Down
16 changes: 9 additions & 7 deletions imageflow_core/src/codecs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use ::std::any::Any;
use ::lcms2::*;
use ::lcms2;
mod gif;

use io::IoProxyRef;

pub trait DecoderFactory{
fn create(c: &Context, io: &mut IoProxy, io_id: i32) -> Option<Result<Box<Decoder>>>;
Expand All @@ -37,7 +37,7 @@ pub trait Encoder{
// encode entire frames and enable transparency (default)
fn write_frame(&mut self, c: &Context, preset: &s::EncoderPreset, frame: &mut BitmapBgra, decoder_io_ids: &[i32]) -> Result<s::EncodeResult>;

fn get_io(&self) -> Result<&IoProxy>;
fn get_io(&self) -> Result<IoProxyRef>;
}

enum CodecKind{
Expand Down Expand Up @@ -354,8 +354,8 @@ impl Encoder for ClassicEncoder{
})
}
}
fn get_io(&self) -> Result<&IoProxy> {
Ok(&self.io)
fn get_io(&self) -> Result<IoProxyRef> {
Ok(IoProxyRef::Borrow(&self.io))
}
}

Expand Down Expand Up @@ -391,11 +391,13 @@ impl CodecInstanceContainer{
}
}

pub fn get_encode_io(&self) -> Result<Option<&IoProxy>>{
pub fn get_encode_io(&self) -> Result<Option<IoProxyRef>>{
if let CodecKind::Encoder(ref e) = self.codec {
Ok(Some(e.get_io().map_err(|e| e.at(here!()))?))
}else{
Ok(self.encode_io.as_ref())
}else if let Some(ref e) = self.encode_io{
Ok(Some(IoProxyRef::Borrow(e)))
} else {
Ok(None)
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion imageflow_core/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ impl Context {
}

pub fn get_output_buffer_slice(&self, io_id: i32) -> Result<&[u8]> {
self.get_codec(io_id).map_err(|e| e.at(here!()))?.get_encode_io()?.expect("Not an output buffer").get_output_buffer_bytes(self).map_err(|e| e.at(here!()))
let codec = self.get_codec(io_id).map_err(|e| e.at(here!()))?;
let io = codec.get_encode_io()?.expect("Not an output buffer");
io.map(|io| io.get_output_buffer_bytes(self).map_err(|e| e.at(here!())))
}

pub fn add_file(&mut self, io_id: i32, direction: IoDirection, path: &str) -> Result<()> {
Expand Down
40 changes: 38 additions & 2 deletions imageflow_core/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ use ::ffi::ImageflowJobIo;
use ::imageflow_types::collections::AddRemoveSet;
use std::ascii::AsciiExt;
use uuid::Uuid;
use std::rc::Rc;


pub enum IoProxyRef<'a>{
Borrow(&'a IoProxy),
BoxedAsRef(Box<AsRef<IoProxy>>),
Ref(Ref<'a, IoProxy>)
}
impl<'a> IoProxyRef<'a> {
pub fn map<B, F>(self, mut f: F) -> B
where
F: FnMut(&IoProxy) -> B{

match self {
IoProxyRef::Borrow(r) => f(r),
IoProxyRef::BoxedAsRef(r) => f((*r).as_ref()),
IoProxyRef::Ref(r) => f(&*r)
}

}
}

pub struct IoProxy{
c: &'static Context,
Expand All @@ -16,6 +37,18 @@ pub struct IoProxy{
drop_with_job: bool
}


pub struct IoProxyProxy(pub Rc<RefCell<IoProxy>>);
impl Write for IoProxyProxy{
fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
self.0.borrow_mut().write(buf)
}

fn flush(&mut self) -> ::std::io::Result<()> {
self.0.borrow_mut().flush()
}
}

// Not sure these are actually used?
impl io::Read for IoProxy{

Expand Down Expand Up @@ -184,8 +217,11 @@ impl IoProxy {
unsafe {
let mut buf_start: *const u8 = ptr::null();
let mut buf_len: usize = 0;
let worked = ::ffi::flow_io_get_output_buffer(self.c.flow_c(),
self.classic,
let flow_c = self.c.flow_c();
let classic = self.classic;

let worked = ::ffi::flow_io_get_output_buffer(flow_c ,
classic,
&mut buf_start as *mut *const u8,
&mut buf_len as *mut usize);
if !worked {
Expand Down

0 comments on commit b0f5132

Please sign in to comment.