pub fn hairy_compile<'a, 'b, 'c>(
    reader: &'b str,
    filename: &'b str,
    inlines: Option<&'a DecodedValue<'b>>,
    defaults: ValueRef<'b>,
    scope: &mut MemoryScope<'c>,
    option_custom: Option<&mut dyn CustomFuncs>,
    escaping: Option<&[(usize, &'b [u8])]>
) -> Result<BytecodeVec, HairCompileError<'b>> where
    'c: 'b,
    'b: 'a, 
Expand description

Converts a Hair template (in reader) to bytecode that can be evaluation later. To help debugging during later evaluation, a filename can be added to the bytecode. A MemoryScope is used to reduce the number of allocated strings. The result stays valid as long as the MemoryScope is in the scope (forced by the lifetime system of Rust). The globals and custom functions are used when evaluation the defaults (for template calls and such).

For an easy to version of this function, see the hairy_compile_html function (which provide auto escaping automatically).

Escaping

Normally, all strings that are dynamically outputted (between an evaluating {{..}} statement) are automatically ‘escaped’ using the escaper as given to an argument to the hairy_eval function. However, often you will want different escape modes depending on the input context. For example in HTML, output may not normally contain < or >, but output inside attributes in HTML tags are normally escaped using url-escaping. Although users can specify for every output the escape mode by appending a :html or :url escaping mode to an expression, this is error prone. Auto escaping is therefore a safer alternative, by automatically dedcing the escape mode from the input. That is where the escaping argument comes in to play. That argument is used to lookup the escaping mode for a certain position in the input.

Example

use hairy::*;
use expry::memorypool::MemoryPool;
use std::io::Write;
let mut allocator = MemoryPool::new();
let mut scope = allocator.rewind();
let template = r#"foo {{bar}}"#;
let result = hairy_compile(template, "test.tpl", None, ValueRef::new(), &mut scope, None, None);
match result {
  Ok(parsed) => {
    let value = ValueRef(b"");
    let output = hairy_eval(parsed.to_ref(), value, &mut scope, None, &[], None);
    if let Ok(output) = output {
      std::io::stdout().write_all(&output.concat());
      // OR, more efficient (avoiding allocations):
      for v in output {
        std::io::stdout().write_all(v);
      }
    }
  },
  Err(err) => {
    eprintln!("{}", hairy_compile_error_format(template, &err, 0));
  }
}