Handle variants of an enum
We have en enum that has 2 or more variants probably with differen attributes. We would like to be able to display the each variant in its own way.
Ideally we would probably be able to use a match inside the templates.
This is a solution that might be overengineered.
use liquid_core::{ Display_filter, Filter, FilterReflection, ParseFilter, Result, Runtime, Value, ValueView, }; use serde::Serialize; #[derive(Clone, ParseFilter, FilterReflection)] #[filter(name = "type", description = "Type", parsed(TypeFilter))] pub struct TypeStr; #[derive(Debug, Default, Display_filter)] #[name = "typestr"] pub struct TypeFilter; impl Filter for TypeFilter { fn evaluate(&self, input: &dyn ValueView, _runtime: &dyn Runtime) -> Result<Value> { let keys = ["Presentation", "Break"]; match input.as_object() { Some(obj) => { for key in keys { if obj.contains_key(key) { return Ok(Value::scalar(format!("{}", key))); } } return Ok(Value::scalar("Unknown Item")); } None => Ok(Value::scalar("Not an object")), } } } #[derive(Serialize)] struct Presentation { title: String, length: u32, speaker: String, } #[derive(Serialize)] struct Break { length: u32, } #[derive(Serialize)] enum Item { Presentation(Presentation), Break(Break), } fn main() { let items = get_items(); let text = items_to_text(&items); //println!("{}", text); let expected_text = "\ Presentation: Introduction to Rust by Alice (30 mins) Break: 15 mins Presentation: Advanced Rust by Bob (45 mins) "; assert_eq!(text, expected_text); let html = render(&items); let expected_html = "\ <ul> <li>Introduction to Rust by Alice - (30 minutes)</li> <li>Break (15 minutes)</li> <li>Advanced Rust by Bob - (45 minutes)</li> </ul>"; assert_eq!(html, expected_html); //println!("{}", html); } fn get_items() -> Vec<Item> { vec![ Item::Presentation(Presentation { title: "Introduction to Rust".to_string(), length: 30, speaker: "Alice".to_string(), }), Item::Break(Break { length: 15 }), Item::Presentation(Presentation { title: "Advanced Rust".to_string(), length: 45, speaker: "Bob".to_string(), }), ] } fn items_to_text(items: &Vec<Item>) -> String { let mut result = String::new(); for item in items { match item { Item::Presentation(p) => { result.push_str(&format!( "Presentation: {} by {} ({} mins)\n", p.title, p.speaker, p.length )); } Item::Break(b) => { result.push_str(&format!("Break: {} mins\n", b.length)); } } } result } fn render(items: &Vec<Item>) -> String { let template = "\ <ul> {%- for item in items -%} {%- assign it = item | type -%} {%- if it == \"Presentation\" %} <li>{{item.Presentation.title}} by {{item.Presentation.speaker}} - ({{item.Presentation.length}} minutes)</li> {%- elsif it == \"Break\" %} <li>Break ({{item.Break.length}} minutes)</li> {%- endif -%} {% endfor %} </ul>"; let template = liquid::ParserBuilder::with_stdlib() .filter(TypeStr) .build() .unwrap() .parse(template) .unwrap(); let globals = liquid::object!({ "name": "Liquid", "items": items, }); let output = template.render(&globals).unwrap(); output }