From 00ffb6d11ed3a1d6508cbf065679b6f04673f238 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 17 Jun 2026 00:05:37 -0700 Subject: I think this is a better structure. We deal with mapped structures better now, and they are distinct from our handy value tree. I haven't figured out how to make it like iterators yet, but I think we're close... --- src/context.rs | 136 ++++++++++++++++++++++++-------------------- src/lib.rs | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 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 @@ use std::collections::HashMap; +use std::fmt; use crate::{Identifier,IdentifierValue}; pub type Context = HashMap; -pub trait MappedStructure { - fn get_value(&self, id: &[IdentifierValue]) -> Option; - fn get_iterable(&self, id: &[IdentifierValue]) -> Option - where - T: IntoIterator, - T::Item: MappedStructure; +pub trait MappedStructure<'a> { + fn get_value(&'a self, id: &str) -> Option>; } -impl MappedStructure for Context { - fn get_value(&self, id: &[IdentifierValue]) -> Option { +impl<'a> MappedStructure<'a> for Context { + fn get_value(&'a self, _id: &str) -> Option> { + /* if id.len() == 0 { return None; } - let mut cur_val : Option<&Value> = if let IdentifierValue::Name(s) = &id[0] { + let mut cur_val : Option<&MappedValue> = if let IdentifierValue::Name(s) = &id[0] { self.get(s) } else { return None; @@ -28,7 +26,7 @@ impl MappedStructure for Context { for idx in 1..id.len() { if let IdentifierValue::Name(s) = &id[idx] && - let Some(Value::Dictionary(d)) = &cur_val { + let Some(MappedValue::Dictionary(d)) = &cur_val { cur_val.replace( if let Some(v) = d.get(s) { v } else { @@ -38,49 +36,64 @@ impl MappedStructure for Context { } return cur_val.cloned(); + */ + + None } - - fn get_iter(&self, id: &[IdentifierValue]) -> Option - where - T: IntoIterator, - T::Item: MappedStructure, { - if id.len() == 0 { - return None; - } - let mut cur_val : Option<&Value> = if let IdentifierValue::Name(s) = &id[0] { - self.get(s) - } else { - return None; - }; - if cur_val.is_none() { - return None; - } +} - for idx in 1..id.len() { - if let IdentifierValue::Name(s) = &id[idx] && - let Some(Value::Dictionary(d)) = &cur_val { - cur_val.replace( if let Some(v) = d.get(s) { - v - } else { - return None; - }); - } - } +pub trait MappedList<'a> { + fn get_index(&'a self, id: usize) -> Option>; +} - if let Some(Value::List(l)) = cur_val { - return l.into - } +pub enum MappedValue<'a> { + Struct(&'a dyn MappedStructure<'a>), + List(&'a dyn MappedList<'a>), + + Str(&'a str), + String(&'a String), + Int8(i8), + Int16(i16), + Int32(i32), + Int64(i64), + UInt8(u8), + UInt16(u16), + UInt32(u32), + UInt64(u64), + Float32(f32), + Float64(f64), + Bool(bool), +} - return cur_val.cloned(); +impl<'a> fmt::Debug for MappedValue<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MappedValue::<'a>::Struct(_) => write!(f, "MappedValue"), + MappedValue::<'a>::List(_) => write!(f, "MappedList"), + MappedValue::<'a>::Str(v) => write!(f, "{:?}", v), + MappedValue::<'a>::String(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Int8(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Int16(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Int32(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Int64(v) => write!(f, "{:?}", v), + MappedValue::<'a>::UInt8(v) => write!(f, "{:?}", v), + MappedValue::<'a>::UInt16(v) => write!(f, "{:?}", v), + MappedValue::<'a>::UInt32(v) => write!(f, "{:?}", v), + MappedValue::<'a>::UInt64(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Float32(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Float64(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Bool(v) => write!(f, "{:?}", v), + } } + } -pub struct StatefulContext<'a, T: MappedStructure> { - pub root: &'a T, +pub struct StatefulContext<'a, T: MappedStructure<'a>> { + root: &'a T, local: &'a T, } -impl<'a, T: MappedStructure> StatefulContext<'a, T> { +impl<'a, T: MappedStructure<'a>> StatefulContext<'a, T> { pub fn root( root: &'a T ) -> Self { Self { root, local: root, @@ -99,25 +112,28 @@ impl<'a, T: MappedStructure> StatefulContext<'a, T> { root, local } } -} -impl<'a, T: MappedStructure> MappedStructure for StatefulContext<'a,T> { - fn get_value(&self, id: &[IdentifierValue]) -> Option { - if id.is_empty() { - return None; - } - if id[0] == IdentifierValue::Root { - self.root.get_value( &id[1..] ) - } else { - self.local.get_value( id ) + pub fn get_value(&self, id: &[IdentifierValue]) -> Option> { + let mut value : Option = Some(MappedValue::Struct(self.root)); + for idpart in id { + match idpart { + IdentifierValue::Root => { + return None + } + IdentifierValue::Name(name) => { + if let Some(MappedValue::Struct(s)) = value && + let Some(nv) = s.get_value( &name ) { + value.replace( nv ); + } else { + return None; + } + } + IdentifierValue::Index(_) => { + return None; + } + } } - } - - fn get_iter(&self, id: &[IdentifierValue]) -> Option - where - U: IntoIterator, - U::Item: MappedStructure, { - None + value } } 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; pub use error::{CrimError,CrimResult}; pub use position::*; -pub use context::{Context,Value,MappedStructure,StatefulContext}; +pub use context::{Context,Value,MappedStructure,StatefulContext,MappedValue,MappedList}; #[derive(Debug)] pub struct Crimtag { @@ -41,7 +41,7 @@ struct View { } impl View { - fn process(&self, input: &T) -> CrimResult { + fn process MappedStructure<'a>>(&self, input: &T) -> CrimResult { let mut out_vars = Context::new(); for output in &self.outputs { let mut buf = String::new(); @@ -163,7 +163,7 @@ impl Crimtag { } } - pub fn render_partial(&self, view: &str, input: &T ) -> CrimResult { + pub fn render_partial MappedStructure<'a>>(&self, view: &str, input: &T ) -> CrimResult { if let Some(view) = self.views.get(view) { return view.process( input ) } else { @@ -171,7 +171,7 @@ impl Crimtag { } } - pub fn render(&self, view: &str, input: &T ) -> CrimResult { + pub fn render MappedStructure<'a>>(&self, view: &str, input: &T ) -> CrimResult { if let Some(view) = self.views.get( view ) { //println!("::Token tree::\n{:?}", view ); let mut output = view.process( input )?; @@ -193,10 +193,11 @@ impl Crimtag { } } -fn exec(input: &StatefulContext, tokens: &Vec, buf: &mut String) -> CrimResult<()> { +fn exec MappedStructure<'a>>(input: &StatefulContext, tokens: &Vec, buf: &mut String) -> CrimResult<()> { for token in tokens { match token { - Token::Loop(ident,code) => { + Token::Loop(_ident,_code) => { + /* if let Some(value) = input.get_value( &ident ) && let Value::List(list) = value { for rec in &list { @@ -212,10 +213,12 @@ fn exec(input: &StatefulContext, tokens: &Vec, buf } } } + */ + return Ok(()); } Token::If(ident,code,other) => { if let Some(value) = input.get_value( &ident ) && - let Value::Bool(b) = value && + let MappedValue::Bool(b) = value && b { exec(input, code, buf)? @@ -231,34 +234,62 @@ fn exec(input: &StatefulContext, tokens: &Vec, buf }; if let Some(value) = input.get_value( &ident ) { match value { - Value::Dictionary(_) => { - buf.push_str(""); + MappedValue::Struct(_) => { + buf.push_str("Struct"); } - Value::List(_) => { - buf.push_str(""); + MappedValue::List(_) => { + buf.push_str("List"); } - Value::Bool(b) => { + MappedValue::Bool(b) => { if b { buf.push_str("true"); } else { buf.push_str("false"); } } - Value::String(s) => { + MappedValue::Str(s) => { + buf.push_str(s); + } + MappedValue::String(s) => { buf.push_str(s.as_str()); } - Value::Int(i) => { + MappedValue::Int8(i) => { + buf.push_str(&i.to_string()); + } + MappedValue::Int16(i) => { + buf.push_str(&i.to_string()); + } + MappedValue::Int32(i) => { + buf.push_str(&i.to_string()); + } + MappedValue::Int64(i) => { + buf.push_str(&i.to_string()); + } + MappedValue::UInt8(i) => { + buf.push_str(&i.to_string()); + } + MappedValue::UInt16(i) => { + buf.push_str(&i.to_string()); + } + MappedValue::UInt32(i) => { buf.push_str(&i.to_string()); } - Value::Float(f) => { + MappedValue::UInt64(i) => { + buf.push_str(&i.to_string()); + } + MappedValue::Float32(f) => { if format == "" { buf.push_str(&f.to_string()); } else { buf.push_str(&f.to_string()); } } - Value::Identifier(_) => { - // ??? + MappedValue::Float64(f) => { + if format == "" { + buf.push_str(&f.to_string()); + } else { + buf.push_str(&f.to_string()); + } } } } @@ -266,7 +297,7 @@ fn exec(input: &StatefulContext, tokens: &Vec, buf Token::Text(s) => { buf.push_str( s ); } - _ => {} + //_ => {} } } Ok(()) @@ -394,4 +425,111 @@ Now with explicit outputs: Ok(()) } + + struct Item { + pub id: i32, + pub title: String, + pub body: String, + } + + struct Person { + pub id: i32, + pub username: String, + pub name: String, + } + + struct Page { + pub user: Person, + pub total_items: i32, + pub total_pages: i32, + pub cur_page: i32, + pub items: Vec, + } + + impl Page { + fn new() -> Page { + Page { + user: Person { + id: 443, + username: "eichlan".into(), + name: "Mike".into(), + }, + total_items: 4000, + total_pages: 400, + cur_page: 35, + items: vec![ + Item{ + id: 123, + title: "hi".into(), + body: "body".into(), + }, + Item{ + id: 124, + title: "bye".into(), + body: "wooo".into(), + }, + Item{ + id: 125, + title: "ciao".into(), + body: "whatever".into(), + } + ], + } + } + } + + impl<'a> MappedStructure<'a> for Page { + fn get_value(&'a self, id: &str) -> Option> { + match id { + "user" => Some(MappedValue::Struct(&self.user)), + "total_items" => Some(MappedValue::Int32(self.total_items)), + "total_pages" => Some(MappedValue::Int32(self.total_pages)), + "cur_page" => Some(MappedValue::Int32(self.cur_page)), + "items" => Some(MappedValue::<'a>::List(&self.items)), + _ => None, + } + } + } + + impl<'a> MappedStructure<'a> for Person { + fn get_value(&'a self, id: &str) -> Option> { + match id { + "id" => Some(MappedValue::Int32(self.id)), + "username" => Some(MappedValue::String(&self.username)), + "name" => Some(MappedValue::String(&self.name)), + _ => None, + } + } + } + + impl<'a> MappedStructure<'a> for Item { + fn get_value(&'a self, id: &str) -> Option> { + match id { + "id" => Some(MappedValue::Int32(self.id)), + "title" => Some(MappedValue::String(&self.title)), + "body" => Some(MappedValue::String(&self.body)), + _ => None, + } + } + } + + impl<'a> MappedList<'a> for Vec { + fn get_index(&'a self, id: usize) -> Option> { + if let Some(x) = self.get(id) { + Some(MappedValue::<'a>::Struct(x)) + } else { + None + } + } + } + + #[test] + fn custom() -> Result<(), CrimError> { + let page = Page::new(); + + println!("{:?}", + page.get_value(&"total_pages") + ); + Ok(()) + } } -- cgit v1.2.3