use alloc::borrow::Cow;
use alloc::boxed::Box;
use core::any::Any;
use crate::format::ImageFormat;
use crate::orientation::OrientationHint;
use crate::output::OwnedAnimationFrame;
use crate::{DecodeCapabilities, DecodeOutput, ImageInfo, OutputInfo, ResourceLimits, StopToken};
use enough::Stop;
use zenpixels::{PixelDescriptor, PixelSlice};
use super::BoxedError;
use super::decoder::{AnimationFrameDecoder, Decode, StreamingDecode};
use super::decoding::{DecodeJob, DecoderConfig};
pub trait DynDecoder {
fn decode(self: Box<Self>) -> Result<DecodeOutput, BoxedError>;
}
impl core::fmt::Debug for dyn DynDecoder + '_ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("DynDecoder").finish_non_exhaustive()
}
}
pub(super) struct DecoderShim<D>(pub(super) D);
impl<D: Decode> DynDecoder for DecoderShim<D> {
fn decode(self: Box<Self>) -> Result<DecodeOutput, BoxedError> {
self.0.decode().map_err(|e| Box::new(e) as BoxedError)
}
}
pub trait DynAnimationFrameDecoder: Send {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any>;
fn info(&self) -> &ImageInfo;
fn frame_count(&self) -> Option<u32>;
fn loop_count(&self) -> Option<u32>;
fn render_next_frame_owned(
&mut self,
stop: Option<&dyn Stop>,
) -> Result<Option<OwnedAnimationFrame>, BoxedError>;
fn render_next_frame_to_sink(
&mut self,
stop: Option<&dyn Stop>,
sink: &mut dyn crate::DecodeRowSink,
) -> Result<Option<OutputInfo>, BoxedError>;
}
impl core::fmt::Debug for dyn DynAnimationFrameDecoder + '_ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("DynAnimationFrameDecoder")
.finish_non_exhaustive()
}
}
pub(super) struct AnimationFrameDecoderShim<F>(pub(super) F);
impl<F: AnimationFrameDecoder + Send + 'static> DynAnimationFrameDecoder
for AnimationFrameDecoderShim<F>
{
fn as_any(&self) -> &dyn Any {
&self.0
}
fn as_any_mut(&mut self) -> &mut dyn Any {
&mut self.0
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
Box::new(self.0)
}
fn info(&self) -> &ImageInfo {
self.0.info()
}
fn frame_count(&self) -> Option<u32> {
self.0.frame_count()
}
fn loop_count(&self) -> Option<u32> {
self.0.loop_count()
}
fn render_next_frame_owned(
&mut self,
stop: Option<&dyn Stop>,
) -> Result<Option<OwnedAnimationFrame>, BoxedError> {
self.0
.render_next_frame_owned(stop)
.map_err(|e| Box::new(e) as BoxedError)
}
fn render_next_frame_to_sink(
&mut self,
stop: Option<&dyn Stop>,
sink: &mut dyn crate::DecodeRowSink,
) -> Result<Option<OutputInfo>, BoxedError> {
self.0
.render_next_frame_to_sink(stop, sink)
.map_err(|e| Box::new(e) as BoxedError)
}
}
pub trait DynStreamingDecoder: Send {
fn next_batch(&mut self) -> Result<Option<(u32, PixelSlice<'_>)>, BoxedError>;
fn info(&self) -> &ImageInfo;
}
impl core::fmt::Debug for dyn DynStreamingDecoder + '_ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("DynStreamingDecoder")
.finish_non_exhaustive()
}
}
pub(super) struct StreamingDecoderShim<S>(pub(super) S);
impl<S: StreamingDecode + Send> DynStreamingDecoder for StreamingDecoderShim<S> {
fn next_batch(&mut self) -> Result<Option<(u32, PixelSlice<'_>)>, BoxedError> {
self.0.next_batch().map_err(|e| Box::new(e) as BoxedError)
}
fn info(&self) -> &ImageInfo {
self.0.info()
}
}
pub trait DynDecodeJob<'a> {
fn set_stop(&mut self, stop: StopToken);
fn set_limits(&mut self, limits: ResourceLimits);
fn set_policy(&mut self, policy: crate::DecodePolicy);
fn probe(&self, data: &[u8]) -> Result<ImageInfo, BoxedError>;
fn probe_full(&self, data: &[u8]) -> Result<ImageInfo, BoxedError>;
fn set_crop_hint(&mut self, x: u32, y: u32, width: u32, height: u32);
fn set_orientation(&mut self, hint: OrientationHint);
fn set_start_frame_index(&mut self, index: u32);
fn set_extract_gain_map(&mut self, _extract: bool) {}
fn extensions(&self) -> Option<&dyn Any>;
fn extensions_mut(&mut self) -> Option<&mut dyn Any>;
fn output_info(&self, data: &[u8]) -> Result<OutputInfo, BoxedError>;
fn into_decoder(
self: Box<Self>,
data: Cow<'a, [u8]>,
preferred: &[PixelDescriptor],
) -> Result<Box<dyn DynDecoder + 'a>, BoxedError>;
fn push_decode(
self: Box<Self>,
data: Cow<'a, [u8]>,
sink: &mut dyn crate::DecodeRowSink,
preferred: &[PixelDescriptor],
) -> Result<OutputInfo, BoxedError>;
fn into_streaming_decoder(
self: Box<Self>,
data: Cow<'a, [u8]>,
preferred: &[PixelDescriptor],
) -> Result<Box<dyn DynStreamingDecoder + 'a>, BoxedError>;
fn into_animation_frame_decoder(
self: Box<Self>,
data: Cow<'a, [u8]>,
preferred: &[PixelDescriptor],
) -> Result<Box<dyn DynAnimationFrameDecoder>, BoxedError>;
}
struct DecodeJobShim<J>(Option<J>);
impl<J> DecodeJobShim<J> {
fn take(&mut self) -> Result<J, BoxedError> {
self.0
.take()
.ok_or_else(|| "DecodeJobShim: job already consumed (double take)".into())
}
fn put(&mut self, job: J) {
self.0 = Some(job);
}
fn as_ref(&self) -> Result<&J, BoxedError> {
self.0
.as_ref()
.ok_or_else(|| "DecodeJobShim: job already consumed (double take)".into())
}
}
impl<'a, J> DynDecodeJob<'a> for DecodeJobShim<J>
where
J: DecodeJob<'a> + 'a,
J::StreamDec: Send,
J::AnimationFrameDec: Send,
{
fn set_stop(&mut self, stop: StopToken) {
if let Ok(job) = self.take() {
self.put(job.with_stop(stop));
}
}
fn set_limits(&mut self, limits: ResourceLimits) {
if let Ok(job) = self.take() {
self.put(job.with_limits(limits));
}
}
fn set_policy(&mut self, policy: crate::DecodePolicy) {
if let Ok(job) = self.take() {
self.put(job.with_policy(policy));
}
}
fn probe(&self, data: &[u8]) -> Result<ImageInfo, BoxedError> {
self.as_ref()?
.probe(data)
.map_err(|e| Box::new(e) as BoxedError)
}
fn probe_full(&self, data: &[u8]) -> Result<ImageInfo, BoxedError> {
self.as_ref()?
.probe_full(data)
.map_err(|e| Box::new(e) as BoxedError)
}
fn set_crop_hint(&mut self, x: u32, y: u32, width: u32, height: u32) {
if let Ok(job) = self.take() {
self.put(job.with_crop_hint(x, y, width, height));
}
}
fn set_orientation(&mut self, hint: OrientationHint) {
if let Ok(job) = self.take() {
self.put(job.with_orientation(hint));
}
}
fn set_start_frame_index(&mut self, index: u32) {
if let Ok(job) = self.take() {
self.put(job.with_start_frame_index(index));
}
}
fn set_extract_gain_map(&mut self, extract: bool) {
if let Ok(job) = self.take() {
self.put(job.with_extract_gain_map(extract));
}
}
fn extensions(&self) -> Option<&dyn Any> {
self.0.as_ref().and_then(|j| j.extensions())
}
fn extensions_mut(&mut self) -> Option<&mut dyn Any> {
self.0.as_mut().and_then(|j| j.extensions_mut())
}
fn output_info(&self, data: &[u8]) -> Result<OutputInfo, BoxedError> {
self.as_ref()?
.output_info(data)
.map_err(|e| Box::new(e) as BoxedError)
}
fn into_decoder(
mut self: Box<Self>,
data: Cow<'a, [u8]>,
preferred: &[PixelDescriptor],
) -> Result<Box<dyn DynDecoder + 'a>, BoxedError> {
let job = self.take()?;
let dec = job
.decoder(data, preferred)
.map_err(|e| Box::new(e) as BoxedError)?;
Ok(Box::new(DecoderShim(dec)))
}
fn push_decode(
mut self: Box<Self>,
data: Cow<'a, [u8]>,
sink: &mut dyn crate::DecodeRowSink,
preferred: &[PixelDescriptor],
) -> Result<OutputInfo, BoxedError> {
let job = self.take()?;
job.push_decoder(data, sink, preferred)
.map_err(|e| Box::new(e) as BoxedError)
}
fn into_streaming_decoder(
mut self: Box<Self>,
data: Cow<'a, [u8]>,
preferred: &[PixelDescriptor],
) -> Result<Box<dyn DynStreamingDecoder + 'a>, BoxedError> {
let job = self.take()?;
let dec = job
.streaming_decoder(data, preferred)
.map_err(|e| Box::new(e) as BoxedError)?;
Ok(Box::new(StreamingDecoderShim(dec)))
}
fn into_animation_frame_decoder(
mut self: Box<Self>,
data: Cow<'a, [u8]>,
preferred: &[PixelDescriptor],
) -> Result<Box<dyn DynAnimationFrameDecoder>, BoxedError> {
let job = self.take()?;
let dec = job
.animation_frame_decoder(data, preferred)
.map_err(|e| Box::new(e) as BoxedError)?;
Ok(Box::new(AnimationFrameDecoderShim(dec)))
}
}
pub trait DynDecoderConfig: Send + Sync {
fn as_any(&self) -> &dyn Any;
fn formats(&self) -> &'static [ImageFormat];
fn supported_descriptors(&self) -> &'static [PixelDescriptor];
fn capabilities(&self) -> &'static DecodeCapabilities;
fn dyn_job(&self) -> Box<dyn DynDecodeJob<'_> + '_>;
}
impl<C> DynDecoderConfig for C
where
C: DecoderConfig + 'static,
{
fn as_any(&self) -> &dyn Any {
self
}
fn formats(&self) -> &'static [ImageFormat] {
C::formats()
}
fn supported_descriptors(&self) -> &'static [PixelDescriptor] {
C::supported_descriptors()
}
fn capabilities(&self) -> &'static DecodeCapabilities {
C::capabilities()
}
fn dyn_job(&self) -> Box<dyn DynDecodeJob<'_> + '_> {
Box::new(DecodeJobShim(Some(self.clone().job())))
}
}