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
use std::sync::{Arc,RwLock};

use quick_xml::{
    Reader
    ,events::Event
};
use semilattice_database::Database;

mod script;
use script::Script;

mod xml_util;
use xml_util::XmlAttr;

mod include;
pub use include::{IncludeAdaptor,IncludeLocal};


pub struct WildDocResult{
    body:Vec<u8>
    ,options_json:String
}
impl WildDocResult{
    pub fn body(&self)->&[u8]{
        &self.body
    }
    pub fn options_json(&self)->&str{
        &self.options_json
    }
}
pub struct WildDoc<T:IncludeAdaptor>{
    database:Arc<RwLock<Database>>
    ,default_include_adaptor:T
}
impl<T:IncludeAdaptor> WildDoc<T>{
    pub fn new(
        dir:&str
        ,default_include_adaptor:T
    )->Result<Self,std::io::Error>{
        Ok(Self{
            database:Arc::new(RwLock::new(Database::new(dir)?))
            ,default_include_adaptor
        })
    }
    pub fn run(&mut self,xml:&str,input_json:&str)->Result<WildDocResult,std::io::Error>{
        let mut reader=Reader::from_str(xml);
        loop{
            match reader.read_event(){
                Ok(Event::Start(e))=>{
                    if e.name().as_ref()==b"wd"{
                        let mut script=Script::new(
                            self.database.clone()
                        );
                        return script.parse_xml(input_json,&mut reader,&mut self.default_include_adaptor);
                    }
                }
                ,_=>{}
            }
        }
    }
    pub fn run_specify_include_adaptor(&mut self,xml:&str,input_json:&str,index_adaptor:&mut impl IncludeAdaptor)->Result<WildDocResult,std::io::Error>{
        let mut reader=Reader::from_str(xml);
        loop{
            match reader.read_event(){
                Ok(Event::Start(e))=>{
                    if e.name().as_ref()==b"wd"{
                        let mut script=Script::new(
                            self.database.clone()
                        );
                        return script.parse_xml(input_json,&mut reader,index_adaptor);
                    }
                }
                ,_=>{
                    return Ok(WildDocResult{
                        body:xml.into()
                        ,options_json:"".to_string()
                    });
                }
            }
        }
    }
}

fn eval<'s>(scope: &mut v8::HandleScope<'s>,code: &str) -> Option<v8::Local<'s, v8::Value>> {
    let scope = &mut v8::EscapableHandleScope::new(scope);
    let source = v8::String::new(scope, code).unwrap();
    let script = v8::Script::compile(scope, source, None).unwrap();
    let r = script.run(scope);
    r.map(|v| scope.escape(v))
}

fn eval_result(scope:&mut v8::HandleScope,value:&str)->String{
    if let Some(v8_value)=v8::String::new(scope,value)
        .and_then(|code|v8::Script::compile(scope, code, None))
        .and_then(|v|v.run(scope))
        .and_then(|v|v.to_string(scope))
    {
        v8_value.to_rust_string_lossy(scope)
    }else{
        "".to_string()
    }
}

fn attr_parse_or_static(scope:&mut v8::HandleScope,attr:&XmlAttr,key:&str)->String{
    let wdkey="wd:".to_owned()+key;
    if let Some(value)=attr.get(&wdkey){
        if let Ok(value)=std::str::from_utf8(value){
            crate::eval_result(scope,value)
        }else{
            "".to_owned()
        }
    }else if let Some(value)=attr.get(key){
        if let Ok(value)=std::str::from_utf8(value){
            value
        }else{
            ""
        }.to_owned()
    }else{
        "".to_owned()
    }
}