pub struct LayoutEngine<'a> { /* private fields */ }Expand description
Deterministic measure → propose → query → resolve → commit engine.
Implementations§
Source§impl<'a> LayoutEngine<'a>
impl<'a> LayoutEngine<'a>
Sourcepub fn new(
limits: &'a ResourceLimits,
fonts: &'a FontManager,
options: LayoutOptions,
) -> Result<Self>
pub fn new( limits: &'a ResourceLimits, fonts: &'a FontManager, options: LayoutOptions, ) -> Result<Self>
Creates an engine over explicit limits and fonts.
Examples found in repository?
examples/basic.rs (line 25)
18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 let limits = ResourceLimits::default();
20 let compiler = Compiler::builder().limits(limits.clone()).build()?;
21 let template = compiler.compile_template_yaml(include_bytes!("basic.yml"))?;
22 let data: DataValue = serde_json::from_slice(include_bytes!("basic-data.json"))?;
23 let document = compiler.bind(&template, &data, &[])?;
24 let fonts = example_fonts()?;
25 let scene = LayoutEngine::new(&limits, &fonts, LayoutOptions::default())?.resolve(&document)?;
26 let (output, outcome) = export_bytes(
27 &scene,
28 &ExportRequest {
29 format: ExportFormat::Svg,
30 ..ExportRequest::default()
31 },
32 &ExportContext {
33 limits: &limits,
34 fonts: &fonts,
35 assets: None,
36 },
37 )?;
38 let output_path = output_path("basic.svg")?;
39 std::fs::write(&output_path, output)?;
40 println!(
41 "pages={} svg_bytes={} output={}",
42 scene.pages.len(),
43 outcome.bytes_written,
44 output_path.display()
45 );
46 Ok(())
47}More examples
examples/intermediate.rs (line 48)
23fn main() -> Result<(), Box<dyn std::error::Error>> {
24 let limits = ResourceLimits::default();
25 let compiler = Compiler::builder().limits(limits.clone()).build()?;
26 let template = compiler.compile_template_yaml(include_bytes!("intermediate.yml"))?;
27 let data: DataValue = serde_json::from_slice(include_bytes!("intermediate-data.json"))?;
28 let mut document = compiler.bind(&template, &data, &[])?;
29 let mut log = OperationLog::new_bounded(8, 8 * 1024 * 1024)?;
30 let patch = Patch {
31 sequence: 1,
32 operations: vec![PatchOperation::Move {
33 id: ElementId::new("review-marker")?,
34 x: "185mm".parse()?,
35 y: "112mm".parse()?,
36 }],
37 };
38 log.apply(&mut document, &patch, limits.max_patch_operations)?;
39 let fonts = example_fonts()?;
40 let fingerprint = DocumentFingerprint::compute_with_patches(
41 &template,
42 &data,
43 std::slice::from_ref(&patch),
44 None,
45 &fonts,
46 &limits,
47 )?;
48 let engine = LayoutEngine::new(&limits, &fonts, LayoutOptions::default())?;
49 let mut cache = SceneCache::with_byte_capacity(8, 64 * 1024 * 1024)?;
50 let scene = engine.resolve_cached(&document, fingerprint, &mut cache)?;
51 let cached = engine.resolve_cached(&document, fingerprint, &mut cache)?;
52 if !Arc::ptr_eq(&scene, &cached) || scene.pages.len() != 2 {
53 return Err(std::io::Error::other("expected one cached two-page scene").into());
54 }
55
56 let pdf_request = ExportRequest {
57 format: ExportFormat::Pdf,
58 pdf_mode: PdfMode::Editable,
59 ..ExportRequest::default()
60 };
61 let context = ExportContext {
62 limits: &limits,
63 fonts: &fonts,
64 assets: None,
65 };
66 let report = preflight(
67 &scene,
68 &pdf_request,
69 &context,
70 &PreflightOptions {
71 strict: true,
72 ..PreflightOptions::default()
73 },
74 &OperationControl::default(),
75 )?;
76 report.enforce(true)?;
77 let (pdf, pdf_outcome) = export_bytes(&scene, &pdf_request, &context)?;
78 let (html, html_outcome) = export_bytes(
79 &scene,
80 &ExportRequest {
81 format: ExportFormat::Html,
82 html_mode: HtmlMode::Fixed,
83 ..ExportRequest::default()
84 },
85 &context,
86 )?;
87 let (page_one_svg, page_one_outcome) = export_svg_page(&scene, 0, &context)?;
88 let (page_two_svg, page_two_outcome) = export_svg_page(&scene, 1, &context)?;
89
90 let pdf_path = output_path("intermediate.pdf")?;
91 let html_path = output_path("intermediate.html")?;
92 let page_one_path = output_path("intermediate-page-1.svg")?;
93 let page_two_path = output_path("intermediate-page-2.svg")?;
94 let report_path = output_path("intermediate-preflight.json")?;
95 std::fs::write(&pdf_path, pdf)?;
96 std::fs::write(&html_path, html)?;
97 std::fs::write(&page_one_path, page_one_svg)?;
98 std::fs::write(&page_two_path, page_two_svg)?;
99 std::fs::write(&report_path, serde_json::to_vec_pretty(&report)?)?;
100 let inspector = SceneInspector::new(&scene);
101 println!(
102 "pages={} roles={:?}/{:?} undo={} pdf_bytes={} html_bytes={} svg_bytes={}/{}\npdf={}\nhtml={}\npage_1={}\npage_2={}\npreflight={}",
103 scene.pages.len(),
104 inspector.inspect_page(0)?.role,
105 inspector.inspect_page(1)?.role,
106 log.undo_len(),
107 pdf_outcome.bytes_written,
108 html_outcome.bytes_written,
109 page_one_outcome.bytes_written,
110 page_two_outcome.bytes_written,
111 pdf_path.display(),
112 html_path.display(),
113 page_one_path.display(),
114 page_two_path.display(),
115 report_path.display()
116 );
117 Ok(())
118}Sourcepub fn new_controlled(
limits: &'a ResourceLimits,
fonts: &'a FontManager,
options: LayoutOptions,
control: OperationControl,
) -> Result<Self>
pub fn new_controlled( limits: &'a ResourceLimits, fonts: &'a FontManager, options: LayoutOptions, control: OperationControl, ) -> Result<Self>
Creates an engine with cooperative cancellation and progress controls.
Sourcepub fn with_assets(self, assets: &'a dyn AssetResolver) -> Self
pub fn with_assets(self, assets: &'a dyn AssetResolver) -> Self
Supplies the explicit resolver needed to resolve image paint geometry.
Sourcepub fn resolve(&self, document: &DocumentIr) -> Result<ResolvedScene>
pub fn resolve(&self, document: &DocumentIr) -> Result<ResolvedScene>
Resolves all geometry before any exporter is selected.
Examples found in repository?
examples/basic.rs (line 25)
18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 let limits = ResourceLimits::default();
20 let compiler = Compiler::builder().limits(limits.clone()).build()?;
21 let template = compiler.compile_template_yaml(include_bytes!("basic.yml"))?;
22 let data: DataValue = serde_json::from_slice(include_bytes!("basic-data.json"))?;
23 let document = compiler.bind(&template, &data, &[])?;
24 let fonts = example_fonts()?;
25 let scene = LayoutEngine::new(&limits, &fonts, LayoutOptions::default())?.resolve(&document)?;
26 let (output, outcome) = export_bytes(
27 &scene,
28 &ExportRequest {
29 format: ExportFormat::Svg,
30 ..ExportRequest::default()
31 },
32 &ExportContext {
33 limits: &limits,
34 fonts: &fonts,
35 assets: None,
36 },
37 )?;
38 let output_path = output_path("basic.svg")?;
39 std::fs::write(&output_path, output)?;
40 println!(
41 "pages={} svg_bytes={} output={}",
42 scene.pages.len(),
43 outcome.bytes_written,
44 output_path.display()
45 );
46 Ok(())
47}Sourcepub fn resolve_cached(
&self,
document: &DocumentIr,
fingerprint: DocumentFingerprint,
cache: &mut SceneCache,
) -> Result<Arc<ResolvedScene>>
pub fn resolve_cached( &self, document: &DocumentIr, fingerprint: DocumentFingerprint, cache: &mut SceneCache, ) -> Result<Arc<ResolvedScene>>
Resolves only on a fingerprint miss and returns an immutable shared scene.
The fingerprint must be computed from the same template, data, patches,
assets, and fonts used to produce document and this engine.
Examples found in repository?
examples/intermediate.rs (line 50)
23fn main() -> Result<(), Box<dyn std::error::Error>> {
24 let limits = ResourceLimits::default();
25 let compiler = Compiler::builder().limits(limits.clone()).build()?;
26 let template = compiler.compile_template_yaml(include_bytes!("intermediate.yml"))?;
27 let data: DataValue = serde_json::from_slice(include_bytes!("intermediate-data.json"))?;
28 let mut document = compiler.bind(&template, &data, &[])?;
29 let mut log = OperationLog::new_bounded(8, 8 * 1024 * 1024)?;
30 let patch = Patch {
31 sequence: 1,
32 operations: vec![PatchOperation::Move {
33 id: ElementId::new("review-marker")?,
34 x: "185mm".parse()?,
35 y: "112mm".parse()?,
36 }],
37 };
38 log.apply(&mut document, &patch, limits.max_patch_operations)?;
39 let fonts = example_fonts()?;
40 let fingerprint = DocumentFingerprint::compute_with_patches(
41 &template,
42 &data,
43 std::slice::from_ref(&patch),
44 None,
45 &fonts,
46 &limits,
47 )?;
48 let engine = LayoutEngine::new(&limits, &fonts, LayoutOptions::default())?;
49 let mut cache = SceneCache::with_byte_capacity(8, 64 * 1024 * 1024)?;
50 let scene = engine.resolve_cached(&document, fingerprint, &mut cache)?;
51 let cached = engine.resolve_cached(&document, fingerprint, &mut cache)?;
52 if !Arc::ptr_eq(&scene, &cached) || scene.pages.len() != 2 {
53 return Err(std::io::Error::other("expected one cached two-page scene").into());
54 }
55
56 let pdf_request = ExportRequest {
57 format: ExportFormat::Pdf,
58 pdf_mode: PdfMode::Editable,
59 ..ExportRequest::default()
60 };
61 let context = ExportContext {
62 limits: &limits,
63 fonts: &fonts,
64 assets: None,
65 };
66 let report = preflight(
67 &scene,
68 &pdf_request,
69 &context,
70 &PreflightOptions {
71 strict: true,
72 ..PreflightOptions::default()
73 },
74 &OperationControl::default(),
75 )?;
76 report.enforce(true)?;
77 let (pdf, pdf_outcome) = export_bytes(&scene, &pdf_request, &context)?;
78 let (html, html_outcome) = export_bytes(
79 &scene,
80 &ExportRequest {
81 format: ExportFormat::Html,
82 html_mode: HtmlMode::Fixed,
83 ..ExportRequest::default()
84 },
85 &context,
86 )?;
87 let (page_one_svg, page_one_outcome) = export_svg_page(&scene, 0, &context)?;
88 let (page_two_svg, page_two_outcome) = export_svg_page(&scene, 1, &context)?;
89
90 let pdf_path = output_path("intermediate.pdf")?;
91 let html_path = output_path("intermediate.html")?;
92 let page_one_path = output_path("intermediate-page-1.svg")?;
93 let page_two_path = output_path("intermediate-page-2.svg")?;
94 let report_path = output_path("intermediate-preflight.json")?;
95 std::fs::write(&pdf_path, pdf)?;
96 std::fs::write(&html_path, html)?;
97 std::fs::write(&page_one_path, page_one_svg)?;
98 std::fs::write(&page_two_path, page_two_svg)?;
99 std::fs::write(&report_path, serde_json::to_vec_pretty(&report)?)?;
100 let inspector = SceneInspector::new(&scene);
101 println!(
102 "pages={} roles={:?}/{:?} undo={} pdf_bytes={} html_bytes={} svg_bytes={}/{}\npdf={}\nhtml={}\npage_1={}\npage_2={}\npreflight={}",
103 scene.pages.len(),
104 inspector.inspect_page(0)?.role,
105 inspector.inspect_page(1)?.role,
106 log.undo_len(),
107 pdf_outcome.bytes_written,
108 html_outcome.bytes_written,
109 page_one_outcome.bytes_written,
110 page_two_outcome.bytes_written,
111 pdf_path.display(),
112 html_path.display(),
113 page_one_path.display(),
114 page_two_path.display(),
115 report_path.display()
116 );
117 Ok(())
118}Auto Trait Implementations§
impl<'a> !RefUnwindSafe for LayoutEngine<'a>
impl<'a> !UnwindSafe for LayoutEngine<'a>
impl<'a> Freeze for LayoutEngine<'a>
impl<'a> Send for LayoutEngine<'a>
impl<'a> Sync for LayoutEngine<'a>
impl<'a> Unpin for LayoutEngine<'a>
impl<'a> UnsafeUnpin for LayoutEngine<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<U, T> ToOwnedObj<U> for Twhere
U: FromObjRef<T>,
impl<U, T> ToOwnedObj<U> for Twhere
U: FromObjRef<T>,
Source§fn to_owned_obj(&self, data: FontData<'_>) -> U
fn to_owned_obj(&self, data: FontData<'_>) -> U
Convert this type into
T, using the provided data to resolve any offsets.