use crate::object::ObjectIdentifier;
use crate::object::Stream;
use crate::reader::ReaderContext;
use crate::sync::FxHashMap;
use crate::sync::{Arc, Mutex, MutexExt};
use crate::util::SegmentList;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter};
#[derive(Clone)]
pub struct PdfData {
#[cfg(feature = "std")]
inner: Arc<dyn AsRef<[u8]> + Send + Sync>,
#[cfg(not(feature = "std"))]
inner: Arc<dyn AsRef<[u8]>>,
}
impl Debug for PdfData {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "PdfData {{ ... }}")
}
}
impl AsRef<[u8]> for PdfData {
fn as_ref(&self) -> &[u8] {
(*self.inner).as_ref()
}
}
#[cfg(feature = "std")]
impl<T: AsRef<[u8]> + Send + Sync + 'static> From<Arc<T>> for PdfData {
fn from(data: Arc<T>) -> Self {
Self { inner: data }
}
}
#[cfg(not(feature = "std"))]
impl<T: AsRef<[u8]> + 'static> From<Arc<T>> for PdfData {
fn from(data: Arc<T>) -> Self {
Self { inner: data }
}
}
impl From<Vec<u8>> for PdfData {
fn from(data: Vec<u8>) -> Self {
Self {
inner: Arc::new(data),
}
}
}
pub(crate) struct Data {
data: PdfData,
decoded: SegmentList<Vec<u8>, 32>,
map: Mutex<FxHashMap<ObjectIdentifier, usize>>,
}
impl Debug for Data {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "Data {{ ... }}")
}
}
impl Data {
pub(crate) fn new(data: PdfData) -> Self {
Self {
data,
decoded: SegmentList::new(),
map: Mutex::new(FxHashMap::default()),
}
}
pub(crate) fn get(&self) -> &PdfData {
&self.data
}
pub(crate) fn get_with(&self, id: ObjectIdentifier, ctx: &ReaderContext<'_>) -> Option<&[u8]> {
if let Some(&idx) = self.map.get().get(&id) {
return self.decoded.get(idx).map(Vec::as_slice);
}
let stream = ctx.xref().get_with::<Stream<'_>>(id, ctx)?;
let decoded = stream.decoded().ok()?.into_owned();
let mut locked = self.map.get();
if let Some(&idx) = locked.get(&id) {
return self.decoded.get(idx).map(Vec::as_slice);
}
let idx = locked.len();
let decoded = self.decoded.get_or_init(idx, || decoded);
locked.insert(id, idx);
Some(decoded.as_slice())
}
}