use std::mem;
use std::marker::PhantomData;
use std::io;
use std::slice;
use std::fmt;
use ffi::{self, cairo_status_t};
use libc::{c_void, c_uchar, c_uint, c_double};
use ::enums::Status;
use surface::{Surface, SurfaceExt};
pub type Constructor = unsafe extern fn (ffi::cairo_write_func_t, *mut c_void, c_double, c_double) -> *mut ffi::cairo_surface_t;
pub trait FromRawSurface {
unsafe fn from_raw_surface(surface: *mut ffi::cairo_surface_t) -> Self;
}
#[derive(Debug)]
pub struct Writer<S: FromRawSurface + AsRef<Surface>, W: io::Write> {
pub surface: S,
writer: Box<W>,
}
impl<S: FromRawSurface + AsRef<Surface>, W: io::Write> Writer<S, W> {
extern fn write_cb(writer: *mut c_void, data: *mut c_uchar, length: c_uint) -> cairo_status_t {
let mut writer: Box<W> = unsafe { Box::from_raw(writer as *mut _) };
let data = unsafe { slice::from_raw_parts(data, length as usize) };
let result = match writer.write_all(data) {
Ok(_) => Status::Success,
Err(_) => Status::WriteError,
};
mem::forget(writer);
result.into()
}
pub fn new(constructor: Constructor, width: f64, height: f64, writer: W) -> Writer<S, W> {
let mut writer = Box::new(writer);
let writer_ptr = unsafe { mem::transmute(&mut *writer) };
let surface = unsafe {
S::from_raw_surface(constructor(Some(Self::write_cb), writer_ptr, width, height))
};
Writer {
surface,
writer,
}
}
pub fn writer(&self) -> &W { self.writer.as_ref() }
pub fn writer_mut(&mut self) -> &mut W { self.writer.as_mut() }
pub fn finish(self) -> W {
let surface = self.surface;
surface.as_ref().finish();
drop(surface);
*self.writer
}
}
impl<S: FromRawSurface + AsRef<Surface>, W: io::Write> fmt::Display for Writer<S, W> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "support::Writer")
}
}
#[derive(Debug)]
pub struct RefWriter<'w, S: FromRawSurface, W: io::Write + 'w> {
pub surface: S,
_reference: PhantomData<&'w mut W>,
}
impl<'w, S: FromRawSurface, W: io::Write + 'w> RefWriter<'w, S, W> {
extern fn write_cb(writer: *mut c_void, data: *mut c_uchar, length: c_uint) -> cairo_status_t {
let writer: &'w mut W = unsafe { mem::transmute(writer) };
let data = unsafe { slice::from_raw_parts(data, length as usize) };
let result = match writer.write_all(data) {
Ok(_) => Status::Success,
Err(_) => Status::WriteError,
};
mem::forget(writer);
result.into()
}
pub fn new(constructor: Constructor, width: f64, height: f64, writer: &'w mut W) -> RefWriter<'w, S, W> {
let writer_ptr = unsafe { mem::transmute(writer) };
let surface = unsafe {
S::from_raw_surface(constructor(Some(Self::write_cb), writer_ptr, width, height))
};
RefWriter {
surface,
_reference: PhantomData,
}
}
}
impl<'w, S: FromRawSurface + AsRef<Surface>, W: io::Write> fmt::Display for RefWriter<'w, S, W> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "support::RefWriter")
}
}