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
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::Result;
use std::fmt::{Display, Formatter};
use std::fs::File;
use std::path::PathBuf;

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Argument {
    None,
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    Bool(bool),
    String(String),
    File(RigzFile),
    Object(HashMap<String, Argument>),
    List(Vec<Argument>),
    FunctionCall(FunctionCall),
    Definition(Definition),
    Error(String),
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RigzFile {
    pub file: PathBuf,
    #[serde(skip_serializing, skip_deserializing)]
    internal: Option<File>,
}

impl RigzFile {
    pub fn file(self) -> Option<File> {
        self.internal
    }
}

impl Display for RigzFile {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "{}", self.file.to_str().unwrap_or("<invalid-utf>"))
    }
}

impl Clone for RigzFile {
    fn clone(&self) -> Self {
        let file = self.file.clone();
        if file.exists() {
            RigzFile {
                internal: Some(File::open(&file).expect("Failed to open file")),
                file,
            }
        } else {
            RigzFile {
                file,
                internal: None,
            }
        }
    }
}

impl PartialEq for RigzFile {
    fn eq(&self, other: &Self) -> bool {
        self.file == other.file
    }
}

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[repr(C)]
pub enum Definition {
    None,
    One(HashMap<String, Argument>),
    Many(Vec<Argument>),
}

impl Display for Argument {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        match self {
            Argument::None => write!(f, "none"),
            Argument::Int(i) => write!(f, "{}", i),
            Argument::Long(l) => write!(f, "{}", l),
            Argument::Float(fl) => write!(f, "{}", fl),
            Argument::Double(d) => write!(f, "{}", d),
            Argument::Bool(b) => write!(f, "{}", b),
            Argument::String(s) => write!(f, "{}", s),
            Argument::Object(o) => write!(f, "{:?}", o),
            Argument::List(l) => write!(f, "{:?}", l),
            Argument::FunctionCall(fc) => write!(f, "{:?}", fc),
            Argument::Definition(d) => write!(f, "{:?}", d),
            Argument::Error(e) => write!(f, "Error: {}", e),
            Argument::File(file) => write!(f, "{}", file),
        }
    }
}

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct FunctionCall {
    pub name: String,
    pub args: Vec<Argument>,
    pub definition: Definition,
}

#[derive(Debug, PartialEq)]
pub enum RuntimeStatus<T> {
    Ok(T),
    NotFound,
    Err(String),
}

pub trait Module {
    fn name(&self) -> &str;

    fn root(&self) -> PathBuf;

    fn function_call(
        &self,
        name: &str,
        arguments: Vec<Argument>,
        definition: Definition,
        prior_result: Argument,
    ) -> RuntimeStatus<Argument>;

    fn initialize(&self) -> RuntimeStatus<()> {
        RuntimeStatus::NotFound
    }
}