bingus 0.10.0

databending made easy
Documentation
use std::borrow::Cow;

use cfg_if::cfg_if;
use printpdf::{
    Op, PdfDocument, PdfPage, PdfParseErrorSeverity, PdfParseOptions, PdfSaveOptions, PdfWarnMsg,
};
#[cfg(feature = "rayon")]
use rayon::iter::{IntoParallelIterator, ParallelIterator};

use crate::{Bendable, IntoDataBytes, TryFromDataBytes};

fn clean_up_warnings(warnings: &mut Vec<PdfWarnMsg>) {
    warnings.retain(|warning| {
        warning.severity == PdfParseErrorSeverity::Warning
            || warning.severity == PdfParseErrorSeverity::Error
    });
}

impl TryFromDataBytes for PdfDocument {
    type Error = String;
    type Format = ();

    fn try_from_data_bytes(
        bytes: crate::Bytes,
        _format: Self::Format,
        _crop: crate::Crop,
    ) -> Result<Self, Self::Error> {
        let mut warnings = Vec::new();
        let result = PdfDocument::parse(
            &bytes,
            &PdfParseOptions {
                fail_on_error: false,
            },
            &mut warnings,
        );
        clean_up_warnings(&mut warnings);
        for warning in warnings {
            println!("Warning: {:#?}", warning);
        }
        result
    }
}

impl IntoDataBytes for PdfDocument {
    fn into_data_bytes(self) -> crate::Bytes {
        let mut warnings = Vec::new();
        let result = self.save(
            &PdfSaveOptions {
                image_optimization: None,
                ..Default::default()
            },
            &mut warnings,
        );
        clean_up_warnings(&mut warnings);
        for warning in warnings {
            println!("Warning: {:#?}", warning);
        }
        result
    }
}

impl Bendable for PdfDocument {
    type Unit = Op;

    fn map<F: Fn(Cow<Self::Unit>) -> Self::Unit + Sync>(self, f: F) -> Self {
        let PdfDocument {
            metadata,
            resources,
            bookmarks,
            pages,
        } = self;
        PdfDocument {
            pages: pages
                .into_iter()
                .map(|page| PdfPage {
                    ops: {
                        cfg_if! {
                            if #[cfg(feature = "rayon")] {
                                page.ops.into_par_iter()
                            } else {
                                page.ops.into_iter()
                            }
                        }
                    }
                    .map(|op| f(Cow::Owned(op)))
                    .collect::<Vec<Op>>(),
                    ..page
                })
                .collect(),
            metadata,
            resources,
            bookmarks,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn map_integrity() {
        let mut warnings = Vec::new();
        let original = PdfDocument::parse(
            include_bytes!("../../../testing material/doc/pdf/basic-text.pdf"),
            &PdfParseOptions {
                fail_on_error: true,
            },
            &mut warnings,
        )
        .unwrap();
        clean_up_warnings(&mut warnings);
        for warning in warnings {
            println!("Warning: {:#?}", warning);
        }
        assert_eq!(
            format!("{:?}", original),
            format!("{:?}", original.clone().map(|u| u.into_owned()))
        )
    }
}