Skip to main content

laser_pdf/
lib.rs

1pub mod elements;
2pub mod flex;
3pub mod fonts;
4pub mod image;
5pub mod serde_elements;
6pub mod test_utils;
7mod text;
8pub mod utils;
9
10use chrono::{Datelike, Timelike, Utc};
11use elements::padding::Padding;
12use fonts::Font;
13use pdf_writer::{Content, Date, Name, Rect, Ref, TextStr};
14use serde::{Deserialize, Serialize};
15use uuid::Uuid;
16use xmp_writer::{DateTime, LangId, Timezone, XmpWriter};
17
18pub use crate::text::TextPiecesCache;
19
20pub type Color = u32;
21
22/// ISO 32000-1:2008 8.4.3.3
23///
24/// The line cap style shall specify the shape that shall be used at the ends of
25/// open subpaths (and dashes, if any) when they are stroked.
26#[derive(Copy, Clone, Serialize, Deserialize)]
27pub enum LineCapStyle {
28    /// 0: Butt cap. The stroke shall be squared off at the endpoint of the
29    /// path. There shall be no projection beyond the end of the path.
30    Butt,
31
32    /// 1: Round cap. A semicircular arc with a diameter equal to the line width
33    /// shall be drawn around the endpoint and shall be filled in.
34    Round,
35
36    /// 2: Projecting square cap. The stroke shall continue beyond the endpoint
37    /// of the path for a distance equal to half the line width and shall be
38    /// squared off.
39    ProjectingSquare,
40}
41
42impl Into<pdf_writer::types::LineCapStyle> for LineCapStyle {
43    fn into(self) -> pdf_writer::types::LineCapStyle {
44        match self {
45            LineCapStyle::Butt => pdf_writer::types::LineCapStyle::ButtCap,
46            LineCapStyle::Round => pdf_writer::types::LineCapStyle::RoundCap,
47            LineCapStyle::ProjectingSquare => pdf_writer::types::LineCapStyle::ProjectingSquareCap,
48        }
49    }
50}
51
52/// ISO 32000-1:2008 8.4.3.6
53///
54/// The line dash pattern shall control the pattern of dashes and gaps used to
55/// stroke paths.
56#[derive(Copy, Clone, Serialize, Deserialize)]
57pub struct LineDashPattern {
58    /// The dash phase shall specify the distance into the dash pattern at which
59    /// to start the dash.
60    pub offset: u16,
61
62    /// The dash array’s elements shall be numbers that specify the lengths of
63    /// alternating dashes and gaps; the numbers shall be nonnegative and not
64    /// all zero.
65    pub dashes: [u16; 2],
66}
67
68#[derive(Copy, Clone, Serialize, Deserialize)]
69pub struct LineStyle {
70    pub thickness: f32,
71    pub color: Color,
72    pub dash_pattern: Option<LineDashPattern>,
73    pub cap_style: LineCapStyle,
74}
75
76#[derive(Copy, Clone, Debug, PartialEq, Eq)]
77#[non_exhaustive]
78pub enum LinkTarget<'a> {
79    Uri(&'a str),
80}
81
82pub struct Layer {
83    pub content: Content,
84    pub graphics_state_restore_required: bool,
85}
86
87pub struct Page {
88    pub annotations: Vec<Ref>,
89    pub ext_g_states: Vec<Ref>, // all objects must be indirect for now
90    pub x_objects: Vec<Ref>,
91    pub layers: Vec<Layer>,
92    pub size: (f32, f32),
93}
94
95impl Page {
96    pub fn add_ext_g_state(&mut self, resource: Ref) -> usize {
97        self.ext_g_states.push(resource);
98        self.ext_g_states.len() - 1
99    }
100
101    pub fn add_x_object(&mut self, resource: Ref) -> String {
102        self.x_objects.push(resource);
103        (self.x_objects.len() - 1).to_string()
104    }
105}
106
107/// See ISO 19005 6.6.3 Table 7
108#[derive(Clone)]
109pub struct Metadata {
110    pub title: String,
111    /// RFC 3066 compliant language identifier
112    pub language: String,
113    pub keywords: Option<String>,
114    pub producer: Option<String>,
115    pub creation_date: chrono::DateTime<Utc>,
116    /// ISO 19005 6.6.5
117    pub identifier: String,
118}
119
120impl Metadata {
121    pub fn new() -> Self {
122        Metadata {
123            title: "".to_string(),
124            language: "en".to_string(),
125            keywords: None,
126            producer: None,
127            creation_date: Utc::now(),
128            identifier: Uuid::new_v4().to_string(),
129        }
130    }
131
132    fn fixed() -> Self {
133        Metadata {
134            title: "".to_string(),
135            language: "en".to_string(),
136            keywords: None,
137            producer: None,
138            creation_date: chrono::DateTime::UNIX_EPOCH,
139            identifier: "00000000-0000-0000-0000-000000000000".to_string(),
140        }
141    }
142}
143
144pub struct Pdf {
145    pub alloc: Ref,
146    pub pdf: pdf_writer::Pdf,
147    pub pages: Vec<Page>,
148    pub fonts: Vec<Ref>,
149    pub metadata: Metadata,
150    truetype_fonts: Vec<fonts::truetype::TruetypeFontState>,
151}
152
153impl Pdf {
154    pub fn new(metadata: Metadata) -> Self {
155        let pdf = pdf_writer::Pdf::new();
156
157        Pdf {
158            alloc: pdf_writer::Ref::new(1),
159            pdf,
160            pages: Vec::new(),
161            fonts: Vec::new(),
162            metadata,
163            truetype_fonts: Vec::new(),
164        }
165    }
166
167    pub fn alloc(&mut self) -> Ref {
168        self.alloc.bump()
169    }
170
171    pub fn add_page(&mut self, size: (f32, f32)) -> Location {
172        self.pages.push(Page {
173            ext_g_states: Vec::new(),
174            x_objects: Vec::new(),
175            annotations: Vec::new(),
176            layers: vec![Layer {
177                content: Content::new(),
178                graphics_state_restore_required: false,
179            }],
180            size,
181        });
182
183        Location {
184            page_idx: self.pages.len() - 1,
185            layer_idx: 0,
186            pos: (0., size.1),
187            scale_factor: 1.,
188        }
189    }
190
191    /// Add an element to the PDF. A new page with the given size is added initially and additional
192    /// pages of the same size are added when the element requests them during drawing.
193    pub fn add_element(&mut self, page_size: (f32, f32), element: impl Element) {
194        let text_pieces_cache = TextPiecesCache::new();
195
196        self.add_element_with_text_pieces_cache(page_size, &text_pieces_cache, element);
197    }
198
199    /// The same as [Pdf::add_element], but with a [TextPiecesCache] parameter. This is useful when
200    /// adding multiple elements to a PDF that share some fonts and text.
201    pub fn add_element_with_text_pieces_cache(
202        &mut self,
203        page_size: (f32, f32),
204        text_pieces_cache: &TextPiecesCache,
205        element: impl Element,
206    ) {
207        let mut page_idx = self.pages.len() as u32;
208
209        let location = self.add_page((page_size.0, page_size.1));
210
211        let entry_page = page_idx;
212
213        let do_break = &mut |pdf: &mut Pdf, location_idx, _height| {
214            while page_idx <= entry_page + location_idx {
215                pdf.add_page((page_size.0, page_size.1));
216                page_idx += 1;
217            }
218
219            Location {
220                page_idx: (entry_page + location_idx + 1) as usize,
221                layer_idx: 0,
222                pos: (0., page_size.1),
223                scale_factor: 1.,
224            }
225        };
226
227        let ctx = DrawCtx {
228            pdf: self,
229            text_pieces_cache,
230            width: WidthConstraint {
231                max: page_size.0,
232                expand: true,
233            },
234            location,
235
236            first_height: page_size.1,
237            preferred_height: None,
238
239            breakable: Some(BreakableDraw {
240                full_height: page_size.1,
241                preferred_height_break_count: 0,
242                do_break,
243            }),
244        };
245
246        element.draw(ctx);
247    }
248
249    pub fn finish(mut self) -> Vec<u8> {
250        let catalog_ref = self.alloc();
251        let page_tree_ref = self.alloc();
252
253        // Write document Info and metadata object
254        {
255            // The XMP writer is used to create the file metadata object.
256            // The schema of it can be seen in ISO 19005 6.6.2.3.3
257            // but it's also represented in the API of the xmp-writer crate.
258            let mut writer = XmpWriter::new();
259
260            // ISO 32000 14.4
261            // ISO 32000 7.5.5 Table 15
262            // ISO 19005 6.1.3
263            let identifier: Vec<u8> = self.metadata.identifier.clone().into();
264            self.pdf.set_file_id((identifier.clone(), identifier));
265
266            {
267                let id = self.alloc();
268                let mut document_info = self.pdf.document_info(id);
269                document_info.title(TextStr(self.metadata.title.clone().as_str()));
270                if let Some(keywords) = &self.metadata.keywords {
271                    document_info.keywords(TextStr(keywords));
272                }
273                if let Some(producer) = &self.metadata.producer {
274                    document_info.producer(TextStr(producer));
275                }
276                document_info.creation_date(
277                    Date::new(self.metadata.creation_date.year() as u16)
278                        .month(self.metadata.creation_date.month() as u8)
279                        .day(self.metadata.creation_date.day() as u8)
280                        .hour(self.metadata.creation_date.hour() as u8)
281                        .minute(self.metadata.creation_date.minute() as u8)
282                        .second(self.metadata.creation_date.second() as u8),
283                );
284            }
285            writer.title([(None, self.metadata.title.as_str())]);
286
287            writer.language([LangId(&self.metadata.language.as_str())]);
288
289            if let Some(ref keywords) = self.metadata.keywords {
290                writer.pdf_keywords(keywords);
291            }
292
293            if let Some(producer) = &self.metadata.producer {
294                writer.producer(producer);
295            }
296
297            writer.create_date(DateTime::new(
298                self.metadata.creation_date.year() as u16,
299                self.metadata.creation_date.month() as u8,
300                self.metadata.creation_date.day() as u8,
301                self.metadata.creation_date.hour() as u8,
302                self.metadata.creation_date.minute() as u8,
303                self.metadata.creation_date.second() as u8,
304                Timezone::Utc,
305            ));
306
307            writer.xmp_identifier([self.metadata.identifier.as_str()]);
308
309            writer.pdfa_part(2);
310            // ISO 19005 5.2-4
311            writer.pdfa_conformance("U");
312            writer.pdf_version("1.7");
313
314            let finished = writer.finish(None);
315
316            let id = self.alloc();
317            let icc_profile_ref = self.alloc();
318            self.pdf.metadata(id, finished.as_bytes());
319            self.pdf
320                .icc_profile(
321                    icc_profile_ref,
322                    include_bytes!("../assets/icc_profiles/sRGB-v4.icc"),
323                )
324                // ISO 32000 8.6.5.5
325                .n(3);
326            let mut catalog = self.pdf.catalog(catalog_ref);
327            catalog.metadata(id).pages(page_tree_ref);
328            // ISO 32000 14.11.5
329            // ISO 19005 6.2.3
330            // ISO 19005 6.2.4.1
331            // ISO 19005 6.2.4.2
332            // ISO 19005 6.2.4.3
333            catalog
334                .output_intents()
335                .push()
336                .subtype(pdf_writer::types::OutputIntentSubtype::PDFA)
337                .dest_output_profile(icc_profile_ref)
338                .output_condition_identifier(TextStr("sRGB-v4"));
339        }
340
341        for mut truetype_font in self.truetype_fonts {
342            truetype_font.finish(&mut self.pdf, &mut self.alloc);
343        }
344
345        let pages = self
346            .pages
347            .iter()
348            .scan(self.alloc, |state, _| Some(state.bump()));
349
350        self.pdf
351            .pages(page_tree_ref)
352            .kids(pages)
353            .count(self.pages.len() as i32);
354
355        let mut page_alloc = self.alloc;
356        self.alloc = Ref::new(self.alloc.get() + self.pages.len() as i32);
357
358        for page in self.pages {
359            let mut page_writer = self.pdf.page(page_alloc.bump());
360
361            page_writer
362                .parent(page_tree_ref)
363                .media_box(Rect::new(
364                    0.,
365                    0.,
366                    (page.size.0 * 72. / 25.4) as f32,
367                    (page.size.1 * 72. / 25.4) as f32,
368                ))
369                .contents_array(
370                    page.layers
371                        .iter()
372                        .scan(self.alloc, |state, _| Some(state.bump())),
373                );
374
375            if !page.annotations.is_empty() {
376                page_writer.annotations(page.annotations);
377            }
378
379            let mut resources = page_writer.resources();
380
381            let mut ext_g_states = resources.ext_g_states();
382            for (i, ext_g_state) in page.ext_g_states.iter().enumerate() {
383                ext_g_states.pair(Name(format!("{i}").as_bytes()), ext_g_state);
384            }
385            drop(ext_g_states);
386
387            if !page.x_objects.is_empty() {
388                let mut x_objects = resources.x_objects();
389                for (i, x_object) in page.x_objects.iter().enumerate() {
390                    x_objects.pair(Name(format!("{i}").as_bytes()), x_object);
391                }
392            }
393
394            let mut fonts = resources.fonts();
395
396            for (i, &font) in self.fonts.iter().enumerate() {
397                // TODO: inherit or make an indirect object
398                fonts.pair(Name(&format!("F{}", i).as_bytes()), font);
399            }
400
401            drop(fonts);
402            drop(resources);
403            drop(page_writer);
404
405            for mut layer in page.layers {
406                if layer.graphics_state_restore_required {
407                    layer.content.restore_state();
408                }
409
410                // This adds up as long as it's not bumped between the contents_array call and here.
411                self.pdf.stream(self.alloc.bump(), &layer.content.finish());
412            }
413        }
414
415        self.pdf.finish()
416    }
417}
418
419/// A position for an element to render at.
420/// This doesn't include the width at the moment, as this would make things much more complicated.
421/// The line breaking iterator wouldn't work in its current form for example.
422/// Things are much easier if an element can make width related calculations in the beginning an
423/// doesn't have to recalculate them on a page break.
424#[derive(Clone, Debug)]
425pub struct Location {
426    pub page_idx: usize,
427    pub layer_idx: usize,
428    pub pos: (f32, f32),
429    pub scale_factor: f32,
430}
431
432impl Location {
433    pub fn layer<'a>(&self, pdf: &'a mut Pdf) -> &'a mut Content {
434        &mut pdf.pages[self.page_idx].layers[self.layer_idx].content
435    }
436
437    pub fn next_layer(&self, pdf: &mut Pdf) -> Location {
438        let page = &mut pdf.pages[self.page_idx];
439
440        let mut content = Content::new();
441
442        let graphics_state_restore_required = if self.scale_factor != 1. {
443            content
444                .save_state()
445                .transform(utils::scale(self.scale_factor));
446            true
447        } else {
448            false
449        };
450
451        // The issue is some of the layers are scaled. That's why we currently can't reuse them.
452        // TODO: Find a better solution that doesn't require adding so many layers, but also doesn't
453        // lead to unbalances saves/restores (which is not allowed by the spec).
454        page.layers.push(Layer {
455            content,
456            graphics_state_restore_required,
457        });
458
459        Location {
460            layer_idx: page.layers.len() - 1,
461            ..*self
462        }
463    }
464}
465
466#[derive(Clone, Copy, Debug, PartialEq)]
467pub struct WidthConstraint {
468    pub max: f32,
469    pub expand: bool,
470}
471
472impl WidthConstraint {
473    pub fn constrain(&self, width: f32) -> f32 {
474        if self.expand {
475            self.max
476        } else {
477            width.min(self.max)
478        }
479    }
480
481    pub fn max(&self, width: f32) -> f32 {
482        if self.expand {
483            width.max(self.max)
484        } else {
485            width
486        }
487    }
488}
489
490pub type Pos = (f32, f32);
491pub type Size = (f32, f32);
492
493/// This returns a new [Location] because some collection elements need to keep multiple
494/// [Location]s at once (e.g. for page breaking inside of a horizontal list)
495///
496/// The second parameter is which location the break is occurring from. This number
497/// must be counted up for sequential page breaks. This allows the same page break to be
498/// performed twice in a row.
499///
500/// The third parameter is the height of the location.
501pub type Break<'a> = &'a mut dyn FnMut(&mut Pdf, u32, Option<f32>) -> Location;
502
503#[derive(Clone, Copy, PartialEq, Eq, Debug)]
504pub enum FirstLocationUsage {
505    /// This means the element has no height at all. Meaning it doesn't break either. If the element
506    /// breaks, but has a height of None for the first location it should use
507    /// [FirstLocationUsage::WillUse] or [FirstLocationUsage::WillSkip] if appropriate.
508    NoneHeight,
509    WillUse,
510    WillSkip,
511}
512
513pub struct FirstLocationUsageCtx<'a> {
514    pub text_pieces_cache: &'a TextPiecesCache,
515    pub width: WidthConstraint,
516    pub first_height: f32,
517
518    // is this needed?
519    // one could argue that the parent should know to not even ask if full height isn't more
520    // on the other hand a text element could have a behavior of printing one line at a time if
521    // full-height is less than the height needed, but available-height might still be even less
522    // than that and in that case text might still use the first one (though the correctness of that
523    // is also questionable)
524    pub full_height: f32,
525}
526
527impl<'a> FirstLocationUsageCtx<'a> {
528    pub fn break_appropriate_for_min_height(&self, height: f32) -> bool {
529        height > self.first_height && self.full_height > self.first_height
530    }
531}
532
533pub struct BreakableMeasure<'a> {
534    pub full_height: f32,
535    pub break_count: &'a mut u32,
536
537    /// The minimum height required for any extra locations added to the end. If, for example,
538    /// there's a flex with a text element that gets repeated for each location and other flex
539    /// elements use more locations than this one, the text element will still be drawn on the last
540    /// location via `preferred_break_count` and `preferred_height`. The flex needs to be able to
541    /// predict the height of the last page so that there isn't a single element that is higher than
542    /// the other ones.
543    /// `None` here means the element does not use extra locations. This means it is not possible
544    /// to have an element that does use extra locations, but returns a `None` height on the last
545    /// one. Should that ever become necessary we'll probably have to change this to an
546    /// `Option<Option<f32>>`.
547    pub extra_location_min_height: &'a mut Option<f32>,
548}
549
550pub struct MeasureCtx<'a> {
551    pub text_pieces_cache: &'a TextPiecesCache,
552    pub width: WidthConstraint,
553    pub first_height: f32,
554    pub breakable: Option<BreakableMeasure<'a>>,
555}
556
557impl<'a> MeasureCtx<'a> {
558    pub fn break_if_appropriate_for_min_height(&mut self, height: f32) -> bool {
559        if let Some(ref mut breakable) = self.breakable {
560            if height > self.first_height && breakable.full_height > self.first_height {
561                *breakable.break_count = 1;
562                return true;
563            }
564        }
565
566        false
567    }
568}
569
570pub struct BreakableDraw<'a> {
571    pub full_height: f32,
572    pub preferred_height_break_count: u32,
573    pub do_break: Break<'a>,
574}
575
576pub struct DrawCtx<'a, 'b> {
577    pub pdf: &'a mut Pdf,
578    pub text_pieces_cache: &'a TextPiecesCache,
579    pub location: Location,
580
581    pub width: WidthConstraint,
582    pub first_height: f32,
583
584    pub preferred_height: Option<f32>,
585
586    pub breakable: Option<BreakableDraw<'b>>,
587}
588
589impl<'a, 'b> DrawCtx<'a, 'b> {
590    pub fn break_if_appropriate_for_min_height(&mut self, height: f32) -> bool {
591        if let Some(ref mut breakable) = self.breakable {
592            if height > self.first_height && breakable.full_height > self.first_height {
593                // TODO: Make sure this is correct. Maybe this function needs to be renamed to make
594                // clear what this actually does.
595                self.location = (breakable.do_break)(self.pdf, 0, None);
596                return true;
597            }
598        }
599
600        false
601    }
602}
603
604#[derive(Copy, Clone, Debug, PartialEq)]
605pub struct ElementSize {
606    pub width: Option<f32>,
607
608    /// None here means that this element doesn't need any space on it's last location. This is
609    /// useful for things like collapsing gaps after a forced break. This in combination with no
610    /// breaks means the element is completely hidden. This can be used to trigger collapsing of
611    /// gaps even hiding certain parent containers, like titled, in turn.
612    pub height: Option<f32>,
613}
614
615impl ElementSize {
616    pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
617        ElementSize { width, height }
618    }
619}
620
621/// Rules:
622/// Width returned from measure has to be matched in draw given the same
623/// constraint (even if there's some preferred height).
624pub trait Element {
625    #[allow(unused_variables)]
626    fn first_location_usage(&self, ctx: FirstLocationUsageCtx) -> FirstLocationUsage {
627        FirstLocationUsage::WillUse
628    }
629
630    fn measure(&self, ctx: MeasureCtx) -> ElementSize;
631
632    fn draw(&self, ctx: DrawCtx) -> ElementSize;
633
634    fn with_padding_top(self, padding: f32) -> Padding<Self>
635    where
636        Self: Sized,
637    {
638        Padding {
639            left: 0.,
640            right: 0.,
641            top: padding,
642            bottom: 0.,
643            element: self,
644        }
645    }
646
647    fn with_padding_bottom(self, padding: f32) -> Padding<Self>
648    where
649        Self: Sized,
650    {
651        Padding {
652            left: 0.,
653            right: 0.,
654            top: 0.,
655            bottom: padding,
656            element: self,
657        }
658    }
659
660    fn with_vertical_padding(self, padding: f32) -> Padding<Self>
661    where
662        Self: Sized,
663    {
664        Padding {
665            left: 0.,
666            right: 0.,
667            top: padding,
668            bottom: padding,
669            element: self,
670        }
671    }
672
673    fn with_padding_left(self, padding: f32) -> Padding<Self>
674    where
675        Self: Sized,
676    {
677        Padding {
678            left: padding,
679            right: 0.,
680            top: 0.,
681            bottom: 0.,
682            element: self,
683        }
684    }
685
686    fn with_padding_right(self, padding: f32) -> Padding<Self>
687    where
688        Self: Sized,
689    {
690        Padding {
691            left: 0.,
692            right: padding,
693            top: 0.,
694            bottom: 0.,
695            element: self,
696        }
697    }
698
699    fn with_horizontal_padding(self, padding: f32) -> Padding<Self>
700    where
701        Self: Sized,
702    {
703        Padding {
704            left: padding,
705            right: padding,
706            top: 0.,
707            bottom: 0.,
708            element: self,
709        }
710    }
711
712    fn debug(self, color: u8) -> elements::debug::Debug<Self>
713    where
714        Self: Sized,
715    {
716        elements::debug::Debug {
717            element: self,
718            color,
719            show_max_width: false,
720            show_last_location_max_height: false,
721        }
722    }
723}
724
725pub trait CompositeElementCallback {
726    fn call(self, element: &impl Element);
727}
728
729pub trait CompositeElement {
730    fn element(&self, callback: impl CompositeElementCallback);
731}
732
733impl<C: CompositeElement> Element for C {
734    fn first_location_usage(&self, ctx: FirstLocationUsageCtx) -> FirstLocationUsage {
735        struct Callback<'a> {
736            ctx: FirstLocationUsageCtx<'a>,
737            ret: &'a mut FirstLocationUsage,
738        }
739
740        impl<'a> CompositeElementCallback for Callback<'a> {
741            fn call(self, element: &impl Element) {
742                *self.ret = element.first_location_usage(self.ctx);
743            }
744        }
745
746        let mut ret = FirstLocationUsage::NoneHeight;
747
748        self.element(Callback { ctx, ret: &mut ret });
749
750        ret
751    }
752
753    fn measure(&self, ctx: MeasureCtx) -> ElementSize {
754        struct Callback<'a> {
755            ctx: MeasureCtx<'a>,
756            ret: &'a mut ElementSize,
757        }
758
759        impl<'a> CompositeElementCallback for Callback<'a> {
760            fn call(self, element: &impl Element) {
761                *self.ret = element.measure(self.ctx);
762            }
763        }
764
765        let mut ret = ElementSize {
766            width: None,
767            height: None,
768        };
769
770        self.element(Callback { ctx, ret: &mut ret });
771
772        ret
773    }
774
775    fn draw(&self, ctx: DrawCtx) -> ElementSize {
776        struct Callback<'pdf, 'a, 'r> {
777            ctx: DrawCtx<'pdf, 'a>,
778            ret: &'r mut ElementSize,
779        }
780
781        impl<'pdf, 'a, 'r> CompositeElementCallback for Callback<'pdf, 'a, 'r> {
782            fn call(self, element: &impl Element) {
783                *self.ret = element.draw(self.ctx);
784            }
785        }
786
787        let mut ret = ElementSize {
788            width: None,
789            height: None,
790        };
791
792        self.element(Callback { ctx, ret: &mut ret });
793
794        ret
795    }
796}