summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/context.rs136
-rw-r--r--src/lib.rs174
2 files changed, 232 insertions, 78 deletions
diff --git a/src/context.rs b/src/context.rs
index 2f12ea9..83f8539 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -1,23 +1,21 @@
1use std::collections::HashMap; 1use std::collections::HashMap;
2use std::fmt;
2 3
3use crate::{Identifier,IdentifierValue}; 4use crate::{Identifier,IdentifierValue};
4 5
5pub type Context = HashMap<String,Value>; 6pub type Context = HashMap<String,Value>;
6 7
7pub trait MappedStructure { 8pub trait MappedStructure<'a> {
8 fn get_value(&self, id: &[IdentifierValue]) -> Option<Value>; 9 fn get_value(&'a self, id: &str) -> Option<MappedValue<'a>>;
9 fn get_iterable<T>(&self, id: &[IdentifierValue]) -> Option<T>
10 where
11 T: IntoIterator,
12 T::Item: MappedStructure;
13} 10}
14 11
15impl MappedStructure for Context { 12impl<'a> MappedStructure<'a> for Context {
16 fn get_value(&self, id: &[IdentifierValue]) -> Option<Value> { 13 fn get_value(&'a self, _id: &str) -> Option<MappedValue<'a>> {
14 /*
17 if id.len() == 0 { 15 if id.len() == 0 {
18 return None; 16 return None;
19 } 17 }
20 let mut cur_val : Option<&Value> = if let IdentifierValue::Name(s) = &id[0] { 18 let mut cur_val : Option<&MappedValue> = if let IdentifierValue::Name(s) = &id[0] {
21 self.get(s) 19 self.get(s)
22 } else { 20 } else {
23 return None; 21 return None;
@@ -28,7 +26,7 @@ impl MappedStructure for Context {
28 26
29 for idx in 1..id.len() { 27 for idx in 1..id.len() {
30 if let IdentifierValue::Name(s) = &id[idx] && 28 if let IdentifierValue::Name(s) = &id[idx] &&
31 let Some(Value::Dictionary(d)) = &cur_val { 29 let Some(MappedValue::Dictionary(d)) = &cur_val {
32 cur_val.replace( if let Some(v) = d.get(s) { 30 cur_val.replace( if let Some(v) = d.get(s) {
33 v 31 v
34 } else { 32 } else {
@@ -38,49 +36,64 @@ impl MappedStructure for Context {
38 } 36 }
39 37
40 return cur_val.cloned(); 38 return cur_val.cloned();
39 */
40
41 None
41 } 42 }
42 43}
43 fn get_iter<T>(&self, id: &[IdentifierValue]) -> Option<T>
44 where
45 T: IntoIterator,
46 T::Item: MappedStructure, {
47 if id.len() == 0 {
48 return None;
49 }
50 let mut cur_val : Option<&Value> = if let IdentifierValue::Name(s) = &id[0] {
51 self.get(s)
52 } else {
53 return None;
54 };
55 if cur_val.is_none() {
56 return None;
57 }
58 44
59 for idx in 1..id.len() { 45pub trait MappedList<'a> {
60 if let IdentifierValue::Name(s) = &id[idx] && 46 fn get_index(&'a self, id: usize) -> Option<MappedValue<'a>>;
61 let Some(Value::Dictionary(d)) = &cur_val { 47}
62 cur_val.replace( if let Some(v) = d.get(s) {
63 v
64 } else {
65 return None;
66 });
67 }
68 }
69 48
70 if let Some(Value::List(l)) = cur_val { 49pub enum MappedValue<'a> {
71 return l.into 50 Struct(&'a dyn MappedStructure<'a>),
72 } 51 List(&'a dyn MappedList<'a>),
52
53 Str(&'a str),
54 String(&'a String),
55 Int8(i8),
56 Int16(i16),
57 Int32(i32),
58 Int64(i64),
59 UInt8(u8),
60 UInt16(u16),
61 UInt32(u32),
62 UInt64(u64),
63 Float32(f32),
64 Float64(f64),
65 Bool(bool),
66}
73 67
74 return cur_val.cloned(); 68impl<'a> fmt::Debug for MappedValue<'a> {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 match self {
71 MappedValue::<'a>::Struct(_) => write!(f, "MappedValue"),
72 MappedValue::<'a>::List(_) => write!(f, "MappedList"),
73 MappedValue::<'a>::Str(v) => write!(f, "{:?}", v),
74 MappedValue::<'a>::String(v) => write!(f, "{:?}", v),
75 MappedValue::<'a>::Int8(v) => write!(f, "{:?}", v),
76 MappedValue::<'a>::Int16(v) => write!(f, "{:?}", v),
77 MappedValue::<'a>::Int32(v) => write!(f, "{:?}", v),
78 MappedValue::<'a>::Int64(v) => write!(f, "{:?}", v),
79 MappedValue::<'a>::UInt8(v) => write!(f, "{:?}", v),
80 MappedValue::<'a>::UInt16(v) => write!(f, "{:?}", v),
81 MappedValue::<'a>::UInt32(v) => write!(f, "{:?}", v),
82 MappedValue::<'a>::UInt64(v) => write!(f, "{:?}", v),
83 MappedValue::<'a>::Float32(v) => write!(f, "{:?}", v),
84 MappedValue::<'a>::Float64(v) => write!(f, "{:?}", v),
85 MappedValue::<'a>::Bool(v) => write!(f, "{:?}", v),
86 }
75 } 87 }
88
76} 89}
77 90
78pub struct StatefulContext<'a, T: MappedStructure> { 91pub struct StatefulContext<'a, T: MappedStructure<'a>> {
79 pub root: &'a T, 92 root: &'a T,
80 local: &'a T, 93 local: &'a T,
81} 94}
82 95
83impl<'a, T: MappedStructure> StatefulContext<'a, T> { 96impl<'a, T: MappedStructure<'a>> StatefulContext<'a, T> {
84 pub fn root( root: &'a T ) -> Self { 97 pub fn root( root: &'a T ) -> Self {
85 Self { 98 Self {
86 root, local: root, 99 root, local: root,
@@ -99,25 +112,28 @@ impl<'a, T: MappedStructure> StatefulContext<'a, T> {
99 root, local 112 root, local
100 } 113 }
101 } 114 }
102}
103 115
104impl<'a, T: MappedStructure> MappedStructure for StatefulContext<'a,T> { 116 pub fn get_value(&self, id: &[IdentifierValue]) -> Option<MappedValue<'a>> {
105 fn get_value(&self, id: &[IdentifierValue]) -> Option<Value> { 117 let mut value : Option<MappedValue> = Some(MappedValue::Struct(self.root));
106 if id.is_empty() { 118 for idpart in id {
107 return None; 119 match idpart {
108 } 120 IdentifierValue::Root => {
109 if id[0] == IdentifierValue::Root { 121 return None
110 self.root.get_value( &id[1..] ) 122 }
111 } else { 123 IdentifierValue::Name(name) => {
112 self.local.get_value( id ) 124 if let Some(MappedValue::Struct(s)) = value &&
125 let Some(nv) = s.get_value( &name ) {
126 value.replace( nv );
127 } else {
128 return None;
129 }
130 }
131 IdentifierValue::Index(_) => {
132 return None;
133 }
134 }
113 } 135 }
114 } 136 value
115
116 fn get_iter<U>(&self, id: &[IdentifierValue]) -> Option<U>
117 where
118 U: IntoIterator,
119 U::Item: MappedStructure, {
120 None
121 } 137 }
122} 138}
123 139
diff --git a/src/lib.rs b/src/lib.rs
index 362e017..eda2f31 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,7 +11,7 @@ mod context;
11 11
12pub use error::{CrimError,CrimResult}; 12pub use error::{CrimError,CrimResult};
13pub use position::*; 13pub use position::*;
14pub use context::{Context,Value,MappedStructure,StatefulContext}; 14pub use context::{Context,Value,MappedStructure,StatefulContext,MappedValue,MappedList};
15 15
16#[derive(Debug)] 16#[derive(Debug)]
17pub struct Crimtag { 17pub struct Crimtag {
@@ -41,7 +41,7 @@ struct View {
41} 41}
42 42
43impl View { 43impl View {
44 fn process<T: MappedStructure>(&self, input: &T) -> CrimResult<Context> { 44 fn process<T: for<'a> MappedStructure<'a>>(&self, input: &T) -> CrimResult<Context> {
45 let mut out_vars = Context::new(); 45 let mut out_vars = Context::new();
46 for output in &self.outputs { 46 for output in &self.outputs {
47 let mut buf = String::new(); 47 let mut buf = String::new();
@@ -163,7 +163,7 @@ impl Crimtag {
163 } 163 }
164 } 164 }
165 165
166 pub fn render_partial<T: MappedStructure>(&self, view: &str, input: &T ) -> CrimResult<Context> { 166 pub fn render_partial<T: for<'a> MappedStructure<'a>>(&self, view: &str, input: &T ) -> CrimResult<Context> {
167 if let Some(view) = self.views.get(view) { 167 if let Some(view) = self.views.get(view) {
168 return view.process( input ) 168 return view.process( input )
169 } else { 169 } else {
@@ -171,7 +171,7 @@ impl Crimtag {
171 } 171 }
172 } 172 }
173 173
174 pub fn render<T: MappedStructure>(&self, view: &str, input: &T ) -> CrimResult<String> { 174 pub fn render<T: for<'a> MappedStructure<'a>>(&self, view: &str, input: &T ) -> CrimResult<String> {
175 if let Some(view) = self.views.get( view ) { 175 if let Some(view) = self.views.get( view ) {
176 //println!("::Token tree::\n{:?}", view ); 176 //println!("::Token tree::\n{:?}", view );
177 let mut output = view.process( input )?; 177 let mut output = view.process( input )?;
@@ -193,10 +193,11 @@ impl Crimtag {
193 } 193 }
194} 194}
195 195
196fn exec<T: MappedStructure>(input: &StatefulContext<T>, tokens: &Vec<Token>, buf: &mut String) -> CrimResult<()> { 196fn exec<T: for<'a> MappedStructure<'a>>(input: &StatefulContext<T>, tokens: &Vec<Token>, buf: &mut String) -> CrimResult<()> {
197 for token in tokens { 197 for token in tokens {
198 match token { 198 match token {
199 Token::Loop(ident,code) => { 199 Token::Loop(_ident,_code) => {
200 /*
200 if let Some(value) = input.get_value( &ident ) && 201 if let Some(value) = input.get_value( &ident ) &&
201 let Value::List(list) = value { 202 let Value::List(list) = value {
202 for rec in &list { 203 for rec in &list {
@@ -212,10 +213,12 @@ fn exec<T: MappedStructure>(input: &StatefulContext<T>, tokens: &Vec<Token>, buf
212 } 213 }
213 } 214 }
214 } 215 }
216 */
217 return Ok(());
215 } 218 }
216 Token::If(ident,code,other) => { 219 Token::If(ident,code,other) => {
217 if let Some(value) = input.get_value( &ident ) && 220 if let Some(value) = input.get_value( &ident ) &&
218 let Value::Bool(b) = value && 221 let MappedValue::Bool(b) = value &&
219 b { 222 b {
220 223
221 exec(input, code, buf)? 224 exec(input, code, buf)?
@@ -231,34 +234,62 @@ fn exec<T: MappedStructure>(input: &StatefulContext<T>, tokens: &Vec<Token>, buf
231 }; 234 };
232 if let Some(value) = input.get_value( &ident ) { 235 if let Some(value) = input.get_value( &ident ) {
233 match value { 236 match value {
234 Value::Dictionary(_) => { 237 MappedValue::Struct(_) => {
235 buf.push_str("<dictionary>"); 238 buf.push_str("Struct");
236 } 239 }
237 Value::List(_) => { 240 MappedValue::List(_) => {
238 buf.push_str("<list>"); 241 buf.push_str("List");
239 } 242 }
240 Value::Bool(b) => { 243 MappedValue::Bool(b) => {
241 if b { 244 if b {
242 buf.push_str("true"); 245 buf.push_str("true");
243 } else { 246 } else {
244 buf.push_str("false"); 247 buf.push_str("false");
245 } 248 }
246 } 249 }
247 Value::String(s) => { 250 MappedValue::Str(s) => {
251 buf.push_str(s);
252 }
253 MappedValue::String(s) => {
248 buf.push_str(s.as_str()); 254 buf.push_str(s.as_str());
249 } 255 }
250 Value::Int(i) => { 256 MappedValue::Int8(i) => {
257 buf.push_str(&i.to_string());
258 }
259 MappedValue::Int16(i) => {
260 buf.push_str(&i.to_string());
261 }
262 MappedValue::Int32(i) => {
263 buf.push_str(&i.to_string());
264 }
265 MappedValue::Int64(i) => {
266 buf.push_str(&i.to_string());
267 }
268 MappedValue::UInt8(i) => {
269 buf.push_str(&i.to_string());
270 }
271 MappedValue::UInt16(i) => {
272 buf.push_str(&i.to_string());
273 }
274 MappedValue::UInt32(i) => {
251 buf.push_str(&i.to_string()); 275 buf.push_str(&i.to_string());
252 } 276 }
253 Value::Float(f) => { 277 MappedValue::UInt64(i) => {
278 buf.push_str(&i.to_string());
279 }
280 MappedValue::Float32(f) => {
254 if format == "" { 281 if format == "" {
255 buf.push_str(&f.to_string()); 282 buf.push_str(&f.to_string());
256 } else { 283 } else {
257 buf.push_str(&f.to_string()); 284 buf.push_str(&f.to_string());
258 } 285 }
259 } 286 }
260 Value::Identifier(_) => { 287 MappedValue::Float64(f) => {
261 // ??? 288 if format == "" {
289 buf.push_str(&f.to_string());
290 } else {
291 buf.push_str(&f.to_string());
292 }
262 } 293 }
263 } 294 }
264 } 295 }
@@ -266,7 +297,7 @@ fn exec<T: MappedStructure>(input: &StatefulContext<T>, tokens: &Vec<Token>, buf
266 Token::Text(s) => { 297 Token::Text(s) => {
267 buf.push_str( s ); 298 buf.push_str( s );
268 } 299 }
269 _ => {} 300 //_ => {}
270 } 301 }
271 } 302 }
272 Ok(()) 303 Ok(())
@@ -394,4 +425,111 @@ Now with explicit outputs:
394 425
395 Ok(()) 426 Ok(())
396 } 427 }
428
429 struct Item {
430 pub id: i32,
431 pub title: String,
432 pub body: String,
433 }
434
435 struct Person {
436 pub id: i32,
437 pub username: String,
438 pub name: String,
439 }
440
441 struct Page {
442 pub user: Person,
443 pub total_items: i32,
444 pub total_pages: i32,
445 pub cur_page: i32,
446 pub items: Vec<Item>,
447 }
448
449 impl Page {
450 fn new() -> Page {
451 Page {
452 user: Person {
453 id: 443,
454 username: "eichlan".into(),
455 name: "Mike".into(),
456 },
457 total_items: 4000,
458 total_pages: 400,
459 cur_page: 35,
460 items: vec![
461 Item{
462 id: 123,
463 title: "hi".into(),
464 body: "body".into(),
465 },
466 Item{
467 id: 124,
468 title: "bye".into(),
469 body: "wooo".into(),
470 },
471 Item{
472 id: 125,
473 title: "ciao".into(),
474 body: "whatever".into(),
475 }
476 ],
477 }
478 }
479 }
480
481 impl<'a> MappedStructure<'a> for Page {
482 fn get_value(&'a self, id: &str) -> Option<MappedValue<'a>> {
483 match id {
484 "user" => Some(MappedValue::Struct(&self.user)),
485 "total_items" => Some(MappedValue::Int32(self.total_items)),
486 "total_pages" => Some(MappedValue::Int32(self.total_pages)),
487 "cur_page" => Some(MappedValue::Int32(self.cur_page)),
488 "items" => Some(MappedValue::<'a>::List(&self.items)),
489 _ => None,
490 }
491 }
492 }
493
494 impl<'a> MappedStructure<'a> for Person {
495 fn get_value(&'a self, id: &str) -> Option<MappedValue<'a>> {
496 match id {
497 "id" => Some(MappedValue::Int32(self.id)),
498 "username" => Some(MappedValue::String(&self.username)),
499 "name" => Some(MappedValue::String(&self.name)),
500 _ => None,
501 }
502 }
503 }
504
505 impl<'a> MappedStructure<'a> for Item {
506 fn get_value(&'a self, id: &str) -> Option<MappedValue<'a>> {
507 match id {
508 "id" => Some(MappedValue::Int32(self.id)),
509 "title" => Some(MappedValue::String(&self.title)),
510 "body" => Some(MappedValue::String(&self.body)),
511 _ => None,
512 }
513 }
514 }
515
516 impl<'a> MappedList<'a> for Vec<Item> {
517 fn get_index(&'a self, id: usize) -> Option<MappedValue<'a>> {
518 if let Some(x) = self.get(id) {
519 Some(MappedValue::<'a>::Struct(x))
520 } else {
521 None
522 }
523 }
524 }
525
526 #[test]
527 fn custom() -> Result<(), CrimError> {
528 let page = Page::new();
529
530 println!("{:?}",
531 page.get_value(&"total_pages")
532 );
533 Ok(())
534 }
397} 535}