Skip to main content

low_level_template/
low_level_template.rs

1//! Low-level Template API example
2//!
3//! Demonstrates using the Template<V,R,FS> API instead of `TemplateArchive`.
4//! This provides more control over value types, renderers, and filesystems.
5//!
6//! Run with: cargo run --example `low_level_template`
7
8use genfile_core::
9{
10  Template,
11  HandlebarsRenderer,
12  MemoryFileSystem,
13  FileDescriptor,
14  WriteMode,
15  Value,
16  FileSystem,
17};
18use std::path::PathBuf;
19
20fn main() -> Result< (), Box< dyn core::error::Error > >
21{
22  println!( "=== Low-Level Template API Example ===" );
23  println!();
24
25  // Create renderer
26  let renderer = HandlebarsRenderer::new();
27
28  // Create two separate filesystems: one for templates, one for output
29  let mut template_fs = MemoryFileSystem::new();
30
31  // Prepare template files in the template filesystem
32  template_fs.write(
33    &PathBuf::from( "/templates/greeting.hbs" ),
34    "Hello, {{name}}!\n"
35  )?;
36
37  template_fs.write(
38    &PathBuf::from( "/templates/config.hbs" ),
39    "server={{server}}\nport={{port}}\n"
40  )?;
41
42  println!( "Template files prepared in memory filesystem" );
43  println!();
44
45  // Create template with explicit types using the template filesystem
46  let mut template = Template::< Value, _, _ >::new( renderer, template_fs );
47
48  // Insert values
49  template.insert_value( "name", Value::String( "World".into() ) );
50  template.insert_value( "server", Value::String( "localhost".into() ) );
51  template.insert_value( "port", Value::Number( 8080 ) );
52
53  // Add file descriptors
54  template.add_file( FileDescriptor
55  {
56    template_path: PathBuf::from( "/templates/greeting.hbs" ),
57    file_path: PathBuf::from( "/output/greeting.txt" ),
58    write_mode: WriteMode::Rewrite,
59  });
60
61  template.add_file( FileDescriptor
62  {
63    template_path: PathBuf::from( "/templates/config.hbs" ),
64    file_path: PathBuf::from( "/output/config.txt" ),
65    write_mode: WriteMode::Rewrite,
66  });
67
68  println!( "File descriptors added:" );
69  println!( "  greeting.hbs -> greeting.txt" );
70  println!( "  config.hbs -> config.txt" );
71  println!();
72
73  // Materialize (modifies the filesystem in place)
74  println!( "Materializing templates..." );
75  template.materialize()?;
76  println!( "✅ Materialization complete" );
77  println!();
78
79  // Access the filesystem via reference to read results
80  println!( "Generated files:" );
81  println!();
82
83  let greeting_content = template.filesystem().read( &PathBuf::from( "/output/greeting.txt" ) )?;
84  println!( "--- /output/greeting.txt ---" );
85  println!( "{greeting_content}" );
86  println!();
87
88  let config_content = template.filesystem().read( &PathBuf::from( "/output/config.txt" ) )?;
89  println!( "--- /output/config.txt ---" );
90  println!( "{config_content}" );
91  println!();
92
93  println!( "=== Advantages of Template API ===" );
94  println!();
95  println!( "• Generic over value types (V: TemplateValue)" );
96  println!( "• Generic over renderers (R: TemplateRenderer)" );
97  println!( "• Generic over filesystems (FS: FileSystem)" );
98  println!( "• Direct control over materialization process" );
99  println!( "• Useful for custom value types or renderers" );
100  println!();
101
102  println!( "=== When to use Template vs TemplateArchive ===" );
103  println!();
104  println!( "Use TemplateArchive when:" );
105  println!( "  • You need serialization (JSON/YAML)" );
106  println!( "  • You want self-contained archives" );
107  println!( "  • You need parameter discovery and analysis" );
108  println!( "  • Default Value type is sufficient" );
109  println!();
110  println!( "Use Template when:" );
111  println!( "  • You need custom value types" );
112  println!( "  • You need custom renderers" );
113  println!( "  • You want fine-grained control" );
114  println!( "  • Serialization is not needed" );
115  println!();
116
117  println!( "✅ Example completed successfully" );
118
119  Ok( () )
120}