-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.rs
140 lines (124 loc) · 4.66 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
mod bindings;
mod input;
mod output;
mod page;
use input::Input;
use output::Output;
use page::Page;
use std::{ops::Deref, sync::Arc};
use bindings::demo::forms::{
types::{self, Context},
wurbo_in,
};
// We will likely have other guests, so let's alias this one to WurboGuest
use bindings::exports::demo::forms::wurbo_out::Guest as WurboGuest;
use wurbo::jinja::{Entry, Index, Rest, Templates};
use wurbo::prelude_bindgen;
/// The struct for the bound component that implements the Guest traits
struct Component;
bindings::export!(Component with_types_in bindings);
const OUTPUT_HTML: &str = "output.html";
const INDEX_HTML: &str = "index.html";
const INPUT_HTML: &str = "input.html";
/// We need to provide the templates for the macro to pull in
fn get_templates() -> Templates {
let templates = Templates::new(
Index::new(
INDEX_HTML.to_owned(),
include_str!("templates/index.html").to_owned(),
),
Entry::new(
OUTPUT_HTML.to_owned(),
include_str!("templates/output.html").to_owned(),
),
Rest::new(vec![Entry::new(
INPUT_HTML.to_owned(),
include_str!("templates/input.html").to_owned(),
)]),
);
templates
}
// Macro builds the Component struct and implements the Guest trait for us, saving copy-and-paste
prelude_bindgen! {WurboGuest, Component, PageContext, Context, LAST_STATE}
/// PageContext is a struct of other structs that implement [`minijinja::value::Object`],
/// which is why it is not a Newtype wrapper like the others are.
#[derive(Debug, Clone)]
pub struct PageContext {
page: Page,
input: Input,
pub(crate) output: Output,
target: Option<String>,
}
impl Object for PageContext {
fn get_value(self: &Arc<Self>, field: &Value) -> Option<Value> {
match field.as_str()? {
"page" => Some(Value::from_object(self.page.clone())),
"input" => Some(Value::from_object(self.input.clone())),
"output" => Some(Value::from_object(self.output.clone())),
_ => None,
}
}
}
/// We received Context from the WIT ABO and need to convert it to PageContext
impl From<&types::Context> for PageContext {
fn from(context: &types::Context) -> Self {
// Output is not a type of context, because it is calculated from the other values
match context {
types::Context::AllContent(c) => PageContext::from(c.clone()),
types::Context::Username(u) => PageContext::from(output::Username::from(u.to_owned())),
types::Context::Password(p) => PageContext::from(output::Password::from(p.to_owned())),
types::Context::File(f) => PageContext::from(output::File::from(f.to_owned())),
types::Context::ExampleVariant(v) => {
println!("Received ExampleVariant: {:?}", v);
// We don't have a variant for this example, so we will just return the default
// derive from LAST_STATE
let state = { LAST_STATE.lock().unwrap().clone().unwrap() };
state
}
}
}
}
/// We have all the content, convert it to PageContext
impl From<types::Content> for PageContext {
fn from(context: types::Content) -> Self {
PageContext {
page: Page::from(context.page),
input: Input::from(context.input),
// We can use default for Output because the minijinja StructObject impl will
// calculate the values from the above inouts for us
output: Output::default(),
// No override for target, use the default
target: None,
}
}
}
impl From<output::Username> for PageContext {
fn from(username: output::Username) -> Self {
// Safe to unwrap here because render on all page content will always be called first
let mut state = { LAST_STATE.lock().unwrap().clone().unwrap() };
state.output.username = username;
state
}
}
impl From<output::Password> for PageContext {
fn from(password: output::Password) -> Self {
// Safe to unwrap here because render on all page content will always be called first
let mut state = { LAST_STATE.lock().unwrap().clone().unwrap() };
state.output.password = password;
state
}
}
impl From<output::File> for PageContext {
fn from(file: output::File) -> Self {
// Safe to unwrap here because render on all page content will always be called first
let mut state = { LAST_STATE.lock().unwrap().clone().unwrap() };
state.output.file = Some(file);
state
}
}
#[cfg(test)]
mod test_forms_ui {
use super::*;
#[test]
fn test_get_context_fields() {}
}